Skip to content

Commit 94421fe

Browse files
authored
Merge pull request #22044 from ChayimFriedman2/internal-features
feat: Do not complete unstable items that use an internal feature
2 parents 4a56d54 + 3898610 commit 94421fe

6 files changed

Lines changed: 238 additions & 5 deletions

File tree

crates/hir-def/src/attrs.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,41 @@ impl AttrFlags {
10761076
})
10771077
}
10781078
}
1079+
1080+
pub fn unstable_feature(self, db: &dyn DefDatabase, owner: AttrDefId) -> Option<Symbol> {
1081+
if !self.contains(AttrFlags::IS_UNSTABLE) {
1082+
return None;
1083+
}
1084+
1085+
return unstable_feature(db, owner);
1086+
1087+
#[salsa::tracked]
1088+
fn unstable_feature(db: &dyn DefDatabase, owner: AttrDefId) -> Option<Symbol> {
1089+
collect_attrs(db, owner, |attr| {
1090+
if let ast::Meta::TokenTreeMeta(attr) = attr
1091+
&& let path = attr.path()
1092+
&& path.is1("unstable")
1093+
&& let Some(tt) = attr.token_tree()
1094+
{
1095+
let mut tt = TokenTreeChildren::new(&tt);
1096+
// Technically the `feature = "..."` always comes first, but it's not a requirement.
1097+
while let Some(token) = tt.next() {
1098+
if let NodeOrToken::Token(token) = token
1099+
&& token.text() == "feature"
1100+
&& let Some(NodeOrToken::Token(eq)) = tt.next()
1101+
&& eq.kind() == T![=]
1102+
&& let Some(NodeOrToken::Token(feature)) = tt.next()
1103+
&& let Some(feature) = ast::String::cast(feature)
1104+
&& let Ok(feature) = feature.value()
1105+
{
1106+
return ControlFlow::Break(Symbol::intern(&feature));
1107+
}
1108+
}
1109+
}
1110+
ControlFlow::Continue(())
1111+
})
1112+
}
1113+
}
10791114
}
10801115

10811116
fn merge_repr(this: &mut ReprOptions, other: ReprOptions) {

crates/hir/src/attrs.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,19 @@ impl AttrsWithOwner {
8585
self.attrs.contains(AttrFlags::IS_UNSTABLE)
8686
}
8787

88+
/// Currently, it could be that `is_unstable() == true` but `unstable_feature == None`
89+
/// (due to unstable features not being retrieved for fields etc.).
90+
#[inline]
91+
pub fn unstable_feature(&self, db: &dyn HirDatabase) -> Option<Symbol> {
92+
match self.owner {
93+
AttrsOwner::AttrDef(owner) => self.attrs.unstable_feature(db, owner),
94+
AttrsOwner::Field(_)
95+
| AttrsOwner::LifetimeParam(_)
96+
| AttrsOwner::TypeOrConstParam(_)
97+
| AttrsOwner::Dummy => None,
98+
}
99+
}
100+
88101
#[inline]
89102
pub fn is_macro_export(&self) -> bool {
90103
self.attrs.contains(AttrFlags::IS_MACRO_EXPORT)

crates/hir/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,10 @@ impl Crate {
342342
})
343343
.map(Crate::from)
344344
}
345+
346+
pub fn is_unstable_feature_enabled(self, db: &dyn HirDatabase, feature: &Symbol) -> bool {
347+
crate_def_map(db, self.id).is_unstable_feature_enabled(feature)
348+
}
345349
}
346350

347351
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

crates/ide-completion/src/context.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ mod analysis;
44
#[cfg(test)]
55
mod tests;
66

7-
use std::iter;
7+
use std::{iter, sync::LazyLock};
88

99
use base_db::toolchain_channel;
1010
use hir::{
1111
DisplayTarget, HasAttrs, InFile, Local, ModuleDef, ModuleSource, Name, PathResolution,
12-
ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo,
12+
ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo, sym,
1313
};
1414
use ide_db::{
1515
FilePosition, FxHashMap, FxHashSet, RootDatabase, famous_defs::FamousDefs,
@@ -601,7 +601,18 @@ impl CompletionContext<'_> {
601601
let Some(attrs) = attrs else {
602602
return true;
603603
};
604-
!attrs.is_unstable() || self.is_nightly
604+
if !attrs.is_unstable() {
605+
return true;
606+
}
607+
if !self.is_nightly {
608+
return false;
609+
}
610+
// Unstable on nightly, but we still don't want to suggest internal features, unless the feature flag is enabled.
611+
let Some(unstable_feature) = attrs.unstable_feature(self.db) else {
612+
return true;
613+
};
614+
!INTERNAL_FEATURES.contains(&unstable_feature)
615+
|| self.krate.is_unstable_feature_enabled(self.db, &unstable_feature)
605616
}
606617

