Skip to content

Commit 24ab3e8

Browse files
Resolve methods and functions better
1 parent 5bf6698 commit 24ab3e8

File tree

2 files changed

+74
-9
lines changed

2 files changed

+74
-9
lines changed

crates/ra_assists/src/handlers/auto_import.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
4646

4747
let name_ref_to_import =
4848
path_under_caret.syntax().descendants().find_map(ast::NameRef::cast)?;
49-
if source_analyzer
50-
.resolve_path(ctx.db, &name_ref_to_import.syntax().ancestors().find_map(ast::Path::cast)?)
51-
.is_some()
49+
if dbg!(source_analyzer
50+
.resolve_path(ctx.db, &name_ref_to_import.syntax().ancestors().find_map(ast::Path::cast)?))
51+
.is_some()
5252
{
5353
return None;
5454
}
@@ -290,4 +290,21 @@ mod tests {
290290
",
291291
);
292292
}
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+
}
293310
}

crates/ra_hir/src/source_analyzer.rs

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,19 @@ use hir_def::{
2020
use hir_expand::{
2121
hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind,
2222
};
23-
use hir_ty::{InEnvironment, InferenceResult, TraitEnvironment};
23+
use hir_ty::{
24+
method_resolution::{iterate_method_candidates, LookupMode},
25+
Canonical, InEnvironment, InferenceResult, TraitEnvironment,
26+
};
2427
use ra_syntax::{
2528
ast::{self, AstNode},
2629
AstPtr, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextUnit,
2730
};
2831
use rustc_hash::FxHashSet;
2932

3033
use crate::{
31-
db::HirDatabase, Adt, Const, DefWithBody, EnumVariant, Function, Local, MacroDef, Name, Path,
32-
ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam,
34+
db::HirDatabase, Adt, AssocItem, Const, DefWithBody, EnumVariant, Function, Local, MacroDef,
35+
ModuleDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam,
3336
};
3437

3538
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
@@ -289,9 +292,11 @@ impl SourceAnalyzer {
289292

290293
pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> {
291294
if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) {
292-
let expr_id = self.expr_id(&path_expr.into())?;
293-
if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) {
294-
return Some(PathResolution::AssocItem(assoc.into()));
295+
let path_resolution = self
296+
.resolve_as_full_path(path_expr.clone())
297+
.or_else(|| self.resolve_as_path_to_method(db, &path_expr));
298+
if path_resolution.is_some() {
299+
return path_resolution;
295300
}
296301
}
297302
if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) {
@@ -305,6 +310,49 @@ impl SourceAnalyzer {
305310
self.resolve_hir_path(db, &hir_path)
306311
}
307312

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+
308356
fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> {
309357
let name = name_ref.as_name();
310358
let source_map = self.body_source_map.as_ref()?;

0 commit comments

Comments
 (0)