diff options
Diffstat (limited to 'crates/ra_hir/src/source_analyzer.rs')
-rw-r--r-- | crates/ra_hir/src/source_analyzer.rs | 247 |
1 files changed, 102 insertions, 145 deletions
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index efa3f8a79..c650a9e08 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -11,32 +11,31 @@ use either::Either; | |||
11 | use hir_def::{ | 11 | use hir_def::{ |
12 | body::{ | 12 | body::{ |
13 | scope::{ExprScopes, ScopeId}, | 13 | scope::{ExprScopes, ScopeId}, |
14 | BodySourceMap, | 14 | Body, BodySourceMap, |
15 | }, | 15 | }, |
16 | expr::{ExprId, PatId}, | 16 | expr::{ExprId, Pat, PatId}, |
17 | resolver::{self, resolver_for_scope, Resolver, TypeNs, ValueNs}, | 17 | resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs}, |
18 | AsMacroCall, DefWithBodyId, TraitId, | 18 | AsMacroCall, DefWithBodyId, |
19 | }; | 19 | }; |
20 | use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile, MacroCallId}; | 20 | use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; |
21 | use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment}; | 21 | use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment}; |
22 | use ra_syntax::{ | 22 | use ra_syntax::{ |
23 | ast::{self, AstNode}, | 23 | ast::{self, AstNode}, |
24 | AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit, | 24 | AstPtr, SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, |
25 | }; | 25 | }; |
26 | use rustc_hash::FxHashSet; | ||
27 | 26 | ||
28 | use crate::{ | 27 | use crate::{ |
29 | db::HirDatabase, Adt, Const, DefWithBody, EnumVariant, Function, Local, MacroDef, Name, Path, | 28 | db::HirDatabase, Adt, Const, EnumVariant, Function, Local, MacroDef, ModuleDef, Path, Static, |
30 | ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, | 29 | Struct, Trait, Type, TypeAlias, TypeParam, |
31 | }; | 30 | }; |
32 | 31 | ||
33 | /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of | 32 | /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of |
34 | /// original source files. It should not be used inside the HIR itself. | 33 | /// original source files. It should not be used inside the HIR itself. |
35 | #[derive(Debug)] | 34 | #[derive(Debug)] |
36 | pub struct SourceAnalyzer { | 35 | pub(crate) struct SourceAnalyzer { |
37 | file_id: HirFileId, | 36 | file_id: HirFileId, |
38 | resolver: Resolver, | 37 | pub(crate) resolver: Resolver, |
39 | body_owner: Option<DefWithBody>, | 38 | body: Option<Arc<Body>>, |
40 | body_source_map: Option<Arc<BodySourceMap>>, | 39 | body_source_map: Option<Arc<BodySourceMap>>, |
41 | infer: Option<Arc<InferenceResult>>, | 40 | infer: Option<Arc<InferenceResult>>, |
42 | scopes: Option<Arc<ExprScopes>>, | 41 | scopes: Option<Arc<ExprScopes>>, |
@@ -55,64 +54,20 @@ pub enum PathResolution { | |||
55 | AssocItem(crate::AssocItem), | 54 | AssocItem(crate::AssocItem), |
56 | } | 55 | } |
57 | 56 | ||
58 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
59 | pub struct ScopeEntryWithSyntax { | ||
60 | pub(crate) name: Name, | ||
61 | pub(crate) ptr: Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>, | ||
62 | } | ||
63 | |||
64 | impl ScopeEntryWithSyntax { | ||
65 | pub fn name(&self) -> &Name { | ||
66 | &self.name | ||
67 | } | ||
68 | |||
69 | pub fn ptr(&self) -> Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>> { | ||
70 | self.ptr | ||
71 | } | ||
72 | } | ||
73 | |||
74 | #[derive(Debug)] | 57 | #[derive(Debug)] |
75 | pub struct ReferenceDescriptor { | 58 | pub struct ReferenceDescriptor { |
76 | pub range: TextRange, | 59 | pub range: TextRange, |
77 | pub name: String, | 60 | pub name: String, |
78 | } | 61 | } |
79 | 62 | ||
80 | #[derive(Debug)] | ||
81 | pub struct Expansion { | ||
82 | macro_call_id: MacroCallId, | ||
83 | } | ||
84 | |||
85 | impl Expansion { | ||
86 | pub fn map_token_down( | ||
87 | &self, | ||
88 | db: &impl HirDatabase, | ||
89 | token: InFile<&SyntaxToken>, | ||
90 | ) -> Option<InFile<SyntaxToken>> { | ||
91 | let exp_info = self.file_id().expansion_info(db)?; | ||
92 | exp_info.map_token_down(token) | ||
93 | } | ||
94 | |||
95 | pub fn file_id(&self) -> HirFileId { | ||
96 | self.macro_call_id.as_file() | ||
97 | } | ||
98 | } | ||
99 | |||
100 | impl SourceAnalyzer { | 63 | impl SourceAnalyzer { |
101 | pub fn new( | ||
102 | db: &impl HirDatabase, | ||
103 | node: InFile<&SyntaxNode>, | ||
104 | offset: Option<TextUnit>, | ||
105 | ) -> SourceAnalyzer { | ||
106 | crate::source_binder::SourceBinder::new(db).analyze(node, offset) | ||
107 | } | ||
108 | |||
109 | pub(crate) fn new_for_body( | 64 | pub(crate) fn new_for_body( |
110 | db: &impl HirDatabase, | 65 | db: &impl HirDatabase, |
111 | def: DefWithBodyId, | 66 | def: DefWithBodyId, |
112 | node: InFile<&SyntaxNode>, | 67 | node: InFile<&SyntaxNode>, |
113 | offset: Option<TextUnit>, | 68 | offset: Option<TextUnit>, |
114 | ) -> SourceAnalyzer { | 69 | ) -> SourceAnalyzer { |
115 | let (_body, source_map) = db.body_with_source_map(def); | 70 | let (body, source_map) = db.body_with_source_map(def); |
116 | let scopes = db.expr_scopes(def); | 71 | let scopes = db.expr_scopes(def); |
117 | let scope = match offset { | 72 | let scope = match offset { |
118 | None => scope_for(&scopes, &source_map, node), | 73 | None => scope_for(&scopes, &source_map, node), |
@@ -121,7 +76,7 @@ impl SourceAnalyzer { | |||
121 | let resolver = resolver_for_scope(db, def, scope); | 76 | let resolver = resolver_for_scope(db, def, scope); |
122 | SourceAnalyzer { | 77 | SourceAnalyzer { |
123 | resolver, | 78 | resolver, |
124 | body_owner: Some(def.into()), | 79 | body: Some(body), |
125 | body_source_map: Some(source_map), | 80 | body_source_map: Some(source_map), |
126 | infer: Some(db.infer(def)), | 81 | infer: Some(db.infer(def)), |
127 | scopes: Some(scopes), | 82 | scopes: Some(scopes), |
@@ -135,7 +90,7 @@ impl SourceAnalyzer { | |||
135 | ) -> SourceAnalyzer { | 90 | ) -> SourceAnalyzer { |
136 | SourceAnalyzer { | 91 | SourceAnalyzer { |
137 | resolver, | 92 | resolver, |
138 | body_owner: None, | 93 | body: None, |
139 | body_source_map: None, | 94 | body_source_map: None, |
140 | infer: None, | 95 | infer: None, |
141 | scopes: None, | 96 | scopes: None, |
@@ -143,10 +98,6 @@ impl SourceAnalyzer { | |||
143 | } | 98 | } |
144 | } | 99 | } |
145 | 100 | ||
146 | pub fn module(&self) -> Option<crate::code_model::Module> { | ||
147 | Some(crate::code_model::Module { id: self.resolver.module()? }) | ||
148 | } | ||
149 | |||
150 | fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { | 101 | fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { |
151 | let src = InFile { file_id: self.file_id, value: expr }; | 102 | let src = InFile { file_id: self.file_id, value: expr }; |
152 | self.body_source_map.as_ref()?.node_expr(src) | 103 | self.body_source_map.as_ref()?.node_expr(src) |
@@ -180,7 +131,7 @@ impl SourceAnalyzer { | |||
180 | TraitEnvironment::lower(db, &self.resolver) | 131 | TraitEnvironment::lower(db, &self.resolver) |
181 | } | 132 | } |
182 | 133 | ||
183 | pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> { | 134 | pub(crate) fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> { |
184 | let expr_id = if let Some(expr) = self.expand_expr(db, InFile::new(self.file_id, expr)) { | 135 | let expr_id = if let Some(expr) = self.expand_expr(db, InFile::new(self.file_id, expr)) { |
185 | self.body_source_map.as_ref()?.node_expr(expr.as_ref())? | 136 | self.body_source_map.as_ref()?.node_expr(expr.as_ref())? |
186 | } else { | 137 | } else { |
@@ -192,24 +143,27 @@ impl SourceAnalyzer { | |||
192 | Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) | 143 | Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) |
193 | } | 144 | } |
194 | 145 | ||
195 | pub fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option<Type> { | 146 | pub(crate) fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option<Type> { |
196 | let pat_id = self.pat_id(pat)?; | 147 | let pat_id = self.pat_id(pat)?; |
197 | let ty = self.infer.as_ref()?[pat_id].clone(); | 148 | let ty = self.infer.as_ref()?[pat_id].clone(); |
198 | let environment = self.trait_env(db); | 149 | let environment = self.trait_env(db); |
199 | Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) | 150 | Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) |
200 | } | 151 | } |
201 | 152 | ||
202 | pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { | 153 | pub(crate) fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> { |
203 | let expr_id = self.expr_id(&call.clone().into())?; | 154 | let expr_id = self.expr_id(&call.clone().into())?; |
204 | self.infer.as_ref()?.method_resolution(expr_id).map(Function::from) | 155 | self.infer.as_ref()?.method_resolution(expr_id).map(Function::from) |
205 | } | 156 | } |
206 | 157 | ||
207 | pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { | 158 | pub(crate) fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> { |
208 | let expr_id = self.expr_id(&field.clone().into())?; | 159 | let expr_id = self.expr_id(&field.clone().into())?; |
209 | self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) | 160 | self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) |
210 | } | 161 | } |
211 | 162 | ||
212 | pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<crate::StructField> { | 163 | pub(crate) fn resolve_record_field( |
164 | &self, | ||
165 | field: &ast::RecordField, | ||
166 | ) -> Option<crate::StructField> { | ||
213 | let expr_id = match field.expr() { | 167 | let expr_id = match field.expr() { |
214 | Some(it) => self.expr_id(&it)?, | 168 | Some(it) => self.expr_id(&it)?, |
215 | None => { | 169 | None => { |
@@ -220,17 +174,23 @@ impl SourceAnalyzer { | |||
220 | self.infer.as_ref()?.record_field_resolution(expr_id).map(|it| it.into()) | 174 | self.infer.as_ref()?.record_field_resolution(expr_id).map(|it| it.into()) |
221 | } | 175 | } |
222 | 176 | ||
223 | pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option<crate::VariantDef> { | 177 | pub(crate) fn resolve_record_literal( |
178 | &self, | ||
179 | record_lit: &ast::RecordLit, | ||
180 | ) -> Option<crate::VariantDef> { | ||
224 | let expr_id = self.expr_id(&record_lit.clone().into())?; | 181 | let expr_id = self.expr_id(&record_lit.clone().into())?; |
225 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id).map(|it| it.into()) | 182 | self.infer.as_ref()?.variant_resolution_for_expr(expr_id).map(|it| it.into()) |
226 | } | 183 | } |
227 | 184 | ||
228 | pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option<crate::VariantDef> { | 185 | pub(crate) fn resolve_record_pattern( |
186 | &self, | ||
187 | record_pat: &ast::RecordPat, | ||
188 | ) -> Option<crate::VariantDef> { | ||
229 | let pat_id = self.pat_id(&record_pat.clone().into())?; | 189 | let pat_id = self.pat_id(&record_pat.clone().into())?; |
230 | self.infer.as_ref()?.variant_resolution_for_pat(pat_id).map(|it| it.into()) | 190 | self.infer.as_ref()?.variant_resolution_for_pat(pat_id).map(|it| it.into()) |
231 | } | 191 | } |
232 | 192 | ||
233 | pub fn resolve_macro_call( | 193 | pub(crate) fn resolve_macro_call( |
234 | &self, | 194 | &self, |
235 | db: &impl HirDatabase, | 195 | db: &impl HirDatabase, |
236 | macro_call: InFile<&ast::MacroCall>, | 196 | macro_call: InFile<&ast::MacroCall>, |
@@ -240,52 +200,29 @@ impl SourceAnalyzer { | |||
240 | self.resolver.resolve_path_as_macro(db, path.mod_path()).map(|it| it.into()) | 200 | self.resolver.resolve_path_as_macro(db, path.mod_path()).map(|it| it.into()) |
241 | } | 201 | } |
242 | 202 | ||
243 | pub fn resolve_hir_path( | 203 | pub(crate) fn resolve_bind_pat_to_const( |
244 | &self, | 204 | &self, |
245 | db: &impl HirDatabase, | 205 | db: &impl HirDatabase, |
246 | path: &crate::Path, | 206 | pat: &ast::BindPat, |
247 | ) -> Option<PathResolution> { | 207 | ) -> Option<ModuleDef> { |
248 | let types = | 208 | let pat_id = self.pat_id(&pat.clone().into())?; |
249 | self.resolver.resolve_path_in_type_ns_fully(db, path.mod_path()).map(|ty| match ty { | 209 | let body = self.body.as_ref()?; |
250 | TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), | 210 | let path = match &body[pat_id] { |
251 | TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }), | 211 | Pat::Path(path) => path, |
252 | TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { | 212 | _ => return None, |
253 | PathResolution::Def(Adt::from(it).into()) | 213 | }; |
254 | } | 214 | let res = resolve_hir_path(db, &self.resolver, &path)?; |
255 | TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), | 215 | match res { |
256 | TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), | 216 | PathResolution::Def(def) => Some(def), |
257 | TypeNs::BuiltinType(it) => PathResolution::Def(it.into()), | 217 | _ => None, |
258 | TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), | 218 | } |
259 | }); | ||
260 | let values = | ||
261 | self.resolver.resolve_path_in_value_ns_fully(db, path.mod_path()).and_then(|val| { | ||
262 | let res = match val { | ||
263 | ValueNs::LocalBinding(pat_id) => { | ||
264 | let var = Local { parent: self.body_owner?, pat_id }; | ||
265 | PathResolution::Local(var) | ||
266 | } | ||
267 | ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), | ||
268 | ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()), | ||
269 | ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()), | ||
270 | ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), | ||
271 | ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), | ||
272 | }; | ||
273 | Some(res) | ||
274 | }); | ||
275 | |||
276 | let items = self | ||
277 | .resolver | ||
278 | .resolve_module_path_in_items(db, path.mod_path()) | ||
279 | .take_types() | ||
280 | .map(|it| PathResolution::Def(it.into())); | ||
281 | types.or(values).or(items).or_else(|| { | ||
282 | self.resolver | ||
283 | .resolve_path_as_macro(db, path.mod_path()) | ||
284 | .map(|def| PathResolution::Macro(def.into())) | ||
285 | }) | ||
286 | } | 219 | } |
287 | 220 | ||
288 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { | 221 | pub(crate) fn resolve_path( |
222 | &self, | ||
223 | db: &impl HirDatabase, | ||
224 | path: &ast::Path, | ||
225 | ) -> Option<PathResolution> { | ||
289 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { | 226 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { |
290 | let expr_id = self.expr_id(&path_expr.into())?; | 227 | let expr_id = self.expr_id(&path_expr.into())?; |
291 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { | 228 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { |
@@ -300,40 +237,24 @@ impl SourceAnalyzer { | |||
300 | } | 237 | } |
301 | // This must be a normal source file rather than macro file. | 238 | // This must be a normal source file rather than macro file. |
302 | let hir_path = crate::Path::from_ast(path.clone())?; | 239 | let hir_path = crate::Path::from_ast(path.clone())?; |
303 | self.resolve_hir_path(db, &hir_path) | 240 | resolve_hir_path(db, &self.resolver, &hir_path) |
304 | } | 241 | } |
305 | 242 | ||
306 | fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { | 243 | fn resolve_local_name( |
244 | &self, | ||
245 | name_ref: &ast::NameRef, | ||
246 | ) -> Option<Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>> { | ||
307 | let name = name_ref.as_name(); | 247 | let name = name_ref.as_name(); |
308 | let source_map = self.body_source_map.as_ref()?; | 248 | let source_map = self.body_source_map.as_ref()?; |
309 | let scopes = self.scopes.as_ref()?; | 249 | let scopes = self.scopes.as_ref()?; |
310 | let scope = scope_for(scopes, source_map, InFile::new(self.file_id, name_ref.syntax()))?; | 250 | let scope = scope_for(scopes, source_map, InFile::new(self.file_id, name_ref.syntax()))?; |
311 | let entry = scopes.resolve_name_in_scope(scope, &name)?; | 251 | let entry = scopes.resolve_name_in_scope(scope, &name)?; |
312 | Some(ScopeEntryWithSyntax { | 252 | Some(source_map.pat_syntax(entry.pat())?.value) |
313 | name: entry.name().clone(), | ||
314 | ptr: source_map.pat_syntax(entry.pat())?.value, | ||
315 | }) | ||
316 | } | ||
317 | |||
318 | pub fn process_all_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, ScopeDef)) { | ||
319 | self.resolver.process_all_names(db, &mut |name, def| { | ||
320 | let def = match def { | ||
321 | resolver::ScopeDef::PerNs(it) => it.into(), | ||
322 | resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), | ||
323 | resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), | ||
324 | resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(TypeParam { id }), | ||
325 | resolver::ScopeDef::Local(pat_id) => { | ||
326 | let parent = self.resolver.body_owner().unwrap().into(); | ||
327 | ScopeDef::Local(Local { parent, pat_id }) | ||
328 | } | ||
329 | }; | ||
330 | f(name, def) | ||
331 | }) | ||
332 | } | 253 | } |
333 | 254 | ||
334 | // FIXME: we only use this in `inline_local_variable` assist, ideally, we | 255 | // FIXME: we only use this in `inline_local_variable` assist, ideally, we |
335 | // should switch to general reference search infra there. | 256 | // should switch to general reference search infra there. |
336 | pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { | 257 | pub(crate) fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { |
337 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); | 258 | let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); |
338 | let ptr = Either::Left(AstPtr::new(&ast::Pat::from(pat.clone()))); | 259 | let ptr = Either::Left(AstPtr::new(&ast::Pat::from(pat.clone()))); |
339 | fn_def | 260 | fn_def |
@@ -342,7 +263,7 @@ impl SourceAnalyzer { | |||
342 | .filter_map(ast::NameRef::cast) | 263 | .filter_map(ast::NameRef::cast) |
343 | .filter(|name_ref| match self.resolve_local_name(&name_ref) { | 264 | .filter(|name_ref| match self.resolve_local_name(&name_ref) { |
344 | None => false, | 265 | None => false, |
345 | Some(entry) => entry.ptr() == ptr, | 266 | Some(d_ptr) => d_ptr == ptr, |
346 | }) | 267 | }) |
347 | .map(|name_ref| ReferenceDescriptor { | 268 | .map(|name_ref| ReferenceDescriptor { |
348 | name: name_ref.text().to_string(), | 269 | name: name_ref.text().to_string(), |
@@ -351,19 +272,14 @@ impl SourceAnalyzer { | |||
351 | .collect() | 272 | .collect() |
352 | } | 273 | } |
353 | 274 | ||
354 | /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type | 275 | pub(crate) fn expand( |
355 | pub fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<TraitId> { | ||
356 | self.resolver.traits_in_scope(db) | ||
357 | } | ||
358 | |||
359 | pub fn expand( | ||
360 | &self, | 276 | &self, |
361 | db: &impl HirDatabase, | 277 | db: &impl HirDatabase, |
362 | macro_call: InFile<&ast::MacroCall>, | 278 | macro_call: InFile<&ast::MacroCall>, |
363 | ) -> Option<Expansion> { | 279 | ) -> Option<HirFileId> { |
364 | let macro_call_id = | 280 | let macro_call_id = |
365 | macro_call.as_call_id(db, |path| self.resolver.resolve_path_as_macro(db, &path))?; | 281 | macro_call.as_call_id(db, |path| self.resolver.resolve_path_as_macro(db, &path))?; |
366 | Some(Expansion { macro_call_id }) | 282 | Some(macro_call_id.as_file()) |
367 | } | 283 | } |
368 | } | 284 | } |
369 | 285 | ||
@@ -409,6 +325,47 @@ fn scope_for_offset( | |||
409 | }) | 325 | }) |
410 | } | 326 | } |
411 | 327 | ||
328 | pub(crate) fn resolve_hir_path( | ||
329 | db: &impl HirDatabase, | ||
330 | resolver: &Resolver, | ||
331 | path: &crate::Path, | ||
332 | ) -> Option<PathResolution> { | ||
333 | let types = resolver.resolve_path_in_type_ns_fully(db, path.mod_path()).map(|ty| match ty { | ||
334 | TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), | ||
335 | TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }), | ||
336 | TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => PathResolution::Def(Adt::from(it).into()), | ||
337 | TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), | ||
338 | TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), | ||
339 | TypeNs::BuiltinType(it) => PathResolution::Def(it.into()), | ||
340 | TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), | ||
341 | }); | ||
342 | let body_owner = resolver.body_owner(); | ||
343 | let values = resolver.resolve_path_in_value_ns_fully(db, path.mod_path()).and_then(|val| { | ||
344 | let res = match val { | ||
345 | ValueNs::LocalBinding(pat_id) => { | ||
346 | let var = Local { parent: body_owner?.into(), pat_id }; | ||
347 | PathResolution::Local(var) | ||
348 | } | ||
349 | ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), | ||
350 | ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()), | ||
351 | ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()), | ||
352 | ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), | ||
353 | ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), | ||
354 | }; | ||
355 | Some(res) | ||
356 | }); | ||
357 | |||
358 | let items = resolver | ||
359 | .resolve_module_path_in_items(db, path.mod_path()) | ||
360 | .take_types() | ||
361 | .map(|it| PathResolution::Def(it.into())); | ||
362 | types.or(values).or(items).or_else(|| { | ||
363 | resolver | ||
364 | .resolve_path_as_macro(db, path.mod_path()) | ||
365 | .map(|def| PathResolution::Macro(def.into())) | ||
366 | }) | ||
367 | } | ||
368 | |||
412 | // XXX: during completion, cursor might be outside of any particular | 369 | // XXX: during completion, cursor might be outside of any particular |
413 | // expression. Try to figure out the correct scope... | 370 | // expression. Try to figure out the correct scope... |
414 | fn adjust( | 371 | fn adjust( |