mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-26 03:45:04 +00:00
Merge pull request #18853 from ChayimFriedman2/no-completion
Fix case where completion inside macro that expands to `#[test]` was unavailable
This commit is contained in:
commit
cd12ef8547
3 changed files with 105 additions and 5 deletions
|
@ -1316,6 +1316,7 @@ impl DefCollector<'_> {
|
||||||
// being cfg'ed out).
|
// being cfg'ed out).
|
||||||
// Ideally we will just expand them to nothing here. But we are only collecting macro calls,
|
// Ideally we will just expand them to nothing here. But we are only collecting macro calls,
|
||||||
// not expanding them, so we have no way to do that.
|
// not expanding them, so we have no way to do that.
|
||||||
|
// If you add an ignored attribute here, also add it to `Semantics::might_be_inside_macro_call()`.
|
||||||
if matches!(
|
if matches!(
|
||||||
def.kind,
|
def.kind,
|
||||||
MacroDefKind::BuiltInAttr(_, expander)
|
MacroDefKind::BuiltInAttr(_, expander)
|
||||||
|
|
|
@ -30,7 +30,7 @@ use hir_expand::{
|
||||||
name::AsName,
|
name::AsName,
|
||||||
ExpandResult, FileRange, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt,
|
ExpandResult, FileRange, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt,
|
||||||
};
|
};
|
||||||
use intern::Symbol;
|
use intern::{sym, Symbol};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
@ -811,10 +811,37 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
item.attrs().any(|attr| {
|
item.attrs().any(|attr| {
|
||||||
let Some(meta) = attr.meta() else { return false };
|
let Some(meta) = attr.meta() else { return false };
|
||||||
let Some(path) = meta.path() else { return false };
|
let Some(path) = meta.path() else { return false };
|
||||||
let Some(attr_name) = path.as_single_name_ref() else { return true };
|
if let Some(attr_name) = path.as_single_name_ref() {
|
||||||
let attr_name = attr_name.text();
|
let attr_name = attr_name.text();
|
||||||
let attr_name = attr_name.as_str();
|
let attr_name = Symbol::intern(attr_name.as_str());
|
||||||
attr_name == "derive" || find_builtin_attr_idx(&Symbol::intern(attr_name)).is_none()
|
if attr_name == sym::derive {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// We ignore `#[test]` and friends in the def map, so we cannot expand them.
|
||||||
|
// FIXME: We match by text. This is both hacky and incorrect (people can, and do, create
|
||||||
|
// other macros named `test`). We cannot fix that unfortunately because we use this method
|
||||||
|
// for speculative expansion in completion, which we cannot analyze. Fortunately, most macros
|
||||||
|
// named `test` are test-like, meaning their expansion is not terribly important for IDE.
|
||||||
|
if attr_name == sym::test
|
||||||
|
|| attr_name == sym::bench
|
||||||
|
|| attr_name == sym::test_case
|
||||||
|
|| find_builtin_attr_idx(&attr_name).is_some()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut segments = path.segments();
|
||||||
|
let mut next_segment_text = || segments.next().and_then(|it| it.name_ref());
|
||||||
|
// `#[core::prelude::rust_2024::test]` or `#[std::prelude::rust_2024::test]`.
|
||||||
|
if next_segment_text().is_some_and(|it| matches!(&*it.text(), "core" | "std"))
|
||||||
|
&& next_segment_text().is_some_and(|it| it.text() == "prelude")
|
||||||
|
&& next_segment_text().is_some()
|
||||||
|
&& next_segment_text()
|
||||||
|
.is_some_and(|it| matches!(&*it.text(), "test" | "bench" | "test_case"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,3 +241,75 @@ impl Copy for S where $0
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_is_not_considered_macro() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
#[rustc_builtin]
|
||||||
|
pub macro test($item:item) {
|
||||||
|
/* compiler built-in */
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! expand_to_test {
|
||||||
|
( $i:ident ) => {
|
||||||
|
#[test]
|
||||||
|
fn foo() { $i; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() {
|
||||||
|
let value = 5;
|
||||||
|
expand_to_test!(v$0);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
ct CONST Unit
|
||||||
|
en Enum Enum
|
||||||
|
fn bar() fn()
|
||||||
|
fn foo() fn()
|
||||||
|
fn function() fn()
|
||||||
|
ma expand_to_test!(…) macro_rules! expand_to_test
|
||||||
|
ma makro!(…) macro_rules! makro
|
||||||
|
ma test!(…) macro test
|
||||||
|
md module
|
||||||
|
sc STATIC Unit
|
||||||
|
st Record Record
|
||||||
|
st Tuple Tuple
|
||||||
|
st Unit Unit
|
||||||
|
un Union Union
|
||||||
|
ev TupleV(…) TupleV(u32)
|
||||||
|
bt u32 u32
|
||||||
|
kw async
|
||||||
|
kw const
|
||||||
|
kw crate::
|
||||||
|
kw enum
|
||||||
|
kw extern
|
||||||
|
kw false
|
||||||
|
kw fn
|
||||||
|
kw for
|
||||||
|
kw if
|
||||||
|
kw if let
|
||||||
|
kw impl
|
||||||
|
kw let
|
||||||
|
kw loop
|
||||||
|
kw match
|
||||||
|
kw mod
|
||||||
|
kw return
|
||||||
|
kw self::
|
||||||
|
kw static
|
||||||
|
kw struct
|
||||||
|
kw trait
|
||||||
|
kw true
|
||||||
|
kw type
|
||||||
|
kw union
|
||||||
|
kw unsafe
|
||||||
|
kw use
|
||||||
|
kw while
|
||||||
|
kw while let
|
||||||
|
sn macro_rules
|
||||||
|
sn pd
|
||||||
|
sn ppd
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue