Skip to content

Commit f98d654

Browse files
committed
Auto merge of rust-lang#15350 - max-heller:issue-11756, r=Veykril
Handle `#[cfg]`s on generic parameters Records attributes on generic parameters in the item tree and filters out generic parameters disabled by `#[cfg]`s in `generic_params_query`. Closes rust-lang#11756
2 parents 44eeaea + 50db877 commit f98d654

File tree

6 files changed

+142
-24
lines changed

6 files changed

+142
-24
lines changed

crates/hir-def/src/generics.rs

+69-8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::{
2121
db::DefDatabase,
2222
dyn_map::{keys, DynMap},
2323
expander::Expander,
24+
item_tree::{AttrOwner, ItemTree},
2425
lower::LowerCtx,
2526
nameres::{DefMap, MacroSubNs},
2627
src::{HasChildSource, HasSource},
@@ -154,12 +155,58 @@ impl GenericParams {
154155
def: GenericDefId,
155156
) -> Interned<GenericParams> {
156157
let _p = profile::span("generic_params_query");
158+
159+
let krate = def.module(db).krate;
160+
let cfg_options = db.crate_graph();
161+
let cfg_options = &cfg_options[krate].cfg_options;
162+
163+
// Returns the generic parameters that are enabled under the current `#[cfg]` options
164+
let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
165+
let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
166+
167+
// In the common case, no parameters will by disabled by `#[cfg]` attributes.
168+
// Therefore, make a first pass to check if all parameters are enabled and, if so,
169+
// clone the `Interned<GenericParams>` instead of recreating an identical copy.
170+
let all_type_or_consts_enabled =
171+
params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
172+
let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));
173+
174+
if all_type_or_consts_enabled && all_lifetimes_enabled {
175+
params.clone()
176+
} else {
177+
Interned::new(GenericParams {
178+
type_or_consts: all_type_or_consts_enabled
179+
.then(|| params.type_or_consts.clone())
180+
.unwrap_or_else(|| {
181+
params
182+
.type_or_consts
183+
.iter()
184+
.filter_map(|(idx, param)| {
185+
enabled(idx.into()).then(|| param.clone())
186+
})
187+
.collect()
188+
}),
189+
lifetimes: all_lifetimes_enabled
190+
.then(|| params.lifetimes.clone())
191+
.unwrap_or_else(|| {
192+
params
193+
.lifetimes
194+
.iter()
195+
.filter_map(|(idx, param)| {
196+
enabled(idx.into()).then(|| param.clone())
197+
})
198+
.collect()
199+
}),
200+
where_predicates: params.where_predicates.clone(),
201+
})
202+
}
203+
};
157204
macro_rules! id_to_generics {
158205
($id:ident) => {{
159206
let id = $id.lookup(db).id;
160207
let tree = id.item_tree(db);
161208
let item = &tree[id.value];
162-
item.generic_params.clone()
209+
enabled_params(&item.generic_params, &tree)
163210
}};
164211
}
165212

@@ -169,7 +216,8 @@ impl GenericParams {
169216
let tree = loc.id.item_tree(db);
170217
let item = &tree[loc.id.value];
171218

172-
let mut generic_params = GenericParams::clone(&item.explicit_generic_params);
219+
let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
220+
let mut generic_params = GenericParams::clone(&enabled_params);
173221

174222
let module = loc.container.module(db);
175223
let func_data = db.function_data(id);
@@ -198,9 +246,14 @@ impl GenericParams {
198246
}
199247
}
200248

