Skip to content

Use resolved paths in SSR rules #5518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jul 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/ra_ide/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,9 +505,10 @@ impl Analysis {
&self,
query: &str,
parse_only: bool,
position: FilePosition,
) -> Cancelable<Result<SourceChange, SsrError>> {
self.with_db(|db| {
let edits = ssr::parse_search_replace(query, parse_only, db)?;
let edits = ssr::parse_search_replace(query, parse_only, db, position)?;
Ok(SourceChange::from(edits))
})
}
Expand Down
35 changes: 20 additions & 15 deletions crates/ra_ide/src/ssr.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use ra_db::SourceDatabaseExt;
use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase};
use ra_db::FilePosition;
use ra_ide_db::RootDatabase;

use crate::SourceFileEdit;
use ra_ssr::{MatchFinder, SsrError, SsrRule};
Expand All @@ -11,6 +11,19 @@ use ra_ssr::{MatchFinder, SsrError, SsrRule};
// A `$<name>` placeholder in the search pattern will match any AST node and `$<name>` will reference it in the replacement.
// Within a macro call, a placeholder will match up until whatever token follows the placeholder.
//
// All paths in both the search pattern and the replacement template must resolve in the context
// in which this command is invoked. Paths in the search pattern will then match the code if they
// resolve to the same item, even if they're written differently. For example if we invoke the
// command in the module `foo` with a pattern of `Bar`, then code in the parent module that refers
// to `foo::Bar` will match.
//
// Paths in the replacement template will be rendered appropriately for the context in which the
// replacement occurs. For example if our replacement template is `foo::Bar` and we match some
// code in the `foo` module, we'll insert just `Bar`.
//
// Method calls should generally be written in UFCS form. e.g. `foo::Bar::baz($s, $a)` will match
// `$s.baz($a)`, provided the method call `baz` resolves to the method `foo::Bar::baz`.
//
// Placeholders may be given constraints by writing them as `${<name>:<constraint1>:<constraint2>...}`.
//
// Supported constraints:
Expand Down Expand Up @@ -43,21 +56,13 @@ pub fn parse_search_replace(
rule: &str,
parse_only: bool,
db: &RootDatabase,
position: FilePosition,
) -> Result<Vec<SourceFileEdit>, SsrError> {
let mut edits = vec![];
let rule: SsrRule = rule.parse()?;
let mut match_finder = MatchFinder::in_context(db, position);
match_finder.add_rule(rule)?;
if parse_only {
return Ok(edits);
}
let mut match_finder = MatchFinder::new(db);
match_finder.add_rule(rule);
for &root in db.local_roots().iter() {
let sr = db.source_root(root);
for file_id in sr.iter() {
if let Some(edit) = match_finder.edits_for_file(file_id) {
edits.push(SourceFileEdit { file_id, edit });
}
}
return Ok(Vec::new());
}
Ok(edits)
Ok(match_finder.edits())
}
35 changes: 20 additions & 15 deletions crates/ra_ide_db/src/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,20 +290,25 @@ pub fn classify_name_ref(

let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
let resolved = sema.resolve_path(&path)?;
let res = match resolved {
PathResolution::Def(def) => Definition::ModuleDef(def),
PathResolution::AssocItem(item) => {
let def = match item {
hir::AssocItem::Function(it) => it.into(),
hir::AssocItem::Const(it) => it.into(),
hir::AssocItem::TypeAlias(it) => it.into(),
};
Definition::ModuleDef(def)
Some(NameRefClass::Definition(resolved.into()))
}

impl From<PathResolution> for Definition {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

fn from(path_resolution: PathResolution) -> Self {
match path_resolution {
PathResolution::Def(def) => Definition::ModuleDef(def),
PathResolution::AssocItem(item) => {
let def = match item {
hir::AssocItem::Function(it) => it.into(),
hir::AssocItem::Const(it) => it.into(),
hir::AssocItem::TypeAlias(it) => it.into(),
};
Definition::ModuleDef(def)
}
PathResolution::Local(local) => Definition::Local(local),
PathResolution::TypeParam(par) => Definition::TypeParam(par),
PathResolution::Macro(def) => Definition::Macro(def),
PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
}
PathResolution::Local(local) => Definition::Local(local),
PathResolution::TypeParam(par) => Definition::TypeParam(par),
PathResolution::Macro(def) => Definition::Macro(def),
PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
};
Some(NameRefClass::Definition(res))
}
}
4 changes: 4 additions & 0 deletions crates/ra_ide_db/src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ impl SearchScope {
SearchScope::new(std::iter::once((file, None)).collect())
}

pub fn files(files: &[FileId]) -> SearchScope {
SearchScope::new(files.iter().map(|f| (*f, None)).collect())
}

pub fn intersection(&self, other: &SearchScope) -> SearchScope {
let (mut small, mut large) = (&self.entries, &other.entries);
if small.len() > large.len() {
Expand Down
3 changes: 3 additions & 0 deletions crates/ra_ssr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ ra_ide_db = { path = "../ra_ide_db" }
hir = { path = "../ra_hir", package = "ra_hir" }
rustc-hash = "1.1.0"
test_utils = { path = "../test_utils" }

[dev-dependencies]
expect = { path = "../expect" }
Loading