rust-analyzer/crates
bors 2025b43653 Auto merge of #17927 - ChayimFriedman2:speedup-new-usages, r=Veykril
perf: Speed up search for short associated functions, especially very common identifiers such as `new`

`@Veykril` said in https://github.com/rust-lang/rust-analyzer/pull/17908#issuecomment-2292958068 that people complain searches for `new()` are slow (they are right), so here I am to help!

The search is used by IDE features such as rename and find all references.

The search is slow because we need to verify each candidate, and that requires analyzing it; the key to speeding it up is to avoid the analysis where possible.

I did that with a bunch of tricks that exploits knowledge about the language and its possibilities. The first key insight is that associated methods may only be referenced in the form `ContainerName::func_name` (parentheses are not necessary!) (Rust doesn't include a way to `use Container::func_name`, and even if it will in the future most usages are likely to stay in that form.

Searching for `::` will help only a bit, but searching for `Container` can help considerably, since it is very rare that there will be two identical instances of both a container and a method of it.

However, things are not as simple as they sound. In Rust a container can be aliased in multiple ways, and even aliased from different files/modules. If we will try to resolve the alias, we will lose any gain from the textual search (although very common method names such as `new` will still benefit, most will suffer because there are more instances of a container name than its associated item).

This is where the key trick enters the picture. The key insight is that there is still a textual property: a container namer cannot be aliased, unless its name is mentioned in the alias declaration, or a name of alias of it is mentioned in the alias declaration.

This becomes a fixpoint algorithm: we expand our list of aliases as we collect more and more (possible) aliases, until we eventually reach a fixpoint. A fixpoint is not guaranteed (and we do have guards for the rare cases where it does not happen), but it is almost so: most types have very few aliases, if at all.

We do use some semantic information while analyzing aliases. It's a balance: too much semantic analysis, and the search will become slow. But too few of it, and we will bring many incorrect aliases to our list, and risk it expands and expands and never reach a fixpoint. At the end, based on benchmarks, it seems worth to do a lot to avoid adding an alias (but not too much), while it is worth to do a lot to avoid the need to semantically analyze func_name matches (but again, not too much).

After we collected our list of aliases, we filter matches based on this list. Only if a match can be real, we do semantic analysis for it.

The results are promising: searching for all references on `new()` in `base-db` in the rust-analyzer repository, which previously took around 60 seconds, now takes as least as two seconds and a half (roughly), while searching for `Vec::new()`, almost an upper bound to how much a symbol can be used, that used to take 7-9 minutes(!) now completes in 100-120 seconds, and with less than half of non-verified results (aka. false positives).

This is the less strictly correct (but faster) branch of this patch; it can miss some (rare) cases (there is a test for that - `goto_ref_on_short_associated_function_complicated_type_magic_can_confuse_our_logic()`). There is another branch that have no false negatives but is slower to search (`Vec::new()` never reaches a fixpoint in aliases collection there). I believe it is possible to create a strategy that will have the best of both worlds, but it will involve significant complexity and I didn't bother, especially considering that in the vast majority of the searches the other branch will be more than enough. But all in all, I decided to bring this branch (of course if the maintainers will agree), since our search is already not 100% accurate (it misses macros), and I believe there is value in the additional perf.

You can find the strict branch at https://github.com/ChayimFriedman2/rust-analyzer/tree/speedup-new-usages-strict.

Should fix #7404, I guess (will check now).
2024-08-23 09:17:47 +00:00
..
base-db Remove unnecessary CfgFlag definition in project-model 2024-08-07 14:27:59 +02:00
cfg Remove unnecessary CfgFlag definition in project-model 2024-08-07 14:27:59 +02:00
hir When descending into macros in search, first check if there is a need to - i.e. if we are inside a macro call 2024-08-22 20:52:51 +03:00
hir-def Auto merge of #17905 - ChayimFriedman2:edition-dependent-raw-keyword, r=Veykril 2024-08-16 13:49:32 +00:00
hir-expand Improve proc-macro panic message and workspace loading failure diagnostic 2024-08-22 18:46:23 +02:00
hir-ty Implement floating point casts in const eval 2024-08-22 09:16:00 -04:00
ide Add cov_marks to test #17927 2024-08-22 20:52:51 +03:00
ide-assists Fully remove old macro descension API 2024-08-22 16:18:01 +02:00
ide-completion Auto merge of #17905 - ChayimFriedman2:edition-dependent-raw-keyword, r=Veykril 2024-08-16 13:49:32 +00:00
ide-db Add cov_marks to test #17927 2024-08-22 20:52:51 +03:00
ide-diagnostics Auto merge of #17905 - ChayimFriedman2:edition-dependent-raw-keyword, r=Veykril 2024-08-16 13:49:32 +00:00
ide-ssr Properly account for editions in names 2024-08-16 16:46:24 +03:00
intern Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
limit Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
load-cargo Auto merge of #17864 - Veykril:lsif, r=Veykril 2024-08-12 12:34:31 +00:00
mbe Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
parser Properly account for editions in names 2024-08-16 16:46:24 +03:00
paths Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
proc-macro-api Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
proc-macro-srv Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
proc-macro-srv-cli Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
profile Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
project-model Improve documentation for InvocationStrategy 2024-08-19 14:23:05 +02:00
rust-analyzer Auto merge of #17912 - alibektas:cargo_check_on_binary, r=Veykril 2024-08-23 09:03:11 +00:00
salsa Fix and enable unsafe_op_in_unsafe_fn 2024-07-25 08:41:30 +03:00
span Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
stdx Use crossbeam-channel from the workspace 2024-08-09 23:48:03 +02:00
syntax Pin rowan to 0.15.15 2024-08-17 21:35:07 +09:00
syntax-bridge Properly account for editions in names 2024-08-16 16:46:24 +03:00
test-fixture Newtype ErasedFileAstId 2024-08-05 13:46:47 +02:00
test-utils Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
text-edit Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
toolchain Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
tt Replace [package.repository] = "…" of published crates with [package.repository.workspace] = true 2024-08-06 00:26:42 +02:00
vfs Remove the ability to configure the user config path 2024-08-19 15:12:33 +02:00
vfs-notify Auto merge of #17843 - mo8it:flycheck, r=Veykril 2024-08-12 09:27:47 +00:00