completion: check stability
This commit is contained in:
parent
584d2697cc
commit
0ce71dd76f
@ -269,6 +269,10 @@ pub fn is_proc_macro_attribute(&self) -> bool {
|
|||||||
pub fn is_proc_macro_derive(&self) -> bool {
|
pub fn is_proc_macro_derive(&self) -> bool {
|
||||||
self.by_key("proc_macro_derive").exists()
|
self.by_key("proc_macro_derive").exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_unstable(&self) -> bool {
|
||||||
|
self.by_key("unstable").exists()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::slice::Iter as SliceIter;
|
use std::slice::Iter as SliceIter;
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use hir::{known, ScopeDef, Variant};
|
use hir::{known, HasAttrs, ScopeDef, Variant};
|
||||||
use ide_db::{imports::import_assets::LocatedImport, SymbolKind};
|
use ide_db::{imports::import_assets::LocatedImport, SymbolKind};
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
@ -181,6 +181,9 @@ pub(crate) fn add_path_resolution(
|
|||||||
resolution: hir::ScopeDef,
|
resolution: hir::ScopeDef,
|
||||||
doc_aliases: Vec<syntax::SmolStr>,
|
doc_aliases: Vec<syntax::SmolStr>,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(resolution.attrs(ctx.db).as_deref()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let is_private_editable = match ctx.def_is_visible(&resolution) {
|
let is_private_editable = match ctx.def_is_visible(&resolution) {
|
||||||
Visible::Yes => false,
|
Visible::Yes => false,
|
||||||
Visible::Editable => true,
|
Visible::Editable => true,
|
||||||
@ -206,6 +209,9 @@ pub(crate) fn add_pattern_resolution(
|
|||||||
local_name: hir::Name,
|
local_name: hir::Name,
|
||||||
resolution: hir::ScopeDef,
|
resolution: hir::ScopeDef,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(resolution.attrs(ctx.db).as_deref()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let is_private_editable = match ctx.def_is_visible(&resolution) {
|
let is_private_editable = match ctx.def_is_visible(&resolution) {
|
||||||
Visible::Yes => false,
|
Visible::Yes => false,
|
||||||
Visible::Editable => true,
|
Visible::Editable => true,
|
||||||
@ -228,6 +234,9 @@ pub(crate) fn add_enum_variants(
|
|||||||
path_ctx: &PathCompletionCtx,
|
path_ctx: &PathCompletionCtx,
|
||||||
e: hir::Enum,
|
e: hir::Enum,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&e.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
e.variants(ctx.db)
|
e.variants(ctx.db)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|variant| self.add_enum_variant(ctx, path_ctx, variant, None));
|
.for_each(|variant| self.add_enum_variant(ctx, path_ctx, variant, None));
|
||||||
@ -241,6 +250,9 @@ pub(crate) fn add_module(
|
|||||||
local_name: hir::Name,
|
local_name: hir::Name,
|
||||||
doc_aliases: Vec<syntax::SmolStr>,
|
doc_aliases: Vec<syntax::SmolStr>,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&module.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.add_path_resolution(
|
self.add_path_resolution(
|
||||||
ctx,
|
ctx,
|
||||||
path_ctx,
|
path_ctx,
|
||||||
@ -257,6 +269,9 @@ pub(crate) fn add_macro(
|
|||||||
mac: hir::Macro,
|
mac: hir::Macro,
|
||||||
local_name: hir::Name,
|
local_name: hir::Name,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&mac.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let is_private_editable = match ctx.is_visible(&mac) {
|
let is_private_editable = match ctx.is_visible(&mac) {
|
||||||
Visible::Yes => false,
|
Visible::Yes => false,
|
||||||
Visible::Editable => true,
|
Visible::Editable => true,
|
||||||
@ -280,6 +295,9 @@ pub(crate) fn add_function(
|
|||||||
func: hir::Function,
|
func: hir::Function,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let is_private_editable = match ctx.is_visible(&func) {
|
let is_private_editable = match ctx.is_visible(&func) {
|
||||||
Visible::Yes => false,
|
Visible::Yes => false,
|
||||||
Visible::Editable => true,
|
Visible::Editable => true,
|
||||||
@ -304,6 +322,9 @@ pub(crate) fn add_method(
|
|||||||
receiver: Option<hir::Name>,
|
receiver: Option<hir::Name>,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let is_private_editable = match ctx.is_visible(&func) {
|
let is_private_editable = match ctx.is_visible(&func) {
|
||||||
Visible::Yes => false,
|
Visible::Yes => false,
|
||||||
Visible::Editable => true,
|
Visible::Editable => true,
|
||||||
@ -328,6 +349,9 @@ pub(crate) fn add_method_with_import(
|
|||||||
func: hir::Function,
|
func: hir::Function,
|
||||||
import: LocatedImport,
|
import: LocatedImport,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let is_private_editable = match ctx.is_visible(&func) {
|
let is_private_editable = match ctx.is_visible(&func) {
|
||||||
Visible::Yes => false,
|
Visible::Yes => false,
|
||||||
Visible::Editable => true,
|
Visible::Editable => true,
|
||||||
@ -348,6 +372,9 @@ pub(crate) fn add_method_with_import(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn add_const(&mut self, ctx: &CompletionContext<'_>, konst: hir::Const) {
|
pub(crate) fn add_const(&mut self, ctx: &CompletionContext<'_>, konst: hir::Const) {
|
||||||
|
if !ctx.check_stability(Some(&konst.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let is_private_editable = match ctx.is_visible(&konst) {
|
let is_private_editable = match ctx.is_visible(&konst) {
|
||||||
Visible::Yes => false,
|
Visible::Yes => false,
|
||||||
Visible::Editable => true,
|
Visible::Editable => true,
|
||||||
@ -364,6 +391,9 @@ pub(crate) fn add_type_alias(
|
|||||||
ctx: &CompletionContext<'_>,
|
ctx: &CompletionContext<'_>,
|
||||||
type_alias: hir::TypeAlias,
|
type_alias: hir::TypeAlias,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&type_alias.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let is_private_editable = match ctx.is_visible(&type_alias) {
|
let is_private_editable = match ctx.is_visible(&type_alias) {
|
||||||
Visible::Yes => false,
|
Visible::Yes => false,
|
||||||
Visible::Editable => true,
|
Visible::Editable => true,
|
||||||
@ -380,6 +410,9 @@ pub(crate) fn add_type_alias_with_eq(
|
|||||||
ctx: &CompletionContext<'_>,
|
ctx: &CompletionContext<'_>,
|
||||||
type_alias: hir::TypeAlias,
|
type_alias: hir::TypeAlias,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&type_alias.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias));
|
self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,6 +423,9 @@ pub(crate) fn add_qualified_enum_variant(
|
|||||||
variant: hir::Variant,
|
variant: hir::Variant,
|
||||||
path: hir::ModPath,
|
path: hir::ModPath,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if let Some(builder) =
|
if let Some(builder) =
|
||||||
render_variant_lit(RenderContext::new(ctx), path_ctx, None, variant, Some(path))
|
render_variant_lit(RenderContext::new(ctx), path_ctx, None, variant, Some(path))
|
||||||
{
|
{
|
||||||
@ -404,6 +440,9 @@ pub(crate) fn add_enum_variant(
|
|||||||
variant: hir::Variant,
|
variant: hir::Variant,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
|
if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
|
||||||
cov_mark::hit!(enum_variant_pattern_path);
|
cov_mark::hit!(enum_variant_pattern_path);
|
||||||
self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name);
|
self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name);
|
||||||
@ -425,6 +464,9 @@ pub(crate) fn add_field(
|
|||||||
field: hir::Field,
|
field: hir::Field,
|
||||||
ty: &hir::Type,
|
ty: &hir::Type,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&field.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let is_private_editable = match ctx.is_visible(&field) {
|
let is_private_editable = match ctx.is_visible(&field) {
|
||||||
Visible::Yes => false,
|
Visible::Yes => false,
|
||||||
Visible::Editable => true,
|
Visible::Editable => true,
|
||||||
@ -448,6 +490,9 @@ pub(crate) fn add_struct_literal(
|
|||||||
path: Option<hir::ModPath>,
|
path: Option<hir::ModPath>,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&strukt.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if let Some(builder) =
|
if let Some(builder) =
|
||||||
render_struct_literal(RenderContext::new(ctx), path_ctx, strukt, path, local_name)
|
render_struct_literal(RenderContext::new(ctx), path_ctx, strukt, path, local_name)
|
||||||
{
|
{
|
||||||
@ -462,6 +507,9 @@ pub(crate) fn add_union_literal(
|
|||||||
path: Option<hir::ModPath>,
|
path: Option<hir::ModPath>,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&un.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let item = render_union_literal(RenderContext::new(ctx), un, path, local_name);
|
let item = render_union_literal(RenderContext::new(ctx), un, path, local_name);
|
||||||
self.add_opt(item);
|
self.add_opt(item);
|
||||||
}
|
}
|
||||||
@ -473,6 +521,8 @@ pub(crate) fn add_tuple_field(
|
|||||||
field: usize,
|
field: usize,
|
||||||
ty: &hir::Type,
|
ty: &hir::Type,
|
||||||
) {
|
) {
|
||||||
|
// Only used for (unnamed) tuples, whose all fields *are* stable. No need to check
|
||||||
|
// stability here.
|
||||||
let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty);
|
let item = render_tuple_field(RenderContext::new(ctx), receiver, field, ty);
|
||||||
self.add(item);
|
self.add(item);
|
||||||
}
|
}
|
||||||
@ -494,6 +544,9 @@ pub(crate) fn add_variant_pat(
|
|||||||
variant: hir::Variant,
|
variant: hir::Variant,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.add_opt(render_variant_pat(
|
self.add_opt(render_variant_pat(
|
||||||
RenderContext::new(ctx),
|
RenderContext::new(ctx),
|
||||||
pattern_ctx,
|
pattern_ctx,
|
||||||
@ -511,6 +564,9 @@ pub(crate) fn add_qualified_variant_pat(
|
|||||||
variant: hir::Variant,
|
variant: hir::Variant,
|
||||||
path: hir::ModPath,
|
path: hir::ModPath,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let path = Some(&path);
|
let path = Some(&path);
|
||||||
self.add_opt(render_variant_pat(
|
self.add_opt(render_variant_pat(
|
||||||
RenderContext::new(ctx),
|
RenderContext::new(ctx),
|
||||||
@ -529,6 +585,9 @@ pub(crate) fn add_struct_pat(
|
|||||||
strukt: hir::Struct,
|
strukt: hir::Struct,
|
||||||
local_name: Option<hir::Name>,
|
local_name: Option<hir::Name>,
|
||||||
) {
|
) {
|
||||||
|
if !ctx.check_stability(Some(&strukt.attrs(ctx.db))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name));
|
self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,8 +267,10 @@ fn import_on_the_fly(
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(ns_filter)
|
.filter(ns_filter)
|
||||||
.filter(|import| {
|
.filter(|import| {
|
||||||
!ctx.is_item_hidden(&import.item_to_import)
|
let item = &import.item_to_import;
|
||||||
&& !ctx.is_item_hidden(&import.original_item)
|
!ctx.is_item_hidden(item)
|
||||||
|
&& !ctx.is_item_hidden(item)
|
||||||
|
&& ctx.check_stability(item.attrs(ctx.db).as_deref())
|
||||||
})
|
})
|
||||||
.sorted_by_key(|located_import| {
|
.sorted_by_key(|located_import| {
|
||||||
compute_fuzzy_completion_order_key(
|
compute_fuzzy_completion_order_key(
|
||||||
@ -315,8 +317,10 @@ fn import_on_the_fly_pat_(
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(ns_filter)
|
.filter(ns_filter)
|
||||||
.filter(|import| {
|
.filter(|import| {
|
||||||
!ctx.is_item_hidden(&import.item_to_import)
|
let item = &import.item_to_import;
|
||||||
&& !ctx.is_item_hidden(&import.original_item)
|
!ctx.is_item_hidden(item)
|
||||||
|
&& !ctx.is_item_hidden(item)
|
||||||
|
&& ctx.check_stability(item.attrs(ctx.db).as_deref())
|
||||||
})
|
})
|
||||||
.sorted_by_key(|located_import| {
|
.sorted_by_key(|located_import| {
|
||||||
compute_fuzzy_completion_order_key(
|
compute_fuzzy_completion_order_key(
|
||||||
|
@ -150,7 +150,10 @@ fn complete_trait_impl(
|
|||||||
impl_def: &ast::Impl,
|
impl_def: &ast::Impl,
|
||||||
) {
|
) {
|
||||||
if let Some(hir_impl) = ctx.sema.to_def(impl_def) {
|
if let Some(hir_impl) = ctx.sema.to_def(impl_def) {
|
||||||
get_missing_assoc_items(&ctx.sema, impl_def).into_iter().for_each(|item| {
|
get_missing_assoc_items(&ctx.sema, impl_def)
|
||||||
|
.into_iter()
|
||||||
|
.filter(|item| ctx.check_stability(Some(&item.attrs(ctx.db))))
|
||||||
|
.for_each(|item| {
|
||||||
use self::ImplCompletionKind::*;
|
use self::ImplCompletionKind::*;
|
||||||
match (item, kind) {
|
match (item, kind) {
|
||||||
(hir::AssocItem::Function(func), All | Fn) => {
|
(hir::AssocItem::Function(func), All | Fn) => {
|
||||||
|
@ -52,6 +52,9 @@ pub(crate) fn complete_use_path(
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
for (name, def) in module_scope {
|
for (name, def) in module_scope {
|
||||||
|
if !ctx.check_stability(def.attrs(ctx.db).as_deref()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let is_name_already_imported = name
|
let is_name_already_imported = name
|
||||||
.as_text()
|
.as_text()
|
||||||
.map_or(false, |text| already_imported_names.contains(text.as_str()));
|
.map_or(false, |text| already_imported_names.contains(text.as_str()));
|
||||||
|
@ -367,6 +367,8 @@ pub(crate) struct CompletionContext<'a> {
|
|||||||
pub(super) krate: hir::Crate,
|
pub(super) krate: hir::Crate,
|
||||||
/// The module of the `scope`.
|
/// The module of the `scope`.
|
||||||
pub(super) module: hir::Module,
|
pub(super) module: hir::Module,
|
||||||
|
/// Whether nightly toolchain is used. Cached since this is looked up a lot.
|
||||||
|
is_nightly: bool,
|
||||||
|
|
||||||
/// The expected name of what we are completing.
|
/// The expected name of what we are completing.
|
||||||
/// This is usually the parameter name of the function argument we are completing.
|
/// This is usually the parameter name of the function argument we are completing.
|
||||||
@ -386,7 +388,7 @@ pub(crate) struct CompletionContext<'a> {
|
|||||||
pub(super) depth_from_crate_root: usize,
|
pub(super) depth_from_crate_root: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CompletionContext<'a> {
|
impl CompletionContext<'_> {
|
||||||
/// The range of the identifier that is being completed.
|
/// The range of the identifier that is being completed.
|
||||||
pub(crate) fn source_range(&self) -> TextRange {
|
pub(crate) fn source_range(&self) -> TextRange {
|
||||||
let kind = self.original_token.kind();
|
let kind = self.original_token.kind();
|
||||||
@ -451,6 +453,12 @@ pub(crate) fn is_item_hidden(&self, item: &hir::ItemInNs) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks whether this item should be listed in regards to stability. Returns `true` if we should.
|
||||||
|
pub(crate) fn check_stability(&self, attrs: Option<&hir::Attrs>) -> bool {
|
||||||
|
let Some(attrs) = attrs else { return true; };
|
||||||
|
!attrs.is_unstable() || self.is_nightly
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the given trait is an operator trait or not.
|
/// Whether the given trait is an operator trait or not.
|
||||||
pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
|
pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
|
||||||
match trait_.attrs(self.db).lang() {
|
match trait_.attrs(self.db).lang() {
|
||||||
@ -624,6 +632,11 @@ pub(super) fn new(
|
|||||||
let krate = scope.krate();
|
let krate = scope.krate();
|
||||||
let module = scope.module();
|
let module = scope.module();
|
||||||
|
|
||||||
|
let toolchain = db.crate_graph()[krate.into()].channel;
|
||||||
|
// `toolchain == None` means we're in some detached files. Since we have no information on
|
||||||
|
// the toolchain being used, let's just allow unstable items to be listed.
|
||||||
|
let is_nightly = matches!(toolchain, Some(base_db::ReleaseChannel::Nightly) | None);
|
||||||
|
|
||||||
let mut locals = FxHashMap::default();
|
let mut locals = FxHashMap::default();
|
||||||
scope.process_all_names(&mut |name, scope| {
|
scope.process_all_names(&mut |name, scope| {
|
||||||
if let ScopeDef::Local(local) = scope {
|
if let ScopeDef::Local(local) = scope {
|
||||||
@ -643,6 +656,7 @@ pub(super) fn new(
|
|||||||
token,
|
token,
|
||||||
krate,
|
krate,
|
||||||
module,
|
module,
|
||||||
|
is_nightly,
|
||||||
expected_name,
|
expected_name,
|
||||||
expected_type,
|
expected_type,
|
||||||
qualifier_ctx,
|
qualifier_ctx,
|
||||||
|
Loading…
Reference in New Issue
Block a user