mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 12:54:58 +00:00
Merge #9033
9033: Complete keywords in (Assoc)ItemList with leading attribute r=Veykril a=Veykril Fixes #7673 bors r+ Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
bca00ac340
2 changed files with 33 additions and 4 deletions
|
@ -394,6 +394,21 @@ fn quux() -> i32 {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_keywords_in_impl_def_with_attr() {
|
||||||
|
check(
|
||||||
|
r"impl My { #[foo] $0 }",
|
||||||
|
expect![[r#"
|
||||||
|
kw fn
|
||||||
|
kw const
|
||||||
|
kw type
|
||||||
|
kw unsafe
|
||||||
|
kw pub(crate)
|
||||||
|
kw pub
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_keywords_in_loop() {
|
fn test_keywords_in_loop() {
|
||||||
check(
|
check(
|
||||||
|
|
|
@ -25,9 +25,10 @@ pub(crate) enum ImmediateLocation {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn determine_location(tok: SyntaxToken) -> Option<ImmediateLocation> {
|
pub(crate) fn determine_location(tok: SyntaxToken) -> Option<ImmediateLocation> {
|
||||||
// First "expand" the element we are completing to its maximum so that we can check in what
|
// First walk the element we are completing up to its highest node that has the same text range
|
||||||
// context it immediately lies. This for example means if the token is a NameRef at the end of
|
// as the element so that we can check in what context it immediately lies. We only do this for
|
||||||
// a path, we want to look at where the path is in the tree.
|
// NameRef -> Path as that's the only thing that makes sense to being "expanded" semantically.
|
||||||
|
// We only wanna do this if the NameRef is the last segment of the path.
|
||||||
let node = match tok.parent().and_then(ast::NameLike::cast)? {
|
let node = match tok.parent().and_then(ast::NameLike::cast)? {
|
||||||
ast::NameLike::NameRef(name_ref) => {
|
ast::NameLike::NameRef(name_ref) => {
|
||||||
if let Some(segment) = name_ref.syntax().parent().and_then(ast::PathSegment::cast) {
|
if let Some(segment) = name_ref.syntax().parent().and_then(ast::PathSegment::cast) {
|
||||||
|
@ -47,7 +48,20 @@ pub(crate) fn determine_location(tok: SyntaxToken) -> Option<ImmediateLocation>
|
||||||
it @ ast::NameLike::Name(_) | it @ ast::NameLike::Lifetime(_) => it.syntax().clone(),
|
it @ ast::NameLike::Name(_) | it @ ast::NameLike::Lifetime(_) => it.syntax().clone(),
|
||||||
};
|
};
|
||||||
let parent = match node.parent() {
|
let parent = match node.parent() {
|
||||||
Some(parent) => parent,
|
Some(parent) => match ast::MacroCall::cast(parent.clone()) {
|
||||||
|
// When a path is being typed in an (Assoc)ItemList the parser will always emit a macro_call.
|
||||||
|
// This is usually fine as the node expansion code above already accounts for that with
|
||||||
|
// the ancestors call, but there is one exception to this which is that when an attribute
|
||||||
|
// precedes it the code above will not walk the Path to the parent MacroCall as their ranges differ.
|
||||||
|
Some(call)
|
||||||
|
if call.excl_token().is_none()
|
||||||
|
&& call.token_tree().is_none()
|
||||||
|
&& call.semicolon_token().is_none() =>
|
||||||
|
{
|
||||||
|
call.syntax().parent()?
|
||||||
|
}
|
||||||
|
_ => parent,
|
||||||
|
},
|
||||||
// SourceFile
|
// SourceFile
|
||||||
None => {
|
None => {
|
||||||
return match node.kind() {
|
return match node.kind() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue