11455: Handle proc-macro functions as the proc-macro they resolve to r=Veykril a=Veykril

Fixes https://github.com/rust-analyzer/rust-analyzer/issues/11212

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
bors[bot] 2022-02-21 16:56:37 +00:00 committed by GitHub
commit 979b5b32bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 89 additions and 9 deletions

View file

@ -1376,6 +1376,23 @@ impl Function {
db.function_data(self.id).has_body() db.function_data(self.id).has_body()
} }
pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<MacroDef> {
let function_data = db.function_data(self.id);
let attrs = &function_data.attrs;
if !(attrs.is_proc_macro()
|| attrs.is_proc_macro_attribute()
|| attrs.is_proc_macro_derive())
{
return None;
}
let loc = self.id.lookup(db.upcast());
let krate = loc.krate(db);
let def_map = db.crate_def_map(krate.into());
let name = &function_data.name;
let mut exported_proc_macros = def_map.exported_proc_macros();
exported_proc_macros.find(|(_, mac_name)| mac_name == name).map(|(id, _)| MacroDef { id })
}
/// A textual representation of the HIR of this function for debugging purposes. /// A textual representation of the HIR of this function for debugging purposes.
pub fn debug_hir(self, db: &dyn HirDatabase) -> String { pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
let body = db.body(self.id.into()); let body = db.body(self.id.into());

View file

@ -236,7 +236,9 @@ impl Attrs {
pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
AttrQuery { attrs: self, key } AttrQuery { attrs: self, key }
} }
}
impl Attrs {
pub fn cfg(&self) -> Option<CfgExpr> { pub fn cfg(&self) -> Option<CfgExpr> {
let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse).collect::<Vec<_>>(); let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse).collect::<Vec<_>>();
match cfgs.len() { match cfgs.len() {
@ -298,6 +300,18 @@ impl Attrs {
matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "hidden") matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "hidden")
}) })
} }
pub fn is_proc_macro(&self) -> bool {
self.by_key("proc_macro").exists()
}
pub fn is_proc_macro_attribute(&self) -> bool {
self.by_key("proc_macro_attribute").exists()
}
pub fn is_proc_macro_derive(&self) -> bool {
self.by_key("proc_macro_derive").exists()
}
} }
impl AttrsWithOwner { impl AttrsWithOwner {

View file

@ -31,12 +31,12 @@ impl ProcMacroKind {
impl Attrs { impl Attrs {
#[rustfmt::skip] #[rustfmt::skip]
pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> { pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> {
if self.by_key("proc_macro").exists() { if self.is_proc_macro() {
Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::FnLike }) Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::FnLike })
} else if self.by_key("proc_macro_attribute").exists() { } else if self.is_proc_macro_attribute() {
Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr }) Some(ProcMacroDef { name: func_name.clone(), kind: ProcMacroKind::Attr })
} else if self.by_key("proc_macro_derive").exists() { } else if self.by_key("proc_macro_derive").exists() {
let derive = self.by_key("proc_macro_derive").tt_values().next().unwrap(); let derive = self.by_key("proc_macro_derive").tt_values().next()?;
match &*derive.token_trees { match &*derive.token_trees {
// `#[proc_macro_derive(Trait)]` // `#[proc_macro_derive(Trait)]`

View file

@ -57,8 +57,6 @@ pub(crate) fn find_all_refs(
let syntax = sema.parse(position.file_id).syntax().clone(); let syntax = sema.parse(position.file_id).syntax().clone();
let make_searcher = |literal_search: bool| { let make_searcher = |literal_search: bool| {
move |def: Definition| { move |def: Definition| {
let mut usages =
def.usages(sema).set_scope(search_scope.clone()).include_self_refs().all();
let declaration = match def { let declaration = match def {
Definition::Module(module) => { Definition::Module(module) => {
Some(NavigationTarget::from_module_to_decl(sema.db, module)) Some(NavigationTarget::from_module_to_decl(sema.db, module))
@ -72,6 +70,8 @@ pub(crate) fn find_all_refs(
nav, nav,
} }
}); });
let mut usages =
def.usages(sema).set_scope(search_scope.clone()).include_self_refs().all();
if literal_search { if literal_search {
retain_adt_literal_usages(&mut usages, def, sema); retain_adt_literal_usages(&mut usages, def, sema);
} }
@ -1535,4 +1535,47 @@ trait Trait {
"#]], "#]],
) )
} }
#[test]
fn attr() {
check(
r#"
//- proc_macros: identity
#[proc_macros::$0identity]
fn func() {}
"#,
expect![[r#"
identity Attribute FileId(1) 1..107 32..40
FileId(0) 16..24
"#]],
);
check(
r#"
#[proc_macro_attribute]
fn func$0() {}
"#,
expect![[r#"
func Attribute FileId(0) 0..36 27..31
(no references)
"#]],
);
}
// FIXME
#[test]
fn derive() {
check(
r#"
//- proc_macros: derive_identity
//- minicore: derive
#[derive(proc_macros::DeriveIdentity$0)]
struct Foo;
"#,
expect![[r#""#]],
)
}
} }

View file

@ -225,7 +225,12 @@ impl NameClass {
Definition::Macro(sema.to_def(&ast::Macro::MacroDef(it))?) Definition::Macro(sema.to_def(&ast::Macro::MacroDef(it))?)
} }
ast::Item::Const(it) => Definition::Const(sema.to_def(&it)?), ast::Item::Const(it) => Definition::Const(sema.to_def(&it)?),
ast::Item::Fn(it) => Definition::Function(sema.to_def(&it)?), ast::Item::Fn(it) => {
let def = sema.to_def(&it)?;
def.as_proc_macro(sema.db)
.map(Definition::Macro)
.unwrap_or(Definition::Function(def))
}
ast::Item::Module(it) => Definition::Module(sema.to_def(&it)?), ast::Item::Module(it) => Definition::Module(sema.to_def(&it)?),
ast::Item::Static(it) => Definition::Static(sema.to_def(&it)?), ast::Item::Static(it) => Definition::Static(sema.to_def(&it)?),
ast::Item::Trait(it) => Definition::Trait(sema.to_def(&it)?), ast::Item::Trait(it) => Definition::Trait(sema.to_def(&it)?),

View file

@ -82,6 +82,9 @@ pub fn pick_best_token(
) -> Option<SyntaxToken> { ) -> Option<SyntaxToken> {
tokens.max_by_key(move |t| f(t.kind())) tokens.max_by_key(move |t| f(t.kind()))
} }
pub fn pick_token<T: AstToken>(mut tokens: TokenAtOffset<SyntaxToken>) -> Option<T> {
tokens.find_map(T::cast)
}
/// Converts the mod path struct into its ast representation. /// Converts the mod path struct into its ast representation.
pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {

View file

@ -275,9 +275,7 @@ pub(crate) fn handle_on_type_formatting(
let char_typed = params.ch.chars().next().unwrap_or('\0'); let char_typed = params.ch.chars().next().unwrap_or('\0');
let text = snap.analysis.file_text(position.file_id)?; let text = snap.analysis.file_text(position.file_id)?;
if !text[usize::from(position.offset)..].starts_with(char_typed) { if stdx::never!(!text[usize::from(position.offset)..].starts_with(char_typed)) {
// Add `always!` here once VS Code bug is fixed:
// https://github.com/rust-analyzer/rust-analyzer/issues/10002
return Ok(None); return Ok(None);
} }