about summary refs log tree commit diff
path: root/src/tools/rust-analyzer/crates/ide-completion
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2025-01-01 14:26:10 +0100
committerLukas Wirth <lukastw97@gmail.com>2025-01-01 14:32:45 +0100
commit786056cb828637f9e1514c8b91e2bb026441cb22 (patch)
treeddf9360631151da96d5b36d7df2beeacbfc97ca9 /src/tools/rust-analyzer/crates/ide-completion
parent13af22df98c790875d0a31f49c19cfd84e14d424 (diff)
downloadrust-786056cb828637f9e1514c8b91e2bb026441cb22.tar.gz
rust-786056cb828637f9e1514c8b91e2bb026441cb22.zip
Simplify completion config path resolutions
Diffstat (limited to 'src/tools/rust-analyzer/crates/ide-completion')
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs103
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs35
2 files changed, 44 insertions, 94 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index db909874dfe..c4365284251 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -7,7 +7,7 @@ mod tests;
 use std::{iter, ops::ControlFlow};
 
 use hir::{
-    db::DefDatabase, HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics,
+    HasAttrs, Local, ModPath, ModuleDef, ModuleSource, Name, PathResolution, ScopeDef, Semantics,
     SemanticsScope, Symbol, Type, TypeInfo,
 };
 use ide_db::{
@@ -758,15 +758,43 @@ impl<'a> CompletionContext<'a> {
         });
 
         let depth_from_crate_root = iter::successors(Some(module), |m| m.parent(db))
-            // `BlockExpr` modules are not count as module depth
+            // `BlockExpr` modules do not count towards module depth
             .filter(|m| !matches!(m.definition_source(db).value, ModuleSource::BlockExpr(_)))
             .count()
             // exclude `m` itself
             .saturating_sub(1);
 
-        let exclude_traits = resolve_exclude_traits_list(db, config.exclude_traits);
-        let mut exclude_flyimport_traits =
-            resolve_exclude_traits_list(db, config.exclude_flyimport_traits);
+        let exclude_traits: FxHashSet<_> = config
+            .exclude_traits
+            .iter()
+            .filter_map(|path| {
+                scope
+                    .resolve_mod_path(&ModPath::from_segments(
+                        hir::PathKind::Plain,
+                        path.split("::").map(Symbol::intern).map(Name::new_symbol_root),
+                    ))
+                    .find_map(|it| match it {
+                        hir::ItemInNs::Types(ModuleDef::Trait(t)) => Some(t),
+                        _ => None,
+                    })
+            })
+            .collect();
+
+        let mut exclude_flyimport_traits: FxHashSet<_> = config
+            .exclude_flyimport_traits
+            .iter()
+            .filter_map(|path| {
+                scope
+                    .resolve_mod_path(&ModPath::from_segments(
+                        hir::PathKind::Plain,
+                        path.split("::").map(Symbol::intern).map(Name::new_symbol_root),
+                    ))
+                    .find_map(|it| match it {
+                        hir::ItemInNs::Types(ModuleDef::Trait(t)) => Some(t),
+                        _ => None,
+                    })
+            })
+            .collect();
         exclude_flyimport_traits.extend(exclude_traits.iter().copied());
 
         let complete_semicolon = if config.add_semicolon_to_unit {
@@ -841,71 +869,6 @@ impl<'a> CompletionContext<'a> {
     }
 }
 
-fn resolve_exclude_traits_list(db: &RootDatabase, traits: &[String]) -> FxHashSet<hir::Trait> {
-    let _g = tracing::debug_span!("resolve_exclude_trait_list", ?traits).entered();
-    let crate_graph = db.crate_graph();
-    let mut crate_name_to_def_map = FxHashMap::default();
-    let mut result = FxHashSet::default();
-    'process_traits: for trait_ in traits {
-        let mut segments = trait_.split("::").peekable();
-        let Some(crate_name) = segments.next() else {
-            tracing::error!(
-                ?trait_,
-                "error resolving trait from traits exclude list: invalid path"
-            );
-            continue;
-        };
-        let Some(def_map) = crate_name_to_def_map.entry(crate_name).or_insert_with(|| {
-            let krate = crate_graph
-                .iter()
-                .find(|&krate| crate_graph[krate].display_name.as_deref() == Some(crate_name));
-            let def_map = krate.map(|krate| db.crate_def_map(krate));
-            if def_map.is_none() {
-                tracing::error!(
-                    "error resolving `{trait_}` from trait exclude lists: crate could not be found"
-                );
-            }
-            def_map
-        }) else {
-            // Do not report more than one error for the same crate.
-            continue;
-        };
-        let mut module = &def_map[hir::DefMap::ROOT];
-        let trait_name = 'lookup_mods: {
-            while let Some(segment) = segments.next() {
-                if segments.peek().is_none() {
-                    break 'lookup_mods segment;
-                }
-
-                let Some(&inner) =
-                    module.children.get(&Name::new_symbol_root(hir::Symbol::intern(segment)))
-                else {
-                    tracing::error!(
-                        "error resolving `{trait_}` from trait exclude lists: could not find module `{segment}`"
-                    );
-                    continue 'process_traits;
-                };
-                module = &def_map[inner];
-            }
-
-            tracing::error!("error resolving `{trait_}` from trait exclude lists: invalid path");
-            continue 'process_traits;
-        };
-        let resolved_trait = module
-            .scope
-            .trait_by_name(&Name::new_symbol_root(hir::Symbol::intern(trait_name)))
-            .map(hir::Trait::from);
-        let Some(resolved_trait) = resolved_trait else {
-            tracing::error!(
-                "error resolving `{trait_}` from trait exclude lists: trait could not be found"
-            );
-            continue;
-        };
-        result.insert(resolved_trait);
-    }
-    result
-}
-
 const OP_TRAIT_LANG_NAMES: &[&str] = &[
     "add_assign",
     "add",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
index 5265aa8515b..04bb178c658 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
@@ -100,9 +100,9 @@
 // }
 // ----
 
+use hir::{ModPath, Name, Symbol};
 use ide_db::imports::import_assets::LocatedImport;
 use itertools::Itertools;
-use syntax::{ast, AstNode, GreenNode, SyntaxNode};
 
 use crate::context::CompletionContext;
 
@@ -123,10 +123,7 @@ pub struct Snippet {
     pub scope: SnippetScope,
     pub description: Option<Box<str>>,
     snippet: String,
-    // These are `ast::Path`'s but due to SyntaxNodes not being Send we store these
-    // and reconstruct them on demand instead. This is cheaper than reparsing them
-    // from strings
-    requires: Box<[GreenNode]>,
+    requires: Box<[ModPath]>,
 }
 
 impl Snippet {
@@ -143,7 +140,6 @@ impl Snippet {
         }
         let (requires, snippet, description) = validate_snippet(snippet, description, requires)?;
         Some(Snippet {
-            // Box::into doesn't work as that has a Copy bound 😒
             postfix_triggers: postfix_triggers.iter().map(String::as_str).map(Into::into).collect(),
             prefix_triggers: prefix_triggers.iter().map(String::as_str).map(Into::into).collect(),
             scope,
@@ -167,15 +163,11 @@ impl Snippet {
     }
 }
 
-fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option<Vec<LocatedImport>> {
+fn import_edits(ctx: &CompletionContext<'_>, requires: &[ModPath]) -> Option<Vec<LocatedImport>> {
     let import_cfg = ctx.config.import_path_config();
 
-    let resolve = |import: &GreenNode| {
-        let path = ast::Path::cast(SyntaxNode::new_root(import.clone()))?;
-        let item = match ctx.scope.speculative_resolve(&path)? {
-            hir::PathResolution::Def(def) => def.into(),
-            _ => return None,
-        };
+    let resolve = |import| {
+        let item = ctx.scope.resolve_mod_path(import).next()?;
         let path = ctx.module.find_use_path(
             ctx.db,
             item,
@@ -198,19 +190,14 @@ fn validate_snippet(
     snippet: &[String],
     description: &str,
     requires: &[String],
-) -> Option<(Box<[GreenNode]>, String, Option<Box<str>>)> {
+) -> Option<(Box<[ModPath]>, String, Option<Box<str>>)> {
     let mut imports = Vec::with_capacity(requires.len());
     for path in requires.iter() {
-        let use_path =
-            ast::SourceFile::parse(&format!("use {path};"), syntax::Edition::CURRENT_FIXME)
-                .syntax_node()
-                .descendants()
-                .find_map(ast::Path::cast)?;
-        if use_path.syntax().text() != path.as_str() {
-            return None;
-        }
-        let green = use_path.syntax().green().into_owned();
-        imports.push(green);
+        let use_path = ModPath::from_segments(
+            hir::PathKind::Plain,
+            path.split("::").map(Symbol::intern).map(Name::new_symbol_root),
+        );
+        imports.push(use_path);
     }
     let snippet = snippet.iter().join("\n");
     let description = (!description.is_empty())