Complete derive helper attributes

Only their names, anything can go inside.
This commit is contained in:
Chayim Refael Friedman 2024-12-04 01:34:52 +02:00
parent e6276c8b64
commit 890d155ffe
5 changed files with 111 additions and 4 deletions

View file

@ -510,6 +510,22 @@ impl<'db> SemanticsImpl<'db> {
self.with_ctx(|ctx| ctx.has_derives(adt))
}
pub fn derive_helpers_in_scope(&self, adt: &ast::Adt) -> Option<Vec<(Symbol, Symbol)>> {
let sa = self.analyze_no_infer(adt.syntax())?;
let id = self.db.ast_id_map(sa.file_id).ast_id(adt);
let result = sa
.resolver
.def_map()
.derive_helpers_in_scope(InFile::new(sa.file_id, id))?
.iter()
.map(|(name, macro_, _)| {
let macro_name = Macro::from(*macro_).name(self.db).symbol().clone();
(name.symbol().clone(), macro_name)
})
.collect();
Some(result)
}
pub fn derive_helper(&self, attr: &ast::Attr) -> Option<Vec<(Macro, MacroFileId)>> {
let adt = attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it {
ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),

View file

@ -86,10 +86,21 @@ pub(crate) fn complete_attribute_path(
acc: &mut Completions,
ctx: &CompletionContext<'_>,
path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
&AttrCtx { kind, annotated_item_kind }: &AttrCtx,
&AttrCtx { kind, annotated_item_kind, ref derive_helpers }: &AttrCtx,
) {
let is_inner = kind == AttrKind::Inner;
for (derive_helper, derive_name) in derive_helpers {
let mut item = CompletionItem::new(
SymbolKind::Attribute,
ctx.source_range(),
derive_helper.as_str(),
ctx.edition,
);
item.detail(format!("derive helper of `{derive_name}`"));
item.add_to(acc, ctx.db);
}
match qualified {
Qualified::With {
resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),

View file

@ -7,8 +7,8 @@ mod tests;
use std::{iter, ops::ControlFlow};
use hir::{
HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type,
TypeInfo,
HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope,
Symbol, Type, TypeInfo,
};
use ide_db::{
base_db::SourceDatabase, famous_defs::FamousDefs, helpers::is_editable_crate, FilePosition,
@ -133,6 +133,7 @@ pub(crate) type ExistingDerives = FxHashSet<hir::Macro>;
pub(crate) struct AttrCtx {
pub(crate) kind: AttrKind,
pub(crate) annotated_item_kind: Option<SyntaxKind>,
pub(crate) derive_helpers: Vec<(Symbol, Symbol)>,
}
#[derive(Debug, PartialEq, Eq)]

View file

@ -1129,7 +1129,22 @@ fn classify_name_ref(
let is_trailing_outer_attr = kind != AttrKind::Inner
&& non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
let annotated_item_kind = if is_trailing_outer_attr { None } else { Some(attached.kind()) };
Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } })
let derive_helpers = annotated_item_kind
.filter(|kind| {
matches!(
kind,
SyntaxKind::STRUCT
| SyntaxKind::ENUM
| SyntaxKind::UNION
| SyntaxKind::VARIANT
| SyntaxKind::TUPLE_FIELD
| SyntaxKind::RECORD_FIELD
)
})
.and_then(|_| nameref.as_ref()?.syntax().ancestors().find_map(ast::Adt::cast))
.and_then(|adt| sema.derive_helpers_in_scope(&adt))
.unwrap_or_default();
Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind, derive_helpers } })
};
// Infer the path kind

View file

@ -8,6 +8,70 @@ fn check(ra_fixture: &str, expect: Expect) {
expect.assert_eq(&actual);
}
#[test]
fn derive_helpers() {
check(
r#"
//- /mac.rs crate:mac
#![crate_type = "proc-macro"]
#[proc_macro_derive(MyDerive, attributes(my_cool_helper_attribute))]
pub fn my_derive() {}
//- /lib.rs crate:lib deps:mac
#[rustc_builtin_macro]
pub macro derive($item:item) {}
#[derive(mac::MyDerive)]
pub struct Foo(#[m$0] i32);
"#,
expect![[r#"
at allow()
at automatically_derived
at cfg()
at cfg_attr()
at cold
at deny()
at deprecated
at derive macro derive
at derive()
at doc = ""
at doc(alias = "")
at doc(hidden)
at expect()
at export_name = ""
at forbid()
at global_allocator
at ignore = ""
at inline
at link
at link_name = ""
at link_section = ""
at macro_export
at macro_use
at must_use
at my_cool_helper_attribute derive helper of `MyDerive`
at no_mangle
at non_exhaustive
at panic_handler
at path = ""
at proc_macro
at proc_macro_attribute
at proc_macro_derive()
at repr()
at should_panic
at target_feature(enable = "")
at test
at track_caller
at used
at warn()
md mac
kw crate::
kw self::
"#]],
)
}
#[test]
fn proc_macros() {
check(