about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMax Heller <max.a.heller@gmail.com>2023-07-30 15:36:42 -0400
committerMax Heller <max.a.heller@gmail.com>2023-07-31 21:21:40 -0400
commitb9ee4a51678ad4ed1bd93b9fc756b3d2877959d3 (patch)
tree1498b7a89db2841cdef97aa6bac3a37836898653
parentc4cff802691aa1ffb3da820e89dfecc41ef13de7 (diff)
downloadrust-b9ee4a51678ad4ed1bd93b9fc756b3d2877959d3.tar.gz
rust-b9ee4a51678ad4ed1bd93b9fc756b3d2877959d3.zip
working for path segments
-rw-r--r--crates/ide-completion/src/completions/type.rs32
-rw-r--r--crates/ide-completion/src/context.rs2
-rw-r--r--crates/ide-completion/src/context/analysis.rs60
-rw-r--r--crates/ide-completion/src/tests/type_pos.rs20
4 files changed, 76 insertions, 38 deletions
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index e4705475638..de855242ee3 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -24,12 +24,23 @@ pub(crate) fn complete_type_path(
             // no values in type places
             ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_)) | ScopeDef::Local(_) => false,
             // unless its a constant in a generic arg list position
-            ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => {
-                matches!(location, TypeLocation::GenericArgList(_))
-            }
-            ScopeDef::ImplSelfType(_) => {
-                !matches!(location, TypeLocation::ImplTarget | TypeLocation::ImplTrait)
-            }
+            ScopeDef::ModuleDef(Const(_)) | ScopeDef::GenericParam(ConstParam(_)) => match location
+            {
+                TypeLocation::GenericArgList(location) => match location {
+                    Some((_, Some(generic_param))) => {
+                        matches!(generic_param, ast::GenericParam::ConstParam(_))
+                    }
+                    _ => true,
+                },
+                _ => false,
+            },
+            ScopeDef::ImplSelfType(_) => match location {
+                TypeLocation::ImplTarget | TypeLocation::ImplTrait => false,
+                TypeLocation::GenericArgList(Some((_, Some(generic_param)))) => {
+                    matches!(generic_param, ast::GenericParam::TypeParam(_))
+                }
+                _ => true,
+            },
             // Don't suggest attribute macros and derives.
             ScopeDef::ModuleDef(Macro(mac)) => mac.is_fn_like(ctx.db),
             // Type things are fine
@@ -38,7 +49,12 @@ pub(crate) fn complete_type_path(
             )
             | ScopeDef::AdtSelfType(_)
             | ScopeDef::Unknown
-            | ScopeDef::GenericParam(TypeParam(_)) => true,
+            | ScopeDef::GenericParam(TypeParam(_)) => match location {
+                TypeLocation::GenericArgList(Some((_, Some(generic_param)))) => {
+                    matches!(generic_param, ast::GenericParam::TypeParam(_))
+                }
+                _ => true,
+            },
         }
     };
 
@@ -157,7 +173,7 @@ pub(crate) fn complete_type_path(
                     });
                     return;
                 }
