diff options
author | Kirill Bulatov <[email protected]> | 2020-02-09 22:22:12 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-02-12 15:18:41 +0000 |
commit | 24ab3e80ca258a3db21bf263225c52d9995a2ea0 (patch) | |
tree | 8704eab78d09528e5d81a1fb328abb26fa448c01 /crates | |
parent | 5bf669860984a2c058b3bdc3e43b4993a0f25b31 (diff) |
Resolve methods and functions better
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/handlers/auto_import.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir/src/source_analyzer.rs | 60 |
2 files changed, 74 insertions, 9 deletions
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 1fb701da5..10984d8ad 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -46,9 +46,9 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { | |||
46 | 46 | ||
47 | let name_ref_to_import = | 47 | let name_ref_to_import = |
48 | path_under_caret.syntax().descendants().find_map(ast::NameRef::cast)?; | 48 | path_under_caret.syntax().descendants().find_map(ast::NameRef::cast)?; |
49 | if source_analyzer | 49 | if dbg!(source_analyzer |
50 | .resolve_path(ctx.db, &name_ref_to_import.syntax().ancestors().find_map(ast::Path::cast)?) | 50 | .resolve_path(ctx.db, &name_ref_to_import.syntax().ancestors().find_map(ast::Path::cast)?)) |
51 | .is_some() | 51 | .is_some() |
52 | { | 52 | { |
53 | return None; | 53 | return None; |
54 | } | 54 | } |
@@ -290,4 +290,21 @@ mod tests { | |||
290 | ", | 290 | ", |
291 | ); | 291 | ); |
292 | } | 292 | } |
293 | |||
294 | #[test] | ||
295 | fn not_applicable_for_imported_function() { | ||
296 | check_assist_not_applicable( | ||
297 | auto_import, | ||
298 | r" | ||
299 | pub mod test_mod { | ||
300 | pub fn test_function() {} | ||
301 | } | ||
302 | |||
303 | use test_mod::test_function; | ||
304 | fn main() { | ||
305 | test_function<|> | ||
306 | } | ||
307 | ", | ||
308 | ); | ||
309 | } | ||
293 | } | 310 | } |
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index bb9a35c5d..49e1a10e0 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -20,7 +20,10 @@ use hir_def::{ | |||
20 | use hir_expand::{ | 20 | use hir_expand::{ |
21 | hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind, | 21 | hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind, |
22 | }; | 22 | }; |
23 | use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment}; | 23 | use hir_ty::{ |
24 | method_resolution::{iterate_method_candidates, LookupMode}, | ||
25 | Canonical, InEnvironment, InferenceResult, TraitEnvironment, | ||
26 | }; | ||
24 | use ra_syntax::{ | 27 | use ra_syntax::{ |
25 | ast::{self, AstNode}, | 28 | ast::{self, AstNode}, |
26 | AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit, | 29 | AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit, |
@@ -28,8 +31,8 @@ use ra_syntax::{ | |||
28 | use rustc_hash::FxHashSet; | 31 | use rustc_hash::FxHashSet; |
29 | 32 | ||
30 | use crate::{ | 33 | use crate::{ |
31 | db::HirDatabase, Adt, Const, DefWithBody, EnumVariant, Function, Local, MacroDef, Name, Path, | 34 | db::HirDatabase, Adt, AssocItem, Const, DefWithBody, EnumVariant, Function, Local, MacroDef, |
32 | ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, | 35 | ModuleDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, |
33 | }; | 36 | }; |
34 | 37 | ||
35 | /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of | 38 | /// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of |
@@ -289,9 +292,11 @@ impl SourceAnalyzer { | |||
289 | 292 | ||
290 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { | 293 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { |
291 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { | 294 | if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { |
292 | let expr_id = self.expr_id(&path_expr.into())?; | 295 | let path_resolution = self |
293 | if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { | 296 | .resolve_as_full_path(path_expr.clone()) |
294 | return Some(PathResolution::AssocItem(assoc.into())); | 297 | .or_else(|| self.resolve_as_path_to_method(db, &path_expr)); |
298 | if path_resolution.is_some() { | ||
299 | return path_resolution; | ||
295 | } | 300 | } |
296 | } | 301 | } |
297 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { | 302 | if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { |
@@ -305,6 +310,49 @@ impl SourceAnalyzer { | |||
305 | self.resolve_hir_path(db, &hir_path) | 310 | self.resolve_hir_path(db, &hir_path) |
306 | } | 311 | } |
307 | 312 | ||
313 | fn resolve_as_full_path(&self, path_expr: ast::PathExpr) -> Option<PathResolution> { | ||
314 | let expr_id = self.expr_id(&path_expr.into())?; | ||
315 | self.infer | ||
316 | .as_ref()? | ||
317 | .assoc_resolutions_for_expr(expr_id) | ||
318 | .map(|assoc| PathResolution::AssocItem(assoc.into())) | ||
319 | } | ||
320 | |||
321 | fn resolve_as_path_to_method( | ||
322 | &self, | ||
323 | db: &impl HirDatabase, | ||
324 | path_expr: &ast::PathExpr, | ||
325 | ) -> Option<PathResolution> { | ||
326 | let full_path = path_expr.path()?; | ||
327 | let path_to_method = full_path.qualifier()?; | ||
328 | let method_name = full_path.segment()?.syntax().to_string(); | ||
329 | match self.resolve_path(db, &path_to_method)? { | ||
330 | PathResolution::Def(ModuleDef::Adt(adt)) => { | ||
331 | let ty = adt.ty(db); | ||
332 | iterate_method_candidates( | ||
333 | &Canonical { value: ty.ty.value, num_vars: 0 }, | ||
334 | db, | ||
335 | ty.ty.environment, | ||
336 | self.resolver.krate()?, | ||
337 | &self.resolver.traits_in_scope(db), | ||
338 | None, | ||
339 | LookupMode::Path, | ||
340 | |_, assoc_item_id| { | ||
341 | let assoc = assoc_item_id.into(); | ||
342 | if let AssocItem::Function(function) = assoc { | ||
343 | if function.name(db).to_string() == method_name { | ||
344 | return Some(assoc); | ||
345 | } | ||
346 | } | ||
347 | None | ||
348 | }, | ||
349 | ) | ||
350 | } | ||
351 | _ => None, | ||
352 | } | ||
353 | .map(PathResolution::AssocItem) | ||
354 | } | ||
355 | |||
308 | fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { | 356 | fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { |
309 | let name = name_ref.as_name(); | 357 | let name = name_ref.as_name(); |
310 | let source_map = self.body_source_map.as_ref()?; | 358 | let source_map = self.body_source_map.as_ref()?; |