607618
pub(crate) fn check_stability_and_hidden<I>(&self, item: I) -> bool
@@ -924,3 +935,40 @@ const OP_TRAIT_LANG: &[hir::LangItem] = &[
924935
hir::LangItem::Shr,
925936
hir::LangItem::Sub,
926937
];
938+
939+
// FIXME: Find a way to keep this up to date somehow?
940+
const INTERNAL_FEATURES_LIST: &[Symbol] = &[
941+
sym::abi_unadjusted,
942+
sym::allocator_internals,
943+
sym::allow_internal_unsafe,
944+
sym::allow_internal_unstable,
945+
sym::cfg_emscripten_wasm_eh,
946+
sym::cfg_target_has_reliable_f16_f128,
947+
sym::compiler_builtins,
948+
sym::custom_mir,
949+
sym::eii_internals,
950+
sym::field_representing_type_raw,
951+
sym::intrinsics,
952+
sym::lang_items,
953+
sym::link_cfg,
954+
sym::more_maybe_bounds,
955+
sym::negative_bounds,
956+
sym::pattern_complexity_limit,
957+
sym::prelude_import,
958+
sym::profiler_runtime,
959+
sym::rustc_attrs,
960+
sym::staged_api,
961+
sym::test_unstable_lint,
962+
sym::builtin_syntax,
963+
sym::link_llvm_intrinsics,
964+
sym::needs_panic_runtime,
965+
sym::panic_runtime,
966+
sym::pattern_types,
967+
sym::rustdoc_internals,
968+
sym::contracts_internals,
969+
sym::freeze_impls,
970+
sym::unsized_fn_params,
971+
];
972+
973+
static INTERNAL_FEATURES: LazyLock<FxHashSet<Symbol>> =
974+
LazyLock::new(|| INTERNAL_FEATURES_LIST.iter().cloned().collect());

crates/ide-completion/src/tests/expression.rs

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2273,7 +2273,7 @@ fn main() {
22732273
$0
22742274
}
22752275
//- /std.rs crate:std
2276-
#[unstable]
2276+
#[unstable(feature = "some_non_internal_feature")]
22772277
pub struct UnstableButWeAreOnNightlyAnyway;
22782278
"#,
22792279
expect![[r#"
@@ -2317,6 +2317,112 @@ pub struct UnstableButWeAreOnNightlyAnyway;
23172317
);
23182318
}
23192319

2320+
#[test]
2321+
fn expr_unstable_item_internal_feature() {
2322+
check(
2323+
r#"
2324+
//- toolchain:nightly
2325+
//- /main.rs crate:main deps:std
2326+
use std::*;
2327+
fn main() {
2328+
$0
2329+
}
2330+
//- /std.rs crate:std
2331+
#[unstable(feature = "intrinsics")]
2332+
pub mod intrinsics {}
2333+
"#,
2334+
expect![[r#"
2335+
fn main() fn()
2336+
md std
2337+
bt u32 u32
2338+
kw async
2339+
kw const
2340+
kw crate::
2341+
kw enum
2342+
kw extern
2343+
kw false
2344+
kw fn
2345+
kw for
2346+
kw if
2347+
kw if let
2348+
kw impl
2349+
kw impl for
2350+
kw let
2351+
kw letm
2352+
kw loop
2353+
kw match
2354+
kw mod
2355+
kw return
2356+
kw self::
2357+
kw static
2358+
kw struct
2359+
kw trait
2360+
kw true
2361+
kw type
2362+
kw union
2363+
kw unsafe
2364+
kw use
2365+
kw while
2366+
kw while let
2367+
sn macro_rules
2368+
sn pd
2369+
sn ppd
2370+
"#]],
2371+
);
2372+
check(
2373+
r#"
2374+
//- toolchain:nightly
2375+
//- /main.rs crate:main deps:std
2376+
#![feature(intrinsics)]
2377+
use std::*;
2378+
fn main() {
2379+
$0
2380+
}
2381+
//- /std.rs crate:std
2382+
#[unstable(feature = "intrinsics")]
2383+
pub mod intrinsics {}
2384+
"#,
2385+
expect![[r#"
2386+
fn main() fn()
2387+
md intrinsics
2388+
md std
2389+
bt u32 u32
2390+
kw async
2391+
kw const
2392+
kw crate::
2393+
kw enum
2394+
kw extern
2395+
kw false
2396+
kw fn
2397+
kw for
2398+
kw if
2399+
kw if let
2400+
kw impl
2401+
kw impl for
2402+
kw let
2403+
kw letm
2404+
kw loop
2405+
kw match
2406+
kw mod
2407+
kw return
2408+
kw self::
2409+
kw static
2410+
kw struct
2411+
kw trait
2412+
kw true
2413+
kw type
2414+
kw union
2415+
kw unsafe
2416+
kw use
2417+
kw while
2418+
kw while let
2419+
sn macro_rules
2420+
sn pd
2421+
sn ppd
2422+
"#]],
2423+
);
2424+
}
2425+
23202426
#[test]
23212427
fn inside_format_args_completions_work() {
23222428
check(

crates/intern/src/symbol/symbols.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ define_symbols! {
123123
all,
124124
alloc_layout,
125125
alloc,
126-
allow_internal_unsafe,
127126
allow,
128127
any,
129128
as_str,
@@ -541,4 +540,32 @@ define_symbols! {
541540
DispatchFromDyn,
542541
define_opaque,
543542
marker,
543+
abi_unadjusted,
544+
allocator_internals,
545+
allow_internal_unsafe,
546+
allow_internal_unstable,
547+
cfg_emscripten_wasm_eh,
548+
cfg_target_has_reliable_f16_f128,
549+
compiler_builtins,
550+
custom_mir,
551+
eii_internals,
552+
field_representing_type_raw,
553+
intrinsics,
554+
link_cfg,
555+
more_maybe_bounds,
556+
negative_bounds,
557+
pattern_complexity_limit,
558+
profiler_runtime,
559+
rustc_attrs,
560+
staged_api,
561+
test_unstable_lint,
562+
builtin_syntax,
563+
link_llvm_intrinsics,
564+
needs_panic_runtime,
565+
panic_runtime,
566+
pattern_types,
567+
rustdoc_internals,
568+
contracts_internals,
569+
freeze_impls,
570+
unsized_fn_params,
544571
}

0 commit comments

Comments
 (0)