Skip to content

Commit 2865b31

Browse files
committed
Simplify completion config path resolutions
1 parent 339f629 commit 2865b31

File tree

3 files changed

+49
-94
lines changed

3 files changed

+49
-94
lines changed

crates/hir/src/semantics.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2060,6 +2060,11 @@ impl SemanticsScope<'_> {
20602060
)
20612061
}
20622062

2063+
pub fn resolve_mod_path(&self, path: &ModPath) -> impl Iterator<Item = ItemInNs> {
2064+
let items = self.resolver.resolve_module_path_in_items(self.db.upcast(), path);
2065+
items.iter_items().map(|(item, _)| item.into())
2066+
}
2067+
20632068
/// Iterates over associated types that may be specified after the given path (using
20642069
/// `Ty::Assoc` syntax).
20652070
pub fn assoc_type_shorthand_candidates<R>(

crates/ide-completion/src/context.rs

Lines changed: 33 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ mod tests;
77
use std::{iter, ops::ControlFlow};
88

99
use hir::{
10-
db::DefDatabase, HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics,
10+
HasAttrs, Local, ModPath, ModuleDef, ModuleSource, Name, PathResolution, ScopeDef, Semantics,
1111
SemanticsScope, Symbol, Type, TypeInfo,
1212
};
1313
use ide_db::{
@@ -758,15 +758,43 @@ impl<'a> CompletionContext<'a> {
758758
});
759759

760760
let depth_from_crate_root = iter::successors(Some(module), |m| m.parent(db))
761-
// `BlockExpr` modules are not count as module depth
761+
// `BlockExpr` modules do not count towards module depth
762762
.filter(|m| !matches!(m.definition_source(db).value, ModuleSource::BlockExpr(_)))
763763
.count()
764764
// exclude `m` itself
765765
.saturating_sub(1);
766766

767-
let exclude_traits = resolve_exclude_traits_list(db, config.exclude_traits);
768-
let mut exclude_flyimport_traits =
769-
resolve_exclude_traits_list(db, config.exclude_flyimport_traits);
767+
let exclude_traits: FxHashSet<_> = config
768+
.exclude_traits
769+
.iter()
770+
.filter_map(|path| {
771+
scope
772+
.resolve_mod_path(&ModPath::from_segments(
773+
hir::PathKind::Plain,
774+
path.split("::").map(Symbol::intern).map(Name::new_symbol_root),
775+
))
776+
.find_map(|it| match it {
777+
hir::ItemInNs::Types(ModuleDef::Trait(t)) => Some(t),
778+
_ => None,
779+
})
780+
})
781+
.collect();
782+
783+
let mut exclude_flyimport_traits: FxHashSet<_> = config
784+
.exclude_flyimport_traits
785+
.iter()
786+
.filter_map(|path| {
787+
scope
788+
.resolve_mod_path(&ModPath::from_segments(
789+
hir::PathKind::Plain,
790+
path.split("::").map(Symbol::intern).map(Name::new_symbol_root),
791+
))
792+
.find_map(|it| match it {
793+
hir::ItemInNs::Types(ModuleDef::Trait(t)) => Some(t),
794+
_ => None,
795+
})
796+
})
797+
.collect();
770798
exclude_flyimport_traits.extend(exclude_traits.iter().copied());
771799

772800
let complete_semicolon = if config.add_semicolon_to_unit {
@@ -841,71 +869,6 @@ impl<'a> CompletionContext<'a> {
841869
}
842870
}
843871

844-
fn resolve_exclude_traits_list(db: &RootDatabase, traits: &[String]) -> FxHashSet<hir::Trait> {
845-
let _g = tracing::debug_span!("resolve_exclude_trait_list", ?traits).entered();
846-
let crate_graph = db.crate_graph();
847-
let mut crate_name_to_def_map = FxHashMap::default();
848-
let mut result = FxHashSet::default();
849-
'process_traits: for trait_ in traits {
850-
let mut segments = trait_.split("::").peekable();
851-
let Some(crate_name) = segments.next() else {
852-
tracing::error!(
853-
?trait_,
854-
"error resolving trait from traits exclude list: invalid path"
855-
);
856-
continue;
857-
};
858-
let Some(def_map) = crate_name_to_def_map.entry(crate_name).or_insert_with(|| {
859-
let krate = crate_graph
860-
.iter()
861-
.find(|&krate| crate_graph[krate].display_name.as_deref() == Some(crate_name));
862-
let def_map = krate.map(|krate| db.crate_def_map(krate));
863-
if def_map.is_none() {
864-
tracing::error!(
865-
"error resolving `{trait_}` from trait exclude lists: crate could not be found"
866-
);
867-
}
868-
def_map
869-
}) else {
870-
// Do not report more than one error for the same crate.
871-
continue;
872-
};
873-
let mut module = &def_map[hir::DefMap::ROOT];
874-
let trait_name = 'lookup_mods: {
875-
while let Some(segment) = segments.next() {
876-
if segments.peek().is_none() {
877-
break 'lookup_mods segment;
878-
}
879-
880-
let Some(&inner) =
881-
module.children.get(&Name::new_symbol_root(hir::Symbol::intern(segment)))
882-
else {
883-
tracing::error!(
884-
"error resolving `{trait_}` from trait exclude lists: could not find module `{segment}`"
885-
);
886-
continue 'process_traits;
887-
};
888-
module = &def_map[inner];
889-
}
890-
891-
tracing::error!("error resolving `{trait_}` from trait exclude lists: invalid path");
892-
continue 'process_traits;
893-
};
894-
let resolved_trait = module
895-
.scope
896-
.trait_by_name(&Name::new_symbol_root(hir::Symbol::intern(trait_name)))
897-
.map(hir::Trait::from);
898-
let Some(resolved_trait) = resolved_trait else {
899-
tracing::error!(
900-
"error resolving `{trait_}` from trait exclude lists: trait could not be found"
901-
);
902-
continue;
903-
};
904-
result.insert(resolved_trait);
905-
}
906-
result
907-
}
908-
909872
const OP_TRAIT_LANG_NAMES: &[&str] = &[
910873
"add_assign",
911874
"add",

crates/ide-completion/src/snippet.rs

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@
100100
// }
101101
// ----
102102

103+
use hir::{ModPath, Name, Symbol};
103104
use ide_db::imports::import_assets::LocatedImport;
104105
use itertools::Itertools;
105-
use syntax::{ast, AstNode, GreenNode, SyntaxNode};
106106

107107
use crate::context::CompletionContext;
108108

@@ -123,10 +123,7 @@ pub struct Snippet {
123123
pub scope: SnippetScope,
124124
pub description: Option<Box<str>>,
125125
snippet: String,
126-
// These are `ast::Path`'s but due to SyntaxNodes not being Send we store these
127-
// and reconstruct them on demand instead. This is cheaper than reparsing them
128-
// from strings
129-
requires: Box<[GreenNode]>,
126+
requires: Box<[ModPath]>,
130127
}
131128

132129
impl Snippet {
@@ -143,7 +140,6 @@ impl Snippet {
143140
}
144141
let (requires, snippet, description) = validate_snippet(snippet, description, requires)?;
145142
Some(Snippet {
146-
// Box::into doesn't work as that has a Copy bound 😒
147143
postfix_triggers: postfix_triggers.iter().map(String::as_str).map(Into::into).collect(),
148144
prefix_triggers: prefix_triggers.iter().map(String::as_str).map(Into::into).collect(),
149145
scope,
@@ -167,15 +163,11 @@ impl Snippet {
167163
}
168164
}
169165

170-
fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option<Vec<LocatedImport>> {
166+
fn import_edits(ctx: &CompletionContext<'_>, requires: &[ModPath]) -> Option<Vec<LocatedImport>> {
171167
let import_cfg = ctx.config.import_path_config();
172168

173-
let resolve = |import: &GreenNode| {
174-
let path = ast::Path::cast(SyntaxNode::new_root(import.clone()))?;
175-
let item = match ctx.scope.speculative_resolve(&path)? {
176-
hir::PathResolution::Def(def) => def.into(),
177-
_ => return None,
178-
};
169+
let resolve = |import| {
170+
let item = ctx.scope.resolve_mod_path(import).next()?;
179171
let path = ctx.module.find_use_path(
180172
ctx.db,
181173
item,
@@ -198,19 +190,14 @@ fn validate_snippet(
198190
snippet: &[String],
199191
description: &str,
200192
requires: &[String],
201-
) -> Option<(Box<[GreenNode]>, String, Option<Box<str>>)> {
193+
) -> Option<(Box<[ModPath]>, String, Option<Box<str>>)> {
202194
let mut imports = Vec::with_capacity(requires.len());
203195
for path in requires.iter() {
204-
let use_path =
205-
ast::SourceFile::parse(&format!("use {path};"), syntax::Edition::CURRENT_FIXME)
206-
.syntax_node()
207-
.descendants()
208-
.find_map(ast::Path::cast)?;
209-
if use_path.syntax().text() != path.as_str() {
210-
return None;
211-
}
212-
let green = use_path.syntax().green().into_owned();
213-
imports.push(green);
196+
let use_path = ModPath::from_segments(
197+
hir::PathKind::Plain,
198+
path.split("::").map(Symbol::intern).map(Name::new_symbol_root),
199+
);
200+
imports.push(use_path);
214201
}
215202
let snippet = snippet.iter().join("\n");
216203
let description = (!description.is_empty())

0 commit comments

Comments
 (0)