mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 21:54:42 +00:00
Merge #10943
10943: feat: Enable completions for attributes r=Veykril a=Veykril Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
6f84bbfa1e
8 changed files with 217 additions and 34 deletions
|
@ -1716,6 +1716,10 @@ impl MacroDef {
|
||||||
MacroKind::Attr | MacroKind::Derive => false,
|
MacroKind::Attr | MacroKind::Derive => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_attr(&self) -> bool {
|
||||||
|
matches!(self.kind(), MacroKind::Attr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
//! See [`import_on_the_fly`].
|
//! See [`import_on_the_fly`].
|
||||||
|
use hir::ItemInNs;
|
||||||
use ide_db::helpers::{
|
use ide_db::helpers::{
|
||||||
import_assets::{ImportAssets, ImportCandidate},
|
import_assets::{ImportAssets, ImportCandidate, LocatedImport},
|
||||||
insert_use::ImportScope,
|
insert_use::ImportScope,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::{AstNode, SyntaxNode, T};
|
use syntax::{AstNode, SyntaxNode, T};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::CompletionContext,
|
context::{CompletionContext, PathKind},
|
||||||
render::{render_resolution_with_import, RenderContext},
|
render::{render_resolution_with_import, RenderContext},
|
||||||
ImportEdit,
|
ImportEdit,
|
||||||
};
|
};
|
||||||
|
@ -135,10 +136,35 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
&ctx.sema,
|
&ctx.sema,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
let ns_filter = |import: &LocatedImport| {
|
||||||
|
let kind = match ctx.path_kind() {
|
||||||
|
Some(kind) => kind,
|
||||||
|
None => {
|
||||||
|
return match import.original_item {
|
||||||
|
ItemInNs::Macros(mac) => mac.is_fn_like(),
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match (kind, import.original_item) {
|
||||||
|
(PathKind::Expr, ItemInNs::Types(_) | ItemInNs::Values(_)) => true,
|
||||||
|
|
||||||
|
(PathKind::Type, ItemInNs::Types(_)) => true,
|
||||||
|
(PathKind::Type, ItemInNs::Values(_)) => false,
|
||||||
|
|
||||||
|
(PathKind::Expr | PathKind::Type, ItemInNs::Macros(mac)) => mac.is_fn_like(),
|
||||||
|
|
||||||
|
(PathKind::Attr, ItemInNs::Types(hir::ModuleDef::Module(_))) => true,
|
||||||
|
(PathKind::Attr, ItemInNs::Macros(mac)) => mac.is_attr(),
|
||||||
|
(PathKind::Attr, _) => false,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
acc.add_all(
|
acc.add_all(
|
||||||
import_assets
|
import_assets
|
||||||
.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
|
.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.filter(ns_filter)
|
||||||
.filter(|import| {
|
.filter(|import| {
|
||||||
!ctx.is_item_hidden(&import.item_to_import)
|
!ctx.is_item_hidden(&import.item_to_import)
|
||||||
&& !ctx.is_item_hidden(&import.original_item)
|
&& !ctx.is_item_hidden(&import.original_item)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
|
use hir::ScopeDef;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
use syntax::{ast, AstNode};
|
use syntax::{ast, AstNode};
|
||||||
|
|
||||||
|
@ -31,12 +32,12 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
|
Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
|
||||||
if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
|
if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
|
||||||
for (name, def) in module.scope(ctx.db, context_module) {
|
for (name, def) in module.scope(ctx.db, context_module) {
|
||||||
if let hir::ScopeDef::MacroDef(macro_def) = def {
|
if let ScopeDef::MacroDef(macro_def) = def {
|
||||||
if macro_def.is_fn_like() {
|
if macro_def.is_fn_like() {
|
||||||
acc.add_macro(ctx, Some(name.clone()), macro_def);
|
acc.add_macro(ctx, Some(name.clone()), macro_def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
|
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = def {
|
||||||
acc.add_resolution(ctx, name, &def);
|
acc.add_resolution(ctx, name, &def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,22 +45,37 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Some(ImmediateLocation::Visibility(_)) => {
|
Some(ImmediateLocation::Visibility(_)) => {
|
||||||
if let hir::PathResolution::Def(hir::ModuleDef::Module(resolved)) = resolution {
|
if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
|
||||||
if let Some(current_module) = ctx.scope.module() {
|
if let Some(current_module) = ctx.scope.module() {
|
||||||
if let Some(next) = current_module
|
if let Some(next) = current_module
|
||||||
.path_to_root(ctx.db)
|
.path_to_root(ctx.db)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.take_while(|&it| it != resolved)
|
.take_while(|&it| it != module)
|
||||||
.next()
|
.next()
|
||||||
{
|
{
|
||||||
if let Some(name) = next.name(ctx.db) {
|
if let Some(name) = next.name(ctx.db) {
|
||||||
acc.add_resolution(ctx, name, &hir::ScopeDef::ModuleDef(next.into()));
|
acc.add_resolution(ctx, name, &ScopeDef::ModuleDef(next.into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Some(ImmediateLocation::Attribute(_)) => {
|
||||||
|
if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
|
||||||
|
for (name, def) in module.scope(ctx.db, context_module) {
|
||||||
|
let add_resolution = match def {
|
||||||
|
ScopeDef::MacroDef(mac) => mac.is_attr(),
|
||||||
|
ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if add_resolution {
|
||||||
|
acc.add_resolution(ctx, name, &def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +107,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
let module_scope = module.scope(ctx.db, context_module);
|
let module_scope = module.scope(ctx.db, context_module);
|
||||||
for (name, def) in module_scope {
|
for (name, def) in module_scope {
|
||||||
if ctx.in_use_tree() {
|
if ctx.in_use_tree() {
|
||||||
if let hir::ScopeDef::Unknown = def {
|
if let ScopeDef::Unknown = def {
|
||||||
if let Some(ast::NameLike::NameRef(name_ref)) = ctx.name_syntax.as_ref() {
|
if let Some(ast::NameLike::NameRef(name_ref)) = ctx.name_syntax.as_ref() {
|
||||||
if name_ref.syntax().text() == name.to_smol_str().as_str() {
|
if name_ref.syntax().text() == name.to_smol_str().as_str() {
|
||||||
// for `use self::foo$0`, don't suggest `foo` as a completion
|
// for `use self::foo$0`, don't suggest `foo` as a completion
|
||||||
|
@ -104,16 +120,16 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
|
|
||||||
let add_resolution = match def {
|
let add_resolution = match def {
|
||||||
// Don't suggest attribute macros and derives.
|
// Don't suggest attribute macros and derives.
|
||||||
hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(),
|
ScopeDef::MacroDef(mac) => mac.is_fn_like(),
|
||||||
// no values in type places
|
// no values in type places
|
||||||
hir::ScopeDef::ModuleDef(
|
ScopeDef::ModuleDef(
|
||||||
hir::ModuleDef::Function(_)
|
hir::ModuleDef::Function(_)
|
||||||
| hir::ModuleDef::Variant(_)
|
| hir::ModuleDef::Variant(_)
|
||||||
| hir::ModuleDef::Static(_),
|
| hir::ModuleDef::Static(_),
|
||||||
)
|
)
|
||||||
| hir::ScopeDef::Local(_) => !ctx.expects_type(),
|
| ScopeDef::Local(_) => !ctx.expects_type(),
|
||||||
// unless its a constant in a generic arg list position
|
// unless its a constant in a generic arg list position
|
||||||
hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => {
|
ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => {
|
||||||
!ctx.expects_type() || ctx.expects_generic_arg()
|
!ctx.expects_type() || ctx.expects_generic_arg()
|
||||||
}
|
}
|
||||||
_ => true,
|
_ => true,
|
||||||
|
|
|
@ -56,6 +56,19 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Some(ImmediateLocation::Attribute(_)) => {
|
||||||
|
ctx.process_all_names(&mut |name, res| {
|
||||||
|
let add_resolution = match res {
|
||||||
|
ScopeDef::MacroDef(mac) => mac.is_attr(),
|
||||||
|
ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if add_resolution {
|
||||||
|
acc.add_resolution(ctx, name, &res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,11 @@ pub(crate) enum PatternRefutability {
|
||||||
Irrefutable,
|
Irrefutable,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub(super) enum PathKind {
|
pub(super) enum PathKind {
|
||||||
Expr,
|
Expr,
|
||||||
Type,
|
Type,
|
||||||
|
Attr,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -232,8 +233,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_path_disallowed(&self) -> bool {
|
pub(crate) fn is_path_disallowed(&self) -> bool {
|
||||||
self.attribute_under_caret.is_some()
|
self.previous_token_is(T![unsafe])
|
||||||
|| self.previous_token_is(T![unsafe])
|
|
||||||
|| matches!(
|
|| matches!(
|
||||||
self.prev_sibling,
|
self.prev_sibling,
|
||||||
Some(ImmediatePrevSibling::Attribute | ImmediatePrevSibling::Visibility)
|
Some(ImmediatePrevSibling::Attribute | ImmediatePrevSibling::Visibility)
|
||||||
|
@ -241,8 +241,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
|| matches!(
|
|| matches!(
|
||||||
self.completion_location,
|
self.completion_location,
|
||||||
Some(
|
Some(
|
||||||
ImmediateLocation::Attribute(_)
|
ImmediateLocation::ModDeclaration(_)
|
||||||
| ImmediateLocation::ModDeclaration(_)
|
|
||||||
| ImmediateLocation::RecordPat(_)
|
| ImmediateLocation::RecordPat(_)
|
||||||
| ImmediateLocation::RecordExpr(_)
|
| ImmediateLocation::RecordExpr(_)
|
||||||
| ImmediateLocation::Rename
|
| ImmediateLocation::Rename
|
||||||
|
@ -274,6 +273,10 @@ impl<'a> CompletionContext<'a> {
|
||||||
self.path_context.as_ref().and_then(|it| it.qualifier.as_ref())
|
self.path_context.as_ref().and_then(|it| it.qualifier.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn path_kind(&self) -> Option<PathKind> {
|
||||||
|
self.path_context.as_ref().and_then(|it| it.kind)
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if an item is visible and not `doc(hidden)` at the completion site.
|
/// Checks if an item is visible and not `doc(hidden)` at the completion site.
|
||||||
pub(crate) fn is_visible<I>(&self, item: &I) -> bool
|
pub(crate) fn is_visible<I>(&self, item: &I) -> bool
|
||||||
where
|
where
|
||||||
|
@ -785,6 +788,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
match parent {
|
match parent {
|
||||||
ast::PathType(_it) => Some(PathKind::Type),
|
ast::PathType(_it) => Some(PathKind::Type),
|
||||||
ast::PathExpr(_it) => Some(PathKind::Expr),
|
ast::PathExpr(_it) => Some(PathKind::Expr),
|
||||||
|
ast::Meta(_it) => Some(PathKind::Attr),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
//! Renderer for macro invocations.
|
//! Renderer for macro invocations.
|
||||||
|
|
||||||
|
use either::Either;
|
||||||
use hir::HasSource;
|
use hir::HasSource;
|
||||||
use ide_db::SymbolKind;
|
use ide_db::SymbolKind;
|
||||||
use syntax::{display::macro_label, SmolStr};
|
use syntax::{
|
||||||
|
display::{fn_as_proc_macro_label, macro_label},
|
||||||
|
SmolStr,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::CallKind,
|
context::CallKind,
|
||||||
|
@ -35,7 +39,8 @@ impl<'a> MacroRender<'a> {
|
||||||
let name = name.to_smol_str();
|
let name = name.to_smol_str();
|
||||||
let docs = ctx.docs(macro_);
|
let docs = ctx.docs(macro_);
|
||||||
let docs_str = docs.as_ref().map_or("", |s| s.as_str());
|
let docs_str = docs.as_ref().map_or("", |s| s.as_str());
|
||||||
let (bra, ket) = guess_macro_braces(&name, docs_str);
|
let (bra, ket) =
|
||||||
|
if macro_.is_fn_like() { guess_macro_braces(&name, docs_str) } else { ("", "") };
|
||||||
|
|
||||||
MacroRender { ctx, name, macro_, docs, bra, ket }
|
MacroRender { ctx, name, macro_, docs, bra, ket }
|
||||||
}
|
}
|
||||||
|
@ -47,15 +52,23 @@ impl<'a> MacroRender<'a> {
|
||||||
} else {
|
} else {
|
||||||
Some(self.ctx.source_range())
|
Some(self.ctx.source_range())
|
||||||
}?;
|
}?;
|
||||||
let mut item = CompletionItem::new(SymbolKind::Macro, source_range, self.label());
|
let kind = match self.macro_.kind() {
|
||||||
|
hir::MacroKind::Derive => SymbolKind::Derive,
|
||||||
|
hir::MacroKind::Attr => SymbolKind::Attribute,
|
||||||
|
hir::MacroKind::BuiltIn | hir::MacroKind::Declarative | hir::MacroKind::ProcMacro => {
|
||||||
|
SymbolKind::Macro
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut item = CompletionItem::new(kind, source_range, self.label());
|
||||||
item.set_deprecated(self.ctx.is_deprecated(self.macro_)).set_detail(self.detail());
|
item.set_deprecated(self.ctx.is_deprecated(self.macro_)).set_detail(self.detail());
|
||||||
|
|
||||||
if let Some(import_to_add) = import_to_add {
|
if let Some(import_to_add) = import_to_add {
|
||||||
item.add_import(import_to_add);
|
item.add_import(import_to_add);
|
||||||
}
|
}
|
||||||
|
|
||||||
let needs_bang = !(self.ctx.completion.in_use_tree()
|
let needs_bang = self.macro_.is_fn_like()
|
||||||
|| matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)));
|
&& !(self.ctx.completion.in_use_tree()
|
||||||
|
|| matches!(self.ctx.completion.path_call_kind(), Some(CallKind::Mac)));
|
||||||
let has_parens = self.ctx.completion.path_call_kind().is_some();
|
let has_parens = self.ctx.completion.path_call_kind().is_some();
|
||||||
|
|
||||||
match self.ctx.snippet_cap() {
|
match self.ctx.snippet_cap() {
|
||||||
|
@ -84,10 +97,10 @@ impl<'a> MacroRender<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn label(&self) -> SmolStr {
|
fn label(&self) -> SmolStr {
|
||||||
if self.needs_bang() && self.ctx.snippet_cap().is_some() {
|
if !self.macro_.is_fn_like() {
|
||||||
SmolStr::from_iter([&*self.name, "!", self.bra, "…", self.ket])
|
|
||||||
} else if self.macro_.kind() == hir::MacroKind::Derive {
|
|
||||||
self.name.clone()
|
self.name.clone()
|
||||||
|
} else if self.needs_bang() && self.ctx.snippet_cap().is_some() {
|
||||||
|
SmolStr::from_iter([&*self.name, "!", self.bra, "…", self.ket])
|
||||||
} else {
|
} else {
|
||||||
self.banged_name()
|
self.banged_name()
|
||||||
}
|
}
|
||||||
|
@ -98,8 +111,11 @@ impl<'a> MacroRender<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detail(&self) -> Option<String> {
|
fn detail(&self) -> Option<String> {
|
||||||
let ast_node = self.macro_.source(self.ctx.db())?.value.left()?;
|
let detail = match self.macro_.source(self.ctx.db())?.value {
|
||||||
Some(macro_label(&ast_node))
|
Either::Left(node) => macro_label(&node),
|
||||||
|
Either::Right(node) => fn_as_proc_macro_label(&node),
|
||||||
|
};
|
||||||
|
Some(detail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,12 @@ fn check(ra_fixture: &str, expect: Expect) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn doesnt_complete_items() {
|
fn proc_macros() {
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
struct Foo;
|
//- proc_macros: identity
|
||||||
#[$0]
|
#[$0]
|
||||||
use self as this;
|
struct Foo;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
at allow(…)
|
at allow(…)
|
||||||
|
@ -29,19 +29,29 @@ use self as this;
|
||||||
at doc(alias = "…")
|
at doc(alias = "…")
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
|
at derive(…)
|
||||||
|
at repr(…)
|
||||||
|
at non_exhaustive
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
|
md proc_macros
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn doesnt_complete_qualified() {
|
fn proc_macros_qualified() {
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
|
//- proc_macros: identity
|
||||||
|
#[proc_macros::$0]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
#[foo::$0]
|
|
||||||
use self as this;
|
|
||||||
"#,
|
"#,
|
||||||
expect![[r#""#]],
|
expect![[r#"
|
||||||
|
at input_replace pub macro input_replace
|
||||||
|
at identity pub macro identity
|
||||||
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +71,9 @@ fn with_existing_attr() {
|
||||||
at deny(…)
|
at deny(…)
|
||||||
at forbid(…)
|
at forbid(…)
|
||||||
at warn(…)
|
at warn(…)
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -90,6 +103,9 @@ fn attr_on_source_file() {
|
||||||
at recursion_limit = "…"
|
at recursion_limit = "…"
|
||||||
at type_length_limit = …
|
at type_length_limit = …
|
||||||
at windows_subsystem = "…"
|
at windows_subsystem = "…"
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -113,6 +129,9 @@ fn attr_on_module() {
|
||||||
at no_mangle
|
at no_mangle
|
||||||
at macro_use
|
at macro_use
|
||||||
at path = "…"
|
at path = "…"
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check(
|
check(
|
||||||
|
@ -131,6 +150,9 @@ fn attr_on_module() {
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
at no_implicit_prelude
|
at no_implicit_prelude
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -154,6 +176,9 @@ fn attr_on_macro_rules() {
|
||||||
at no_mangle
|
at no_mangle
|
||||||
at macro_export
|
at macro_export
|
||||||
at macro_use
|
at macro_use
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -175,6 +200,9 @@ fn attr_on_macro_def() {
|
||||||
at doc(alias = "…")
|
at doc(alias = "…")
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -197,6 +225,9 @@ fn attr_on_extern_crate() {
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
at macro_use
|
at macro_use
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -218,6 +249,9 @@ fn attr_on_use() {
|
||||||
at doc(alias = "…")
|
at doc(alias = "…")
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -239,6 +273,9 @@ fn attr_on_type_alias() {
|
||||||
at doc(alias = "…")
|
at doc(alias = "…")
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -263,6 +300,9 @@ fn attr_on_struct() {
|
||||||
at derive(…)
|
at derive(…)
|
||||||
at repr(…)
|
at repr(…)
|
||||||
at non_exhaustive
|
at non_exhaustive
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -287,6 +327,9 @@ fn attr_on_enum() {
|
||||||
at derive(…)
|
at derive(…)
|
||||||
at repr(…)
|
at repr(…)
|
||||||
at non_exhaustive
|
at non_exhaustive
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -308,6 +351,9 @@ fn attr_on_const() {
|
||||||
at doc(alias = "…")
|
at doc(alias = "…")
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -334,6 +380,9 @@ fn attr_on_static() {
|
||||||
at link_section = "…"
|
at link_section = "…"
|
||||||
at global_allocator
|
at global_allocator
|
||||||
at used
|
at used
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -356,6 +405,9 @@ fn attr_on_trait() {
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
at must_use
|
at must_use
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -378,6 +430,9 @@ fn attr_on_impl() {
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
at automatically_derived
|
at automatically_derived
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check(
|
check(
|
||||||
|
@ -395,6 +450,9 @@ fn attr_on_impl() {
|
||||||
at doc(alias = "…")
|
at doc(alias = "…")
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -417,6 +475,9 @@ fn attr_on_extern_block() {
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
at link
|
at link
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
check(
|
check(
|
||||||
|
@ -435,6 +496,9 @@ fn attr_on_extern_block() {
|
||||||
at must_use
|
at must_use
|
||||||
at no_mangle
|
at no_mangle
|
||||||
at link
|
at link
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -451,6 +515,9 @@ fn attr_on_variant() {
|
||||||
at forbid(…)
|
at forbid(…)
|
||||||
at warn(…)
|
at warn(…)
|
||||||
at non_exhaustive
|
at non_exhaustive
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -487,6 +554,9 @@ fn attr_on_fn() {
|
||||||
at target_feature = "…"
|
at target_feature = "…"
|
||||||
at test
|
at test
|
||||||
at track_caller
|
at track_caller
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -503,6 +573,9 @@ fn attr_on_expr() {
|
||||||
at deny(…)
|
at deny(…)
|
||||||
at forbid(…)
|
at forbid(…)
|
||||||
at warn(…)
|
at warn(…)
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -548,6 +621,9 @@ fn attr_in_source_file_end() {
|
||||||
at track_caller
|
at track_caller
|
||||||
at used
|
at used
|
||||||
at warn(…)
|
at warn(…)
|
||||||
|
kw self
|
||||||
|
kw super
|
||||||
|
kw crate
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1043,3 +1043,31 @@ enum Foo {
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn flyimport_attribute() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- proc_macros:identity
|
||||||
|
#[ide$0]
|
||||||
|
struct Foo;
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
at identity (use proc_macros::identity) pub macro identity
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check_edit(
|
||||||
|
"identity",
|
||||||
|
r#"
|
||||||
|
//- proc_macros:identity
|
||||||
|
#[ide$0]
|
||||||
|
struct Foo;
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
use proc_macros::identity;
|
||||||
|
|
||||||
|
#[identity]
|
||||||
|
struct Foo;
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue