Description
Environment
- IntelliJ Rust plugin version: 0.4.181.4920-222-nightly
- Rust toolchain version: 1.64.0 (a55dd71d5 2022-09-19) x86_64-unknown-linux-gnu
- IDE name and version: CLion 2022.2.3 (CL-222.4167.35)
- Operating system: Linux 5.4.0-126-generic
- Macro expansion: enabled
- Additional experimental features: org.rust.cargo.features.settings.gutter, org.rust.cargo.emulate.terminal, org.rust.cargo.evaluate.build.scripts, org.rust.macros.proc
Suggestion
Find Usages is currently very limited on large projects, since many natural categories of usages are lacking. I propose the following additions:
-
For traits, add usage categories
- Trait objects (
dyn Trait
usages) - Implementations (
impl Trait for Foo
) - Trait bounds (
foo<T1, T2: Trait>(x: impl Trait) where T1: Trait
, as well as bounds on generics parameters and associated types). - Opaque types (
foo(_: impl Trait) -> impl Trait
, as well asimpl Trait
in type aliases and nested types). - Supertrait (
trait T: Trait
).
- Trait objects (
-
For structs, there are ostensibly many categories (although some don't make sense, what the hell is "dot expr"?). However, in practice the categorization is very incoherent, and the same type of expression appear to be dumped in different categories ostensibly at random. Also, almost all usages are dumped in the catch-all "type reference" category. For example, searching for
std::option::Option
in all of my dependencies gives me the following category counts:- Unclassified - 7
- argument - 20
- dot expr - 2
- expr - 3
- function call - 17
- impl - 82
- type reference - 10 235 (sic!)
- use - 22
This is plain useless. The only categories which seem to work as indended are impl and use. type_reference is just a dump which can't meaningfully be analyzed, and the others contain expressions likeOption::from
in all of them.
I propose the following categories:
- impl - as above,
impl Trait for Type
. - use - as above, all
use foo::Type
andpub use bar::Type
statements. - inherent method calls - all calls of inherent methods on
Type
. - trait method calls - all calls of trait methods on
Trait
. We separate it from inherent methods, since the set of inherent methods is closed (only in the declaring crate) and usually small, while anyone can add trait methods. - usage in return type -
foo() -> Struct
- usage in argument type -
foo(_: Struct)
. We separate return and argument position, since they are quite different from the PoV of an API consumer. One is the way to use a type, while the other is a way to construct it. Include type in nested positions (foo(_: Box<Struct>) -> Vec<Struct>
), because they are part of the same use-vs-create paradigm. - field type -
struct Foo { a: Struct }
,struct Foo(Struct)
, and same with enums and unions. As above, we include type in nested position. - associated type -
impl Trait for Foo { type T = Struct; }
, and also default associated types (unstable). - type aliases -
type Foo = Struct
. This includes inherent type aliases on types (unstable,impl Foo { type Bar = Struct; }
). This is different from associated types, even though the syntax is similar. Associated types are more widely used, and they have semantic meaning (the return value of a type-level function corresponding to a trait), while type aliases are just a convenient name for a more complex type, and are semantically equivalent to that type. - trait bounds -
.. where Struct: Trait
. This is an uncommon usage, since the trait bounds are usually placed directly on generic parameters (e.g.T: Trait
rather thanOption<T>: Trait
), but it is allowed by the language and is occasionally useful. For example, look at the trait bounds infutures
crate. It would be more widely used ifchalk
was stable, since the current trait resolution hits critical bugs for more complex types in where-clauses. - qualified paths -
Struct::foo
. Note that it's separate from methods, which don't explicitly mention the type. - type ascription -
let x: Struct = ...;
. Note that type ascription expressions were removed from the language, so only let-bindings need to be searched. - expression generic parameters -
foo::<Struct>()
. - literal expressions -
Struct { a: 3, b: 4 }
,Enum::Variant
. - All other usages. This will likely be small.
-
It should be possible to select the required usage categories from the "Find Usages" dialogue. If I'm only interested in trait impls, there is no point in dumping all other usages on me. This also saves time and memory when dealing with huge number of usages (like for
std
types).