6587: SSR: Support statement matching and replacing r=davidlattimore a=MarijnS95
For #3186
Hi!
This is a smaller initial patchset that came up while working on support for statement lists (and my first time working on RA 😁). It has me stuck on trailing semicolons for which I hope to receive some feedback. Matching (and replacing) `let` bindings with a trailing semicolon works fine, but trying to omit these (to make patterns more ergonomic) turns out more complex than expected.
The "optional trailing semicolon solution" implemented in this PR is ugly because `Matcher::attempt_match_token` should only consume a trailing `;` when parsing `let` bindings to prevent other code from breaking. That at the same time has a nasty side-effect of `;` ending up in the matched code: any replacements on that should include the trailing semicolon as well even if it was not in the pattern. A better example is in the tests:
3ae1649c24/crates/ssr/src/tests.rs (L178-L184)
The end result to achieve is (I guess) allowing replacement of let bindings without trailing semicolon like `let x = $a ==>> let x = 1` (but including them on both sides is still fine), and should make replacement in a macro call (where `foo!(let a = 2;)` for a `$x:stmt` is invalid syntax) possible as well. That should allow to enable/fix these tests:
3ae1649c24/crates/ssr/src/tests.rs (L201-L214)
A possible MVP of this PR might be to drop this optional `;' handling entirely and only allow an SSR pattern/template with semicolons on either side.
Co-authored-by: Marijn Suijten <marijn@traverseresearch.nl>
Now that statements can be matched and replaced (#6587) some usecases
require expressions to be replaced with statements as well. This happens
when something that can ambiguously be an expression or statement like
`if` and loop blocks appear in the last position of a block, as trailing
expression. In this case a replacement pattern of the form `if
foo(){$a();}==>>$a();` will only substitute `if` blocks in the list of
statements but not if they (implicitly) end up in the trailing
expression, where they are not wrapped by an EXPR_STMT (but the pattern
and template are, as parsing only succeeds for the `stmt ==>> stmt`
case).
Instead of adding two rules that match an expression - and emit
duplicate matching errors - allow the template for expressions to be a
statement if it fails to parse as an expression.
7068: Add VSCode command to view the hir of a function body r=theotherphil a=theotherphil
Will fix https://github.com/rust-analyzer/rust-analyzer/issues/7061. Very rough initial version just to work out where I needed to wire everything up.
@matklad would you be happy merging a hir visualiser of some kind? If so, do you have any thoughts on what you'd like it show, and how?
I've spent very little time on this thus far, so I'm fine with throwing away the contents of this PR, but I want to avoid taking the time to make this more polished/interactive/useful only to discover that no-one else has any interest in this functionality.
![image](https://user-images.githubusercontent.com/1974256/103236081-bb58f700-493b-11eb-9d12-55ae1b870f8f.png)
Co-authored-by: Phil Ellison <phil.j.ellison@gmail.com>
7115: Migrate HasSource::source to return Option r=matklad a=nick96
I've made a start on fixing #6913 based on the provided work plan, migrating `HasSource::source` to return an `Option`. The simple cases are migrated but there are a few that I'm unsure exactly how they should be handled:
- Logging the processing of functions in `AnalysisStatsCmd::run`: In verbose mode it includes the path to the module containing the function and the syntax range. I've handled this with an if-let but would it be better to blow up here with `expect`? I'm not 100% on the code paths but if we're processing a function definition then the source should exist.
I've handled `source()` in all code paths as `None` being a valid return value but are there some cases where we should just blow up? Also, all I've done is bubble up the returned `None`s, there may be some places where we can recover and still provide something.
Co-authored-by: Nick Spain <nicholas.spain@stileeducation.com>
Co-authored-by: Nick Spain <nicholas.spain96@gmail.com>
7133: Proper handling $crate and local_inner_macros r=jonas-schievink a=edwin0cheng
This PR introduces `HygineFrames` to store the macro definition/call site hierarchy in hyginee and when resolving `local_inner_macros` and `$crate`, we use the token to look up the corresponding frame and return the correct value.
See also: https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies
fixe #6890 and #6788
r? @jonas-schievink
Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
7130: Add extract_assignment assist r=Jesse-Bakker a=Jesse-Bakker
Add extract-assignment assist (#7006).
Assist is for now only implemented on if/match-statements where the assigment is the last statement in every block,
as for other cases, one would have to check whether the assignment has effects on the rest of the block and
extract a temporary variable for it in the block.
Co-authored-by: Jesse Bakker <github@jessebakker.com>
The `LifetimeParam` and `Local` variants use `source()` to find their
range. Now that `source()` returns an `Option` we need to handle the
`None` case.
In #6901 some special case handling for proc-macros was introduced to
prevent panicing as they have no AST. Now the new HasSource::source
method is used that returns an option.
Generally this was a pretty trivial change, the only thing of much
interest is that `hir::MacroDef` now implements `TryToNav` not `ToNav`
as this allows us to handle `HasSource::source` now returning an option.
Added the error message to the doc for the UnresolvedProcMacro
diagnostic, explaining that either enabling the procMacro setting
or disabling this diagnostic should make the warnings go away.
7116: Fix deep syntax tree bug generated by proc-macro r=jonas-schievink a=edwin0cheng
This PR fixed a bug from `semver-parser` and `pest_derive` crates which generate a very deep syntax tree such that serde reject to de-serialize. To fix this bug, we disabled recursion limit in `serde` (by calling [`Deserializer::disable_recursion_limit`](https://docs.rs/serde_json/1.0.61/serde_json/struct.Deserializer.html#method.disable_recursion_limit))
I have a feeling that we still need some way to protect against bad proc-macro generating huge syntax node, but I have no idea right now.
r? @jonas-schievink
Fixes#7103
Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
7102: Fix completion of Default struct update syntax r=Veykril a=nick96
Previously the inserted text was always `..Default::default()` which ends up as `...Default::default()`
if `.` was typed. Now checks if the current token is `.` and inserts `.Default::default()`
if it is, so `..Default::default()` is correctly completed.
I think there's probably a better way to implement this context aware completion because I've seen it in other parts of rust-analyzer as a user but I'm not sure how to do it.
Fixes#6969
Co-authored-by: Nick Spain <nicholas.spain@stileeducation.com>
7071: Pass --all-targets to "cargo check" when discovering external resources r=matklad a=WasabiFan
There is a repro case and background in the linked issue.
In short, the goal of this MR is to allow rust-analyzer to discover proc-macros which come from your tests (including, most importantly, dev-dependencies).
By default, `cargo check` implies the equivalent of `--lib --bins`, meaning it'll check your libraries and binaries -- but not tests! This means proc-macros (or, I guess, build scripts as well) weren't discovered by rust-analyzer if they came from tests.
One solution would be to manually add `--lib --bins --tests` (i.e., just augment the effective options to include tests). However, in this MR, I threw in `--all-targets`, which [according to the docs](https://doc.rust-lang.org/cargo/commands/cargo-check.html#target-selection) implies `--benches --examples` too. I have absolutely no idea what repercussions that will have on rust-analyzer for other projects, nor do I know if it's a problem that build scripts will now be discovered for tests/examples/benches. But I am not aware of a reason you _wouldn't_ want to discover these things in your examples too.
I think the main drawback of this change is that it will likely slow down the `cargo check`. At a minimum, it'll now be checking your tests _and_ their dependencies. The `cargo check` docs also say that including `--tests` as I have here may cause your lib crate to be built _twice_, once for the normal target and again for unit tests. My reading of that caveat suggests that "building twice" means it's built once for the tests _inside_ your lib, with a test profile, and again for any consumers of your lib, now using a normal release profile or similar. This doesn't seem surprising.
Very minor caveat: `--tests` will not include tests within a binary if it has `test = false` set in `Cargo.toml`. (I discovered this manually by trial-and-error, but hey, it actually says that in the docs!) This is likely not an issue, but _does_ mean that if you are -- for whatever reason -- disabling tests like that and then manually specifying `cargo test --package <...> --bin <...>` to run them, rust-analyzer will remain unaware of proc-macros in your tests.
I have confirmed this fixes the original issue in my sandbox example linked in #7034 and in my own project in which I originally discovered this. I've left it configured as my default RA language server and will report back if I notice any unexpected side-effects.
Fixes#7034
Co-authored-by: Kaelin Laundry <wasabifan@outlook.com>
In an attempt to fix#6052 and #4249 this attempts to detect
if rustfmt is a rustup proxy which isn't installed, and reports
the error message to the user for them to fix.
In theory this ought to be memoised but for now it'll do as-is.
Future work might be to ask the user if they would like us to
trigger the installation (if possible).
Signed-off-by: Daniel Silverstone <dsilvers@digital-scurf.org>
Previously the inserted text was always `..Default::default()` which ends up as `...Default::default()`
if `.` was typed. Now checks if the current token is `.` and inserts `.Default::default()`
if it is, so `..Default::default()` is correctly completed.
Fixes#6969
7083: Refactor mbe parsing code r=edwin0cheng a=edwin0cheng
Inspire by #5426 , this PR refactor out the parsing code such that it only parsed on `mbe::Rule`, but not on invocations.
However, it just improve the overall performance unnoticeablely :(
Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
7064: Ignore qualifiers when doing autoimport completions lookup r=lnicola a=SomeoneToIgnore
A follow-up of https://github.com/rust-analyzer/rust-analyzer/pull/6918#issuecomment-748511151 and the PR itself.
Tweaks the `import_map` query api to be more flexible with the ways to match against the import path and now fuzzy imports search in names only.
This had improved the completion speed for me locally in ~5 times for `fuzzy_completion` span time, but please recheck me here.
IMO we're fast and presice enough now, so I've added the modules back to the fuzzy search output.
Also tweaks the the expect tests to display functions explicitly, to avoid confusing "duplicate" results.
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>