mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-11 17:37:41 +00:00
Merge #8138
8138: Set up a search scope when searching for mbe macro references r=Veykril a=Veykril Closes #6184 Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
258afb8fb8
@ -1116,6 +1116,14 @@ impl BuiltinType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum MacroKind {
|
||||||
|
Declarative,
|
||||||
|
ProcMacro,
|
||||||
|
Derive,
|
||||||
|
BuiltIn,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct MacroDef {
|
pub struct MacroDef {
|
||||||
pub(crate) id: MacroDefId,
|
pub(crate) id: MacroDefId,
|
||||||
@ -1140,15 +1148,15 @@ impl MacroDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicate it is a proc-macro
|
pub fn kind(&self) -> MacroKind {
|
||||||
pub fn is_proc_macro(&self) -> bool {
|
match self.id.kind {
|
||||||
matches!(self.id.kind, MacroDefKind::ProcMacro(..))
|
MacroDefKind::Declarative(_) => MacroKind::Declarative,
|
||||||
}
|
MacroDefKind::BuiltIn(_, _) => MacroKind::BuiltIn,
|
||||||
|
MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive,
|
||||||
/// Indicate it is a derive macro
|
MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn,
|
||||||
pub fn is_derive_macro(&self) -> bool {
|
// FIXME might be a derive
|
||||||
// FIXME: wrong for `ProcMacro`
|
MacroDefKind::ProcMacro(_, _) => MacroKind::ProcMacro,
|
||||||
matches!(self.id.kind, MacroDefKind::ProcMacro(..) | MacroDefKind::BuiltInDerive(..))
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1294,4 +1294,34 @@ pub use level1::Foo;
|
|||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decl_macro_references() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- /lib.rs crate:lib
|
||||||
|
#[macro_use]
|
||||||
|
mod qux;
|
||||||
|
mod bar;
|
||||||
|
|
||||||
|
pub use self::foo;
|
||||||
|
//- /qux.rs
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! foo$0 {
|
||||||
|
() => {struct Foo;};
|
||||||
|
}
|
||||||
|
//- /bar.rs
|
||||||
|
foo!();
|
||||||
|
//- /other.rs crate:other deps:lib new_source_root:
|
||||||
|
lib::foo!();
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
foo Macro FileId(1) 0..61 29..32
|
||||||
|
|
||||||
|
FileId(0) 46..49
|
||||||
|
FileId(2) 0..3
|
||||||
|
FileId(3) 5..8
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,7 +246,8 @@ fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
|
|||||||
let mut result = FxHashSet::default();
|
let mut result = FxHashSet::default();
|
||||||
ctx.scope.process_all_names(&mut |name, scope_def| {
|
ctx.scope.process_all_names(&mut |name, scope_def| {
|
||||||
if let hir::ScopeDef::MacroDef(mac) = scope_def {
|
if let hir::ScopeDef::MacroDef(mac) = scope_def {
|
||||||
if mac.is_derive_macro() {
|
// FIXME kind() doesn't check whether proc-macro is a derive
|
||||||
|
if mac.kind() == hir::MacroKind::Derive || mac.kind() == hir::MacroKind::ProcMacro {
|
||||||
result.insert(name.to_string());
|
result.insert(name.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
use std::{convert::TryInto, mem};
|
use std::{convert::TryInto, mem};
|
||||||
|
|
||||||
use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
|
use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
|
||||||
use hir::{DefWithBody, HasSource, Module, ModuleSource, Semantics, Visibility};
|
use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility};
|
||||||
use once_cell::unsync::Lazy;
|
use once_cell::unsync::Lazy;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
|
use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
|
||||||
@ -78,6 +78,76 @@ impl SearchScope {
|
|||||||
SearchScope { entries }
|
SearchScope { entries }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn crate_graph(db: &RootDatabase) -> SearchScope {
|
||||||
|
let mut entries = FxHashMap::default();
|
||||||
|
|
||||||
|
let graph = db.crate_graph();
|
||||||
|
for krate in graph.iter() {
|
||||||
|
let root_file = graph[krate].root_file_id;
|
||||||
|
let source_root_id = db.file_source_root(root_file);
|
||||||
|
let source_root = db.source_root(source_root_id);
|
||||||
|
entries.extend(source_root.iter().map(|id| (id, None)));
|
||||||
|
}
|
||||||
|
SearchScope { entries }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reverse_dependencies(db: &RootDatabase, of: hir::Crate) -> SearchScope {
|
||||||
|
let mut entries = FxHashMap::default();
|
||||||
|
for rev_dep in of.transitive_reverse_dependencies(db) {
|
||||||
|
let root_file = rev_dep.root_file(db);
|
||||||
|
let source_root_id = db.file_source_root(root_file);
|
||||||
|
let source_root = db.source_root(source_root_id);
|
||||||
|
entries.extend(source_root.iter().map(|id| (id, None)));
|
||||||
|
}
|
||||||
|
SearchScope { entries }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn krate(db: &RootDatabase, of: hir::Crate) -> SearchScope {
|
||||||
|
let root_file = of.root_file(db);
|
||||||
|
let source_root_id = db.file_source_root(root_file);
|
||||||
|
let source_root = db.source_root(source_root_id);
|
||||||
|
SearchScope {
|
||||||
|
entries: source_root.iter().map(|id| (id, None)).collect::<FxHashMap<_, _>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn module(db: &RootDatabase, module: hir::Module) -> SearchScope {
|
||||||
|
let mut entries = FxHashMap::default();
|
||||||
|
|
||||||
|
let mut to_visit = vec![module];
|
||||||
|
let mut is_first = true;
|
||||||
|
while let Some(module) = to_visit.pop() {
|
||||||
|
let src = module.definition_source(db);
|
||||||
|
let file_id = src.file_id.original_file(db);
|
||||||
|
match src.value {
|
||||||
|
ModuleSource::Module(m) => {
|
||||||
|
if is_first {
|
||||||
|
let range = Some(m.syntax().text_range());
|
||||||
|
entries.insert(file_id, range);
|
||||||
|
} else {
|
||||||
|
// We have already added the enclosing file to the search scope,
|
||||||
|
// so do nothing.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ModuleSource::BlockExpr(b) => {
|
||||||
|
if is_first {
|
||||||
|
let range = Some(b.syntax().text_range());
|
||||||
|
entries.insert(file_id, range);
|
||||||
|
} else {
|
||||||
|
// We have already added the enclosing file to the search scope,
|
||||||
|
// so do nothing.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ModuleSource::SourceFile(_) => {
|
||||||
|
entries.insert(file_id, None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
is_first = false;
|
||||||
|
to_visit.extend(module.children(db));
|
||||||
|
}
|
||||||
|
SearchScope { entries }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn empty() -> SearchScope {
|
pub fn empty() -> SearchScope {
|
||||||
SearchScope::new(FxHashMap::default())
|
SearchScope::new(FxHashMap::default())
|
||||||
}
|
}
|
||||||
@ -140,24 +210,15 @@ impl Definition {
|
|||||||
let _p = profile::span("search_scope");
|
let _p = profile::span("search_scope");
|
||||||
|
|
||||||
if let Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) = self {
|
if let Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) = self {
|
||||||
let mut res = FxHashMap::default();
|
return SearchScope::crate_graph(db);
|
||||||
|
|
||||||
let graph = db.crate_graph();
|
|
||||||
for krate in graph.iter() {
|
|
||||||
let root_file = graph[krate].root_file_id;
|
|
||||||
let source_root_id = db.file_source_root(root_file);
|
|
||||||
let source_root = db.source_root(source_root_id);
|
|
||||||
res.extend(source_root.iter().map(|id| (id, None)));
|
|
||||||
}
|
|
||||||
return SearchScope::new(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let module = match self.module(db) {
|
let module = match self.module(db) {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => return SearchScope::empty(),
|
None => return SearchScope::empty(),
|
||||||
};
|
};
|
||||||
let module_src = module.definition_source(db);
|
let InFile { file_id, value: module_source } = module.definition_source(db);
|
||||||
let file_id = module_src.file_id.original_file(db);
|
let file_id = file_id.original_file(db);
|
||||||
|
|
||||||
if let Definition::Local(var) = self {
|
if let Definition::Local(var) = self {
|
||||||
let range = match var.parent(db) {
|
let range = match var.parent(db) {
|
||||||
@ -165,9 +226,10 @@ impl Definition {
|
|||||||
DefWithBody::Const(c) => c.source(db).map(|src| src.value.syntax().text_range()),
|
DefWithBody::Const(c) => c.source(db).map(|src| src.value.syntax().text_range()),
|
||||||
DefWithBody::Static(s) => s.source(db).map(|src| src.value.syntax().text_range()),
|
DefWithBody::Static(s) => s.source(db).map(|src| src.value.syntax().text_range()),
|
||||||
};
|
};
|
||||||
let mut res = FxHashMap::default();
|
return match range {
|
||||||
res.insert(file_id, range);
|
Some(range) => SearchScope::file_range(FileRange { file_id, range }),
|
||||||
return SearchScope::new(res);
|
None => SearchScope::single_file(file_id),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self {
|
if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self {
|
||||||
@ -198,73 +260,39 @@ impl Definition {
|
|||||||
it.source(db).map(|src| src.value.syntax().text_range())
|
it.source(db).map(|src| src.value.syntax().text_range())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut res = FxHashMap::default();
|
return match range {
|
||||||
res.insert(file_id, range);
|
Some(range) => SearchScope::file_range(FileRange { file_id, range }),
|
||||||
return SearchScope::new(res);
|
None => SearchScope::single_file(file_id),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Definition::Macro(macro_def) = self {
|
||||||
|
if macro_def.kind() == hir::MacroKind::Declarative {
|
||||||
|
return if macro_def.attrs(db).by_key("macro_export").exists() {
|
||||||
|
SearchScope::reverse_dependencies(db, module.krate())
|
||||||
|
} else {
|
||||||
|
SearchScope::krate(db, module.krate())
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let vis = self.visibility(db);
|
let vis = self.visibility(db);
|
||||||
|
|
||||||
if let Some(Visibility::Module(module)) = vis.and_then(|it| it.into()) {
|
|
||||||
let module: Module = module.into();
|
|
||||||
let mut res = FxHashMap::default();
|
|
||||||
|
|
||||||
let mut to_visit = vec![module];
|
|
||||||
let mut is_first = true;
|
|
||||||
while let Some(module) = to_visit.pop() {
|
|
||||||
let src = module.definition_source(db);
|
|
||||||
let file_id = src.file_id.original_file(db);
|
|
||||||
match src.value {
|
|
||||||
ModuleSource::Module(m) => {
|
|
||||||
if is_first {
|
|
||||||
let range = Some(m.syntax().text_range());
|
|
||||||
res.insert(file_id, range);
|
|
||||||
} else {
|
|
||||||
// We have already added the enclosing file to the search scope,
|
|
||||||
// so do nothing.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ModuleSource::BlockExpr(b) => {
|
|
||||||
if is_first {
|
|
||||||
let range = Some(b.syntax().text_range());
|
|
||||||
res.insert(file_id, range);
|
|
||||||
} else {
|
|
||||||
// We have already added the enclosing file to the search scope,
|
|
||||||
// so do nothing.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ModuleSource::SourceFile(_) => {
|
|
||||||
res.insert(file_id, None);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
is_first = false;
|
|
||||||
to_visit.extend(module.children(db));
|
|
||||||
}
|
|
||||||
|
|
||||||
return SearchScope::new(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(Visibility::Public) = vis {
|
if let Some(Visibility::Public) = vis {
|
||||||
let mut res = FxHashMap::default();
|
return SearchScope::reverse_dependencies(db, module.krate());
|
||||||
|
}
|
||||||
let krate = module.krate();
|
if let Some(Visibility::Module(module)) = vis {
|
||||||
for rev_dep in krate.transitive_reverse_dependencies(db) {
|
return SearchScope::module(db, module.into());
|
||||||
let root_file = rev_dep.root_file(db);
|
|
||||||
let source_root_id = db.file_source_root(root_file);
|
|
||||||
let source_root = db.source_root(source_root_id);
|
|
||||||
res.extend(source_root.iter().map(|id| (id, None)));
|
|
||||||
}
|
|
||||||
return SearchScope::new(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut res = FxHashMap::default();
|
let range = match module_source {
|
||||||
let range = match module_src.value {
|
|
||||||
ModuleSource::Module(m) => Some(m.syntax().text_range()),
|
ModuleSource::Module(m) => Some(m.syntax().text_range()),
|
||||||
ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()),
|
ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()),
|
||||||
ModuleSource::SourceFile(_) => None,
|
ModuleSource::SourceFile(_) => None,
|
||||||
};
|
};
|
||||||
res.insert(file_id, range);
|
match range {
|
||||||
SearchScope::new(res)
|
Some(range) => SearchScope::file_range(FileRange { file_id, range }),
|
||||||
|
None => SearchScope::single_file(file_id),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {
|
pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {
|
||||||
|
Loading…
Reference in New Issue
Block a user