201-
pub(crate) fn fill(&mut self, lower_ctx: &LowerCtx<'_>, node: &dyn HasGenericParams) {
249+
pub(crate) fn fill(
250+
&mut self,
251+
lower_ctx: &LowerCtx<'_>,
252+
node: &dyn HasGenericParams,
253+
add_param_attrs: impl FnMut(AttrOwner, ast::GenericParam),
254+
) {
202255
if let Some(params) = node.generic_param_list() {
203-
self.fill_params(lower_ctx, params)
256+
self.fill_params(lower_ctx, params, add_param_attrs)
204257
}
205258
if let Some(where_clause) = node.where_clause() {
206259
self.fill_where_predicates(lower_ctx, where_clause);
@@ -218,7 +271,12 @@ impl GenericParams {
218271
}
219272
}
220273

221-
fn fill_params(&mut self, lower_ctx: &LowerCtx<'_>, params: ast::GenericParamList) {
274+
fn fill_params(
275+
&mut self,
276+
lower_ctx: &LowerCtx<'_>,
277+
params: ast::GenericParamList,
278+
mut add_param_attrs: impl FnMut(AttrOwner, ast::GenericParam),
279+
) {
222280
for type_or_const_param in params.type_or_const_params() {
223281
match type_or_const_param {
224282
ast::TypeOrConstParam::Type(type_param) => {
@@ -232,13 +290,14 @@ impl GenericParams {
232290
default,
233291
provenance: TypeParamProvenance::TypeParamList,
234292
};
235-
self.type_or_consts.alloc(param.into());
293+
let idx = self.type_or_consts.alloc(param.into());
236294
let type_ref = TypeRef::Path(name.into());
237295
self.fill_bounds(
238296
lower_ctx,
239297
type_param.type_bound_list(),
240298
Either::Left(type_ref),
241299
);
300+
add_param_attrs(idx.into(), ast::GenericParam::TypeParam(type_param));
242301
}
243302
ast::TypeOrConstParam::Const(const_param) => {
244303
let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
@@ -250,21 +309,23 @@ impl GenericParams {
250309
ty: Interned::new(ty),
251310
has_default: const_param.default_val().is_some(),
252311
};
253-
self.type_or_consts.alloc(param.into());
312+
let idx = self.type_or_consts.alloc(param.into());
313+
add_param_attrs(idx.into(), ast::GenericParam::ConstParam(const_param));
254314
}
255315
}
256316
}
257317
for lifetime_param in params.lifetime_params() {
258318
let name =
259319
lifetime_param.lifetime().map_or_else(Name::missing, |lt| Name::new_lifetime(&lt));
260320
let param = LifetimeParamData { name: name.clone() };
261-
self.lifetimes.alloc(param);
321+
let idx = self.lifetimes.alloc(param);
262322
let lifetime_ref = LifetimeRef::new_name(name);
263323
self.fill_bounds(
264324
lower_ctx,
265325
lifetime_param.type_bound_list(),
266326
Either::Right(lifetime_ref),
267327
);
328+
add_param_attrs(idx.into(), ast::GenericParam::LifetimeParam(lifetime_param));
268329
}
269330
}
270331

crates/hir-def/src/item_tree.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ use triomphe::Arc;
6464
use crate::{
6565
attr::Attrs,
6666
db::DefDatabase,
67-
generics::GenericParams,
67+
generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
6868
path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
6969
type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
7070
visibility::RawVisibility,
@@ -296,10 +296,12 @@ pub enum AttrOwner {
296296
Variant(Idx<Variant>),
297297
Field(Idx<Field>),
298298
Param(Idx<Param>),
299+
TypeOrConstParamData(Idx<TypeOrConstParamData>),
300+
LifetimeParamData(Idx<LifetimeParamData>),
299301
}
300302

301303
macro_rules! from_attrs {
302-
( $( $var:ident($t:ty) ),+ ) => {
304+
( $( $var:ident($t:ty) ),+ $(,)? ) => {
303305
$(
304306
impl From<$t> for AttrOwner {
305307
fn from(t: $t) -> AttrOwner {
@@ -310,7 +312,14 @@ macro_rules! from_attrs {
310312
};
311313
}
312314

313-
from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>), Param(Idx<Param>));
315+
from_attrs!(
316+
ModItem(ModItem),
317+
Variant(Idx<Variant>),
318+
Field(Idx<Field>),
319+
Param(Idx<Param>),
320+
TypeOrConstParamData(Idx<TypeOrConstParamData>),
321+
LifetimeParamData(Idx<LifetimeParamData>),
322+
);
314323

315324
/// Trait implemented by all item nodes in the item tree.
316325
pub trait ItemTreeNode: Clone {

crates/hir-def/src/item_tree/lower.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,21 @@ impl<'a> Ctx<'a> {
602602
generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param));
603603
}
604604

605-
generics.fill(&self.body_ctx, node);
605+
let add_param_attrs = |item, param| {
606+
let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.hygiene());
607+
// This is identical to the body of `Ctx::add_attrs()` but we can't call that here
608+
// because it requires `&mut self` and the call to `generics.fill()` below also
609+
// references `self`.
610+
match self.tree.attrs.entry(item) {
611+
Entry::Occupied(mut entry) => {
612+
*entry.get_mut() = entry.get().merge(attrs);
613+
}
614+
Entry::Vacant(entry) => {
615+
entry.insert(attrs);
616+
}
617+
}
618+
};
619+
generics.fill(&self.body_ctx, node, add_param_attrs);
606620

607621
generics.shrink_to_fit();
608622
Interned::new(generics)

crates/hir-def/src/item_tree/pretty.rs

+15-12
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub(super) fn print_item_tree(db: &dyn ExpandDatabase, tree: &ItemTree) -> Strin
1616
let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true };
1717

1818
if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
19-
p.print_attrs(attrs, true);
19+
p.print_attrs(attrs, true, "\n");
2020
}
2121
p.blank();
2222

@@ -84,22 +84,23 @@ impl Printer<'_> {
8484
}
8585
}
8686

87-
fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) {
87+
fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool, separated_by: &str) {
8888
let inner = if inner { "!" } else { "" };
8989
for attr in &**attrs {
90-
wln!(
90+
w!(
9191
self,
92-
"#{}[{}{}]",
92+
"#{}[{}{}]{}",
9393
inner,
9494
attr.path.display(self.db),
9595
attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
96+
separated_by,
9697
);
9798
}
9899
}
99100

100-
fn print_attrs_of(&mut self, of: impl Into<AttrOwner>) {
101+
fn print_attrs_of(&mut self, of: impl Into<AttrOwner>, separated_by: &str) {
101102
if let Some(attrs) = self.tree.attrs.get(&of.into()) {
102-
self.print_attrs(attrs, false);
103+
self.print_attrs(attrs, false, separated_by);
103104
}
104105
}
105106

@@ -118,7 +119,7 @@ impl Printer<'_> {
118119
self.indented(|this| {
119120
for field in fields.clone() {
120121
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
121-
this.print_attrs_of(field);
122+
this.print_attrs_of(field, "\n");
122123
this.print_visibility(*visibility);
123124
w!(this, "{}: ", name.display(self.db));
124125
this.print_type_ref(type_ref);
@@ -132,7 +133,7 @@ impl Printer<'_> {
132133
self.indented(|this| {
133134
for field in fields.clone() {
134135
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
135-
this.print_attrs_of(field);
136+
this.print_attrs_of(field, "\n");
136137
this.print_visibility(*visibility);
137138
w!(this, "{}: ", name.display(self.db));
138139
this.print_type_ref(type_ref);
@@ -195,7 +196,7 @@ impl Printer<'_> {
195196
}
196197

197198
fn print_mod_item(&mut self, item: ModItem) {
198-
self.print_attrs_of(item);
199+
self.print_attrs_of(item, "\n");
199200

200201
match item {
201202
ModItem::Use(it) => {
@@ -261,7 +262,7 @@ impl Printer<'_> {
261262
if !params.is_empty() {
262263
self.indented(|this| {
263264
for param in params.clone() {
264-
this.print_attrs_of(param);
265+
this.print_attrs_of(param, "\n");
265266
match &this.tree[param] {
266267
Param::Normal(ty) => {
267268
if flags.contains(FnFlags::HAS_SELF_PARAM) {
@@ -319,7 +320,7 @@ impl Printer<'_> {
319320
self.indented(|this| {
320321
for variant in variants.clone() {
321322
let Variant { name, fields, ast_id: _ } = &this.tree[variant];
322-
this.print_attrs_of(variant);
323+
this.print_attrs_of(variant, "\n");
323324
w!(this, "{}", name.display(self.db));
324325
this.print_fields(fields);
325326
wln!(this, ",");
@@ -484,18 +485,20 @@ impl Printer<'_> {
484485

485486
w!(self, "<");
486487
let mut first = true;
487-
for (_, lt) in params.lifetimes.iter() {
488+
for (idx, lt) in params.lifetimes.iter() {
488489
if !first {
489490
w!(self, ", ");
490491
}
491492
first = false;
493+
self.print_attrs_of(idx, " ");
492494
w!(self, "{}", lt.name.display(self.db));
493495
}
494496
for (idx, x) in params.type_or_consts.iter() {
495497
if !first {
496498
w!(self, ", ");
497499
}
498500
first = false;
501+
self.print_attrs_of(idx, " ");
499502
match x {
500503
TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
501504
Some(name) => w!(self, "{}", name.display(self.db)),

crates/hir-def/src/item_tree/tests.rs

+12
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,15 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {}
358358
"#]],
359359
)
360360
}
361+
362+
#[test]
363+
fn generics_with_attributes() {
364+
check(
365+
r#"
366+
struct S<#[cfg(never)] T>;
367+
"#,
368+
expect![[r#"
369+
pub(self) struct S<#[cfg(never)] T>;
370+
"#]],
371+
)
372+
}

crates/ide/src/hover/tests.rs

+19
Original file line numberDiff line numberDiff line change
@@ -6469,3 +6469,22 @@ fn test() {
64696469
"#]],
64706470
);
64716471
}
6472+
6473+
#[test]
6474+
fn generic_params_disabled_by_cfg() {
6475+
check(
6476+
r#"
6477+
struct S<#[cfg(never)] T>;
6478+
fn test() {
6479+
let s$0: S = S;
6480+
}
6481+
"#,
6482+
expect![[r#"
6483+
*s*
6484+
6485+
```rust
6486+
let s: S // size = 0, align = 1
6487+
```
6488+
"#]],
6489+
);
6490+
}

0 commit comments

Comments
 (0)