diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-07-24 13:46:55 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-07-24 13:46:55 +0100 |
commit | c3defe2532ba6ffd12a13bcbc8fdeda037665efc (patch) | |
tree | 831bf4dd44ec83d927face4ba17e57dcdeab7fbe /crates/ra_ide/src/ssr.rs | |
parent | 0e5095d3cac11d4b569c6e1594bd07937556c812 (diff) | |
parent | 58680cb08ea535e1fb567416fa3466a744a01b99 (diff) |
Merge #5518
5518: Use resolved paths in SSR rules r=matklad a=davidlattimore
The main user-visible changes are:
* SSR now matches paths based on whether they resolve to the same thing instead of whether they're written the same.
* So `foo()` won't match `foo()` if it's a different function `foo()`, but will match `bar::foo()` if it's the same `foo`.
* Paths in the replacement will now be rendered with appropriate qualification for their context.
* For example `foo::Bar` will render as just `Bar` inside the module `foo`, but might render as `baz::foo::Bar` from elsewhere.
* This means that all paths in the search pattern and replacement template must be able to be resolved.
* It now also matters where you invoke SSR from, since paths are resolved relative to wherever that is.
* Search now uses find-uses on paths to locate places to try matching. This means that when a path is present in the pattern, search will generally be pretty fast.
* Function calls can now match method calls again, but this time only if they resolve to the same function.
Co-authored-by: David Lattimore <[email protected]>
Diffstat (limited to 'crates/ra_ide/src/ssr.rs')
-rw-r--r-- | crates/ra_ide/src/ssr.rs | 35 |
1 files changed, 20 insertions, 15 deletions
diff --git a/crates/ra_ide/src/ssr.rs b/crates/ra_ide/src/ssr.rs index b3e9e5dfe..95d8f79b8 100644 --- a/crates/ra_ide/src/ssr.rs +++ b/crates/ra_ide/src/ssr.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use ra_db::SourceDatabaseExt; | 1 | use ra_db::FilePosition; |
2 | use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; | 2 | use ra_ide_db::RootDatabase; |
3 | 3 | ||
4 | use crate::SourceFileEdit; | 4 | use crate::SourceFileEdit; |
5 | use ra_ssr::{MatchFinder, SsrError, SsrRule}; | 5 | use ra_ssr::{MatchFinder, SsrError, SsrRule}; |
@@ -11,6 +11,19 @@ use ra_ssr::{MatchFinder, SsrError, SsrRule}; | |||
11 | // A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement. | 11 | // A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement. |
12 | // Within a macro call, a placeholder will match up until whatever token follows the placeholder. | 12 | // Within a macro call, a placeholder will match up until whatever token follows the placeholder. |
13 | // | 13 | // |
14 | // All paths in both the search pattern and the replacement template must resolve in the context | ||
15 | // in which this command is invoked. Paths in the search pattern will then match the code if they | ||
16 | // resolve to the same item, even if they're written differently. For example if we invoke the | ||
17 | // command in the module `foo` with a pattern of `Bar`, then code in the parent module that refers | ||
18 | // to `foo::Bar` will match. | ||
19 | // | ||
20 | // Paths in the replacement template will be rendered appropriately for the context in which the | ||
21 | // replacement occurs. For example if our replacement template is `foo::Bar` and we match some | ||
22 | // code in the `foo` module, we'll insert just `Bar`. | ||
23 | // | ||
24 | // Method calls should generally be written in UFCS form. e.g. `foo::Bar::baz($s, $a)` will match | ||
25 | // `$s.baz($a)`, provided the method call `baz` resolves to the method `foo::Bar::baz`. | ||
26 | // | ||
14 | // Placeholders may be given constraints by writing them as `${<name>:<constraint1>:<constraint2>...}`. | 27 | // Placeholders may be given constraints by writing them as `${<name>:<constraint1>:<constraint2>...}`. |
15 | // | 28 | // |
16 | // Supported constraints: | 29 | // Supported constraints: |
@@ -43,21 +56,13 @@ pub fn parse_search_replace( | |||
43 | rule: &str, | 56 | rule: &str, |
44 | parse_only: bool, | 57 | parse_only: bool, |
45 | db: &RootDatabase, | 58 | db: &RootDatabase, |
59 | position: FilePosition, | ||
46 | ) -> Result<Vec<SourceFileEdit>, SsrError> { | 60 | ) -> Result<Vec<SourceFileEdit>, SsrError> { |
47 | let mut edits = vec![]; | ||
48 | let rule: SsrRule = rule.parse()?; | 61 | let rule: SsrRule = rule.parse()?; |
62 | let mut match_finder = MatchFinder::in_context(db, position); | ||
63 | match_finder.add_rule(rule)?; | ||
49 | if parse_only { | 64 | if parse_only { |
50 | return Ok(edits); | 65 | return Ok(Vec::new()); |
51 | } | ||
52 | let mut match_finder = MatchFinder::new(db); | ||
53 | match_finder.add_rule(rule); | ||
54 | for &root in db.local_roots().iter() { | ||
55 | let sr = db.source_root(root); | ||
56 | for file_id in sr.iter() { | ||
57 | if let Some(edit) = match_finder.edits_for_file(file_id) { | ||
58 | edits.push(SourceFileEdit { file_id, edit }); | ||
59 | } | ||
60 | } | ||
61 | } | 66 | } |
62 | Ok(edits) | 67 | Ok(match_finder.edits()) |
63 | } | 68 | } |