aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/nameres
diff options
context:
space:
mode:
authorSeivan Heidari <[email protected]>2019-11-09 01:19:31 +0000
committerSeivan Heidari <[email protected]>2019-11-09 01:19:31 +0000
commit81662d23a64c7eb7ea10cb7bbf316f17d78dc4bc (patch)
treeec06c6081d4459911079b176bb557fa3d92ea2cb /crates/ra_hir_def/src/nameres
parent32d749c77562c5004f4b4e87f205758c7653e29d (diff)
parent23939cabcc10ecc045a97361df182b9b4db32953 (diff)
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates/ra_hir_def/src/nameres')
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs10
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs261
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs48
3 files changed, 292 insertions, 27 deletions
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index 3b61d9895..aacd50df8 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -14,8 +14,8 @@ use crate::{
14 attr::Attr, 14 attr::Attr,
15 db::DefDatabase2, 15 db::DefDatabase2,
16 nameres::{ 16 nameres::{
17 diagnostics::DefDiagnostic, mod_resolution::ModDir, per_ns::PerNs, raw, CrateDefMap, 17 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
18 ModuleData, ReachedFixedPoint, Resolution, ResolveMode, 18 per_ns::PerNs, raw, CrateDefMap, ModuleData, Resolution, ResolveMode,
19 }, 19 },
20 path::{Path, PathKind}, 20 path::{Path, PathKind},
21 AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId, 21 AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId,
@@ -182,7 +182,11 @@ where
182 // In Rust, `#[macro_export]` macros are unconditionally visible at the 182 // In Rust, `#[macro_export]` macros are unconditionally visible at the
183 // crate root, even if the parent modules is **not** visible. 183 // crate root, even if the parent modules is **not** visible.
184 if export { 184 if export {
185 self.update(self.def_map.root, None, &[(name, Resolution::from_macro(macro_))]); 185 self.update(
186 self.def_map.root,
187 None,
188 &[(name, Resolution { def: PerNs::macros(macro_), import: None })],
189 );
186 } 190 }
187 } 191 }
188 192
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
new file mode 100644
index 000000000..95692f826
--- /dev/null
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -0,0 +1,261 @@
1//! This modules implements a function to resolve a path `foo::bar::baz` to a
2//! def, which is used within the name resolution.
3//!
4//! When name resolution is finished, the result of resolving a path is either
5//! `Some(def)` or `None`. However, when we are in process of resolving imports
6//! or macros, there's a third possibility:
7//!
8//! I can't resolve this path right now, but I might be resolve this path
9//! later, when more macros are expanded.
10//!
11//! `ReachedFixedPoint` signals about this.
12
13use hir_expand::name::Name;
14use ra_db::Edition;
15use test_utils::tested_by;
16
17use crate::{
18 db::DefDatabase2,
19 nameres::{per_ns::PerNs, CrateDefMap},
20 path::{Path, PathKind},
21 AdtId, CrateModuleId, EnumVariantId, ModuleDefId, ModuleId,
22};
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub(super) enum ResolveMode {
26 Import,
27 Other,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub(super) enum ReachedFixedPoint {
32 Yes,
33 No,
34}
35
36#[derive(Debug, Clone)]
37pub(super) struct ResolvePathResult {
38 pub(super) resolved_def: PerNs,
39 pub(super) segment_index: Option<usize>,
40 pub(super) reached_fixedpoint: ReachedFixedPoint,
41}
42
43impl ResolvePathResult {
44 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
45 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
46 }
47
48 fn with(
49 resolved_def: PerNs,
50 reached_fixedpoint: ReachedFixedPoint,
51 segment_index: Option<usize>,
52 ) -> ResolvePathResult {
53 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index }
54 }
55}
56
57impl CrateDefMap {
58 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
59 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
60 }
61
62 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
63 // the result.
64 pub(super) fn resolve_path_fp_with_macro(
65 &self,
66 db: &impl DefDatabase2,
67 mode: ResolveMode,
68 original_module: CrateModuleId,
69 path: &Path,
70 ) -> ResolvePathResult {
71 let mut segments = path.segments.iter().enumerate();
72 let mut curr_per_ns: PerNs = match path.kind {
73 PathKind::DollarCrate(krate) => {
74 if krate == self.krate {
75 tested_by!(macro_dollar_crate_self);
76 PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
77 } else {
78 let def_map = db.crate_def_map(krate);
79 let module = ModuleId { krate, module_id: def_map.root };
80 tested_by!(macro_dollar_crate_other);
81 PerNs::types(module.into())
82 }
83 }
84 PathKind::Crate => {
85 PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into())
86 }
87 PathKind::Self_ => {
88 PerNs::types(ModuleId { krate: self.krate, module_id: original_module }.into())
89 }
90 // plain import or absolute path in 2015: crate-relative with
91 // fallback to extern prelude (with the simplification in
92 // rust-lang/rust#57745)
93 // FIXME there must be a nicer way to write this condition
94 PathKind::Plain | PathKind::Abs
95 if self.edition == Edition::Edition2015
96 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
97 {
98 let segment = match segments.next() {
99 Some((_, segment)) => segment,
100 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
101 };
102 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
103 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
104 }
105 PathKind::Plain => {
106 let segment = match segments.next() {
107 Some((_, segment)) => segment,
108 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
109 };
110 log::debug!("resolving {:?} in module", segment);
111 self.resolve_name_in_module(db, original_module, &segment.name)
112 }
113 PathKind::Super => {
114 if let Some(p) = self.modules[original_module].parent {
115 PerNs::types(ModuleId { krate: self.krate, module_id: p }.into())
116 } else {
117 log::debug!("super path in root module");
118 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
119 }
120 }
121 PathKind::Abs => {
122 // 2018-style absolute path -- only extern prelude
123 let segment = match segments.next() {
124 Some((_, segment)) => segment,
125 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
126 };
127 if let Some(def) = self.extern_prelude.get(&segment.name) {
128 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
129 PerNs::types(*def)
130 } else {
131 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
132 }
133 }
134 PathKind::Type(_) => {
135 // This is handled in `infer::infer_path_expr`
136 // The result returned here does not matter
137 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
138 }
139 };
140
141 for (i, segment) in segments {
142 let curr = match curr_per_ns.take_types() {
143 Some(r) => r,
144 None => {
145 // we still have path segments left, but the path so far
146 // didn't resolve in the types namespace => no resolution
147 // (don't break here because `curr_per_ns` might contain
148 // something in the value namespace, and it would be wrong
149 // to return that)
150 return ResolvePathResult::empty(ReachedFixedPoint::No);
151 }
152 };
153 // resolve segment in curr
154
155 curr_per_ns = match curr {
156 ModuleDefId::ModuleId(module) => {
157 if module.krate != self.krate {
158 let path =
159 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
160 log::debug!("resolving {:?} in other crate", path);
161 let defp_map = db.crate_def_map(module.krate);
162 let (def, s) = defp_map.resolve_path(db, module.module_id, &path);
163 return ResolvePathResult::with(
164 def,
165 ReachedFixedPoint::Yes,
166 s.map(|s| s + i),
167 );
168 }
169
170 // Since it is a qualified path here, it should not contains legacy macros
171 match self[module.module_id].scope.get(&segment.name) {
172 Some(res) => res.def,
173 _ => {
174 log::debug!("path segment {:?} not found", segment.name);
175 return ResolvePathResult::empty(ReachedFixedPoint::No);
176 }
177 }
178 }
179 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
180 // enum variant
181 tested_by!(can_import_enum_variant);
182 let enum_data = db.enum_data(e);
183 match enum_data.variant(&segment.name) {
184 Some(local_id) => {
185 let variant = EnumVariantId { parent: e, local_id };
186 PerNs::both(variant.into(), variant.into())
187 }
188 None => {
189 return ResolvePathResult::with(
190 PerNs::types(e.into()),
191 ReachedFixedPoint::Yes,
192 Some(i),
193 );
194 }
195 }
196 }
197 s => {
198 // could be an inherent method call in UFCS form
199 // (`Struct::method`), or some other kind of associated item
200 log::debug!(
201 "path segment {:?} resolved to non-module {:?}, but is not last",
202 segment.name,
203 curr,
204 );
205
206 return ResolvePathResult::with(
207 PerNs::types(s),
208 ReachedFixedPoint::Yes,
209 Some(i),
210 );
211 }
212 };
213 }
214 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
215 }
216
217 fn resolve_name_in_module(
218 &self,
219 db: &impl DefDatabase2,
220 module: CrateModuleId,
221 name: &Name,
222 ) -> PerNs {
223 // Resolve in:
224 // - legacy scope of macro
225 // - current module / scope
226 // - extern prelude
227 // - std prelude
228 let from_legacy_macro =
229 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
230 let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
231 let from_extern_prelude =
232 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
233 let from_prelude = self.resolve_in_prelude(db, name);
234
235 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
236 }
237
238 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
239 let from_crate_root =
240 self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
241 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
242
243 from_crate_root.or(from_extern_prelude)
244 }
245
246 fn resolve_in_prelude(&self, db: &impl DefDatabase2, name: &Name) -> PerNs {
247 if let Some(prelude) = self.prelude {
248 let keep;
249 let def_map = if prelude.krate == self.krate {
250 self
251 } else {
252 // Extend lifetime
253 keep = db.crate_def_map(prelude.krate);
254 &keep
255 };
256 def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
257 } else {
258 PerNs::none()
259 }
260 }
261}
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index cb47fa317..369376f30 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -88,7 +88,7 @@ impl RawItems {
88 (Arc::new(collector.raw_items), Arc::new(collector.source_map)) 88 (Arc::new(collector.raw_items), Arc::new(collector.source_map))
89 } 89 }
90 90
91 pub fn items(&self) -> &[RawItem] { 91 pub(super) fn items(&self) -> &[RawItem] {
92 &self.items 92 &self.items
93 } 93 }
94} 94}
@@ -125,19 +125,19 @@ impl Index<Macro> for RawItems {
125type Attrs = Option<Arc<[Attr]>>; 125type Attrs = Option<Arc<[Attr]>>;
126 126
127#[derive(Debug, PartialEq, Eq, Clone)] 127#[derive(Debug, PartialEq, Eq, Clone)]
128pub struct RawItem { 128pub(super) struct RawItem {
129 attrs: Attrs, 129 attrs: Attrs,
130 pub kind: RawItemKind, 130 pub(super) kind: RawItemKind,
131} 131}
132 132
133impl RawItem { 133impl RawItem {
134 pub fn attrs(&self) -> &[Attr] { 134 pub(super) fn attrs(&self) -> &[Attr] {
135 self.attrs.as_ref().map_or(&[], |it| &*it) 135 self.attrs.as_ref().map_or(&[], |it| &*it)
136 } 136 }
137} 137}
138 138
139#[derive(Debug, PartialEq, Eq, Clone, Copy)] 139#[derive(Debug, PartialEq, Eq, Clone, Copy)]
140pub enum RawItemKind { 140pub(super) enum RawItemKind {
141 Module(Module), 141 Module(Module),
142 Import(ImportId), 142 Import(ImportId),
143 Def(Def), 143 Def(Def),
@@ -145,11 +145,11 @@ pub enum RawItemKind {
145} 145}
146 146
147#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 147#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
148pub struct Module(RawId); 148pub(super) struct Module(RawId);
149impl_arena_id!(Module); 149impl_arena_id!(Module);
150 150
151#[derive(Debug, PartialEq, Eq)] 151#[derive(Debug, PartialEq, Eq)]
152pub enum ModuleData { 152pub(super) enum ModuleData {
153 Declaration { name: Name, ast_id: FileAstId<ast::Module> }, 153 Declaration { name: Name, ast_id: FileAstId<ast::Module> },
154 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, 154 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
155} 155}
@@ -160,26 +160,26 @@ impl_arena_id!(ImportId);
160 160
161#[derive(Debug, Clone, PartialEq, Eq)] 161#[derive(Debug, Clone, PartialEq, Eq)]
162pub struct ImportData { 162pub struct ImportData {
163 pub path: Path, 163 pub(super) path: Path,
164 pub alias: Option<Name>, 164 pub(super) alias: Option<Name>,
165 pub is_glob: bool, 165 pub(super) is_glob: bool,
166 pub is_prelude: bool, 166 pub(super) is_prelude: bool,
167 pub is_extern_crate: bool, 167 pub(super) is_extern_crate: bool,
168 pub is_macro_use: bool, 168 pub(super) is_macro_use: bool,
169} 169}
170 170
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
172pub struct Def(RawId); 172pub(super) struct Def(RawId);
173impl_arena_id!(Def); 173impl_arena_id!(Def);
174 174
175#[derive(Debug, PartialEq, Eq)] 175#[derive(Debug, PartialEq, Eq)]
176pub struct DefData { 176pub(super) struct DefData {
177 pub name: Name, 177 pub(super) name: Name,
178 pub kind: DefKind, 178 pub(super) kind: DefKind,
179} 179}
180 180
181#[derive(Debug, PartialEq, Eq, Clone, Copy)] 181#[derive(Debug, PartialEq, Eq, Clone, Copy)]
182pub enum DefKind { 182pub(super) enum DefKind {
183 Function(FileAstId<ast::FnDef>), 183 Function(FileAstId<ast::FnDef>),
184 Struct(FileAstId<ast::StructDef>), 184 Struct(FileAstId<ast::StructDef>),
185 Union(FileAstId<ast::StructDef>), 185 Union(FileAstId<ast::StructDef>),
@@ -191,15 +191,15 @@ pub enum DefKind {
191} 191}
192 192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
194pub struct Macro(RawId); 194pub(super) struct Macro(RawId);
195impl_arena_id!(Macro); 195impl_arena_id!(Macro);
196 196
197#[derive(Debug, PartialEq, Eq)] 197#[derive(Debug, PartialEq, Eq)]
198pub struct MacroData { 198pub(super) struct MacroData {
199 pub ast_id: FileAstId<ast::MacroCall>, 199 pub(super) ast_id: FileAstId<ast::MacroCall>,
200 pub path: Path, 200 pub(super) path: Path,
201 pub name: Option<Name>, 201 pub(super) name: Option<Name>,
202 pub export: bool, 202 pub(super) export: bool,
203} 203}
204 204
205struct RawItemsCollector { 205struct RawItemsCollector {