Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/context.rs')
-rw-r--r--crates/ide-completion/src/context.rs88
1 files changed, 80 insertions, 8 deletions
diff --git a/crates/ide-completion/src/context.rs b/crates/ide-completion/src/context.rs
index 4fd0348156..b9520e9132 100644
--- a/crates/ide-completion/src/context.rs
+++ b/crates/ide-completion/src/context.rs
@@ -4,12 +4,12 @@ mod analysis;
#[cfg(test)]
mod tests;
-use std::iter;
+use std::{iter, sync::LazyLock};
-use base_db::RootQueryDb as _;
+use base_db::toolchain_channel;
use hir::{
DisplayTarget, HasAttrs, InFile, Local, ModuleDef, ModuleSource, Name, PathResolution,
- ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo,
+ ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo, sym,
};
use ide_db::{
FilePosition, FxHashMap, FxHashSet, RootDatabase, famous_defs::FamousDefs,
@@ -102,6 +102,28 @@ impl PathCompletionCtx<'_> {
}
)
}
+
+ pub(crate) fn required_thin_arrow(&self) -> Option<(&'static str, TextSize)> {
+ let PathKind::Type {
+ location:
+ TypeLocation::TypeAscription(TypeAscriptionTarget::RetType {
+ item: Some(ref fn_item),
+ ..
+ }),
+ } = self.kind
+ else {
+ return None;
+ };
+ if fn_item.ret_type().is_some_and(|it| it.thin_arrow_token().is_some()) {
+ return None;
+ }
+ let ret_type = fn_item.ret_type().and_then(|it| it.ty());
+ match (ret_type, fn_item.param_list()) {
+ (Some(ty), _) => Some(("-> ", ty.syntax().text_range().start())),
+ (None, Some(param)) => Some((" ->", param.syntax().text_range().end())),
+ (None, None) => None,
+ }
+ }
}
/// The kind of path we are completing right now.
@@ -231,7 +253,7 @@ impl TypeLocation {
pub(crate) enum TypeAscriptionTarget {
Let(Option<ast::Pat>),
FnParam(Option<ast::Pat>),
- RetType(Option<ast::Expr>),
+ RetType { body: Option<ast::Expr>, item: Option<ast::Fn> },
Const(Option<ast::Expr>),
}
@@ -386,9 +408,11 @@ pub(crate) enum CompletionAnalysis<'db> {
/// Set if we are currently completing in an unexpanded attribute, this usually implies a builtin attribute like `allow($0)`
UnexpandedAttrTT {
colon_prefix: bool,
- fake_attribute_under_caret: Option<ast::Attr>,
+ fake_attribute_under_caret: Option<ast::TokenTreeMeta>,
extern_crate: Option<ast::ExternCrate>,
},
+ /// Set if we are inside the predicate of a `#[cfg]` or `#[cfg_attr]`.
+ CfgPredicate,
MacroSegment,
}
@@ -577,7 +601,18 @@ impl CompletionContext<'_> {
let Some(attrs) = attrs else {
return true;
};
- !attrs.is_unstable() || self.is_nightly
+ if !attrs.is_unstable() {
+ return true;
+ }
+ if !self.is_nightly {
+ return false;
+ }
+ // Unstable on nightly, but we still don't want to suggest internal features, unless the feature flag is enabled.
+ let Some(unstable_feature) = attrs.unstable_feature(self.db) else {
+ return true;
+ };
+ !INTERNAL_FEATURES.contains(&unstable_feature)
+ || self.krate.is_unstable_feature_enabled(self.db, &unstable_feature)
}
pub(crate) fn check_stability_and_hidden<I>(&self, item: I) -> bool
@@ -715,7 +750,7 @@ impl<'db> CompletionContext<'db> {
// actual completion.
let file_with_fake_ident = {
let (_, edition) = editioned_file_id.unpack(db);
- let parse = db.parse(editioned_file_id);
+ let parse = editioned_file_id.parse(db);
parse.reparse(TextRange::empty(offset), COMPLETION_MARKER, edition).tree()
};
@@ -768,7 +803,7 @@ impl<'db> CompletionContext<'db> {
let containing_function = scope.containing_function();
let edition = krate.edition(db);
- let toolchain = db.toolchain_channel(krate.into());
+ let toolchain = toolchain_channel(db, krate.into());
// `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);
@@ -900,3 +935,40 @@ const OP_TRAIT_LANG: &[hir::LangItem] = &[
hir::LangItem::Shr,
hir::LangItem::Sub,
];
+
+// FIXME: Find a way to keep this up to date somehow?
+const INTERNAL_FEATURES_LIST: &[Symbol] = &[
+ sym::abi_unadjusted,
+ sym::allocator_internals,
+ sym::allow_internal_unsafe,
+ sym::allow_internal_unstable,
+ sym::cfg_emscripten_wasm_eh,
+ sym::cfg_target_has_reliable_f16_f128,
+ sym::compiler_builtins,
+ sym::custom_mir,
+ sym::eii_internals,
+ sym::field_representing_type_raw,
+ sym::intrinsics,
+ sym::lang_items,
+ sym::link_cfg,
+ sym::more_maybe_bounds,
+ sym::negative_bounds,
+ sym::pattern_complexity_limit,
+ sym::prelude_import,
+ sym::profiler_runtime,
+ sym::rustc_attrs,
+ sym::staged_api,
+ sym::test_unstable_lint,
+ sym::builtin_syntax,
+ sym::link_llvm_intrinsics,
+ sym::needs_panic_runtime,
+ sym::panic_runtime,
+ sym::pattern_types,
+ sym::rustdoc_internals,
+ sym::contracts_internals,
+ sym::freeze_impls,
+ sym::unsized_fn_params,
+];
+
+static INTERNAL_FEATURES: LazyLock<FxHashSet<Symbol>> =
+ LazyLock::new(|| INTERNAL_FEATURES_LIST.iter().cloned().collect());