aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/nameres.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/nameres.rs')
-rw-r--r--crates/ra_hir_def/src/nameres.rs224
1 files changed, 111 insertions, 113 deletions
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index 2359386c2..5d4ca73a3 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -57,24 +57,23 @@ mod tests;
57 57
58use std::sync::Arc; 58use std::sync::Arc;
59 59
60use hir_expand::{ 60use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile};
61 ast_id_map::FileAstId, diagnostics::DiagnosticSink, either::Either, name::Name, MacroDefId,
62 Source,
63};
64use once_cell::sync::Lazy;
65use ra_arena::Arena; 61use ra_arena::Arena;
66use ra_db::{CrateId, Edition, FileId}; 62use ra_db::{CrateId, Edition, FileId, FilePosition};
67use ra_prof::profile; 63use ra_prof::profile;
68use ra_syntax::ast; 64use ra_syntax::{
65 ast::{self, AstNode},
66 SyntaxNode,
67};
69use rustc_hash::FxHashMap; 68use rustc_hash::FxHashMap;
70 69
71use crate::{ 70use crate::{
72 builtin_type::BuiltinType,
73 db::DefDatabase, 71 db::DefDatabase,
72 item_scope::{BuiltinShadowMode, ItemScope},
74 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, 73 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
75 path::Path, 74 path::ModPath,
76 per_ns::PerNs, 75 per_ns::PerNs,
77 AstId, FunctionId, ImplId, LocalImportId, LocalModuleId, ModuleDefId, ModuleId, TraitId, 76 AstId, LocalModuleId, ModuleDefId, ModuleId,
78}; 77};
79 78
80/// Contains all top-level defs from a macro-expanded crate 79/// Contains all top-level defs from a macro-expanded crate
@@ -100,106 +99,76 @@ impl std::ops::Index<LocalModuleId> for CrateDefMap {
100 } 99 }
101} 100}
102 101
103#[derive(Default, Debug, PartialEq, Eq)] 102#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
104pub struct ModuleData { 103pub enum ModuleOrigin {
105 pub parent: Option<LocalModuleId>, 104 CrateRoot {
106 pub children: FxHashMap<Name, LocalModuleId>, 105 definition: FileId,
107 pub scope: ModuleScope, 106 },
108
109 // FIXME: these can't be both null, we need a three-state enum here.
110 /// None for root
111 pub declaration: Option<AstId<ast::Module>>,
112 /// None for inline modules.
113 ///
114 /// Note that non-inline modules, by definition, live inside non-macro file. 107 /// Note that non-inline modules, by definition, live inside non-macro file.
115 pub definition: Option<FileId>, 108 File {
116 109 declaration: AstId<ast::Module>,
117 pub impls: Vec<ImplId>, 110 definition: FileId,
118} 111 },
119 112 Inline {
120#[derive(Default, Debug, PartialEq, Eq)] 113 definition: AstId<ast::Module>,
121pub(crate) struct Declarations { 114 },
122 fns: FxHashMap<FileAstId<ast::FnDef>, FunctionId>,
123} 115}
124 116
125#[derive(Debug, Default, PartialEq, Eq)] 117impl Default for ModuleOrigin {
126pub struct ModuleScope { 118 fn default() -> Self {
127 items: FxHashMap<Name, Resolution>, 119 ModuleOrigin::CrateRoot { definition: FileId(0) }
128 /// Macros visable in current module in legacy textual scope
129 ///
130 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
131 /// If it yields no result, then it turns to module scoped `macros`.
132 /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
133 /// and only normal scoped `macros` will be searched in.
134 ///
135 /// Note that this automatically inherit macros defined textually before the definition of module itself.
136 ///
137 /// Module scoped macros will be inserted into `items` instead of here.
138 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
139 // be all resolved to the last one defined if shadowing happens.
140 legacy_macros: FxHashMap<Name, MacroDefId>,
141}
142
143static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
144 BuiltinType::ALL
145 .iter()
146 .map(|(name, ty)| {
147 (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None })
148 })
149 .collect()
150});
151
152/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
153/// Other methods will only resolve values, types and module scoped macros only.
154impl ModuleScope {
155 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
156 //FIXME: shadowing
157 self.items.iter().chain(BUILTIN_SCOPE.iter())
158 }
159
160 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
161 self.entries()
162 .filter_map(|(_name, res)| if res.import.is_none() { Some(res.def) } else { None })
163 .flat_map(|per_ns| {
164 per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter())
165 })
166 }
167
168 /// Iterate over all module scoped macros
169 pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
170 self.items
171 .iter()
172 .filter_map(|(name, res)| res.def.take_macros().map(|macro_| (name, macro_)))
173 } 120 }
121}
174 122
175 /// Iterate over all legacy textual scoped macros visable at the end of the module 123impl ModuleOrigin {
176 pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { 124 pub(crate) fn not_sure_file(file: Option<FileId>, declaration: AstId<ast::Module>) -> Self {
177 self.legacy_macros.iter().map(|(name, def)| (name, *def)) 125 match file {
126 None => ModuleOrigin::Inline { definition: declaration },
127 Some(definition) => ModuleOrigin::File { declaration, definition },
128 }
178 } 129 }
179 130
180 /// Get a name from current module scope, legacy macros are not included 131 fn declaration(&self) -> Option<AstId<ast::Module>> {
181 pub fn get(&self, name: &Name) -> Option<&Resolution> { 132 match self {
182 self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)) 133 ModuleOrigin::File { declaration: module, .. }
134 | ModuleOrigin::Inline { definition: module, .. } => Some(*module),
135 ModuleOrigin::CrateRoot { .. } => None,
136 }
183 } 137 }
184 138
185 pub fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { 139 pub fn file_id(&self) -> Option<FileId> {
186 self.items.values().filter_map(|r| match r.def.take_types() { 140 match self {
187 Some(ModuleDefId::TraitId(t)) => Some(t), 141 ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
142 Some(*definition)
143 }
188 _ => None, 144 _ => None,
189 }) 145 }
190 } 146 }
191 147
192 fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> { 148 /// Returns a node which defines this module.
193 self.legacy_macros.get(name).copied() 149 /// That is, a file or a `mod foo {}` with items.
150 fn definition_source(&self, db: &impl DefDatabase) -> InFile<ModuleSource> {
151 match self {
152 ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
153 let file_id = *definition;
154 let sf = db.parse(file_id).tree();
155 return InFile::new(file_id.into(), ModuleSource::SourceFile(sf));
156 }
157 ModuleOrigin::Inline { definition } => {
158 InFile::new(definition.file_id, ModuleSource::Module(definition.to_node(db)))
159 }
160 }
194 } 161 }
195} 162}
196 163
197#[derive(Debug, Clone, PartialEq, Eq, Default)] 164#[derive(Default, Debug, PartialEq, Eq)]
198pub struct Resolution { 165pub struct ModuleData {
199 /// None for unresolved 166 pub parent: Option<LocalModuleId>,
200 pub def: PerNs, 167 pub children: FxHashMap<Name, LocalModuleId>,
201 /// ident by which this is imported into local scope. 168 pub scope: ItemScope,
202 pub import: Option<LocalImportId>, 169
170 /// Where does this module come from?
171 pub origin: ModuleOrigin,
203} 172}
204 173
205impl CrateDefMap { 174impl CrateDefMap {
@@ -241,7 +210,7 @@ impl CrateDefMap {
241 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ { 210 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ {
242 self.modules 211 self.modules
243 .iter() 212 .iter()
244 .filter(move |(_id, data)| data.definition == Some(file_id)) 213 .filter(move |(_id, data)| data.origin.file_id() == Some(file_id))
245 .map(|(id, _data)| id) 214 .map(|(id, _data)| id)
246 } 215 }
247 216
@@ -249,33 +218,62 @@ impl CrateDefMap {
249 &self, 218 &self,
250 db: &impl DefDatabase, 219 db: &impl DefDatabase,
251 original_module: LocalModuleId, 220 original_module: LocalModuleId,
252 path: &Path, 221 path: &ModPath,
222 shadow: BuiltinShadowMode,
253 ) -> (PerNs, Option<usize>) { 223 ) -> (PerNs, Option<usize>) {
254 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); 224 let res =
225 self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
255 (res.resolved_def, res.segment_index) 226 (res.resolved_def, res.segment_index)
256 } 227 }
257} 228}
258 229
259impl ModuleData { 230impl ModuleData {
260 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. 231 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
261 pub fn definition_source( 232 pub fn definition_source(&self, db: &impl DefDatabase) -> InFile<ModuleSource> {
262 &self, 233 self.origin.definition_source(db)
263 db: &impl DefDatabase,
264 ) -> Source<Either<ast::SourceFile, ast::Module>> {
265 if let Some(file_id) = self.definition {
266 let sf = db.parse(file_id).tree();
267 return Source::new(file_id.into(), Either::A(sf));
268 }
269 let decl = self.declaration.unwrap();
270 Source::new(decl.file_id(), Either::B(decl.to_node(db)))
271 } 234 }
272 235
273 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. 236 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
274 /// `None` for the crate root. 237 /// `None` for the crate root or block.
275 pub fn declaration_source(&self, db: &impl DefDatabase) -> Option<Source<ast::Module>> { 238 pub fn declaration_source(&self, db: &impl DefDatabase) -> Option<InFile<ast::Module>> {
276 let decl = self.declaration?; 239 let decl = self.origin.declaration()?;
277 let value = decl.to_node(db); 240 let value = decl.to_node(db);
278 Some(Source { file_id: decl.file_id(), value }) 241 Some(InFile { file_id: decl.file_id, value })
242 }
243}
244
245#[derive(Debug, Clone, PartialEq, Eq)]
246pub enum ModuleSource {
247 SourceFile(ast::SourceFile),
248 Module(ast::Module),
249}
250
251impl ModuleSource {
252 // FIXME: this methods do not belong here
253 pub fn from_position(db: &impl DefDatabase, position: FilePosition) -> ModuleSource {
254 let parse = db.parse(position.file_id);
255 match &ra_syntax::algo::find_node_at_offset::<ast::Module>(
256 parse.tree().syntax(),
257 position.offset,
258 ) {
259 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
260 _ => {
261 let source_file = parse.tree();
262 ModuleSource::SourceFile(source_file)
263 }
264 }
265 }
266
267 pub fn from_child_node(db: &impl DefDatabase, child: InFile<&SyntaxNode>) -> ModuleSource {
268 if let Some(m) =
269 child.value.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi())
270 {
271 ModuleSource::Module(m)
272 } else {
273 let file_id = child.file_id.original_file(db);
274 let source_file = db.parse(file_id).tree();
275 ModuleSource::SourceFile(source_file)
276 }
279 } 277 }
280} 278}
281 279
@@ -309,7 +307,7 @@ mod diagnostics {
309 } 307 }
310 let decl = declaration.to_node(db); 308 let decl = declaration.to_node(db);
311 sink.push(UnresolvedModule { 309 sink.push(UnresolvedModule {
312 file: declaration.file_id(), 310 file: declaration.file_id,
313 decl: AstPtr::new(&decl), 311 decl: AstPtr::new(&decl),
314 candidate: candidate.clone(), 312 candidate: candidate.clone(),
315 }) 313 })