aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/lib.rs26
-rw-r--r--crates/ide/src/references.rs30
-rw-r--r--crates/ide_completion/src/completions/attribute.rs3
-rw-r--r--crates/ide_db/src/search.rs168
4 files changed, 147 insertions, 80 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 68f4551c0..5da6a0340 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1117,6 +1117,14 @@ impl BuiltinType {
1117} 1117}
1118 1118
1119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 1119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1120pub enum MacroKind {
1121 Declarative,
1122 ProcMacro,
1123 Derive,
1124 BuiltIn,
1125}
1126
1127#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1120pub struct MacroDef { 1128pub struct MacroDef {
1121 pub(crate) id: MacroDefId, 1129 pub(crate) id: MacroDefId,
1122} 1130}
@@ -1140,15 +1148,15 @@ impl MacroDef {
1140 } 1148 }
1141 } 1149 }
1142 1150
1143 /// Indicate it is a proc-macro 1151 pub fn kind(&self) -> MacroKind {
1144 pub fn is_proc_macro(&self) -> bool { 1152 match self.id.kind {
1145 matches!(self.id.kind, MacroDefKind::ProcMacro(..)) 1153 MacroDefKind::Declarative(_) => MacroKind::Declarative,
1146 } 1154 MacroDefKind::BuiltIn(_, _) => MacroKind::BuiltIn,
1147 1155 MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive,
1148 /// Indicate it is a derive macro 1156 MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn,
1149 pub fn is_derive_macro(&self) -> bool { 1157 // FIXME might be a derive
1150 // FIXME: wrong for `ProcMacro` 1158 MacroDefKind::ProcMacro(_, _) => MacroKind::ProcMacro,
1151 matches!(self.id.kind, MacroDefKind::ProcMacro(..) | MacroDefKind::BuiltInDerive(..)) 1159 }
1152 } 1160 }
1153} 1161}
1154 1162
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 379674530..95ed8a045 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -1294,4 +1294,34 @@ pub use level1::Foo;
1294 "#]], 1294 "#]],
1295 ); 1295 );
1296 } 1296 }
1297
1298 #[test]
1299 fn test_decl_macro_references() {
1300 check(
1301 r#"
1302//- /lib.rs crate:lib
1303#[macro_use]
1304mod qux;
1305mod bar;
1306
1307pub use self::foo;
1308//- /qux.rs
1309#[macro_export]
1310macro_rules! foo$0 {
1311 () => {struct Foo;};
1312}
1313//- /bar.rs
1314foo!();
1315//- /other.rs crate:other deps:lib new_source_root:
1316lib::foo!();
1317"#,
1318 expect![[r#"
1319 foo Macro FileId(1) 0..61 29..32
1320
1321 FileId(0) 46..49
1322 FileId(2) 0..3
1323 FileId(3) 5..8
1324 "#]],
1325 );
1326 }
1297} 1327}
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index e846678b4..b1505c74b 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -246,7 +246,8 @@ fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
246 let mut result = FxHashSet::default(); 246 let mut result = FxHashSet::default();
247 ctx.scope.process_all_names(&mut |name, scope_def| { 247 ctx.scope.process_all_names(&mut |name, scope_def| {
248 if let hir::ScopeDef::MacroDef(mac) = scope_def { 248 if let hir::ScopeDef::MacroDef(mac) = scope_def {
249 if mac.is_derive_macro() { 249 // FIXME kind() doesn't check whether proc-macro is a derive
250 if mac.kind() == hir::MacroKind::Derive || mac.kind() == hir::MacroKind::ProcMacro {
250 result.insert(name.to_string()); 251 result.insert(name.to_string());
251 } 252 }
252 } 253 }
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 8e93de277..3634b2b26 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -7,7 +7,7 @@
7use std::{convert::TryInto, mem}; 7use std::{convert::TryInto, mem};
8 8
9use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt}; 9use base_db::{FileId, FileRange, SourceDatabase, SourceDatabaseExt};
10use hir::{DefWithBody, HasSource, Module, ModuleSource, Semantics, Visibility}; 10use hir::{DefWithBody, HasAttrs, HasSource, InFile, ModuleSource, Semantics, Visibility};
11use once_cell::unsync::Lazy; 11use once_cell::unsync::Lazy;
12use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
13use syntax::{ast, match_ast, AstNode, TextRange, TextSize}; 13use syntax::{ast, match_ast, AstNode, TextRange, TextSize};
@@ -78,6 +78,76 @@ impl SearchScope {
78 SearchScope { entries } 78 SearchScope { entries }
79 } 79 }
80 80
81 fn crate_graph(db: &RootDatabase) -> SearchScope {
82 let mut entries = FxHashMap::default();
83
84 let graph = db.crate_graph();
85 for krate in graph.iter() {
86 let root_file = graph[krate].root_file_id;
87 let source_root_id = db.file_source_root(root_file);
88 let source_root = db.source_root(source_root_id);
89 entries.extend(source_root.iter().map(|id| (id, None)));
90 }
91 SearchScope { entries }
92 }
93
94 fn reverse_dependencies(db: &RootDatabase, of: hir::Crate) -> SearchScope {
95 let mut entries = FxHashMap::default();
96 for rev_dep in of.transitive_reverse_dependencies(db) {
97 let root_file = rev_dep.root_file(db);
98 let source_root_id = db.file_source_root(root_file);
99 let source_root = db.source_root(source_root_id);
100 entries.extend(source_root.iter().map(|id| (id, None)));
101 }
102 SearchScope { entries }
103 }
104
105 fn krate(db: &RootDatabase, of: hir::Crate) -> SearchScope {
106 let root_file = of.root_file(db);
107 let source_root_id = db.file_source_root(root_file);
108 let source_root = db.source_root(source_root_id);
109 SearchScope {
110 entries: source_root.iter().map(|id| (id, None)).collect::<FxHashMap<_, _>>(),
111 }
112 }
113
114 fn module(db: &RootDatabase, module: hir::Module) -> SearchScope {
115 let mut entries = FxHashMap::default();
116
117 let mut to_visit = vec![module];
118 let mut is_first = true;
119 while let Some(module) = to_visit.pop() {
120 let src = module.definition_source(db);
121 let file_id = src.file_id.original_file(db);
122 match src.value {
123 ModuleSource::Module(m) => {
124 if is_first {
125 let range = Some(m.syntax().text_range());
126 entries.insert(file_id, range);
127 } else {
128 // We have already added the enclosing file to the search scope,
129 // so do nothing.
130 }
131 }
132 ModuleSource::BlockExpr(b) => {
133 if is_first {
134 let range = Some(b.syntax().text_range());
135 entries.insert(file_id, range);
136 } else {
137 // We have already added the enclosing file to the search scope,
138 // so do nothing.
139 }
140 }
141 ModuleSource::SourceFile(_) => {
142 entries.insert(file_id, None);
143 }
144 };
145 is_first = false;
146 to_visit.extend(module.children(db));
147 }
148 SearchScope { entries }
149 }
150
81 pub fn empty() -> SearchScope { 151 pub fn empty() -> SearchScope {
82 SearchScope::new(FxHashMap::default()) 152 SearchScope::new(FxHashMap::default())
83 } 153 }
@@ -140,24 +210,15 @@ impl Definition {
140 let _p = profile::span("search_scope"); 210 let _p = profile::span("search_scope");
141 211
142 if let Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) = self { 212 if let Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)) = self {
143 let mut res = FxHashMap::default(); 213 return SearchScope::crate_graph(db);
144
145 let graph = db.crate_graph();
146 for krate in graph.iter() {
147 let root_file = graph[krate].root_file_id;
148 let source_root_id = db.file_source_root(root_file);
149 let source_root = db.source_root(source_root_id);
150 res.extend(source_root.iter().map(|id| (id, None)));
151 }
152 return SearchScope::new(res);
153 } 214 }
154 215
155 let module = match self.module(db) { 216 let module = match self.module(db) {
156 Some(it) => it, 217 Some(it) => it,
157 None => return SearchScope::empty(), 218 None => return SearchScope::empty(),
158 }; 219 };
159 let module_src = module.definition_source(db); 220 let InFile { file_id, value: module_source } = module.definition_source(db);
160 let file_id = module_src.file_id.original_file(db); 221 let file_id = file_id.original_file(db);
161 222
162 if let Definition::Local(var) = self { 223 if let Definition::Local(var) = self {
163 let range = match var.parent(db) { 224 let range = match var.parent(db) {
@@ -165,9 +226,10 @@ impl Definition {
165 DefWithBody::Const(c) => c.source(db).map(|src| src.value.syntax().text_range()), 226 DefWithBody::Const(c) => c.source(db).map(|src| src.value.syntax().text_range()),
166 DefWithBody::Static(s) => s.source(db).map(|src| src.value.syntax().text_range()), 227 DefWithBody::Static(s) => s.source(db).map(|src| src.value.syntax().text_range()),
167 }; 228 };
168 let mut res = FxHashMap::default(); 229 return match range {
169 res.insert(file_id, range); 230 Some(range) => SearchScope::file_range(FileRange { file_id, range }),
170 return SearchScope::new(res); 231 None => SearchScope::single_file(file_id),
232 };
171 } 233 }
172 234
173 if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self { 235 if let Definition::GenericParam(hir::GenericParam::LifetimeParam(param)) = self {
@@ -198,73 +260,39 @@ impl Definition {
198 it.source(db).map(|src| src.value.syntax().text_range()) 260 it.source(db).map(|src| src.value.syntax().text_range())
199 } 261 }
200 }; 262 };
201 let mut res = FxHashMap::default(); 263 return match range {
202 res.insert(file_id, range); 264 Some(range) => SearchScope::file_range(FileRange { file_id, range }),
203 return SearchScope::new(res); 265 None => SearchScope::single_file(file_id),
266 };
204 } 267 }
205 268
206 let vis = self.visibility(db); 269 if let Definition::Macro(macro_def) = self {
207 270 if macro_def.kind() == hir::MacroKind::Declarative {
208 if let Some(Visibility::Module(module)) = vis.and_then(|it| it.into()) { 271 return if macro_def.attrs(db).by_key("macro_export").exists() {
209 let module: Module = module.into(); 272 SearchScope::reverse_dependencies(db, module.krate())
210 let mut res = FxHashMap::default(); 273 } else {
211 274 SearchScope::krate(db, module.krate())
212 let mut to_visit = vec![module];
213 let mut is_first = true;
214 while let Some(module) = to_visit.pop() {
215 let src = module.definition_source(db);
216 let file_id = src.file_id.original_file(db);
217 match src.value {
218 ModuleSource::Module(m) => {
219 if is_first {
220 let range = Some(m.syntax().text_range());
221 res.insert(file_id, range);
222 } else {
223 // We have already added the enclosing file to the search scope,
224 // so do nothing.
225 }
226 }
227 ModuleSource::BlockExpr(b) => {
228 if is_first {
229 let range = Some(b.syntax().text_range());
230 res.insert(file_id, range);
231 } else {
232 // We have already added the enclosing file to the search scope,
233 // so do nothing.
234 }
235 }
236 ModuleSource::SourceFile(_) => {
237 res.insert(file_id, None);
238 }
239 }; 275 };
240 is_first = false;
241 to_visit.extend(module.children(db));
242 } 276 }
243
244 return SearchScope::new(res);
245 } 277 }
246 278
279 let vis = self.visibility(db);
247 if let Some(Visibility::Public) = vis { 280 if let Some(Visibility::Public) = vis {
248 let mut res = FxHashMap::default(); 281 return SearchScope::reverse_dependencies(db, module.krate());
249 282 }
250 let krate = module.krate(); 283 if let Some(Visibility::Module(module)) = vis {
251 for rev_dep in krate.transitive_reverse_dependencies(db) { 284 return SearchScope::module(db, module.into());
252 let root_file = rev_dep.root_file(db);
253 let source_root_id = db.file_source_root(root_file);
254 let source_root = db.source_root(source_root_id);
255 res.extend(source_root.iter().map(|id| (id, None)));
256 }
257 return SearchScope::new(res);
258 } 285 }
259 286
260 let mut res = FxHashMap::default(); 287 let range = match module_source {
261 let range = match module_src.value {
262 ModuleSource::Module(m) => Some(m.syntax().text_range()), 288 ModuleSource::Module(m) => Some(m.syntax().text_range()),
263 ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()), 289 ModuleSource::BlockExpr(b) => Some(b.syntax().text_range()),
264 ModuleSource::SourceFile(_) => None, 290 ModuleSource::SourceFile(_) => None,
265 }; 291 };
266 res.insert(file_id, range); 292 match range {
267 SearchScope::new(res) 293 Some(range) => SearchScope::file_range(FileRange { file_id, range }),
294 None => SearchScope::single_file(file_id),
295 }
268 } 296 }
269 297
270 pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> { 298 pub fn usages<'a>(&'a self, sema: &'a Semantics<RootDatabase>) -> FindUsages<'a> {