Merge #11676
11676: internal: Expand into pseudo-derive attribute expansions in completions r=Veykril a=Veykril With this we now properly handle qualified path completions in derives bors r+ Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
69e5bd5a25
@ -18,8 +18,8 @@ use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
|
||||
LifetimeParam, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, TypeOrConstParam,
|
||||
TypeParam, Union, Variant,
|
||||
LifetimeParam, Macro, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias,
|
||||
TypeOrConstParam, TypeParam, Union, Variant,
|
||||
};
|
||||
|
||||
impl HirDisplay for Function {
|
||||
@ -509,3 +509,14 @@ impl HirDisplay for Module {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Macro {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
match self.id {
|
||||
hir_def::MacroId::Macro2Id(_) => write!(f, "macro"),
|
||||
hir_def::MacroId::MacroRulesId(_) => write!(f, "macro_rules!"),
|
||||
hir_def::MacroId::ProcMacroId(_) => write!(f, "proc_macro"),
|
||||
}?;
|
||||
write!(f, " {}", self.name(f.db))
|
||||
}
|
||||
}
|
||||
|
@ -1811,6 +1811,10 @@ impl Macro {
|
||||
pub fn is_attr(&self, db: &dyn HirDatabase) -> bool {
|
||||
matches!(self.kind(db), MacroKind::Attr)
|
||||
}
|
||||
|
||||
pub fn is_derive(&self, db: &dyn HirDatabase) -> bool {
|
||||
matches!(self.kind(db), MacroKind::Derive)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasVisibility for Macro {
|
||||
|
@ -151,6 +151,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
||||
self.imp.expand_attr_macro(item)
|
||||
}
|
||||
|
||||
pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> {
|
||||
self.imp.expand_derive_as_pseudo_attr_macro(attr)
|
||||
}
|
||||
|
||||
pub fn resolve_derive_macro(&self, derive: &ast::Attr) -> Option<Vec<Option<Macro>>> {
|
||||
self.imp.resolve_derive_macro(derive)
|
||||
}
|
||||
@ -185,6 +189,19 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
||||
self.imp.speculative_expand_attr(actual_macro_call, speculative_args, token_to_map)
|
||||
}
|
||||
|
||||
pub fn speculative_expand_derive_as_pseudo_attr_macro(
|
||||
&self,
|
||||
actual_macro_call: &ast::Attr,
|
||||
speculative_args: &ast::Attr,
|
||||
token_to_map: SyntaxToken,
|
||||
) -> Option<(SyntaxNode, SyntaxToken)> {
|
||||
self.imp.speculative_expand_derive_as_pseudo_attr_macro(
|
||||
actual_macro_call,
|
||||
speculative_args,
|
||||
token_to_map,
|
||||
)
|
||||
}
|
||||
|
||||
/// Descend the token into macrocalls to its first mapped counterpart.
|
||||
pub fn descend_into_macros_single(&self, token: SyntaxToken) -> SyntaxToken {
|
||||
self.imp.descend_into_macros_single(token)
|
||||
@ -438,9 +455,16 @@ impl<'db> SemanticsImpl<'db> {
|
||||
fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> {
|
||||
let src = self.wrap_node_infile(item.clone());
|
||||
let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?;
|
||||
let file_id = macro_call_id.as_file();
|
||||
let node = self.parse_or_expand(file_id)?;
|
||||
Some(node)
|
||||
self.parse_or_expand(macro_call_id.as_file())
|
||||
}
|
||||
|
||||
fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> {
|
||||
let src = self.wrap_node_infile(attr.clone());
|
||||
let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
|
||||
let call_id = self.with_ctx(|ctx| {
|
||||
ctx.attr_to_derive_macro_call(src.with_value(&adt), src).map(|(_, it, _)| it)
|
||||
})?;
|
||||
self.parse_or_expand(call_id.as_file())
|
||||
}
|
||||
|
||||
fn resolve_derive_macro(&self, attr: &ast::Attr) -> Option<Vec<Option<Macro>>> {
|
||||
@ -533,6 +557,25 @@ impl<'db> SemanticsImpl<'db> {
|
||||
)
|
||||
}
|
||||
|
||||
fn speculative_expand_derive_as_pseudo_attr_macro(
|
||||
&self,
|
||||
actual_macro_call: &ast::Attr,
|
||||
speculative_args: &ast::Attr,
|
||||
token_to_map: SyntaxToken,
|
||||
) -> Option<(SyntaxNode, SyntaxToken)> {
|
||||
let attr = self.wrap_node_infile(actual_macro_call.clone());
|
||||
let adt = actual_macro_call.syntax().parent().and_then(ast::Adt::cast)?;
|
||||
let macro_call_id = self.with_ctx(|ctx| {
|
||||
ctx.attr_to_derive_macro_call(attr.with_value(&adt), attr).map(|(_, it, _)| it)
|
||||
})?;
|
||||
hir_expand::db::expand_speculative(
|
||||
self.db.upcast(),
|
||||
macro_call_id,
|
||||
speculative_args.syntax(),
|
||||
token_to_map,
|
||||
)
|
||||
}
|
||||
|
||||
// This might not be the correct way to do this, but it works for now
|
||||
fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
|
||||
let mut res = smallvec![];
|
||||
|
@ -1,7 +1,5 @@
|
||||
//! Builtin attributes.
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{db::AstDatabase, name, ExpandResult, MacroCallId, MacroCallKind};
|
||||
|
||||
macro_rules! register_builtin {
|
||||
@ -98,10 +96,16 @@ fn derive_attr_expand(
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let loc = db.lookup_intern_macro_call(id);
|
||||
let derives = match &loc.kind {
|
||||
MacroCallKind::Attr { attr_args, .. } => &attr_args.0,
|
||||
_ => return ExpandResult::ok(tt.clone()),
|
||||
MacroCallKind::Attr { attr_args, is_derive: true, .. } => &attr_args.0,
|
||||
_ => return ExpandResult::ok(Default::default()),
|
||||
};
|
||||
pseudo_derive_attr_expansion(tt, derives)
|
||||
}
|
||||
|
||||
pub fn pseudo_derive_attr_expansion(
|
||||
tt: &tt::Subtree,
|
||||
args: &tt::Subtree,
|
||||
) -> ExpandResult<tt::Subtree> {
|
||||
let mk_leaf = |char| {
|
||||
tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
|
||||
char,
|
||||
@ -111,21 +115,12 @@ fn derive_attr_expand(
|
||||
};
|
||||
|
||||
let mut token_trees = Vec::new();
|
||||
for (comma, group) in &derives
|
||||
.token_trees
|
||||
.iter()
|
||||
.filter_map(|tt| match tt {
|
||||
tt::TokenTree::Leaf(l) => Some(l),
|
||||
tt::TokenTree::Subtree(_) => None,
|
||||
})
|
||||
.group_by(|l| matches!(l, tt::Leaf::Punct(tt::Punct { char: ',', .. })))
|
||||
for tt in (&args.token_trees)
|
||||
.split(|tt| matches!(tt, tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', .. }))))
|
||||
{
|
||||
if comma {
|
||||
continue;
|
||||
}
|
||||
token_trees.push(mk_leaf('#'));
|
||||
token_trees.push(mk_leaf('['));
|
||||
token_trees.extend(group.cloned().map(tt::TokenTree::Leaf));
|
||||
token_trees.extend(tt.iter().cloned());
|
||||
token_trees.push(mk_leaf(']'));
|
||||
}
|
||||
token_trees.push(mk_leaf('('));
|
||||
|
@ -14,10 +14,10 @@ use syntax::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ast_id_map::AstIdMap, fixup, hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander,
|
||||
BuiltinFnLikeExpander, ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr,
|
||||
MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile,
|
||||
ProcMacroExpander,
|
||||
ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, fixup,
|
||||
hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
|
||||
ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind,
|
||||
MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
|
||||
};
|
||||
|
||||
/// Total limit on the number of tokens produced by any macro invocation.
|
||||
@ -161,14 +161,16 @@ pub fn expand_speculative(
|
||||
);
|
||||
|
||||
let (attr_arg, token_id) = match loc.kind {
|
||||
MacroCallKind::Attr { invoc_attr_index, .. } => {
|
||||
MacroCallKind::Attr { invoc_attr_index, is_derive, .. } => {
|
||||
let attr = if is_derive {
|
||||
// for pseudo-derive expansion we actually pass the attribute itself only
|
||||
ast::Attr::cast(speculative_args.clone())
|
||||
} else {
|
||||
// Attributes may have an input token tree, build the subtree and map for this as well
|
||||
// then try finding a token id for our token if it is inside this input subtree.
|
||||
let item = ast::Item::cast(speculative_args.clone())?;
|
||||
let attr = item
|
||||
.doc_comments_and_attrs()
|
||||
.nth(invoc_attr_index as usize)
|
||||
.and_then(Either::left)?;
|
||||
item.doc_comments_and_attrs().nth(invoc_attr_index as usize).and_then(Either::left)
|
||||
}?;
|
||||
match attr.token_tree() {
|
||||
Some(token_tree) => {
|
||||
let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax());
|
||||
@ -205,11 +207,15 @@ pub fn expand_speculative(
|
||||
|
||||
// Do the actual expansion, we need to directly expand the proc macro due to the attribute args
|
||||
// Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
|
||||
let mut speculative_expansion = if let MacroDefKind::ProcMacro(expander, ..) = loc.def.kind {
|
||||
let mut speculative_expansion = match loc.def.kind {
|
||||
MacroDefKind::ProcMacro(expander, ..) => {
|
||||
tt.delimiter = None;
|
||||
expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
|
||||
} else {
|
||||
macro_def.expand(db, actual_macro_call, &tt)
|
||||
}
|
||||
MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
|
||||
pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?)
|
||||
}
|
||||
_ => macro_def.expand(db, actual_macro_call, &tt),
|
||||
};
|
||||
|
||||
let expand_to = macro_expand_to(db, actual_macro_call);
|
||||
|
@ -2,7 +2,7 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use either::Either;
|
||||
use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
|
||||
use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HirDisplay, Semantics, TypeInfo};
|
||||
use ide_db::{
|
||||
base_db::SourceDatabase,
|
||||
defs::Definition,
|
||||
@ -13,9 +13,7 @@ use ide_db::{
|
||||
use itertools::Itertools;
|
||||
use stdx::format_to;
|
||||
use syntax::{
|
||||
algo, ast,
|
||||
display::{fn_as_proc_macro_label, macro_label},
|
||||
match_ast, AstNode, Direction,
|
||||
algo, ast, match_ast, AstNode, Direction,
|
||||
SyntaxKind::{LET_EXPR, LET_STMT},
|
||||
SyntaxToken, T,
|
||||
};
|
||||
@ -342,14 +340,8 @@ pub(super) fn definition(
|
||||
) -> Option<Markup> {
|
||||
let mod_path = definition_mod_path(db, &def);
|
||||
let (label, docs) = match def {
|
||||
Definition::Macro(it) => (
|
||||
match &it.source(db)?.value {
|
||||
Either::Left(mac) => macro_label(mac),
|
||||
Either::Right(mac_fn) => fn_as_proc_macro_label(mac_fn),
|
||||
},
|
||||
it.attrs(db).docs(),
|
||||
),
|
||||
Definition::Field(def) => label_and_docs(db, def),
|
||||
Definition::Macro(it) => label_and_docs(db, it),
|
||||
Definition::Field(it) => label_and_docs(db, it),
|
||||
Definition::Module(it) => label_and_docs(db, it),
|
||||
Definition::Function(it) => label_and_docs(db, it),
|
||||
Definition::Adt(it) => label_and_docs(db, it),
|
||||
|
@ -4109,7 +4109,7 @@ identity!{
|
||||
```
|
||||
|
||||
```rust
|
||||
pub macro Copy
|
||||
macro Copy
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
@ -4133,7 +4133,7 @@ struct Foo;
|
||||
```
|
||||
|
||||
```rust
|
||||
pub macro Copy
|
||||
macro Copy
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
@ -4155,7 +4155,7 @@ struct Foo;
|
||||
```
|
||||
|
||||
```rust
|
||||
pub macro Copy
|
||||
macro Copy
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
|
@ -32,7 +32,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||
}
|
||||
|
||||
let mac_input = tt.syntax().children_with_tokens().skip(1).take_while(|it| *it != r_delim);
|
||||
let input_expressions = mac_input.into_iter().group_by(|tok| tok.kind() == T![,]);
|
||||
let input_expressions = mac_input.group_by(|tok| tok.kind() == T![,]);
|
||||
let input_expressions = input_expressions
|
||||
.into_iter()
|
||||
.filter_map(|(is_sep, group)| (!is_sep).then(|| group))
|
||||
|
@ -29,6 +29,8 @@ mod derive;
|
||||
mod lint;
|
||||
mod repr;
|
||||
|
||||
pub(crate) use self::derive::complete_derive;
|
||||
|
||||
/// Complete inputs to known builtin attributes as well as derive attributes
|
||||
pub(crate) fn complete_known_attribute_input(
|
||||
acc: &mut Completions,
|
||||
@ -46,7 +48,6 @@ pub(crate) fn complete_known_attribute_input(
|
||||
|
||||
match path.text().as_str() {
|
||||
"repr" => repr::complete_repr(acc, ctx, tt),
|
||||
"derive" => derive::complete_derive(acc, ctx, ctx.attr.as_ref()?),
|
||||
"feature" => lint::complete_lint(acc, ctx, &parse_tt_as_comma_sep_paths(tt)?, FEATURES),
|
||||
"allow" | "warn" | "deny" | "forbid" => {
|
||||
let existing_lints = parse_tt_as_comma_sep_paths(tt)?;
|
||||
@ -62,9 +63,7 @@ pub(crate) fn complete_known_attribute_input(
|
||||
|
||||
lint::complete_lint(acc, ctx, &existing_lints, &lints);
|
||||
}
|
||||
"cfg" => {
|
||||
cfg::complete_cfg(acc, ctx);
|
||||
}
|
||||
"cfg" => cfg::complete_cfg(acc, ctx),
|
||||
_ => (),
|
||||
}
|
||||
Some(())
|
||||
@ -347,7 +346,7 @@ fn parse_comma_sep_expr(input: ast::TokenTree) -> Option<Vec<ast::Expr>> {
|
||||
.children_with_tokens()
|
||||
.skip(1)
|
||||
.take_while(|it| it.as_token() != Some(&r_paren));
|
||||
let input_expressions = tokens.into_iter().group_by(|tok| tok.kind() == T![,]);
|
||||
let input_expressions = tokens.group_by(|tok| tok.kind() == T![,]);
|
||||
Some(
|
||||
input_expressions
|
||||
.into_iter()
|
||||
|
@ -1,40 +1,86 @@
|
||||
//! Completion for derives
|
||||
use hir::{HasAttrs, Macro, MacroKind};
|
||||
use ide_db::{
|
||||
imports::{import_assets::ImportAssets, insert_use::ImportScope},
|
||||
SymbolKind,
|
||||
};
|
||||
use hir::{HasAttrs, ScopeDef};
|
||||
use ide_db::SymbolKind;
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::FxHashSet;
|
||||
use syntax::{ast, SmolStr, SyntaxKind};
|
||||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
completions::flyimport::compute_fuzzy_completion_order_key, context::CompletionContext,
|
||||
item::CompletionItem, Completions, ImportEdit,
|
||||
context::{CompletionContext, PathCompletionCtx, PathKind, PathQualifierCtx},
|
||||
item::CompletionItem,
|
||||
Completions,
|
||||
};
|
||||
|
||||
pub(super) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, attr: &ast::Attr) {
|
||||
let core = ctx.famous_defs().core();
|
||||
let existing_derives: FxHashSet<_> =
|
||||
ctx.sema.resolve_derive_macro(attr).into_iter().flatten().flatten().collect();
|
||||
pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
let (qualifier, is_absolute_path) = match ctx.path_context {
|
||||
Some(PathCompletionCtx {
|
||||
kind: Some(PathKind::Derive),
|
||||
ref qualifier,
|
||||
is_absolute_path,
|
||||
..
|
||||
}) => (qualifier, is_absolute_path),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
for (name, mac) in get_derives_in_scope(ctx) {
|
||||
if existing_derives.contains(&mac) {
|
||||
continue;
|
||||
let core = ctx.famous_defs().core();
|
||||
|
||||
match qualifier {
|
||||
Some(PathQualifierCtx { resolution, is_super_chain, .. }) => {
|
||||
if *is_super_chain {
|
||||
acc.add_keyword(ctx, "super::");
|
||||
}
|
||||
|
||||
let name = name.to_smol_str();
|
||||
let (label, lookup) = match (core, mac.module(ctx.db).krate()) {
|
||||
// show derive dependencies for `core`/`std` derives
|
||||
(Some(core), mac_krate) if core == mac_krate => {
|
||||
if let Some(derive_completion) = DEFAULT_DERIVE_DEPENDENCIES
|
||||
.iter()
|
||||
.find(|derive_completion| derive_completion.label == name)
|
||||
let module = match resolution {
|
||||
Some(hir::PathResolution::Def(hir::ModuleDef::Module(it))) => it,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
for (name, def) in module.scope(ctx.db, ctx.module) {
|
||||
let add_def = match def {
|
||||
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
|
||||
!ctx.existing_derives.contains(&mac) && mac.is_derive(ctx.db)
|
||||
}
|
||||
ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => true,
|
||||
_ => false,
|
||||
};
|
||||
if add_def {
|
||||
acc.add_resolution(ctx, name, def);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
None if is_absolute_path => acc.add_crate_roots(ctx),
|
||||
// only show modules in a fresh UseTree
|
||||
None => {
|
||||
ctx.process_all_names(&mut |name, def| {
|
||||
let mac = match def {
|
||||
ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac))
|
||||
if !ctx.existing_derives.contains(&mac) && mac.is_derive(ctx.db) =>
|
||||
{
|
||||
mac
|
||||
}
|
||||
ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) => {
|
||||
return acc.add_resolution(ctx, name, def);
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
|
||||
match (core, mac.module(ctx.db).krate()) {
|
||||
// show derive dependencies for `core`/`std` derives
|
||||
(Some(core), mac_krate) if core == mac_krate && qualifier.is_none() => {}
|
||||
_ => return acc.add_resolution(ctx, name, def),
|
||||
};
|
||||
|
||||
let name_ = name.to_smol_str();
|
||||
let find = DEFAULT_DERIVE_DEPENDENCIES
|
||||
.iter()
|
||||
.find(|derive_completion| derive_completion.label == name_);
|
||||
|
||||
match find {
|
||||
Some(derive_completion) => {
|
||||
let mut components = vec![derive_completion.label];
|
||||
components.extend(derive_completion.dependencies.iter().filter(
|
||||
|&&dependency| {
|
||||
!existing_derives
|
||||
!ctx.existing_derives
|
||||
.iter()
|
||||
.map(|it| it.name(ctx.db))
|
||||
.any(|it| it.to_smol_str() == dependency)
|
||||
@ -42,82 +88,24 @@ pub(super) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, at
|
||||
));
|
||||
let lookup = components.join(", ");
|
||||
let label = Itertools::intersperse(components.into_iter().rev(), ", ");
|
||||
(SmolStr::from_iter(label), Some(lookup))
|
||||
} else {
|
||||
(name, None)
|
||||
}
|
||||
}
|
||||
_ => (name, None),
|
||||
};
|
||||
|
||||
let mut item = CompletionItem::new(SymbolKind::Derive, ctx.source_range(), label);
|
||||
if let Some(docs) = mac.docs(ctx.db) {
|
||||
item.documentation(docs);
|
||||
}
|
||||
if let Some(lookup) = lookup {
|
||||
item.lookup_by(lookup);
|
||||
}
|
||||
item.add_to(acc);
|
||||
}
|
||||
|
||||
flyimport_derive(acc, ctx);
|
||||
}
|
||||
|
||||
fn get_derives_in_scope(ctx: &CompletionContext) -> Vec<(hir::Name, Macro)> {
|
||||
let mut result = Vec::default();
|
||||
ctx.process_all_names(&mut |name, scope_def| {
|
||||
if let hir::ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) = scope_def {
|
||||
if mac.kind(ctx.db) == hir::MacroKind::Derive {
|
||||
result.push((name, mac));
|
||||
}
|
||||
}
|
||||
});
|
||||
result
|
||||
}
|
||||
|
||||
fn flyimport_derive(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
|
||||
if ctx.token.kind() != SyntaxKind::IDENT {
|
||||
return None;
|
||||
};
|
||||
let potential_import_name = ctx.token.to_string();
|
||||
let module = ctx.module?;
|
||||
let parent = ctx.token.parent()?;
|
||||
let user_input_lowercased = potential_import_name.to_lowercase();
|
||||
let import_assets = ImportAssets::for_fuzzy_path(
|
||||
module,
|
||||
None,
|
||||
potential_import_name,
|
||||
&ctx.sema,
|
||||
parent.clone(),
|
||||
)?;
|
||||
let import_scope = ImportScope::find_insert_use_container(&parent, &ctx.sema)?;
|
||||
acc.add_all(
|
||||
import_assets
|
||||
.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
|
||||
.into_iter()
|
||||
.filter_map(|import| match import.original_item {
|
||||
hir::ItemInNs::Macros(mac) => Some((import, mac)),
|
||||
_ => None,
|
||||
})
|
||||
.filter(|&(_, mac)| mac.kind(ctx.db) == MacroKind::Derive)
|
||||
.filter(|&(_, mac)| !ctx.is_item_hidden(&hir::ItemInNs::Macros(mac)))
|
||||
.sorted_by_key(|(import, _)| {
|
||||
compute_fuzzy_completion_order_key(&import.import_path, &user_input_lowercased)
|
||||
})
|
||||
.filter_map(|(import, mac)| {
|
||||
let mut item = CompletionItem::new(
|
||||
SymbolKind::Derive,
|
||||
ctx.source_range(),
|
||||
mac.name(ctx.db).to_smol_str(),
|
||||
SmolStr::from_iter(label),
|
||||
);
|
||||
item.add_import(ImportEdit { import, scope: import_scope.clone() });
|
||||
if let Some(docs) = mac.docs(ctx.db) {
|
||||
item.documentation(docs);
|
||||
}
|
||||
Some(item.build())
|
||||
}),
|
||||
);
|
||||
Some(())
|
||||
item.lookup_by(lookup);
|
||||
item.add_to(acc);
|
||||
}
|
||||
None => acc.add_resolution(ctx, name, def),
|
||||
}
|
||||
});
|
||||
acc.add_nameref_keywords(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DeriveDependencies {
|
||||
|
@ -142,7 +142,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
|
||||
)?;
|
||||
|
||||
let ns_filter = |import: &LocatedImport| {
|
||||
let kind = match ctx.path_kind() {
|
||||
let path_kind = match ctx.path_kind() {
|
||||
Some(kind) => kind,
|
||||
None => {
|
||||
return match import.original_item {
|
||||
@ -151,7 +151,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
|
||||
}
|
||||
}
|
||||
};
|
||||
match (kind, import.original_item) {
|
||||
match (path_kind, import.original_item) {
|
||||
// Aren't handled in flyimport
|
||||
(PathKind::Vis { .. } | PathKind::Use, _) => false,
|
||||
// modules are always fair game
|
||||
@ -173,6 +173,11 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
|
||||
|
||||
(PathKind::Attr { .. }, ItemInNs::Macros(mac)) => mac.is_attr(ctx.db),
|
||||
(PathKind::Attr { .. }, _) => false,
|
||||
|
||||
(PathKind::Derive, ItemInNs::Macros(mac)) => {
|
||||
mac.is_derive(ctx.db) && !ctx.existing_derives.contains(&mac)
|
||||
}
|
||||
(PathKind::Derive, _) => false,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -63,7 +63,13 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||
}
|
||||
|
||||
match kind {
|
||||
Some(PathKind::Pat | PathKind::Attr { .. } | PathKind::Vis { .. } | PathKind::Use) => {
|
||||
Some(
|
||||
PathKind::Pat
|
||||
| PathKind::Attr { .. }
|
||||
| PathKind::Vis { .. }
|
||||
| PathKind::Use
|
||||
| PathKind::Derive,
|
||||
) => {
|
||||
return;
|
||||
}
|
||||
_ => {
|
||||
@ -415,10 +421,10 @@ macro_rules! foo { () => {} }
|
||||
|
||||
fn main() { let _ = crate::$0 }
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
fn main() fn()
|
||||
ma foo!(…) #[macro_export] macro_rules! foo
|
||||
"##]],
|
||||
ma foo!(…) macro_rules! foo
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -19,10 +19,11 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
||||
Some(PathCompletionCtx {
|
||||
kind:
|
||||
Some(
|
||||
PathKind::Vis { .. }
|
||||
| PathKind::Attr { .. }
|
||||
PathKind::Attr { .. }
|
||||
| PathKind::Derive
|
||||
| PathKind::Pat
|
||||
| PathKind::Use { .. }
|
||||
| PathKind::Pat,
|
||||
| PathKind::Vis { .. },
|
||||
),
|
||||
..
|
||||
}) => return,
|
||||
@ -207,12 +208,12 @@ mod macros {
|
||||
macro_rules! concat { }
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
fn f() fn()
|
||||
ma concat!(…) #[macro_export] macro_rules! concat
|
||||
ma concat!(…) macro_rules! concat
|
||||
md std
|
||||
bt u32
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ use ide_db::{
|
||||
famous_defs::FamousDefs,
|
||||
RootDatabase,
|
||||
};
|
||||
use rustc_hash::FxHashSet;
|
||||
use syntax::{
|
||||
algo::{find_node_at_offset, non_trivia_sibling},
|
||||
ast::{self, AttrKind, HasName, NameOrNameRef},
|
||||
@ -43,11 +44,12 @@ pub(crate) enum Visible {
|
||||
No,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(super) enum PathKind {
|
||||
Expr,
|
||||
Type,
|
||||
Attr { kind: AttrKind, annotated_item_kind: Option<SyntaxKind> },
|
||||
Derive,
|
||||
Mac,
|
||||
Pat,
|
||||
Vis { has_in_token: bool },
|
||||
@ -126,7 +128,6 @@ pub(crate) struct CompletionContext<'a> {
|
||||
|
||||
/// The parent function of the cursor position if it exists.
|
||||
pub(super) function_def: Option<ast::Fn>,
|
||||
pub(super) attr: Option<ast::Attr>,
|
||||
/// The parent impl of the cursor position if it exists.
|
||||
pub(super) impl_def: Option<ast::Impl>,
|
||||
/// The NameLike under the cursor in the original file if it exists.
|
||||
@ -142,6 +143,8 @@ pub(crate) struct CompletionContext<'a> {
|
||||
pub(super) pattern_ctx: Option<PatternContext>,
|
||||
pub(super) path_context: Option<PathCompletionCtx>,
|
||||
|
||||
pub(super) existing_derives: FxHashSet<hir::Macro>,
|
||||
|
||||
pub(super) locals: Vec<(Name, Local)>,
|
||||
|
||||
no_completion_required: bool,
|
||||
@ -439,7 +442,6 @@ impl<'a> CompletionContext<'a> {
|
||||
expected_name: None,
|
||||
expected_type: None,
|
||||
function_def: None,
|
||||
attr: None,
|
||||
impl_def: None,
|
||||
name_syntax: None,
|
||||
lifetime_ctx: None,
|
||||
@ -452,6 +454,7 @@ impl<'a> CompletionContext<'a> {
|
||||
locals,
|
||||
incomplete_let: false,
|
||||
no_completion_required: false,
|
||||
existing_derives: Default::default(),
|
||||
};
|
||||
ctx.expand_and_fill(
|
||||
original_file.syntax().clone(),
|
||||
@ -472,6 +475,8 @@ impl<'a> CompletionContext<'a> {
|
||||
mut fake_ident_token: SyntaxToken,
|
||||
) {
|
||||
let _p = profile::span("CompletionContext::expand_and_fill");
|
||||
let mut derive_ctx = None;
|
||||
|
||||
'expansion: loop {
|
||||
let parent_item =
|
||||
|item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
|
||||
@ -509,11 +514,45 @@ impl<'a> CompletionContext<'a> {
|
||||
_ => break 'expansion,
|
||||
}
|
||||
}
|
||||
let orig_tt = match find_node_at_offset::<ast::TokenTree>(&original_file, offset) {
|
||||
Some(it) => it,
|
||||
None => break,
|
||||
};
|
||||
let spec_tt = match find_node_at_offset::<ast::TokenTree>(&speculative_file, offset) {
|
||||
Some(it) => it,
|
||||
None => break,
|
||||
};
|
||||
|
||||
// Expand pseudo-derive expansion
|
||||
if let (Some(orig_attr), Some(spec_attr)) = (
|
||||
orig_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
|
||||
spec_tt.syntax().parent().and_then(ast::Meta::cast).and_then(|it| it.parent_attr()),
|
||||
) {
|
||||
match (
|
||||
self.sema.expand_derive_as_pseudo_attr_macro(&orig_attr),
|
||||
self.sema.speculative_expand_derive_as_pseudo_attr_macro(
|
||||
&orig_attr,
|
||||
&spec_attr,
|
||||
fake_ident_token.clone(),
|
||||
),
|
||||
) {
|
||||
// Clearly not a derive macro
|
||||
(None, None) => (),
|
||||
// successful expansions
|
||||
(Some(actual_expansion), Some((fake_expansion, fake_mapped_token))) => {
|
||||
let new_offset = fake_mapped_token.text_range().start();
|
||||
derive_ctx = Some((actual_expansion, fake_expansion, new_offset));
|
||||
break 'expansion;
|
||||
}
|
||||
// exactly one expansion failed, inconsistent state so stop expanding completely
|
||||
_ => break 'expansion,
|
||||
}
|
||||
}
|
||||
|
||||
// Expand fn-like macro calls
|
||||
if let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
|
||||
find_node_at_offset::<ast::MacroCall>(&original_file, offset),
|
||||
find_node_at_offset::<ast::MacroCall>(&speculative_file, offset),
|
||||
orig_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
|
||||
spec_tt.syntax().ancestors().find_map(ast::MacroCall::cast),
|
||||
) {
|
||||
let mac_call_path0 = actual_macro_call.path().as_ref().map(|s| s.syntax().text());
|
||||
let mac_call_path1 =
|
||||
@ -553,7 +592,7 @@ impl<'a> CompletionContext<'a> {
|
||||
break;
|
||||
}
|
||||
|
||||
self.fill(&original_file, speculative_file, offset);
|
||||
self.fill(&original_file, speculative_file, offset, derive_ctx);
|
||||
}
|
||||
|
||||
fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
|
||||
@ -697,6 +736,7 @@ impl<'a> CompletionContext<'a> {
|
||||
original_file: &SyntaxNode,
|
||||
file_with_fake_ident: SyntaxNode,
|
||||
offset: TextSize,
|
||||
derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize)>,
|
||||
) {
|
||||
let fake_ident_token = file_with_fake_ident.token_at_offset(offset).right_biased().unwrap();
|
||||
let syntax_element = NodeOrToken::Token(fake_ident_token);
|
||||
@ -708,11 +748,6 @@ impl<'a> CompletionContext<'a> {
|
||||
(fn_is_prev && !inside_impl_trait_block) || for_is_prev2
|
||||
};
|
||||
|
||||
self.attr = self
|
||||
.sema
|
||||
.token_ancestors_with_macros(self.token.clone())
|
||||
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
|
||||
.find_map(ast::Attr::cast);
|
||||
self.fake_attribute_under_caret = syntax_element.ancestors().find_map(ast::Attr::cast);
|
||||
|
||||
self.incomplete_let =
|
||||
@ -724,6 +759,33 @@ impl<'a> CompletionContext<'a> {
|
||||
self.expected_type = expected_type;
|
||||
self.expected_name = expected_name;
|
||||
|
||||
// Overwrite the path kind for derives
|
||||
if let Some((original_file, file_with_fake_ident, offset)) = derive_ctx {
|
||||
let attr = self
|
||||
.sema
|
||||
.token_ancestors_with_macros(self.token.clone())
|
||||
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
|
||||
.find_map(ast::Attr::cast);
|
||||
if let Some(attr) = &attr {
|
||||
self.existing_derives =
|
||||
self.sema.resolve_derive_macro(attr).into_iter().flatten().flatten().collect();
|
||||
}
|
||||
|
||||
if let Some(ast::NameLike::NameRef(name_ref)) =
|
||||
find_node_at_offset(&file_with_fake_ident, offset)
|
||||
{
|
||||
self.name_syntax =
|
||||
find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
|
||||
if let Some((path_ctx, _)) =
|
||||
Self::classify_name_ref(&self.sema, &original_file, name_ref)
|
||||
{
|
||||
self.path_context =
|
||||
Some(PathCompletionCtx { kind: Some(PathKind::Derive), ..path_ctx });
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let name_like = match find_node_at_offset(&file_with_fake_ident, offset) {
|
||||
Some(it) => it,
|
||||
None => return,
|
||||
@ -743,6 +805,7 @@ impl<'a> CompletionContext<'a> {
|
||||
.token_ancestors_with_macros(self.token.clone())
|
||||
.take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE)
|
||||
.find_map(ast::Fn::cast);
|
||||
|
||||
match name_like {
|
||||
ast::NameLike::Lifetime(lifetime) => {
|
||||
self.lifetime_ctx =
|
||||
|
@ -152,6 +152,7 @@ pub fn completions(
|
||||
|
||||
let mut acc = Completions::default();
|
||||
completions::attribute::complete_attribute(&mut acc, &ctx);
|
||||
completions::attribute::complete_derive(&mut acc, &ctx);
|
||||
completions::attribute::complete_known_attribute_input(&mut acc, &ctx);
|
||||
completions::dot::complete_dot(&mut acc, &ctx);
|
||||
completions::extern_abi::complete_extern_abi(&mut acc, &ctx);
|
||||
|
@ -1,12 +1,8 @@
|
||||
//! Renderer for macro invocations.
|
||||
|
||||
use either::Either;
|
||||
use hir::{Documentation, HasSource, InFile, Semantics};
|
||||
use ide_db::{RootDatabase, SymbolKind};
|
||||
use syntax::{
|
||||
display::{fn_as_proc_macro_label, macro_label},
|
||||
SmolStr,
|
||||
};
|
||||
use hir::{Documentation, HirDisplay};
|
||||
use ide_db::SymbolKind;
|
||||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
context::PathKind,
|
||||
@ -52,7 +48,7 @@ fn render(
|
||||
label(&ctx, needs_bang, bra, ket, &name),
|
||||
);
|
||||
item.set_deprecated(ctx.is_deprecated(macro_))
|
||||
.set_detail(detail(&completion.sema, macro_))
|
||||
.detail(macro_.display(completion.db).to_string())
|
||||
.set_documentation(docs)
|
||||
.set_relevance(ctx.completion_relevance());
|
||||
|
||||
@ -103,17 +99,6 @@ fn banged_name(name: &str) -> SmolStr {
|
||||
SmolStr::from_iter([name, "!"])
|
||||
}
|
||||
|
||||
fn detail(sema: &Semantics<RootDatabase>, macro_: hir::Macro) -> Option<String> {
|
||||
// FIXME: This is parsing the file!
|
||||
let InFile { file_id, value } = macro_.source(sema.db)?;
|
||||
let _ = sema.parse_or_expand(file_id);
|
||||
let detail = match value {
|
||||
Either::Left(node) => macro_label(&node),
|
||||
Either::Right(node) => fn_as_proc_macro_label(&node),
|
||||
};
|
||||
Some(detail)
|
||||
}
|
||||
|
||||
fn guess_macro_braces(macro_name: &str, docs: &str) -> (&'static str, &'static str) {
|
||||
let mut votes = [0, 0, 0];
|
||||
for (idx, s) in docs.match_indices(¯o_name) {
|
||||
|
@ -62,7 +62,7 @@ fn proc_macros_qualified() {
|
||||
struct Foo;
|
||||
"#,
|
||||
expect![[r#"
|
||||
at identity pub macro identity
|
||||
at identity proc_macro identity
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
@ -302,7 +302,7 @@ struct Foo;
|
||||
"#,
|
||||
expect![[r#"
|
||||
md core
|
||||
at derive pub macro derive
|
||||
at derive macro derive
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
@ -688,13 +688,17 @@ mod derive {
|
||||
#[derive($0)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
de Default
|
||||
md core
|
||||
de Default macro Default
|
||||
de Clone, Copy
|
||||
de PartialEq
|
||||
de PartialEq macro PartialEq
|
||||
de PartialEq, Eq
|
||||
de PartialEq, Eq, PartialOrd, Ord
|
||||
de Clone
|
||||
de Clone macro Clone
|
||||
de PartialEq, PartialOrd
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -707,12 +711,16 @@ mod derive {
|
||||
#[derive(serde::Serialize, PartialEq, $0)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
de Default
|
||||
md core
|
||||
de Default macro Default
|
||||
de Clone, Copy
|
||||
de Eq
|
||||
de Eq, PartialOrd, Ord
|
||||
de Clone
|
||||
de Clone macro Clone
|
||||
de PartialOrd
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
@ -725,33 +733,17 @@ mod derive {
|
||||
#[derive($0 serde::Serialize, PartialEq)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
de Default
|
||||
md core
|
||||
de Default macro Default
|
||||
de Clone, Copy
|
||||
de Eq
|
||||
de Eq, PartialOrd, Ord
|
||||
de Clone
|
||||
de Clone macro Clone
|
||||
de PartialOrd
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_no_attrs() {
|
||||
check_derive(
|
||||
r#"
|
||||
//- proc_macros: identity
|
||||
//- minicore: derive
|
||||
#[derive($0)] struct Test;
|
||||
"#,
|
||||
expect![[r#""#]],
|
||||
);
|
||||
check_derive(
|
||||
r#"
|
||||
//- proc_macros: identity
|
||||
//- minicore: derive
|
||||
#[derive(i$0)] struct Test;
|
||||
"#,
|
||||
expect![[r#""#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -760,20 +752,32 @@ mod derive {
|
||||
check_derive(
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
//- minicore: derive
|
||||
#[derive(der$0)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
de DeriveIdentity (use proc_macros::DeriveIdentity)
|
||||
md proc_macros
|
||||
md core
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
de DeriveIdentity (use proc_macros::DeriveIdentity) proc_macro DeriveIdentity
|
||||
"#]],
|
||||
);
|
||||
check_derive(
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
//- minicore: derive
|
||||
use proc_macros::DeriveIdentity;
|
||||
#[derive(der$0)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
de DeriveIdentity
|
||||
de DeriveIdentity proc_macro DeriveIdentity
|
||||
md proc_macros
|
||||
md core
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -784,6 +788,7 @@ use proc_macros::DeriveIdentity;
|
||||
"DeriveIdentity",
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
//- minicore: derive
|
||||
#[derive(der$0)] struct Test;
|
||||
"#,
|
||||
r#"
|
||||
@ -793,6 +798,30 @@ use proc_macros::DeriveIdentity;
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn qualified() {
|
||||
check_derive(
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
//- minicore: derive, copy, clone
|
||||
#[derive(proc_macros::$0)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
de DeriveIdentity proc_macro DeriveIdentity
|
||||
"#]],
|
||||
);
|
||||
check_derive(
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
//- minicore: derive, copy, clone
|
||||
#[derive(proc_macros::C$0)] struct Test;
|
||||
"#,
|
||||
expect![[r#"
|
||||
de DeriveIdentity proc_macro DeriveIdentity
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod lint {
|
||||
|
@ -30,7 +30,7 @@ fn baz() {
|
||||
}
|
||||
"#,
|
||||
// This should not contain `FooDesc {…}`.
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw unsafe
|
||||
kw match
|
||||
kw while
|
||||
@ -57,13 +57,13 @@ fn baz() {
|
||||
fn baz() fn()
|
||||
st Unit
|
||||
md _69latrick
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
fn function() fn()
|
||||
sc STATIC
|
||||
un Union
|
||||
ev TupleV(…) (u32)
|
||||
ct CONST
|
||||
"##]],
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ impl Unit {
|
||||
}
|
||||
"#,
|
||||
// `self` is in here twice, once as the module, once as the local
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
me self.foo() fn(self)
|
||||
kw unsafe
|
||||
kw fn
|
||||
@ -166,14 +166,14 @@ impl Unit {
|
||||
md module
|
||||
st Unit
|
||||
md qualified
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
?? Unresolved
|
||||
fn function() fn()
|
||||
sc STATIC
|
||||
un Union
|
||||
ev TupleV(…) (u32)
|
||||
ct CONST
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
@ -187,7 +187,7 @@ impl Unit {
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
tt Trait
|
||||
en Enum
|
||||
st Record
|
||||
@ -195,14 +195,14 @@ impl Unit {
|
||||
md module
|
||||
st Unit
|
||||
md qualified
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
?? Unresolved
|
||||
fn function() fn()
|
||||
sc STATIC
|
||||
un Union
|
||||
ev TupleV(…) (u32)
|
||||
ct CONST
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1108,7 +1108,7 @@ fn flyimport_attribute() {
|
||||
struct Foo;
|
||||
"#,
|
||||
expect![[r#"
|
||||
at identity (use proc_macros::identity) pub macro identity
|
||||
at identity (use proc_macros::identity) proc_macro identity
|
||||
"#]],
|
||||
);
|
||||
check_edit(
|
||||
|
@ -17,7 +17,7 @@ fn target_type_or_trait_in_impl_block() {
|
||||
r#"
|
||||
impl Tra$0
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
@ -27,10 +27,10 @@ impl Tra$0
|
||||
st Tuple
|
||||
md module
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
un Union
|
||||
bt u32
|
||||
"##]],
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ fn target_type_in_trait_impl_block() {
|
||||
r#"
|
||||
impl Trait for Str$0
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
@ -50,10 +50,10 @@ impl Trait for Str$0
|
||||
st Tuple
|
||||
md module
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
un Union
|
||||
bt u32
|
||||
"##]],
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ fn after_struct_name() {
|
||||
// FIXME: This should emit `kw where` only
|
||||
check(
|
||||
r"struct Struct $0",
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw pub(crate)
|
||||
kw pub(super)
|
||||
kw pub
|
||||
@ -109,8 +109,8 @@ fn after_struct_name() {
|
||||
kw super
|
||||
kw crate
|
||||
md module
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@ fn after_fn_name() {
|
||||
// FIXME: This should emit `kw where` only
|
||||
check(
|
||||
r"fn func() $0",
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw pub(crate)
|
||||
kw pub(super)
|
||||
kw pub
|
||||
@ -143,8 +143,8 @@ fn after_fn_name() {
|
||||
kw super
|
||||
kw crate
|
||||
md module
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ fn check(ra_fixture: &str, expect: Expect) {
|
||||
fn in_mod_item_list() {
|
||||
check(
|
||||
r#"mod tests { $0 }"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw pub(crate)
|
||||
kw pub(super)
|
||||
kw pub
|
||||
@ -35,8 +35,8 @@ fn in_mod_item_list() {
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ fn in_mod_item_list() {
|
||||
fn in_source_file_item_list() {
|
||||
check(
|
||||
r#"$0"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw pub(crate)
|
||||
kw pub(super)
|
||||
kw pub
|
||||
@ -68,8 +68,8 @@ fn in_source_file_item_list() {
|
||||
kw super
|
||||
kw crate
|
||||
md module
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
@ -106,10 +106,10 @@ fn in_qualified_path() {
|
||||
cov_mark::check!(no_keyword_completion_in_non_trivial_path);
|
||||
check(
|
||||
r#"crate::$0"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
md module
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
@ -162,7 +162,7 @@ fn after_visibility_unsafe() {
|
||||
fn in_impl_assoc_item_list() {
|
||||
check(
|
||||
r#"impl Struct { $0 }"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw pub(crate)
|
||||
kw pub(super)
|
||||
kw pub
|
||||
@ -174,8 +174,8 @@ fn in_impl_assoc_item_list() {
|
||||
kw super
|
||||
kw crate
|
||||
md module
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
@ -199,7 +199,7 @@ fn in_impl_assoc_item_list_after_attr() {
|
||||
fn in_trait_assoc_item_list() {
|
||||
check(
|
||||
r"trait Foo { $0 }",
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw unsafe
|
||||
kw fn
|
||||
kw const
|
||||
@ -208,8 +208,8 @@ fn in_trait_assoc_item_list() {
|
||||
kw super
|
||||
kw crate
|
||||
md module
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -233,7 +233,7 @@ impl Test for () {
|
||||
$0
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw pub(crate)
|
||||
kw pub(super)
|
||||
kw pub
|
||||
@ -245,7 +245,7 @@ impl Test for () {
|
||||
kw super
|
||||
kw crate
|
||||
md module
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ fn foo() {
|
||||
if let a$0
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
en Enum
|
||||
@ -112,11 +112,11 @@ fn foo() {
|
||||
st Tuple
|
||||
md module
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
bn TupleV TupleV($1)$0
|
||||
ev TupleV
|
||||
ct CONST
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -132,7 +132,7 @@ fn foo() {
|
||||
let a$0
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
bn Record Record { field$1 }$0
|
||||
@ -142,8 +142,8 @@ fn foo() {
|
||||
ev Variant
|
||||
en SingleVariantEnum
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ fn in_param() {
|
||||
fn foo(a$0) {
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
bn Record Record { field$1 }: Record$0
|
||||
@ -162,15 +162,15 @@ fn foo(a$0) {
|
||||
bn Tuple Tuple($1): Tuple$0
|
||||
st Tuple
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
fn foo(a$0: Tuple) {
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw ref
|
||||
kw mut
|
||||
bn Record Record { field$1 }$0
|
||||
@ -178,8 +178,8 @@ fn foo(a$0: Tuple) {
|
||||
bn Tuple Tuple($1)$0
|
||||
st Tuple
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ fn predicate_start() {
|
||||
r#"
|
||||
struct Foo<'lt, T, const C: usize> where $0 {}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
@ -26,10 +26,10 @@ struct Foo<'lt, T, const C: usize> where $0 {}
|
||||
md module
|
||||
st Foo<…>
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
un Union
|
||||
bt u32
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -39,14 +39,14 @@ fn bound_for_type_pred() {
|
||||
r#"
|
||||
struct Foo<'lt, T, const C: usize> where T: $0 {}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
tt Trait
|
||||
md module
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -58,14 +58,14 @@ fn bound_for_lifetime_pred() {
|
||||
r#"
|
||||
struct Foo<'lt, T, const C: usize> where 'lt: $0 {}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
tt Trait
|
||||
md module
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -75,14 +75,14 @@ fn bound_for_for_pred() {
|
||||
r#"
|
||||
struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
tt Trait
|
||||
md module
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
"##]],
|
||||
ma makro!(…) macro_rules! makro
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ fn param_list_for_for_pred() {
|
||||
r#"
|
||||
struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
@ -103,10 +103,10 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
|
||||
md module
|
||||
st Foo<…>
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
un Union
|
||||
bt u32
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -118,7 +118,7 @@ impl Record {
|
||||
fn method(self) where $0 {}
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
@ -129,9 +129,9 @@ impl Record {
|
||||
st Tuple
|
||||
md module
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
un Union
|
||||
bt u32
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ struct Foo<'lt, T, const C: usize> {
|
||||
f: $0
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
@ -29,10 +29,10 @@ struct Foo<'lt, T, const C: usize> {
|
||||
md module
|
||||
st Foo<…>
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
un Union
|
||||
bt u32
|
||||
"##]],
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ fn tuple_struct_field() {
|
||||
r#"
|
||||
struct Foo<'lt, T, const C: usize>(f$0);
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw pub(crate)
|
||||
kw pub(super)
|
||||
kw pub
|
||||
@ -58,10 +58,10 @@ struct Foo<'lt, T, const C: usize>(f$0);
|
||||
md module
|
||||
st Foo<…>
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
un Union
|
||||
bt u32
|
||||
"##]],
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ fn fn_return_type() {
|
||||
r#"
|
||||
fn x<'lt, T, const C: usize>() -> $0
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
@ -82,10 +82,10 @@ fn x<'lt, T, const C: usize>() -> $0
|
||||
st Tuple
|
||||
md module
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
un Union
|
||||
bt u32
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ fn foo<'lt, T, const C: usize>() {
|
||||
let _: $0;
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
@ -109,10 +109,10 @@ fn foo<'lt, T, const C: usize>() {
|
||||
st Tuple
|
||||
md module
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
un Union
|
||||
bt u32
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
@ -121,16 +121,16 @@ fn foo<'lt, T, const C: usize>() {
|
||||
let _: self::$0;
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
tt Trait
|
||||
en Enum
|
||||
st Record
|
||||
st Tuple
|
||||
md module
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
un Union
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ trait Trait2 {
|
||||
|
||||
fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
@ -157,12 +157,12 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {}
|
||||
st Tuple
|
||||
md module
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
tt Trait2
|
||||
un Union
|
||||
ct CONST
|
||||
bt u32
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
@ -172,18 +172,18 @@ trait Trait2 {
|
||||
|
||||
fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {}
|
||||
"#,
|
||||
expect![[r##"
|
||||
expect![[r#"
|
||||
tt Trait
|
||||
en Enum
|
||||
st Record
|
||||
st Tuple
|
||||
md module
|
||||
st Unit
|
||||
ma makro!(…) #[macro_export] macro_rules! makro
|
||||
ma makro!(…) macro_rules! makro
|
||||
tt Trait2
|
||||
un Union
|
||||
ct CONST
|
||||
"##]],
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -443,7 +443,7 @@ pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option<Vec<ast::Pat
|
||||
None => None,
|
||||
Some(tok) => Some(tok),
|
||||
});
|
||||
let input_expressions = tokens.into_iter().group_by(|tok| tok.kind() == T![,]);
|
||||
let input_expressions = tokens.group_by(|tok| tok.kind() == T![,]);
|
||||
let paths = input_expressions
|
||||
.into_iter()
|
||||
.filter_map(|(is_sep, group)| (!is_sep).then(|| group))
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! This module contains utilities for rendering syntax nodes into a string representing their signature.
|
||||
|
||||
use crate::ast::{self, HasAttrs, HasGenericParams, HasName};
|
||||
use crate::ast::{self, HasGenericParams, HasName};
|
||||
|
||||
use ast::HasVisibility;
|
||||
use stdx::format_to;
|
||||
@ -49,37 +49,3 @@ pub fn function_declaration(node: &ast::Fn) -> String {
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn macro_label(node: &ast::Macro) -> String {
|
||||
let name = node.name();
|
||||
let mut s = String::new();
|
||||
match node {
|
||||
ast::Macro::MacroRules(node) => {
|
||||
let vis = if node.has_atom_attr("macro_export") { "#[macro_export] " } else { "" };
|
||||
format_to!(s, "{}macro_rules!", vis);
|
||||
}
|
||||
ast::Macro::MacroDef(node) => {
|
||||
if let Some(vis) = node.visibility() {
|
||||
format_to!(s, "{} ", vis);
|
||||
}
|
||||
format_to!(s, "macro");
|
||||
}
|
||||
}
|
||||
if let Some(name) = name {
|
||||
format_to!(s, " {}", name);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
pub fn fn_as_proc_macro_label(node: &ast::Fn) -> String {
|
||||
let name = node.name();
|
||||
let mut s = String::new();
|
||||
if let Some(vis) = node.visibility() {
|
||||
format_to!(s, "{} ", vis);
|
||||
}
|
||||
format_to!(s, "macro");
|
||||
if let Some(name) = name {
|
||||
format_to!(s, " {}", name);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user