about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2022-01-11 10:07:16 +0100
committerLukas Wirth <lukastw97@gmail.com>2022-01-11 10:28:38 +0100
commit4901ea3eef1aa01a231f76767fa5ee19e7f76cd9 (patch)
treed9a22004272429499cc0cbb9f65dc4a6fa30dfb8
parent94b369faa3bec8bfcbb833bae34682fad6f89bc4 (diff)
downloadrust-4901ea3eef1aa01a231f76767fa5ee19e7f76cd9.tar.gz
rust-4901ea3eef1aa01a231f76767fa5ee19e7f76cd9.zip
Lookup lang attribute on assoc item trait directly
-rw-r--r--crates/hir_def/src/attr.rs16
-rw-r--r--crates/ide_completion/src/context.rs81
-rw-r--r--crates/ide_completion/src/item.rs6
-rw-r--r--crates/ide_completion/src/render.rs18
4 files changed, 67 insertions, 54 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 30642f6cc61..c60ef87a939 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -255,6 +255,10 @@ impl Attrs {
         }
     }
 
+    pub fn lang(&self) -> Option<&SmolStr> {
+        self.by_key("lang").string_value()
+    }
+
     pub fn docs(&self) -> Option<Documentation> {
         let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? {
             AttrInput::Literal(s) => Some(s),
@@ -754,20 +758,20 @@ impl Attr {
 }
 
 #[derive(Debug, Clone, Copy)]
-pub struct AttrQuery<'a> {
-    attrs: &'a Attrs,
+pub struct AttrQuery<'attr> {
+    attrs: &'attr Attrs,
     key: &'static str,
 }
 
-impl<'a> AttrQuery<'a> {
-    pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
+impl<'attr> AttrQuery<'attr> {
+    pub fn tt_values(self) -> impl Iterator<Item = &'attr Subtree> {
         self.attrs().filter_map(|attr| match attr.input.as_deref()? {
             AttrInput::TokenTree(it, _) => Some(it),
             _ => None,
         })
     }
 
-    pub fn string_value(self) -> Option<&'a SmolStr> {
+    pub fn string_value(self) -> Option<&'attr SmolStr> {
         self.attrs().find_map(|attr| match attr.input.as_deref()? {
             AttrInput::Literal(it) => Some(it),
             _ => None,
@@ -778,7 +782,7 @@ impl<'a> AttrQuery<'a> {
         self.attrs().next().is_some()
     }
 
-    pub fn attrs(self) -> impl Iterator<Item = &'a Attr> + Clone {
+    pub fn attrs(self) -> impl Iterator<Item = &'attr Attr> + Clone {
         let key = self.key;
         self.attrs
             .iter()
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 965f9b356a4..0baca08ca99 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -3,14 +3,13 @@
 use std::iter;
 
 use base_db::SourceDatabaseExt;
-use hir::{known, Local, Name, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo};
+use hir::{HasAttrs, Local, Name, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo};
 use ide_db::{
     active_parameter::ActiveParameter,
     base_db::{FilePosition, SourceDatabase},
     helpers::FamousDefs,
     RootDatabase,
 };
-use rustc_hash::FxHashSet;
 use syntax::{
     algo::find_node_at_offset,
     ast::{self, HasName, NameOrNameRef},
@@ -124,8 +123,6 @@ pub(crate) struct CompletionContext<'a> {
     pub(super) path_context: Option<PathCompletionContext>,
 
     pub(super) locals: Vec<(Name, Local)>,
-    /// Operator traits defined in the project
-    pub(super) ops_traits: FxHashSet<hir::Trait>,
 
     no_completion_required: bool,
 }
@@ -315,7 +312,10 @@ impl<'a> CompletionContext<'a> {
 
     /// Whether the given trait is an operator trait or not.
     pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
-        self.ops_traits.contains(&trait_)
+        match trait_.attrs(self.db).lang() {
+            Some(lang) => OP_TRAIT_LANG_NAMES.contains(&lang.as_str()),
+            None => false,
+        }
     }
 
     /// A version of [`SemanticsScope::process_all_names`] that filters out `#[doc(hidden)]` items.
@@ -398,16 +398,6 @@ impl<'a> CompletionContext<'a> {
                 locals.push((name, local));
             }
         });
-        let mut ops_traits =
-            FxHashSet::with_capacity_and_hasher(OP_TRAIT_LANG_NAMES.len(), Default::default());
-        if let Some(krate) = krate {
-            let _p = profile::span("CompletionContext::new ops");
-            for trait_ in
-                OP_TRAIT_LANG_NAMES.iter().filter_map(|item| hir::Trait::lang(db, krate, item))
-            {
-                ops_traits.insert(trait_);
-            }
-        }
 
         let mut ctx = CompletionContext {
             sema,
@@ -434,7 +424,6 @@ impl<'a> CompletionContext<'a> {
             locals,
             incomplete_let: false,
             no_completion_required: false,
-            ops_traits,
         };
         ctx.expand_and_fill(
             original_file.syntax().clone(),
@@ -938,36 +927,36 @@ fn has_ref(token: &SyntaxToken) -> bool {
     token.kind() == T![&]
 }
 
-const OP_TRAIT_LANG_NAMES: &[hir::Name] = &[
-    known::add_assign,
-    known::add,
-    known::bitand_assign,
-    known::bitand,
-    known::bitor_assign,
-    known::bitor,
-    known::bitxor_assign,
-    known::bitxor,
-    known::deref_mut,
-    known::deref,
-    known::div_assign,
-    known::div,
-    known::fn_mut,
-    known::fn_once,
-    known::r#fn,
-    known::index_mut,
-    known::index,
-    known::mul_assign,
-    known::mul,
-    known::neg,
-    known::not,
-    known::rem_assign,
-    known::rem,
-    known::shl_assign,
-    known::shl,
-    known::shr_assign,
-    known::shr,
-    known::sub,
-    known::sub,
+const OP_TRAIT_LANG_NAMES: &[&str] = &[
+    "add_assign",
+    "add",
+    "bitand_assign",
+    "bitand",
+    "bitor_assign",
+    "bitor",
+    "bitxor_assign",
+    "bitxor",
+    "deref_mut",
+    "deref",
+    "div_assign",
+    "div",
+    "fn_mut",
+    "fn_once",
+    "fn",
+    "index_mut",
+    "index",
+    "mul_assign",
+    "mul",
+    "neg",
+    "not",
+    "rem_assign",
+    "rem",
+    "shl_assign",
+    "shl",
+    "shr_assign",
+    "shr",
+    "sub",
+    "sub",
 ];
 #[cfg(test)]
 mod tests {
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index f2cf577285c..8ac4291078a 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -177,6 +177,7 @@ pub enum CompletionRelevanceTypeMatch {
 }
 
 impl CompletionRelevance {
+    const BASE_LINE: u32 = 1;
     /// Provides a relevance score. Higher values are more relevant.
     ///
     /// The absolute value of the relevance score is not meaningful, for
@@ -187,7 +188,7 @@ impl CompletionRelevance {
     /// See is_relevant if you need to make some judgement about score
     /// in an absolute sense.
     pub fn score(&self) -> u32 {
-        let mut score = 0;
+        let mut score = Self::BASE_LINE;
 
         if self.exact_name_match {
             score += 1;
@@ -213,7 +214,7 @@ impl CompletionRelevance {
     /// some threshold such that we think it is especially likely
     /// to be relevant.
     pub fn is_relevant(&self) -> bool {
-        self.score() > 0
+        self.score() > (Self::BASE_LINE + 1)
     }
 }
 
@@ -563,6 +564,7 @@ mod tests {
         // This test asserts that the relevance score for these items is ascending, and
         // that any items in the same vec have the same score.
         let expected_relevance_order = vec![
+            vec![CompletionRelevance { is_op_method: true, ..CompletionRelevance::default() }],
             vec![CompletionRelevance::default()],
             vec![
                 CompletionRelevance { exact_name_match: true, ..CompletionRelevance::default() },
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 648dce43068..15dacc8e462 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -400,6 +400,7 @@ mod tests {
                 (relevance.exact_name_match, "name"),
                 (relevance.is_local, "local"),
                 (relevance.exact_postfix_snippet_match, "snippet"),
+                (relevance.is_op_method, "op_method"),
             ]
             .into_iter()
             .filter_map(|(cond, desc)| if cond { Some(desc) } else { None })
@@ -1353,6 +1354,23 @@ fn main() {
     }
 
     #[test]
+    fn op_method_relevances() {
+        check_relevance(
+            r#"
+#[lang = "sub"]
+trait Sub {
+    fn sub(self, other: Self) -> Self { self }
+}
+impl Sub for u32 {}
+fn foo(a: u32) { a.$0 }
+"#,
+            expect![[r#"
+                me sub(…) (as Sub) [op_method]
+            "#]],
+        )
+    }
+
+    #[test]
     fn struct_field_method_ref() {
         check_kinds(
             r#"