Add completion module tailored towards use trees
This commit is contained in:
parent
6940cca760
commit
661d721e20
12 changed files with 270 additions and 165 deletions
|
@ -481,7 +481,7 @@ impl HirDisplay for Module {
|
|||
// FIXME: Module doesn't have visibility saved in data.
|
||||
match self.name(f.db) {
|
||||
Some(name) => write!(f, "mod {}", name),
|
||||
None if self.crate_root(f.db) == *self => match self.krate().display_name(f.db) {
|
||||
None if self.is_crate_root(f.db) => match self.krate().display_name(f.db) {
|
||||
Some(name) => write!(f, "extern crate {}", name),
|
||||
None => write!(f, "extern crate {{unknown}}"),
|
||||
},
|
||||
|
|
|
@ -452,6 +452,11 @@ impl Module {
|
|||
Module { id: def_map.module_id(def_map.root()) }
|
||||
}
|
||||
|
||||
pub fn is_crate_root(self, db: &dyn HirDatabase) -> bool {
|
||||
let def_map = db.crate_def_map(self.id.krate());
|
||||
def_map.root() == self.id.local_id
|
||||
}
|
||||
|
||||
/// Iterates over all child modules.
|
||||
pub fn children(self, db: &dyn HirDatabase) -> impl Iterator<Item = Module> {
|
||||
let def_map = self.id.def_map(db.upcast());
|
||||
|
|
|
@ -4,9 +4,11 @@ pub(crate) mod attribute;
|
|||
pub(crate) mod dot;
|
||||
pub(crate) mod flyimport;
|
||||
pub(crate) mod fn_param;
|
||||
pub(crate) mod format_string;
|
||||
pub(crate) mod keyword;
|
||||
pub(crate) mod lifetime;
|
||||
pub(crate) mod mod_;
|
||||
pub(crate) mod use_;
|
||||
pub(crate) mod pattern;
|
||||
pub(crate) mod postfix;
|
||||
pub(crate) mod qualified_path;
|
||||
|
@ -14,7 +16,6 @@ pub(crate) mod record;
|
|||
pub(crate) mod snippet;
|
||||
pub(crate) mod trait_impl;
|
||||
pub(crate) mod unqualified_path;
|
||||
pub(crate) mod format_string;
|
||||
|
||||
use std::iter;
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
//! Completion for attributes
|
||||
//! Completion for (built-in) attributes, derives and lints.
|
||||
//!
|
||||
//! This module uses a bit of static metadata to provide completions
|
||||
//! for built-in attributes.
|
||||
//! Non-built-in attribute (excluding derives attributes) completions are done in [`super::unqualified_path`].
|
||||
//! This module uses a bit of static metadata to provide completions for builtin-in attributes and lints.
|
||||
|
||||
use std::iter;
|
||||
|
||||
use hir::ScopeDef;
|
||||
use ide_db::{
|
||||
helpers::{
|
||||
generated_lints::{
|
||||
|
@ -85,24 +86,45 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
|
|||
_ => return,
|
||||
};
|
||||
|
||||
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);
|
||||
match qualifier {
|
||||
Some((path, qualifier)) => {
|
||||
let is_super_chain = iter::successors(Some(path.clone()), |p| p.qualifier())
|
||||
.all(|p| p.segment().and_then(|s| s.super_token()).is_some());
|
||||
if is_super_chain {
|
||||
acc.add_keyword(ctx, "super::");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.process_all_names(&mut |name, def| {
|
||||
if let Some(def) = module_or_attr(def) {
|
||||
acc.add_resolution(ctx, name, def);
|
||||
let module = match qualifier {
|
||||
Some(hir::PathResolution::Def(hir::ModuleDef::Module(it))) => it,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
// fresh use tree with leading colon2, only show crate roots
|
||||
None if !is_trivial_path => {
|
||||
ctx.process_all_names(&mut |name, res| match res {
|
||||
ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
_ => (),
|
||||
});
|
||||
}
|
||||
// only show modules in a fresh UseTree
|
||||
None => {
|
||||
ctx.process_all_names(&mut |name, def| {
|
||||
if let Some(def) = module_or_attr(def) {
|
||||
acc.add_resolution(ctx, name, def);
|
||||
}
|
||||
});
|
||||
["self::", "super::", "crate::"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
|
||||
}
|
||||
}
|
||||
|
||||
let attributes = annotated_item_kind.and_then(|kind| {
|
||||
if ast::Expr::can_cast(kind) {
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
//! Completion of paths, i.e. `some::prefix::$0`.
|
||||
|
||||
use std::iter;
|
||||
|
||||
use hir::{ScopeDef, Trait};
|
||||
use rustc_hash::FxHashSet;
|
||||
use syntax::{ast, AstNode};
|
||||
use syntax::ast;
|
||||
|
||||
use crate::{
|
||||
completions::module_or_fn_macro,
|
||||
|
@ -17,14 +15,11 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
|||
if ctx.is_path_disallowed() || ctx.has_impl_or_trait_prev_sibling() {
|
||||
return;
|
||||
}
|
||||
let ((path, resolution), use_tree_parent, kind) = match ctx.path_context {
|
||||
let ((path, resolution), kind) = match ctx.path_context {
|
||||
// let ... else, syntax would come in really handy here right now
|
||||
Some(PathCompletionContext {
|
||||
qualifier: Some(ref qualifier),
|
||||
use_tree_parent,
|
||||
kind,
|
||||
..
|
||||
}) => (qualifier, use_tree_parent, kind),
|
||||
Some(PathCompletionContext { qualifier: Some(ref qualifier), kind, .. }) => {
|
||||
(qualifier, kind)
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
|
||||
|
@ -86,52 +81,23 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
|
|||
}
|
||||
return;
|
||||
}
|
||||
Some(PathKind::Attr { .. }) => {
|
||||
Some(PathKind::Attr { .. } | PathKind::Use) => {
|
||||
return;
|
||||
}
|
||||
Some(PathKind::Use) => {
|
||||
if iter::successors(Some(path.clone()), |p| p.qualifier())
|
||||
.all(|p| p.segment().and_then(|s| s.super_token()).is_some())
|
||||
{
|
||||
acc.add_keyword(ctx, "super::");
|
||||
}
|
||||
// only show `self` in a new use-tree when the qualifier doesn't end in self
|
||||
if use_tree_parent
|
||||
&& !matches!(
|
||||
path.segment().and_then(|it| it.kind()),
|
||||
Some(ast::PathSegmentKind::SelfKw)
|
||||
)
|
||||
{
|
||||
acc.add_keyword(ctx, "self");
|
||||
}
|
||||
Some(PathKind::Pat) => (),
|
||||
_ => {
|
||||
// Add associated types on type parameters and `Self`.
|
||||
ctx.scope.assoc_type_shorthand_candidates(&resolution, |_, alias| {
|
||||
acc.add_type_alias(ctx, alias);
|
||||
None::<()>
|
||||
});
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if !matches!(kind, Some(PathKind::Pat)) {
|
||||
// Add associated types on type parameters and `Self`.
|
||||
ctx.scope.assoc_type_shorthand_candidates(&resolution, |_, alias| {
|
||||
acc.add_type_alias(ctx, alias);
|
||||
None::<()>
|
||||
});
|
||||
}
|
||||
|
||||
match resolution {
|
||||
hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
|
||||
let module_scope = module.scope(ctx.db, ctx.module);
|
||||
for (name, def) in module_scope {
|
||||
if let Some(PathKind::Use) = kind {
|
||||
if let ScopeDef::Unknown = def {
|
||||
if let Some(ast::NameLike::NameRef(name_ref)) = ctx.name_syntax.as_ref() {
|
||||
if name_ref.syntax().text() == name.to_smol_str().as_str() {
|
||||
// for `use self::foo$0`, don't suggest `foo` as a completion
|
||||
cov_mark::hit!(dont_complete_current_use);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let add_resolution = match def {
|
||||
// Don't suggest attribute macros and derives.
|
||||
ScopeDef::MacroDef(mac) => mac.is_fn_like(),
|
||||
|
|
|
@ -20,25 +20,11 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
|
|||
_ => return,
|
||||
};
|
||||
|
||||
if let Some(PathKind::Use) = kind {
|
||||
// only show modules in a fresh UseTree
|
||||
cov_mark::hit!(unqualified_path_only_modules_in_import);
|
||||
ctx.process_all_names(&mut |name, res| {
|
||||
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
});
|
||||
|
||||
["self::", "super::", "crate::"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
|
||||
return;
|
||||
}
|
||||
["self", "super", "crate"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
|
||||
|
||||
match kind {
|
||||
Some(PathKind::Vis { .. }) => return,
|
||||
Some(PathKind::Attr { .. }) => return,
|
||||
Some(PathKind::Vis { .. } | PathKind::Attr { .. } | PathKind::Use { .. }) => return,
|
||||
_ => (),
|
||||
}
|
||||
["self", "super", "crate"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
|
||||
|
||||
match &ctx.completion_location {
|
||||
Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
|
||||
|
|
109
crates/ide_completion/src/completions/use_.rs
Normal file
109
crates/ide_completion/src/completions/use_.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
//! Completion for use trees
|
||||
//!
|
||||
//! This module uses a bit of static metadata to provide completions
|
||||
//! for built-in attributes.
|
||||
//! Non-built-in attribute (excluding derives attributes) completions are done in [`super::unqualified_path`].
|
||||
|
||||
use std::iter;
|
||||
|
||||
use hir::ScopeDef;
|
||||
use syntax::{ast, AstNode};
|
||||
|
||||
use crate::{
|
||||
context::{CompletionContext, PathCompletionContext, PathKind},
|
||||
Completions,
|
||||
};
|
||||
|
||||
pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext) {
|
||||
let (is_trivial_path, qualifier, use_tree_parent) = match ctx.path_context {
|
||||
Some(PathCompletionContext {
|
||||
kind: Some(PathKind::Use),
|
||||
is_trivial_path,
|
||||
use_tree_parent,
|
||||
ref qualifier,
|
||||
..
|
||||
}) => (is_trivial_path, qualifier, use_tree_parent),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
match qualifier {
|
||||
Some((path, qualifier)) => {
|
||||
let is_super_chain = iter::successors(Some(path.clone()), |p| p.qualifier())
|
||||
.all(|p| p.segment().and_then(|s| s.super_token()).is_some());
|
||||
if is_super_chain {
|
||||
acc.add_keyword(ctx, "super::");
|
||||
}
|
||||
// only show `self` in a new use-tree when the qualifier doesn't end in self
|
||||
let not_preceded_by_self = use_tree_parent
|
||||
&& !matches!(
|
||||
path.segment().and_then(|it| it.kind()),
|
||||
Some(ast::PathSegmentKind::SelfKw)
|
||||
);
|
||||
if not_preceded_by_self {
|
||||
acc.add_keyword(ctx, "self");
|
||||
}
|
||||
|
||||
let qualifier = match qualifier {
|
||||
Some(it) => it,
|
||||
None => return,
|
||||
};
|
||||
|
||||
match qualifier {
|
||||
hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
|
||||
let module_scope = module.scope(ctx.db, ctx.module);
|
||||
let unknown_is_current = |name: &hir::Name| {
|
||||
matches!(
|
||||
ctx.name_syntax.as_ref(),
|
||||
Some(ast::NameLike::NameRef(name_ref))
|
||||
if name_ref.syntax().text() == name.to_smol_str().as_str()
|
||||
)
|
||||
};
|
||||
for (name, def) in module_scope {
|
||||
let add_resolution = match def {
|
||||
ScopeDef::Unknown if unknown_is_current(&name) => {
|
||||
// for `use self::foo$0`, don't suggest `foo` as a completion
|
||||
cov_mark::hit!(dont_complete_current_use);
|
||||
continue;
|
||||
}
|
||||
ScopeDef::ModuleDef(_) | ScopeDef::MacroDef(_) | ScopeDef::Unknown => {
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if add_resolution {
|
||||
acc.add_resolution(ctx, name, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
|
||||
cov_mark::hit!(enum_plain_qualified_use_tree);
|
||||
e.variants(ctx.db)
|
||||
.into_iter()
|
||||
.for_each(|variant| acc.add_enum_variant(ctx, variant, None));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// fresh use tree with leading colon2, only show crate roots
|
||||
None if !is_trivial_path => {
|
||||
cov_mark::hit!(use_tree_crate_roots_only);
|
||||
ctx.process_all_names(&mut |name, res| match res {
|
||||
ScopeDef::ModuleDef(hir::ModuleDef::Module(m)) if m.is_crate_root(ctx.db) => {
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
_ => (),
|
||||
});
|
||||
}
|
||||
// only show modules in a fresh UseTree
|
||||
None => {
|
||||
cov_mark::hit!(unqualified_path_only_modules_in_import);
|
||||
ctx.process_all_names(&mut |name, res| {
|
||||
if let ScopeDef::ModuleDef(hir::ModuleDef::Module(_)) = res {
|
||||
acc.add_resolution(ctx, name, res);
|
||||
}
|
||||
});
|
||||
["self::", "super::", "crate::"].into_iter().for_each(|kw| acc.add_keyword(ctx, kw));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -153,6 +153,7 @@ pub fn completions(
|
|||
let mut acc = Completions::default();
|
||||
completions::attribute::complete_known_attribute_input(&mut acc, &ctx);
|
||||
completions::attribute::complete_attribute(&mut acc, &ctx);
|
||||
completions::use_::complete_use_tree(&mut acc, &ctx);
|
||||
completions::fn_param::complete_fn_param(&mut acc, &ctx);
|
||||
completions::keyword::complete_expr_keyword(&mut acc, &ctx);
|
||||
completions::snippet::complete_expr_snippet(&mut acc, &ctx);
|
||||
|
|
|
@ -18,6 +18,9 @@ struct Foo;
|
|||
"#,
|
||||
expect![[r#"
|
||||
md proc_macros
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -33,9 +36,6 @@ struct Foo;
|
|||
at derive(…)
|
||||
at repr(…)
|
||||
at non_exhaustive
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -61,7 +61,10 @@ fn proc_macros_qualified() {
|
|||
#[proc_macros::$0]
|
||||
struct Foo;
|
||||
"#,
|
||||
expect![[r#""#]],
|
||||
expect![[r#"
|
||||
at input_replace pub macro input_replace
|
||||
at identity pub macro identity
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -75,15 +78,15 @@ fn with_existing_attr() {
|
|||
check(
|
||||
r#"#[no_mangle] #[$0] mcall!();"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
at deny(…)
|
||||
at forbid(…)
|
||||
at warn(…)
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -93,6 +96,9 @@ fn attr_on_source_file() {
|
|||
check(
|
||||
r#"#![$0]"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -113,9 +119,6 @@ fn attr_on_source_file() {
|
|||
at recursion_limit = "…"
|
||||
at type_length_limit = …
|
||||
at windows_subsystem = "…"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -125,6 +128,9 @@ fn attr_on_module() {
|
|||
check(
|
||||
r#"#[$0] mod foo;"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -139,14 +145,14 @@ fn attr_on_module() {
|
|||
at no_mangle
|
||||
at macro_use
|
||||
at path = "…"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"mod foo {#![$0]}"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -160,9 +166,6 @@ fn attr_on_module() {
|
|||
at must_use
|
||||
at no_mangle
|
||||
at no_implicit_prelude
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -172,6 +175,9 @@ fn attr_on_macro_rules() {
|
|||
check(
|
||||
r#"#[$0] macro_rules! foo {}"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -186,9 +192,6 @@ fn attr_on_macro_rules() {
|
|||
at no_mangle
|
||||
at macro_export
|
||||
at macro_use
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -198,6 +201,9 @@ fn attr_on_macro_def() {
|
|||
check(
|
||||
r#"#[$0] macro foo {}"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -210,9 +216,6 @@ fn attr_on_macro_def() {
|
|||
at doc(alias = "…")
|
||||
at must_use
|
||||
at no_mangle
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -222,6 +225,9 @@ fn attr_on_extern_crate() {
|
|||
check(
|
||||
r#"#[$0] extern crate foo;"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -235,9 +241,6 @@ fn attr_on_extern_crate() {
|
|||
at must_use
|
||||
at no_mangle
|
||||
at macro_use
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -247,6 +250,9 @@ fn attr_on_use() {
|
|||
check(
|
||||
r#"#[$0] use foo;"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -259,9 +265,6 @@ fn attr_on_use() {
|
|||
at doc(alias = "…")
|
||||
at must_use
|
||||
at no_mangle
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -271,6 +274,9 @@ fn attr_on_type_alias() {
|
|||
check(
|
||||
r#"#[$0] type foo = ();"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -283,9 +289,6 @@ fn attr_on_type_alias() {
|
|||
at doc(alias = "…")
|
||||
at must_use
|
||||
at no_mangle
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -301,6 +304,9 @@ struct Foo;
|
|||
expect![[r#"
|
||||
md core
|
||||
at derive pub macro derive
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -316,9 +322,6 @@ struct Foo;
|
|||
at derive(…)
|
||||
at repr(…)
|
||||
at non_exhaustive
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -328,6 +331,9 @@ fn attr_on_enum() {
|
|||
check(
|
||||
r#"#[$0] enum Foo {}"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -343,9 +349,6 @@ fn attr_on_enum() {
|
|||
at derive(…)
|
||||
at repr(…)
|
||||
at non_exhaustive
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -355,6 +358,9 @@ fn attr_on_const() {
|
|||
check(
|
||||
r#"#[$0] const FOO: () = ();"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -367,9 +373,6 @@ fn attr_on_const() {
|
|||
at doc(alias = "…")
|
||||
at must_use
|
||||
at no_mangle
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -379,6 +382,9 @@ fn attr_on_static() {
|
|||
check(
|
||||
r#"#[$0] static FOO: () = ()"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -396,9 +402,6 @@ fn attr_on_static() {
|
|||
at link_section = "…"
|
||||
at global_allocator
|
||||
at used
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -408,6 +411,9 @@ fn attr_on_trait() {
|
|||
check(
|
||||
r#"#[$0] trait Foo {}"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -421,9 +427,6 @@ fn attr_on_trait() {
|
|||
at must_use
|
||||
at no_mangle
|
||||
at must_use
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -433,6 +436,9 @@ fn attr_on_impl() {
|
|||
check(
|
||||
r#"#[$0] impl () {}"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -446,14 +452,14 @@ fn attr_on_impl() {
|
|||
at must_use
|
||||
at no_mangle
|
||||
at automatically_derived
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"impl () {#![$0]}"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -466,9 +472,6 @@ fn attr_on_impl() {
|
|||
at doc(alias = "…")
|
||||
at must_use
|
||||
at no_mangle
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -478,6 +481,9 @@ fn attr_on_extern_block() {
|
|||
check(
|
||||
r#"#[$0] extern {}"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -491,14 +497,14 @@ fn attr_on_extern_block() {
|
|||
at must_use
|
||||
at no_mangle
|
||||
at link
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"extern {#![$0]}"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -512,9 +518,6 @@ fn attr_on_extern_block() {
|
|||
at must_use
|
||||
at no_mangle
|
||||
at link
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -524,6 +527,9 @@ fn attr_on_variant() {
|
|||
check(
|
||||
r#"enum Foo { #[$0] Bar }"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -531,9 +537,6 @@ fn attr_on_variant() {
|
|||
at forbid(…)
|
||||
at warn(…)
|
||||
at non_exhaustive
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -543,6 +546,9 @@ fn attr_on_fn() {
|
|||
check(
|
||||
r#"#[$0] fn main() {}"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
|
@ -570,9 +576,6 @@ fn attr_on_fn() {
|
|||
at target_feature = "…"
|
||||
at test
|
||||
at track_caller
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -583,15 +586,15 @@ fn attr_on_expr() {
|
|||
check(
|
||||
r#"fn main() { #[$0] foo() }"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at cfg(…)
|
||||
at cfg_attr(…)
|
||||
at deny(…)
|
||||
at forbid(…)
|
||||
at warn(…)
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -601,6 +604,9 @@ fn attr_in_source_file_end() {
|
|||
check(
|
||||
r#"#[$0]"#,
|
||||
expect![[r#"
|
||||
kw self::
|
||||
kw super::
|
||||
kw crate::
|
||||
at allow(…)
|
||||
at automatically_derived
|
||||
at cfg(…)
|
||||
|
@ -637,9 +643,6 @@ fn attr_in_source_file_end() {
|
|||
at track_caller
|
||||
at used
|
||||
at warn(…)
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -134,6 +134,25 @@ struct Bar;
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_plain_qualified_use_tree() {
|
||||
cov_mark::check!(enum_plain_qualified_use_tree);
|
||||
check(
|
||||
r#"
|
||||
use Foo::$0
|
||||
|
||||
enum Foo { Variant }
|
||||
impl Foo {
|
||||
const CONST: () = ()
|
||||
fn func() {}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
ev Variant ()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn self_qualified_use_tree() {
|
||||
check(
|
||||
|
|
|
@ -17,9 +17,6 @@ pub($0)
|
|||
"#,
|
||||
expect![[r#"
|
||||
kw in
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -30,11 +27,7 @@ fn after_in_kw() {
|
|||
r#"
|
||||
pub(in $0)
|
||||
"#,
|
||||
expect![[r#"
|
||||
kw self
|
||||
kw super
|
||||
kw crate
|
||||
"#]],
|
||||
expect![[r#""#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ impl Definition {
|
|||
// def is crate root
|
||||
// FIXME: We don't do searches for crates currently, as a crate does not actually have a single name
|
||||
if let &Definition::Module(module) = self {
|
||||
if module.crate_root(db) == module {
|
||||
if module.is_crate_root(db) {
|
||||
return SearchScope::reverse_dependencies(db, module.krate());
|
||||
}
|
||||
}
|
||||
|
@ -378,7 +378,7 @@ impl<'a> FindUsages<'a> {
|
|||
|
||||
let name = match self.def {
|
||||
// special case crate modules as these do not have a proper name
|
||||
Definition::Module(module) if module.crate_root(self.sema.db) == module => {
|
||||
Definition::Module(module) if module.is_crate_root(self.sema.db) => {
|
||||
// FIXME: This assumes the crate name is always equal to its display name when it really isn't
|
||||
module
|
||||
.krate()
|
||||
|
@ -460,7 +460,7 @@ impl<'a> FindUsages<'a> {
|
|||
Definition::Module(module) => {
|
||||
let scope = search_scope.intersection(&SearchScope::module(self.sema.db, module));
|
||||
|
||||
let is_crate_root = module.crate_root(self.sema.db) == module;
|
||||
let is_crate_root = module.is_crate_root(self.sema.db);
|
||||
|
||||
for (text, file_id, search_range) in scope_files(sema, &scope) {
|
||||
let tree = Lazy::new(move || sema.parse(file_id).syntax().clone());
|
||||
|
|
Loading…
Add table
Reference in a new issue