mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 06:03:58 +00:00
Complete derive helper attributes
Only their names, anything can go inside.
This commit is contained in:
parent
e6276c8b64
commit
890d155ffe
5 changed files with 111 additions and 4 deletions
|
@ -510,6 +510,22 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
self.with_ctx(|ctx| ctx.has_derives(adt))
|
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)>> {
|
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 {
|
let adt = attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it {
|
||||||
ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
|
ast::Item::Struct(it) => Some(ast::Adt::Struct(it)),
|
||||||
|
|
|
@ -86,10 +86,21 @@ pub(crate) fn complete_attribute_path(
|
||||||
acc: &mut Completions,
|
acc: &mut Completions,
|
||||||
ctx: &CompletionContext<'_>,
|
ctx: &CompletionContext<'_>,
|
||||||
path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
|
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;
|
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 {
|
match qualified {
|
||||||
Qualified::With {
|
Qualified::With {
|
||||||
resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),
|
resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))),
|
||||||
|
|
|
@ -7,8 +7,8 @@ mod tests;
|
||||||
use std::{iter, ops::ControlFlow};
|
use std::{iter, ops::ControlFlow};
|
||||||
|
|
||||||
use hir::{
|
use hir::{
|
||||||
HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type,
|
HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope,
|
||||||
TypeInfo,
|
Symbol, Type, TypeInfo,
|
||||||
};
|
};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::SourceDatabase, famous_defs::FamousDefs, helpers::is_editable_crate, FilePosition,
|
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) struct AttrCtx {
|
||||||
pub(crate) kind: AttrKind,
|
pub(crate) kind: AttrKind,
|
||||||
pub(crate) annotated_item_kind: Option<SyntaxKind>,
|
pub(crate) annotated_item_kind: Option<SyntaxKind>,
|
||||||
|
pub(crate) derive_helpers: Vec<(Symbol, Symbol)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
|
|
@ -1129,7 +1129,22 @@ fn classify_name_ref(
|
||||||
let is_trailing_outer_attr = kind != AttrKind::Inner
|
let is_trailing_outer_attr = kind != AttrKind::Inner
|
||||||
&& non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
|
&& 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()) };
|
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
|
// Infer the path kind
|
||||||
|
|
|
@ -8,6 +8,70 @@ fn check(ra_fixture: &str, expect: Expect) {
|
||||||
expect.assert_eq(&actual);
|
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]
|
#[test]
|
||||||
fn proc_macros() {
|
fn proc_macros() {
|
||||||
check(
|
check(
|
||||||
|
|
Loading…
Reference in a new issue