fix: Fix resolution of label inside macro
When working on Something Else (TM) (I left a hint in the commits :P), I noticed to my surprise that labels inside macros are not resolved. This led to a discovery of *two* unrelated bugs, which are hereby fixed in two commits.
This fixes a bug where labels inside macros were not resolved, but more importantly this prepares us to a future where we have hygiene, and textual equivalence isn't enough to resolve identifiers.
internal: Send less data during `textDocument/completion` if possible
Similar to https://github.com/rust-lang/rust-analyzer/pull/15522, stops sending extra data during `textDocument/completion` if that data was set in the client completions resolve capabilities, and sends those only during `completionItem/resolve` requests.
Currently, rust-analyzer sends back all fields (including potentially huge docs) for every completion item which might get large.
Same as the other one, this PR aims to keep the changes minimal and does not remove extra computations for such fields — instead, it just filters them out before sending to the client.
The PR omits primitive, boolean and integer, types such as `deprecated`, `preselect`, `insertTextFormat`, `insertTextMode`, etc. AND `additionalTextEdits` — this one looks very dangerous to compute for each completion item (as the spec says we ought to if there's no corresponding resolve capabilities provided) due to the diff computations and the fact that this code had been in the resolution for some time.
It would be good to resolve this lazily too, please let me know if it's ok to do.
When tested with Zed which only defines `documentation` and `additionalTextEdits` in its client completion resolve capabilities, rust-analyzer starts to send almost 3 times less characters:
Request:
```json
{"jsonrpc":"2.0","id":104,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///Users/someonetoignore/work/rust-analyzer/crates/ide/src/inlay_hints.rs"},"position":{"line":90,"character":14},"context":{"triggerKind":1}}}
```
<img width="1338" alt="image" src="https://github.com/user-attachments/assets/104f19b5-7095-4fc1-b008-5d829623b2e2">
Before: 381944 characters
[before.json](https://github.com/user-attachments/files/17092385/before.json)
After: 140503 characters
[after.json](https://github.com/user-attachments/files/17092386/after.json)
After Zed's [patch](https://github.com/zed-industries/zed/pull/18212) to enable all resolving possible: 84452 characters
[after-after.json](https://github.com/user-attachments/files/17092755/after-after.json)
fix: Ambiguity with CamelCase diagnostic messages, align with rustc warnings
Fixed diagnostic messages so they say UpperCamelCase rather than CamelCase, as it is ambiguous.
Usually I'd call it PascalCase, but in the code base it is called UpperCamelCase so I left it with that naming choice.
`rustc` says `upper camel case` also when the case is wrong
```
warning: trait `testThing` should have an upper camel case name
--> src/main.rs:5:7
|
5 | trait testThing {
| ^^^^^^^^^ help: convert the identifier to upper camel case: `TestThing`
|
= note: `#[warn(non_camel_case_types)]` on by default
```
This is in line with the UPPER_SNAKE_CASE diagnostic messages.
546339a7be/crates/hir-ty/src/diagnostics/decl_check.rs (L60)546339a7be/crates/ide-diagnostics/src/handlers/incorrect_case.rs (L535)
This will mean users opting to not activate `cfg(test)` will lose IDE experience on them, which is quite unfortunate, but this is unavoidable if we want to avoid false positives on e.g. diagnostics. The real fix is to provide IDE experience even for cfg'ed out code, but this is out of scope for this PR.
Rename object_safety
First PR here (yay!), so I read some of the getting started docs. There are a couple references to `handlers.rs`, which as far as I can tell has been refactored into `handlers/*.rs`. I made some tweaks to that in one commit. There is one fixme about a function called `to_lsp_runnable`, which I can't find anywhere at all. I can update that if I get some more info there.
Otherwise I changed references to object safety, is object safe, etc., trying to match case/style as I went. There was one case I found where there's a trait from somewhere else called `is_object_safe`, which I found defined in my cargo registry. I didn't touch that for now, just marked it with a fixme
Include buildfiles in VFS
We subscribe to `textDocument/didSave` for `filesToWatch`, but the VFS doesn't contain those files. Before https://github.com/rust-lang/rust-analyzer/pull/18105, this would bring down the server. Now, it's only a benign error logged:
```
ERROR notification handler failed handler=textDocument/didSave error=file not found: /foo/bar/TARGETS
```
It's benign, because we will also receive a `workspace/didChangeWatchedFiles` for the file which will invalidate and load it.
Explicitly include the buildfiles in the VFS to prevent the handler from erroring.
internal: Add `SyntaxFactory` to ease generating nodes with syntax mappings
Part of [#15710](https://github.com/rust-lang/rust-analyzer/issues/15710)
Instead of requiring passing a `&mut SyntaxEditor` to every make constructor to generate mappings, we instead wrap that logic in `SyntaxFactory`, and afterwards add all the mappings to the `SyntaxEditor`.
Includes an example of using `SyntaxEditor` & `SyntaxFactory` in the `extract_variable` assist.
minor: Stricter requirements for package wide flycheck
Require the existence of a target and `check_workspace` to be false to restart package-wide flycheck. Fixes#18194 , #18104
Previously, r-a would show an error if both fetch_workspaces_queue and
discover_workspace_queue were empty. We're in this state at startup,
so users would see an error if they'd configured
discover_workspace_config.
Instead, allow the fetch_workspaces_queue to have zero items if
discover_workspace_config is set.
Whilst we're here, prefer "failed to fetch" over "failed to discover",
so the error message better reflects what this function is doing.
feat: Index workspace symbols at startup rather than on the first symbol search.
This will eliminate potential many-second delays when performing the first search, at the price of making cache priming (“Indexing N/M” in the VS Code status bar) take a little longer in total. Hopefully this additional time is insignificant because a typical session will involve at least one symbol search.
Further improvement would be to do this as a separate parallel task (which will be beneficial if the workspace contains a small number of large crates), but that would require significant additional refactoring of the progress-reporting mechanism to understand multiple tasks per crate. Happy to tackle that in this PR if desired, but I thought I'd propose the minimal change first.
internal: add tracing to project discovery and VFS loading
With `"env RA_PROFILE=vfs_load|parallel_prime_caches|discover_command>500`, this results in the following output:
```
21888ms discover_command
11627ms vfs_load @ total = 701
1503ms vfs_load @ total = 701
30211ms parallel_prime_caches
```
As a followup, I'd like to make hprof emit the information above as JSON.
fix: Fix a bug in span map merge, and add explanations of how span maps are stored
Because it took me hours to figure out that contrary to common sense, the offset stored is the *end* of the node, and we search by the *start*. Which is why we need a convoluted `partition_point()` instead of a simple `binary_search()`. And this was not documented at all. Which made me make mistakes with my implementation of `SpanMap::merge()`.
The other bug fixed about span map merging is correctly keeping track of the current offset in presence of multiple sibling macro invocations. Unrelated, but because of the previous issue it took me hours to debug, so I figured out I'll put them together for posterity.
Fixes#18163.
fix: Fix name resolution when an import is resolved to some namespace and then later in the algorithm another namespace is added
The import is flagged as "indeterminate", and previously it was re-resolved, but only at the end of name resolution, when it's already too late for anything that depends on it.
This issue was tried to fix in https://github.com/rust-lang/rust-analyzer/pull/2466, but it was not fixed fully.
That PR is also why IDE features did work: the import at the end was resolved correctly, so IDE features that re-resolved the macro path resolved it correctly.
I was concerned about the performance of this, but this doesn't seem to regress `analysis-stats .`, so I guess it's fine to land this. I have no idea about the incremental perf however and I don't know how to measure that, although when typing in `zbus` (including creating a new function, which should recompute the def map) completion was fast enough.
I didn't check what rustc does, so maybe it does something more performant, like keeping track of only possibly problematic imports.
Fixes#18138.
Probably fixes#17630.
analysis-stats: respect `--disable-proc-macros` flag
I noticed that this flag wasn't being respected by `analysis-stats` when profiling proc macro expansion, so here's a small fix.
internal: Make COMPLETION_MARKER more explicitly r-a
If a user ever sees the completion marker, it's confusing to see text about IntelliJ. Use a string that's more explicitly about completion for rust-analyzer.
If a user ever sees the completion marker, it's confusing to see text
about IntelliJ. Use a string that's more explicitly about completion
for rust-analyzer.
Because it took me hours to figure out that contrary to common sense, the offset stored is the *end* of the node, and we search by the *start*. Which is why we need a convoluted `partition_point()` instead of a simple `binary_search()`. And this was not documented at all. Which made me make mistakes with my implementation of `SpanMap::merge()`.
The other bug fixed about span map merging is correctly keeping track of the current offset in presence of multiple sibling macro invocations. Unrelated, but because of the previous issue it took me hours to debug, so I figured out I'll put them together for posterity.
The import is flagged as "indeterminate", and previously it was re-resolved, but only at the end of name resolution, when it's already too late for anything that depends on it.
This issue was tried to fix in https://github.com/rust-lang/rust-analyzer/pull/2466, but it was not fixed fully.
feat: Support the `${concat(...)}` metavariable expression
I didn't follow rustc precisely, because I think it does some things wrongly (or they are FIXME), but I only allowed more code, not less. So we're all fine.
Closes#18145.
fix: Handle lint attributes that are under `#[cfg_attr]`
I forgot `cfg_attr` while working on #18099. Although the original code also didn't handle that (although case lints specifically were correct, by virtue of using hir attrs).
I didn't follow rustc precisely, because I think it does some things wrongly (or they are FIXME), but I only allowed more code, not less. So we're all fine.
fix: Remove check that text of `parse_expr_from_str()` matches the produced parsed tree
This check is incorrect when we have comments and whitespace in the text.
We can strip comments, but then we still have whitespace, which we cannot strip without changing meaning for the parser. So instead I opt to remove the check, and wrap the expression in parentheses (asserting what produced is a parenthesized expression) to strengthen verification.
Fixes#18144.
This check is incorrect when we have comments and whitespace in the text.
We can strip comments, but then we still have whitespace, which we cannot strip without changing meaning for the parser. So instead I opt to remove the check, and wrap the expression in parentheses (asserting what produced is a parenthesized expression) to strengthen verification.
fix: Get rid of `$crate` in expansions shown to the user
Be it "Expand Macro Recursively", "Inline macro" or few other things.
We replace it with the crate name, as should've always been.
Probably fixes some issues, but I don't know what they are.
fix: Extend `type_variable_table` when modifying index is larger than the table size
Fixes#18109
Whenever we create an inference variable in r-a, we extend `type_variable_table` to matching size here;
f4aca78c92/crates/hir-ty/src/infer/unify.rs (L378-L381)
But sometimes, an inference variable is [created from chalk](ab710e0c9b/chalk-solve/src/infer/unify.rs (L743)) and passed to r-a as a type of an expression or a pattern.
If r-a set diverging flag to this before the table is extended to a sufficient size, it panics here;
f4aca78c92/crates/hir-ty/src/infer/unify.rs (L275-L277)
I think that extending table when setting diverging flag is reasonable becase we are already doing such extending to a size that covers the inference vars created from chalk and this change only covers the order-dependent random cases that this might fail
fix: Always cache macro expansions' root node in Semantics
Previously some expansions were not cached, but were cached in the expansion cache, which caused panics when later queries tried to lookup the node from the expansion cache.
Fixes#18089.
fix: Handle errors and lints from external macros
Some lints should not be reported if they originate from an external macro, and quickfixes should be disabled (or they'll change library code).
Fixes#18122.
Closes#18124.
Don't lint names of #[no_mangle] extern fns
[Rust doesn't run the `non_snake_case_name` lint on `extern fn`s with the `#[no_mangle]` attribute](https://github.com/rust-lang/rust/pull/44966).
The conditions are:
- The function must be `extern` and have a `#[no_mangle]` attribute.
- The function's ABI must not be explicitly set to "Rust".
This PR replicates that logic here.
Previously some expansions were not cached, but were cached in the expansion cache, which caused panics when later queries tried to lookup the node from the expansion cache.
Use more correct handling of lint attributes
The previous analysis was top-down, and worked on a single file (expanding macros). The new analysis is bottom-up, starting from the diagnostics and climbing up the syntax and module tree.
While this is more efficient (and in fact, efficiency was the motivating reason to work on this), unfortunately the code was already fast enough. But luckily, it also fixes a correctness problem: outline parent modules' attributes were not respected for the previous analysis. Case lints specifically did their own analysis to accommodate that, but it was limited to only them. The new analysis works on all kinds of lints, present and future.
It was basically impossible to fix the old analysis without rewriting it because navigating the module hierarchy must come bottom-up, and if we already have a bottom-up analysis (including syntax analysis because modules can be nested in other syntax elements, including macros), it makes sense to use only this kind of analysis.
Few other bugs (not fundamental to the previous analysis) are also fixed, e.g. overwriting of lint levels (i.e. `#[allow(lint)] mod foo { #[warn(lint)] mod bar; }`.
After this PR is merged I intend to work on an editor command that does workspace-wide diagnostics analysis (that is, `rust-analyzer diagnostics` but from your editor and without having to spawn a new process, which will have to analyze the workspace from scratch). This can be useful to users who do not want to enable check on save because of its overhead, but want to see workspace wide diagnostics from r-a (or to maintainers of rust-analyzer).
Closes#18086.
Closes#18081.
Fixes#18056.
The previous analysis was top-down, and worked on a single file (expanding macros). The new analysis is bottom-up, starting from the diagnostics and climbing up the syntax and module tree.
While this is more efficient (and in fact, efficiency was the motivating reason to work on this), unfortunately the code was already fast enough. But luckily, it also fixes a correctness problem: outline parent modules' attributes were not respected for the previous analysis. Case lints specifically did their own analysis to accommodate that, but it was limited to only them. The new analysis works on all kinds of lints, present and future.
It was basically impossible to fix the old analysis without rewriting it because navigating the module hierarchy must come bottom-up, and if we already have a bottom-up analysis (including syntax analysis because modules can be nested in other syntax elements, including macros), it makes sense to use only this kind of analysis.
Few other bugs (not fundamental ti the previous analysis) are also fixed, e.g. overwriting of lint levels (i.e. `#[allow(lint)] mod foo { #[warn(lint)] mod bar; }`.
feat: generate names for tuple-struct in add-missing-match-arms
fix#18034.
This PR includes the following enhancement:
- Introduced a `NameGenerator` in `suggest_name`, which implements an automatic renaming algorithm to avoid name conflicts. Here are a few examples:
```rust
let mut generator = NameGenerator::new();
assert_eq!(generator.suggest_name("a"), "a");
assert_eq!(generator.suggest_name("a"), "a1");
assert_eq!(generator.suggest_name("a"), "a2");
assert_eq!(generator.suggest_name("b"), "b");
assert_eq!(generator.suggest_name("b"), "b1");
assert_eq!(generator.suggest_name("b2"), "b2");
assert_eq!(generator.suggest_name("b"), "b3");
assert_eq!(generator.suggest_name("b"), "b4");
assert_eq!(generator.suggest_name("b3"), "b5");
```
- Updated existing testcases in ide-assists for the new `NameGenerator` (only modified generated names).
- Generate names for tuple structs instead of using wildcard patterns in `add-missing-match-arms`.
fix: Faulty notifications should not bring down the server
Fixes https://github.com/rust-lang/rust-analyzer/issues/18055, if a client sends us an unregistered document path in a did save notification it would force us to exit the thread. That is obviously not great behavior, we should be more fallible here
feat: render patterns in params for hovering
Fix#17858
This PR introduces an option to [hir-def/src/body/pretty.rs](08c7bbc2db/crates/hir-def/src/body/pretty.rs) to render the result as a single line, which is then reused for rendering patterns in parameters for hovering.
internal: Better testing infra for ratoml
This PR makes some improvements on how we test configs that come from `rust-analyzer.toml` files.
It was primarily used to solve #18021 but along the way I could not really determine the cause of the said issue which makes me think that it may not be related to the changes that I made earlier to the ratoml infra. In either way `custom_snippets` are now made `global` because we still don't have a tree that maps a `SourceRootId` to a set of `Snippet`s.
fix: Fix `inline_const_as_literal` error when the number >= 10
## Description
### The Bug
This PR fixes a small bug in the IDE assistence (`inline_const_as_literal`). When the being-inlined constant is a number and it is greater than or equal to 10, the assistence inserts unexpected string `(0x...)` after the number itself. A simple example is followed:
Current `inline_const_as_literal` changes
```rs
const A: usize = 16;
fn f() -> usize {
A // inline the constant
}
```
into
```rs
const A: usize = 16;
fn f() -> usize {
16 (0x10)
}
```
The bug originates from #14925 & #15306 . #14925 added some unittests, but it just tested the number-inlining behavior when the number is `0`.
50882fbfa2/crates/ide-assists/src/handlers/inline_const_as_literal.rs (L124-L138)
And #15306 modified the behavior of `Const::render_eval` and added the `(0x...)` part after the number (if the number >= `10`). Because of insufficient unittests in #14925, changes about `Const::render_eval` in #15306 introduced this bug with no CI failure.
### The Fix
I think `Const::render_eval` is intended for user-facing value displaying (e.g. hover) and not designed for `inline_const_as_literal`. To fix the bug, I defined a new function named `Const::eval`, which evaluates the value itself faithfully and simply and does nothing else.
## Thanks
Thanks `@roife` for your kind help. Your guidance helped me better understand the code.
feat: Automatically add semicolon when completing unit-returning functions
But provide a config to suppress that.
I didn't check whether we are in statement expression position, because this is hard in completion (due to the natural incompleteness of source code when completion is invoked), and anyway using function returning unit as an argument to something seems... dubious.
Fixes#17263.
assist: ensure `replace_qualified_name_with_use` applies to the first path segment
This change helps a bit with the discoverability of `replace_qualified_name_with_use`. Specifically, it ensures that a cursor on the first path segment (e.g., `$0std::fmt::Debug`, where `$0` is the cursor) would result in an import along the lines of `use std::fmt;` and `fmt::Debug;` at the usage sites.
Skip checks for cast to dyn traits
It seems that chalk fails to solve some obvious goals when there are some recursiveness in trait environments.
And it doesn't support trait upcasting yet. rust-lang/chalk#796
This PR just skips for casting into types containing `dyn Trait` to prevent false positive diagnostics like #18047 and #18083
This is a small change, but it was the cause of 90% of the errors in `rust-analyzer diagnostics .` 🫢
With this change and #18085 together, all remaining errors are type errors.
This may mean we can enable more errors, but this is out of scope for this PR.
internal: Add preliminary `SyntaxEditor` functionality
Related to #15710
Implements a `SyntaxEditor` interface to abstract over the details of modifying syntax trees, to both simplify creating new code fixes and code actions, as well as start on the path of getting rid of mutable syntax nodes.
`SyntaxEditor` relies on `SyntaxMappingBuilder`s to feed in the correct information to map AST nodes created by `make` constructors, as `make` constructors do not guarantee that node identity is preserved. This is to paper over the fact that `make` constructors simply re-parse text input instead of building AST nodes from the ground up and re-using the provided syntax nodes.
`SyntaxAnnotation`s are used to find where syntax elements have ended up after edits are applied. This is primarily useful for the `add_{placeholder,tabstop}` set of methods on `SourceChangeBuilder`, as that currently relies on the nodes provided being in the final syntax tree.
Eventually, the goal should be to move this into the `rowan` crate when we move away from mutable syntax nodes, but for now it'll stay in the `syntax` crate.
---
Closes#14921 as `SyntaxEditor` ensures that all replace changes are disjoint
Closes#9649 by implementing `SyntaxAnnotation`s
feat: better name suggestions for fn
fix#17631.
Better name suggestions for fn-calls / method-calls in the form of `from()`, `from_xxx()`, `into()`, etc.
But provide a config to suppress that.
I didn't check whether we are in statement expression position, because this is hard in completion (due to the natural incompleteness of source code when completion is invoked), and anyway using function returning unit as an argument to something seems... dubious.
`linkedProjects` is owned by the user's configuration, so when users
update this setting, `linkedProjects` is reset. This is problematic when
`linkedProjects` also contains projects discovered with `discoverCommand`.
The buggy behaviour occurred when:
(1) The user configures `discoverCommand` and loads a Rust project.
(2) The user changes any setting in VS Code, so rust-analyzer receives
`workspace/didChangeConfiguration`.
(3) `handle_did_change_configuration` ultimately calls
`Client::apply_change_with_sink()`, which updates `config.user_config`
and discards any items we added in `linkedProjects`.
Instead, separate out `discovered_projects_from_filesystem` and
`discovered_projects_from_command` from user configuration, so user
settings cannot affect any type of discovered project.
This fixes the subtle issue mentioned here:
https://github.com/rust-lang/rust-analyzer/pull/17246#issuecomment-2185259122