mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Move attribute path completions into attribute completion module
This commit is contained in:
parent
46b5089bfa
commit
6940cca760
11 changed files with 139 additions and 107 deletions
|
@ -949,12 +949,15 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Either::Left(path) => resolve_hir_path(
|
Either::Left(path) => {
|
||||||
self.db,
|
let len = path.len();
|
||||||
&self.scope(derive.syntax()).resolver,
|
resolve_hir_path(
|
||||||
&Path::from_known_path(path, []),
|
self.db,
|
||||||
)
|
&self.scope(derive.syntax()).resolver,
|
||||||
.filter(|res| matches!(res, PathResolution::Def(ModuleDef::Module(_)))),
|
&Path::from_known_path(path, vec![None; len]),
|
||||||
|
)
|
||||||
|
.filter(|res| matches!(res, PathResolution::Def(ModuleDef::Module(_))))
|
||||||
|
}
|
||||||
Either::Right(derive) => derive
|
Either::Right(derive) => derive
|
||||||
.map(|call| MacroDef { id: self.db.lookup_intern_macro_call(call).def })
|
.map(|call| MacroDef { id: self.db.lookup_intern_macro_call(call).def })
|
||||||
.map(PathResolution::Macro),
|
.map(PathResolution::Macro),
|
||||||
|
|
|
@ -92,7 +92,9 @@ impl Path {
|
||||||
path: ModPath,
|
path: ModPath,
|
||||||
generic_args: impl Into<Box<[Option<Interned<GenericArgs>>]>>,
|
generic_args: impl Into<Box<[Option<Interned<GenericArgs>>]>>,
|
||||||
) -> Path {
|
) -> Path {
|
||||||
Path { type_anchor: None, mod_path: Interned::new(path), generic_args: generic_args.into() }
|
let generic_args = generic_args.into();
|
||||||
|
assert_eq!(path.len(), generic_args.len());
|
||||||
|
Path { type_anchor: None, mod_path: Interned::new(path), generic_args }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&self) -> &PathKind {
|
pub fn kind(&self) -> &PathKind {
|
||||||
|
|
|
@ -253,6 +253,7 @@ pub enum PointerCast {
|
||||||
/// Go from a mut raw pointer to a const raw pointer.
|
/// Go from a mut raw pointer to a const raw pointer.
|
||||||
MutToConstPointer,
|
MutToConstPointer,
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
/// Go from `*const [T; N]` to `*const T`
|
/// Go from `*const [T; N]` to `*const T`
|
||||||
ArrayToPointer,
|
ArrayToPointer,
|
||||||
|
|
||||||
|
|
|
@ -16,62 +16,95 @@ use ide_db::{
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use syntax::{algo::non_trivia_sibling, ast, AstNode, Direction, SyntaxKind, T};
|
use syntax::{
|
||||||
|
ast::{self, AttrKind},
|
||||||
|
AstNode, SyntaxKind, T,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{context::CompletionContext, item::CompletionItem, Completions};
|
use crate::{
|
||||||
|
completions::module_or_attr,
|
||||||
|
context::{CompletionContext, PathCompletionContext, PathKind},
|
||||||
|
item::CompletionItem,
|
||||||
|
Completions,
|
||||||
|
};
|
||||||
|
|
||||||
mod cfg;
|
mod cfg;
|
||||||
mod derive;
|
mod derive;
|
||||||
mod lint;
|
mod lint;
|
||||||
mod repr;
|
mod repr;
|
||||||
|
|
||||||
pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
|
/// Complete inputs to known builtin attributes as well as derive attributes
|
||||||
|
pub(crate) fn complete_known_attribute_input(
|
||||||
|
acc: &mut Completions,
|
||||||
|
ctx: &CompletionContext,
|
||||||
|
) -> Option<()> {
|
||||||
let attribute = ctx.fake_attribute_under_caret.as_ref()?;
|
let attribute = ctx.fake_attribute_under_caret.as_ref()?;
|
||||||
let name_ref = match attribute.path() {
|
let name_ref = match attribute.path() {
|
||||||
Some(p) => Some(p.as_single_name_ref()?),
|
Some(p) => Some(p.as_single_name_ref()?),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
match (name_ref, attribute.token_tree()) {
|
let (path, tt) = name_ref.zip(attribute.token_tree())?;
|
||||||
(Some(path), Some(tt)) if tt.l_paren_token().is_some() => match path.text().as_str() {
|
if tt.l_paren_token().is_none() {
|
||||||
"repr" => repr::complete_repr(acc, ctx, tt),
|
return None;
|
||||||
"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)?;
|
|
||||||
|
|
||||||
let lints: Vec<Lint> = CLIPPY_LINT_GROUPS
|
match path.text().as_str() {
|
||||||
.iter()
|
"repr" => repr::complete_repr(acc, ctx, tt),
|
||||||
.map(|g| &g.lint)
|
"derive" => derive::complete_derive(acc, ctx, ctx.attr.as_ref()?),
|
||||||
.chain(DEFAULT_LINTS.iter())
|
"feature" => lint::complete_lint(acc, ctx, &parse_tt_as_comma_sep_paths(tt)?, FEATURES),
|
||||||
.chain(CLIPPY_LINTS.iter())
|
"allow" | "warn" | "deny" | "forbid" => {
|
||||||
.chain(RUSTDOC_LINTS)
|
let existing_lints = parse_tt_as_comma_sep_paths(tt)?;
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
lint::complete_lint(acc, ctx, &existing_lints, &lints);
|
let lints: Vec<Lint> = CLIPPY_LINT_GROUPS
|
||||||
}
|
.iter()
|
||||||
"cfg" => {
|
.map(|g| &g.lint)
|
||||||
cfg::complete_cfg(acc, ctx);
|
.chain(DEFAULT_LINTS)
|
||||||
}
|
.chain(CLIPPY_LINTS)
|
||||||
_ => (),
|
.chain(RUSTDOC_LINTS)
|
||||||
},
|
.cloned()
|
||||||
(_, Some(_)) => (),
|
.collect();
|
||||||
(_, None) if attribute.expr().is_some() => (),
|
|
||||||
(_, None) => complete_new_attribute(acc, ctx, attribute),
|
lint::complete_lint(acc, ctx, &existing_lints, &lints);
|
||||||
|
}
|
||||||
|
"cfg" => {
|
||||||
|
cfg::complete_cfg(acc, ctx);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME?: Move this functionality to (un)qualified_path, make this module work solely for builtin/known attributes for their inputs?
|
pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) {
|
||||||
fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attribute: &ast::Attr) {
|
let (is_trivial_path, qualifier, is_inner, annotated_item_kind) = match ctx.path_context {
|
||||||
let is_inner = attribute.kind() == ast::AttrKind::Inner;
|
Some(PathCompletionContext {
|
||||||
let attribute_annotated_item_kind =
|
kind: Some(PathKind::Attr { kind, annotated_item_kind }),
|
||||||
attribute.syntax().parent().map(|it| it.kind()).filter(|_| {
|
is_trivial_path,
|
||||||
is_inner
|
ref qualifier,
|
||||||
// If we got nothing coming after the attribute it could be anything so filter it the kind out
|
..
|
||||||
|| non_trivia_sibling(attribute.syntax().clone().into(), Direction::Next).is_some()
|
}) => (is_trivial_path, qualifier, kind == AttrKind::Inner, annotated_item_kind),
|
||||||
});
|
_ => return,
|
||||||
let attributes = attribute_annotated_item_kind.and_then(|kind| {
|
};
|
||||||
|
|
||||||
|
if !is_trivial_path {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((_, Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))))) = qualifier {
|
||||||
|
for (name, def) in module.scope(ctx.db, ctx.module) {
|
||||||
|
if let Some(def) = module_or_attr(def) {
|
||||||
|
acc.add_resolution(ctx, name, def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.process_all_names(&mut |name, def| {
|
||||||
|
if let Some(def) = module_or_attr(def) {
|
||||||
|
acc.add_resolution(ctx, name, def);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let attributes = annotated_item_kind.and_then(|kind| {
|
||||||
if ast::Expr::can_cast(kind) {
|
if ast::Expr::can_cast(kind) {
|
||||||
Some(EXPR_ATTRIBUTES)
|
Some(EXPR_ATTRIBUTES)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -171,8 +171,8 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
|
||||||
(PathKind::Type, ItemInNs::Types(_)) => true,
|
(PathKind::Type, ItemInNs::Types(_)) => true,
|
||||||
(PathKind::Type, ItemInNs::Values(_)) => false,
|
(PathKind::Type, ItemInNs::Values(_)) => false,
|
||||||
|
|
||||||
(PathKind::Attr, ItemInNs::Macros(mac)) => mac.is_attr(),
|
(PathKind::Attr { .. }, ItemInNs::Macros(mac)) => mac.is_attr(),
|
||||||
(PathKind::Attr, _) => false,
|
(PathKind::Attr { .. }, _) => false,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ use rustc_hash::FxHashSet;
|
||||||
use syntax::{ast, AstNode};
|
use syntax::{ast, AstNode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
completions::{module_or_attr, module_or_fn_macro},
|
completions::module_or_fn_macro,
|
||||||
context::{PathCompletionContext, PathKind},
|
context::{PathCompletionContext, PathKind},
|
||||||
patterns::ImmediateLocation,
|
patterns::ImmediateLocation,
|
||||||
CompletionContext, Completions,
|
CompletionContext, Completions,
|
||||||
|
@ -17,7 +17,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() {
|
if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let (path, use_tree_parent, kind) = match ctx.path_context {
|
let ((path, resolution), use_tree_parent, kind) = match ctx.path_context {
|
||||||
// let ... else, syntax would come in really handy here right now
|
// let ... else, syntax would come in really handy here right now
|
||||||
Some(PathCompletionContext {
|
Some(PathCompletionContext {
|
||||||
qualifier: Some(ref qualifier),
|
qualifier: Some(ref qualifier),
|
||||||
|
@ -47,17 +47,15 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let resolution = match ctx.sema.resolve_path(path) {
|
let resolution = match resolution {
|
||||||
Some(res) => res,
|
Some(res) => res,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let context_module = ctx.module;
|
|
||||||
|
|
||||||
match ctx.completion_location {
|
match ctx.completion_location {
|
||||||
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, ctx.module) {
|
||||||
if let Some(def) = module_or_fn_macro(def) {
|
if let Some(def) = module_or_fn_macro(def) {
|
||||||
acc.add_resolution(ctx, name, def);
|
acc.add_resolution(ctx, name, def);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +74,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
let next_towards_current = current_module
|
let next_towards_current = current_module
|
||||||
.path_to_root(ctx.db)
|
.path_to_root(ctx.db)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.take_while(|&it| it != module)
|
.take_while(|it| it != module)
|
||||||
.next();
|
.next();
|
||||||
if let Some(next) = next_towards_current {
|
if let Some(next) = next_towards_current {
|
||||||
if let Some(name) = next.name(ctx.db) {
|
if let Some(name) = next.name(ctx.db) {
|
||||||
|
@ -88,14 +86,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Some(PathKind::Attr) => {
|
Some(PathKind::Attr { .. }) => {
|
||||||
if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
|
|
||||||
for (name, def) in module.scope(ctx.db, context_module) {
|
|
||||||
if let Some(def) = module_or_attr(def) {
|
|
||||||
acc.add_resolution(ctx, name, def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Some(PathKind::Use) => {
|
Some(PathKind::Use) => {
|
||||||
|
@ -127,7 +118,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
|
|
||||||
match resolution {
|
match resolution {
|
||||||
hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
|
hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
|
||||||
let module_scope = module.scope(ctx.db, context_module);
|
let module_scope = module.scope(ctx.db, ctx.module);
|
||||||
for (name, def) in module_scope {
|
for (name, def) in module_scope {
|
||||||
if let Some(PathKind::Use) = kind {
|
if let Some(PathKind::Use) = kind {
|
||||||
if let ScopeDef::Unknown = def {
|
if let ScopeDef::Unknown = def {
|
||||||
|
@ -168,7 +159,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
||||||
| hir::ModuleDef::TypeAlias(_)
|
| hir::ModuleDef::TypeAlias(_)
|
||||||
| hir::ModuleDef::BuiltinType(_)),
|
| hir::ModuleDef::BuiltinType(_)),
|
||||||
) => {
|
) => {
|
||||||
if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
|
if let &hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def {
|
||||||
add_enum_variants(acc, ctx, e);
|
add_enum_variants(acc, ctx, e);
|
||||||
}
|
}
|
||||||
let ty = match def {
|
let ty = match def {
|
||||||
|
@ -622,18 +613,6 @@ fn foo() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn dont_complete_attr() {
|
|
||||||
check(
|
|
||||||
r#"
|
|
||||||
mod foo { pub struct Foo; }
|
|
||||||
#[foo::$0]
|
|
||||||
fn f() {}
|
|
||||||
"#,
|
|
||||||
expect![[""]],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn completes_variant_through_self() {
|
fn completes_variant_through_self() {
|
||||||
check(
|
check(
|
||||||
|
|
|
@ -4,7 +4,7 @@ use hir::ScopeDef;
|
||||||
use syntax::{ast, AstNode};
|
use syntax::{ast, AstNode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
completions::{module_or_attr, module_or_fn_macro},
|
completions::module_or_fn_macro,
|
||||||
context::{PathCompletionContext, PathKind},
|
context::{PathCompletionContext, PathKind},
|
||||||
patterns::ImmediateLocation,
|
patterns::ImmediateLocation,
|
||||||
CompletionContext, Completions,
|
CompletionContext, Completions,
|
||||||
|
@ -36,14 +36,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
Some(PathKind::Vis { .. }) => return,
|
Some(PathKind::Vis { .. }) => return,
|
||||||
Some(PathKind::Attr) => {
|
Some(PathKind::Attr { .. }) => return,
|
||||||
ctx.process_all_names(&mut |name, def| {
|
|
||||||
if let Some(def) = module_or_attr(def) {
|
|
||||||
acc.add_resolution(ctx, name, def);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use base_db::SourceDatabaseExt;
|
use base_db::SourceDatabaseExt;
|
||||||
use hir::{HasAttrs, Local, Name, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo};
|
use hir::{
|
||||||
|
HasAttrs, Local, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type, TypeInfo,
|
||||||
|
};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
active_parameter::ActiveParameter,
|
active_parameter::ActiveParameter,
|
||||||
base_db::{FilePosition, SourceDatabase},
|
base_db::{FilePosition, SourceDatabase},
|
||||||
|
@ -11,8 +13,8 @@ use ide_db::{
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
algo::find_node_at_offset,
|
algo::{find_node_at_offset, non_trivia_sibling},
|
||||||
ast::{self, HasName, NameOrNameRef},
|
ast::{self, AttrKind, HasName, NameOrNameRef},
|
||||||
match_ast, AstNode, NodeOrToken,
|
match_ast, AstNode, NodeOrToken,
|
||||||
SyntaxKind::{self, *},
|
SyntaxKind::{self, *},
|
||||||
SyntaxNode, SyntaxToken, TextRange, TextSize, T,
|
SyntaxNode, SyntaxToken, TextRange, TextSize, T,
|
||||||
|
@ -44,7 +46,7 @@ pub(crate) enum Visible {
|
||||||
pub(super) enum PathKind {
|
pub(super) enum PathKind {
|
||||||
Expr,
|
Expr,
|
||||||
Type,
|
Type,
|
||||||
Attr,
|
Attr { kind: AttrKind, annotated_item_kind: Option<SyntaxKind> },
|
||||||
Mac,
|
Mac,
|
||||||
Pat,
|
Pat,
|
||||||
Vis { has_in_token: bool },
|
Vis { has_in_token: bool },
|
||||||
|
@ -58,7 +60,7 @@ pub(crate) struct PathCompletionContext {
|
||||||
/// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
|
/// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
|
||||||
pub(super) is_trivial_path: bool,
|
pub(super) is_trivial_path: bool,
|
||||||
/// If not a trivial path, the prefix (qualifier).
|
/// If not a trivial path, the prefix (qualifier).
|
||||||
pub(super) qualifier: Option<ast::Path>,
|
pub(super) qualifier: Option<(ast::Path, Option<PathResolution>)>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
/// If not a trivial path, the suffix (parent).
|
/// If not a trivial path, the suffix (parent).
|
||||||
pub(super) parent: Option<ast::Path>,
|
pub(super) parent: Option<ast::Path>,
|
||||||
|
@ -282,7 +284,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn path_qual(&self) -> Option<&ast::Path> {
|
pub(crate) fn path_qual(&self) -> Option<&ast::Path> {
|
||||||
self.path_context.as_ref().and_then(|it| it.qualifier.as_ref())
|
self.path_context.as_ref().and_then(|it| it.qualifier.as_ref().map(|(it, _)| it))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn path_kind(&self) -> Option<PathKind> {
|
pub(crate) fn path_kind(&self) -> Option<PathKind> {
|
||||||
|
@ -786,7 +788,7 @@ impl<'a> CompletionContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn classify_name_ref(
|
fn classify_name_ref(
|
||||||
_sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
original_file: &SyntaxNode,
|
original_file: &SyntaxNode,
|
||||||
name_ref: ast::NameRef,
|
name_ref: ast::NameRef,
|
||||||
) -> Option<(PathCompletionContext, Option<PatternContext>)> {
|
) -> Option<(PathCompletionContext, Option<PatternContext>)> {
|
||||||
|
@ -808,8 +810,9 @@ impl<'a> CompletionContext<'a> {
|
||||||
let mut pat_ctx = None;
|
let mut pat_ctx = None;
|
||||||
path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
|
path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
|
||||||
|
|
||||||
path_ctx.kind = path.syntax().ancestors().find_map(|it| {
|
path_ctx.kind = path.syntax().ancestors().find_map(|it| {
|
||||||
match_ast! {
|
// using Option<Option<PathKind>> as extra controlflow
|
||||||
|
let kind = match_ast! {
|
||||||
match it {
|
match it {
|
||||||
ast::PathType(_) => Some(PathKind::Type),
|
ast::PathType(_) => Some(PathKind::Type),
|
||||||
ast::PathExpr(it) => {
|
ast::PathExpr(it) => {
|
||||||
|
@ -830,21 +833,41 @@ impl<'a> CompletionContext<'a> {
|
||||||
Some(PathKind::Pat)
|
Some(PathKind::Pat)
|
||||||
},
|
},
|
||||||
ast::MacroCall(it) => it.excl_token().and(Some(PathKind::Mac)),
|
ast::MacroCall(it) => it.excl_token().and(Some(PathKind::Mac)),
|
||||||
ast::Meta(_) => Some(PathKind::Attr),
|
ast::Meta(meta) => (|| {
|
||||||
|
let attr = meta.parent_attr()?;
|
||||||
|
let kind = attr.kind();
|
||||||
|
let attached = attr.syntax().parent()?;
|
||||||
|
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 {
|
||||||
|
kind,
|
||||||
|
annotated_item_kind,
|
||||||
|
})
|
||||||
|
})(),
|
||||||
ast::Visibility(it) => Some(PathKind::Vis { has_in_token: it.in_token().is_some() }),
|
ast::Visibility(it) => Some(PathKind::Vis { has_in_token: it.in_token().is_some() }),
|
||||||
ast::UseTree(_) => Some(PathKind::Use),
|
ast::UseTree(_) => Some(PathKind::Use),
|
||||||
_ => None,
|
_ => return None,
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
});
|
Some(kind)
|
||||||
|
}).flatten();
|
||||||
path_ctx.has_type_args = segment.generic_arg_list().is_some();
|
path_ctx.has_type_args = segment.generic_arg_list().is_some();
|
||||||
|
|
||||||
if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
|
if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
|
||||||
path_ctx.use_tree_parent = use_tree_parent;
|
path_ctx.use_tree_parent = use_tree_parent;
|
||||||
path_ctx.qualifier = path
|
let path = path
|
||||||
.segment()
|
.segment()
|
||||||
.and_then(|it| find_node_in_file(original_file, &it))
|
.and_then(|it| find_node_in_file(original_file, &it))
|
||||||
.map(|it| it.parent_path());
|
.map(|it| it.parent_path());
|
||||||
|
path_ctx.qualifier = path.map(|path| {
|
||||||
|
let res = sema.resolve_path(&path);
|
||||||
|
(path, res)
|
||||||
|
});
|
||||||
return Some((path_ctx, pat_ctx));
|
return Some((path_ctx, pat_ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,6 +151,7 @@ pub fn completions(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut acc = Completions::default();
|
let mut acc = Completions::default();
|
||||||
|
completions::attribute::complete_known_attribute_input(&mut acc, &ctx);
|
||||||
completions::attribute::complete_attribute(&mut acc, &ctx);
|
completions::attribute::complete_attribute(&mut acc, &ctx);
|
||||||
completions::fn_param::complete_fn_param(&mut acc, &ctx);
|
completions::fn_param::complete_fn_param(&mut acc, &ctx);
|
||||||
completions::keyword::complete_expr_keyword(&mut acc, &ctx);
|
completions::keyword::complete_expr_keyword(&mut acc, &ctx);
|
||||||
|
|
|
@ -17,6 +17,7 @@ fn proc_macros() {
|
||||||
struct Foo;
|
struct Foo;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
|
md proc_macros
|
||||||
at allow(…)
|
at allow(…)
|
||||||
at cfg(…)
|
at cfg(…)
|
||||||
at cfg_attr(…)
|
at cfg_attr(…)
|
||||||
|
@ -35,7 +36,6 @@ struct Foo;
|
||||||
kw self
|
kw self
|
||||||
kw super
|
kw super
|
||||||
kw crate
|
kw crate
|
||||||
md proc_macros
|
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -61,10 +61,7 @@ fn proc_macros_qualified() {
|
||||||
#[proc_macros::$0]
|
#[proc_macros::$0]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#""#]],
|
||||||
at input_replace pub macro input_replace
|
|
||||||
at identity pub macro identity
|
|
||||||
"#]],
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +299,8 @@ fn attr_on_struct() {
|
||||||
struct Foo;
|
struct Foo;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
|
md core
|
||||||
|
at derive pub macro derive
|
||||||
at allow(…)
|
at allow(…)
|
||||||
at cfg(…)
|
at cfg(…)
|
||||||
at cfg_attr(…)
|
at cfg_attr(…)
|
||||||
|
@ -320,8 +319,6 @@ struct Foo;
|
||||||
kw self
|
kw self
|
||||||
kw super
|
kw super
|
||||||
kw crate
|
kw crate
|
||||||
md core
|
|
||||||
at derive pub macro derive
|
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ impl From<ast::AssocItem> for ast::Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum AttrKind {
|
pub enum AttrKind {
|
||||||
Inner,
|
Inner,
|
||||||
Outer,
|
Outer,
|
||||||
|
|
Loading…
Reference in a new issue