-                TypeLocation::GenericArgList(Some(arg_list)) => {
+                TypeLocation::GenericArgList(Some((arg_list, generic_param))) => {
                     let in_assoc_type_arg = ctx
                         .original_token
                         .parent_ancestors()
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 3cb65b2729a..8ec5c6c8bfd 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -155,7 +155,7 @@ pub(crate) struct ExprCtx {
 pub(crate) enum TypeLocation {
     TupleField,
     TypeAscription(TypeAscriptionTarget),
-    GenericArgList(Option<ast::GenericArgList>),
+    GenericArgList(Option<(ast::GenericArgList, Option<ast::GenericParam>)>),
     TypeBound,
     ImplTarget,
     ImplTrait,
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index aeec1ea6f77..cc9e4581bed 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -1,11 +1,11 @@
 //! Module responsible for analyzing the code surrounding the cursor for completion.
 use std::iter;
 
-use hir::{Semantics, Type, TypeInfo, Variant};
+use hir::{HasSource, Semantics, Type, TypeInfo, Variant};
 use ide_db::{active_parameter::ActiveParameter, RootDatabase};
 use syntax::{
     algo::{find_node_at_offset, non_trivia_sibling},
-    ast::{self, AttrKind, HasArgList, HasLoopBody, HasName, NameOrNameRef},
+    ast::{self, AttrKind, HasArgList, HasGenericParams, HasLoopBody, HasName, NameOrNameRef},
     match_ast, AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode,
     SyntaxToken, TextRange, TextSize, T,
 };
@@ -774,9 +774,40 @@ fn classify_name_ref(
                 ast::TypeBound(_) => TypeLocation::TypeBound,
                 // is this case needed?
                 ast::TypeBoundList(_) => TypeLocation::TypeBound,
-                ast::GenericArg(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, it.syntax().parent().and_then(ast::GenericArgList::cast))),
+                ast::GenericArg(it) => {
+                    let location = find_opt_node_in_file_compensated(sema, original_file, it.syntax().parent().and_then(ast::GenericArgList::cast))
+                        .map(|args| {
+                            // Determine the index of the parameter in the `GenericArgList`
+                            // (subtract 1 because `siblings` includes the node itself)
+                            let param_idx = it.syntax().siblings(Direction::Prev).count() - 1;
+                            let param = args
+                                .syntax()
+                                .parent()
+                                .and_then(|p| ast::PathSegment::cast(p))
+                                .and_then(|segment| sema.resolve_path(&segment.parent_path().top_path()))
+                                .and_then(|resolved| {
+                                    match resolved {
+                                        hir::PathResolution::Def(def) => match def {
+                                            hir::ModuleDef::Function(func) => {
+                                                let src = func.source(sema.db)?;
+                                                let params = src.value.generic_param_list()?;
+                                                params.generic_params().nth(param_idx)
+                                            }
+                                            _ => None,
+                                        },
+                                        _ => None,
+                                    }
+                                });
+                            (args, param)
+                        });
+                    TypeLocation::GenericArgList(location)
+                },
                 // is this case needed?
-                ast::GenericArgList(it) => TypeLocation::GenericArgList(find_opt_node_in_file_compensated(sema, original_file, Some(it))),
+                ast::GenericArgList(it) => {
+                    let location = find_opt_node_in_file_compensated(sema, original_file, Some(it))
+                        .map(|node| (node, None));
+                    TypeLocation::GenericArgList(location)
+                },
                 ast::TupleField(_) => TypeLocation::TupleField,
                 _ => return None,
             }
@@ -883,25 +914,8 @@ fn classify_name_ref(
         }
     };
     let make_path_kind_type = |ty: ast::Type| {
-        let location = type_location(ty.syntax()).unwrap_or(TypeLocation::Other);
-        match &location {
-            TypeLocation::TupleField => (),
-            TypeLocation::TypeAscription(_) => (),
-            TypeLocation::GenericArgList(args) => {
-                dbg!(&args);
-                if let Some(segment) =
-                    args.as_ref().and_then(|args| ast::PathSegment::cast(args.syntax().parent()?))
-                {
-                    let path = dbg!(segment.parent_path().top_path());
-                    dbg!(sema.resolve_path(&path));
-                }
-            }
-            TypeLocation::TypeBound => (),
-            TypeLocation::ImplTarget => (),
-            TypeLocation::ImplTrait => (),
-            TypeLocation::Other => (),
-        }
-        PathKind::Type { location }
+        let location = type_location(ty.syntax());
+        PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
     };
 
     let mut kind_macro_call = |it: ast::MacroCall| {
diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs
index 4869ac17ad9..2a05aef17f9 100644
--- a/crates/ide-completion/src/tests/type_pos.rs
+++ b/crates/ide-completion/src/tests/type_pos.rs
@@ -726,15 +726,21 @@ fn completes_const_and_type_generics_separately() {
         r#"
 struct Foo;
 const X: usize = 0;
-mod foo {
-    fn foo<T>() {}
-}
+fn foo<T, const N: usize>() {}
 fn main() {
-    self::foo::foo::<F$0>();
+    foo::<F$0, _>();
 }
 "#,
         expect![[r#"
+            en Enum
+            ma makro!(…) macro_rules! makro
+            md module
             st Foo
+            st Record
+            st Tuple
+            st Unit
+            tt Trait
+            un Union
             bt u32
             kw crate::
             kw self::
@@ -744,13 +750,15 @@ fn main() {
         r#"
 struct Foo;
 const X: usize = 0;
-fn foo<const X: usize>() {}
+fn foo<T, const N: usize>() {}
 fn main() {
-    foo::<F$0>();
+    foo::<_, $0>();
 }
 "#,
         expect![[r#"
+            ct CONST
             ct X
+            ma makro!(…) macro_rules! makro
             kw crate::
             kw self::
         "#]],