Skip to content

Commit 89107d5

Browse files
committed
Emit unconfigured code diagnostics for fields
1 parent 1a24003 commit 89107d5

File tree

10 files changed

+730
-33
lines changed

10 files changed

+730
-33
lines changed

crates/hir-def/src/item_tree.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,7 @@ impl AssocItem {
943943
pub struct Variant {
944944
pub name: Name,
945945
pub fields: Fields,
946+
pub ast_id: FileAstId<ast::Variant>,
946947
}
947948

948949
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -952,10 +953,17 @@ pub enum Fields {
952953
Unit,
953954
}
954955

956+
#[derive(Debug, Clone, PartialEq, Eq)]
957+
pub enum FieldAstId {
958+
Record(FileAstId<ast::RecordField>),
959+
Tuple(FileAstId<ast::TupleField>),
960+
}
961+
955962
/// A single field of an enum variant or struct
956963
#[derive(Debug, Clone, PartialEq, Eq)]
957964
pub struct Field {
958965
pub name: Name,
959966
pub type_ref: Interned<TypeRef>,
960967
pub visibility: RawVisibilityId,
968+
pub ast_id: FieldAstId,
961969
}

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,8 @@ impl<'a> Ctx<'a> {
184184
let name = field.name()?.as_name();
185185
let visibility = self.lower_visibility(field);
186186
let type_ref = self.lower_type_ref_opt(field.ty());
187-
let res = Field { name, type_ref, visibility };
187+
let ast_id = FieldAstId::Record(self.source_ast_id_map.ast_id(field));
188+
let res = Field { name, type_ref, visibility, ast_id };
188189
Some(res)
189190
}
190191

@@ -203,7 +204,8 @@ impl<'a> Ctx<'a> {
203204
let name = Name::new_tuple_field(idx);
204205
let visibility = self.lower_visibility(field);
205206
let type_ref = self.lower_type_ref_opt(field.ty());
206-
Field { name, type_ref, visibility }
207+
let ast_id = FieldAstId::Tuple(self.source_ast_id_map.ast_id(field));
208+
Field { name, type_ref, visibility, ast_id }
207209
}
208210

209211
fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
@@ -247,7 +249,8 @@ impl<'a> Ctx<'a> {
247249
fn lower_variant(&mut self, variant: &ast::Variant) -> Option<Variant> {
248250
let name = variant.name()?.as_name();
249251
let fields = self.lower_fields(&variant.kind());
250-
let res = Variant { name, fields };
252+
let ast_id = self.source_ast_id_map.ast_id(variant);
253+
let res = Variant { name, fields, ast_id };
251254
Some(res)
252255
}
253256

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ impl<'a> Printer<'a> {
115115
w!(self, "{{");
116116
self.indented(|this| {
117117
for field in fields.clone() {
118-
let Field { visibility, name, type_ref } = &this.tree[field];
118+
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
119119
this.print_attrs_of(field);
120120
this.print_visibility(*visibility);
121121
w!(this, "{}: ", name);
@@ -129,7 +129,7 @@ impl<'a> Printer<'a> {
129129
w!(self, "(");
130130
self.indented(|this| {
131131
for field in fields.clone() {
132-
let Field { visibility, name, type_ref } = &this.tree[field];
132+
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
133133
this.print_attrs_of(field);
134134
this.print_visibility(*visibility);
135135
w!(this, "{}: ", name);
@@ -323,7 +323,7 @@ impl<'a> Printer<'a> {
323323
self.print_where_clause_and_opening_brace(generic_params);
324324
self.indented(|this| {
325325
for variant in variants.clone() {
326-
let Variant { name, fields } = &this.tree[variant];
326+
let Variant { name, fields, ast_id: _ } = &this.tree[variant];
327327
this.print_attrs_of(variant);
328328
w!(this, "{}", name);
329329
this.print_fields(fields);

crates/hir-def/src/nameres/collector.rs

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ use crate::{
3232
derive_macro_as_call_id,
3333
item_scope::{ImportType, PerNsGlobImports},
3434
item_tree::{
35-
self, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, MacroCall,
36-
MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
35+
self, FieldAstId, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode,
36+
MacroCall, MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
3737
},
3838
macro_call_as_call_id, macro_id_to_def_id,
3939
nameres::{
@@ -1511,7 +1511,10 @@ impl ModCollector<'_, '_> {
15111511
let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
15121512
if let Some(cfg) = attrs.cfg() {
15131513
if !self.is_cfg_enabled(&cfg) {
1514-
self.emit_unconfigured_diagnostic(item, &cfg);
1514+
self.emit_unconfigured_diagnostic(
1515+
InFile::new(self.file_id(), item.ast_id(&self.item_tree).upcast()),
1516+
&cfg,
1517+
);
15151518
continue;
15161519
}
15171520
}
@@ -1523,22 +1526,20 @@ impl ModCollector<'_, '_> {
15231526
}
15241527

15251528
let db = self.def_collector.db;
1526-
let module = self.def_collector.def_map.module_id(self.module_id);
1527-
let def_map = &mut self.def_collector.def_map;
1529+
let module_id = self.module_id;
1530+
let module = self.def_collector.def_map.module_id(module_id);
15281531
let update_def =
15291532
|def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
1530-
def_collector.def_map.modules[self.module_id].scope.declare(id);
1533+
def_collector.def_map.modules[module_id].scope.declare(id);
15311534
def_collector.update(
1532-
self.module_id,
1535+
module_id,
15331536
&[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
15341537
vis,
15351538
ImportType::Named,
15361539
)
15371540
};
15381541
let resolve_vis = |def_map: &DefMap, visibility| {
1539-
def_map
1540-
.resolve_visibility(db, self.module_id, visibility)
1541-
.unwrap_or(Visibility::Public)
1542+
def_map.resolve_visibility(db, module_id, visibility).unwrap_or(Visibility::Public)
15421543
};
15431544

15441545
match item {
@@ -1594,6 +1595,7 @@ impl ModCollector<'_, '_> {
15941595
let fn_id =
15951596
FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
15961597

1598+
let def_map = &self.def_collector.def_map;
15971599
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
15981600
if self.def_collector.is_proc_macro {
15991601
if self.module_id == def_map.root {
@@ -1614,7 +1616,10 @@ impl ModCollector<'_, '_> {
16141616
ModItem::Struct(id) => {
16151617
let it = &self.item_tree[id];
16161618

1617-
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
1619+
self.process_fields(&it.fields);
1620+
1621+
let vis =
1622+
resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
16181623
update_def(
16191624
self.def_collector,
16201625
StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1628,7 +1633,10 @@ impl ModCollector<'_, '_> {
16281633
ModItem::Union(id) => {
16291634
let it = &self.item_tree[id];
16301635

1631-
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
1636+
self.process_fields(&it.fields);
1637+
1638+
let vis =
1639+
resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
16321640
update_def(
16331641
self.def_collector,
16341642
UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1642,7 +1650,21 @@ impl ModCollector<'_, '_> {
16421650
ModItem::Enum(id) => {
16431651
let it = &self.item_tree[id];
16441652

1645-
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
1653+
for id in it.variants.clone() {
1654+
let variant = &self.item_tree[id];
1655+
let attrs = self.item_tree.attrs(self.def_collector.db, krate, id.into());
1656+
if let Some(cfg) = attrs.cfg() {
1657+
if !self.is_cfg_enabled(&cfg) {
1658+
self.emit_unconfigured_diagnostic(
1659+
InFile::new(self.file_id(), variant.ast_id.upcast()),
1660+
&cfg,
1661+
);
1662+
}
1663+
}
1664+
}
1665+
1666+
let vis =
1667+
resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
16461668
update_def(
16471669
self.def_collector,
16481670
EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1660,7 +1682,10 @@ impl ModCollector<'_, '_> {
16601682

16611683
match &it.name {
16621684
Some(name) => {
1663-
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
1685+
let vis = resolve_vis(
1686+
&self.def_collector.def_map,
1687+
&self.item_tree[it.visibility],
1688+
);
16641689
update_def(self.def_collector, const_id.into(), name, vis, false);
16651690
}
16661691
None => {
@@ -1674,7 +1699,8 @@ impl ModCollector<'_, '_> {
16741699
ModItem::Static(id) => {
16751700
let it = &self.item_tree[id];
16761701

1677-
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
1702+
let vis =
1703+
resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
16781704
update_def(
16791705
self.def_collector,
16801706
StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
@@ -1688,7 +1714,8 @@ impl ModCollector<'_, '_> {
16881714
ModItem::Trait(id) => {
16891715
let it = &self.item_tree[id];
16901716

1691-
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
1717+
let vis =
1718+
resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
16921719
update_def(
16931720
self.def_collector,
16941721
TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
@@ -1702,7 +1729,8 @@ impl ModCollector<'_, '_> {
17021729
ModItem::TypeAlias(id) => {
17031730
let it = &self.item_tree[id];
17041731

1705-
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
1732+
let vis =
1733+
resolve_vis(&self.def_collector.def_map, &self.item_tree[it.visibility]);
17061734
update_def(
17071735
self.def_collector,
17081736
TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
@@ -2115,17 +2143,44 @@ impl ModCollector<'_, '_> {
21152143
}
21162144
}
21172145

2146+
fn process_fields(&mut self, fields: &Fields) {
2147+
match fields {
2148+
Fields::Record(range) | Fields::Tuple(range) => {
2149+
for id in range.clone() {
2150+
let field = &self.item_tree[id];
2151+
let attrs = self.item_tree.attrs(
2152+
self.def_collector.db,
2153+
self.def_collector.def_map.krate,
2154+
id.into(),
2155+
);
2156+
if let Some(cfg) = attrs.cfg() {
2157+
if !self.is_cfg_enabled(&cfg) {
2158+
self.emit_unconfigured_diagnostic(
2159+
InFile::new(
2160+
self.file_id(),
2161+
match field.ast_id {
2162+
FieldAstId::Record(it) => it.upcast(),
2163+
FieldAstId::Tuple(it) => it.upcast(),
2164+
},
2165+
),
2166+
&cfg,
2167+
);
2168+
}
2169+
}
2170+
}
2171+
}
2172+
Fields::Unit => {}
2173+
}
2174+
}
2175+
21182176
fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool {
21192177
self.def_collector.cfg_options.check(cfg) != Some(false)
21202178
}
21212179

2122-
fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
2123-
let ast_id = item.ast_id(self.item_tree);
2124-
2125-
let ast_id = InFile::new(self.file_id(), ast_id);
2180+
fn emit_unconfigured_diagnostic(&mut self, ast: AstId<ast::AnyHasAttrs>, cfg: &CfgExpr) {
21262181
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
21272182
self.module_id,
2128-
ast_id,
2183+
ast,
21292184
cfg.clone(),
21302185
self.def_collector.cfg_options.clone(),
21312186
));

crates/hir-def/src/nameres/diagnostics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use base_db::CrateId;
44
use cfg::{CfgExpr, CfgOptions};
55
use hir_expand::MacroCallKind;
66
use la_arena::Idx;
7-
use syntax::ast;
7+
use syntax::ast::{self, AnyHasAttrs};
88

99
use crate::{
1010
attr::AttrId,
@@ -22,7 +22,7 @@ pub enum DefDiagnosticKind {
2222

2323
UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> },
2424

25-
UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions },
25+
UnconfiguredCode { ast: AstId<AnyHasAttrs>, cfg: CfgExpr, opts: CfgOptions },
2626

2727
UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
2828

@@ -75,7 +75,7 @@ impl DefDiagnostic {
7575

7676
pub fn unconfigured_code(
7777
container: LocalModuleId,
78-
ast: AstId<ast::Item>,
78+
ast: AstId<ast::AnyHasAttrs>,
7979
cfg: CfgExpr,
8080
opts: CfgOptions,
8181
) -> Self {

crates/hir-expand/src/ast_id_map.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,12 @@ impl AstIdMap {
9393
// trait does not change ids of top-level items, which helps caching.
9494
bdfs(node, |it| {
9595
let kind = it.kind();
96-
if ast::Item::can_cast(kind) || ast::BlockExpr::can_cast(kind) {
96+
if ast::Item::can_cast(kind)
97+
|| ast::BlockExpr::can_cast(kind)
98+
|| ast::Variant::can_cast(kind)
99+
|| ast::RecordField::can_cast(kind)
100+
|| ast::TupleField::can_cast(kind)
101+
{
97102
res.alloc(&it);
98103
true
99104
} else {

crates/hir/src/diagnostics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Re-export diagnostics such that clients of `hir` don't have to depend on
22
//! low-level crates.
33
//!
4-
//! This probably isn't the best way to do this -- ideally, diagnistics should
4+
//! This probably isn't the best way to do this -- ideally, diagnostics should
55
//! be expressed in terms of hir types themselves.
66
use base_db::CrateId;
77
use cfg::{CfgExpr, CfgOptions};

crates/ide-diagnostics/src/handlers/inactive_code.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,31 @@ trait Bar {
137137
138138
#[cfg_attr(not(never), inline, cfg(no))] fn h() {}
139139
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: no is disabled
140+
"#,
141+
);
142+
}
143+
144+
#[test]
145+
fn inactive_fields() {
146+
check(
147+
r#"
148+
enum Foo {
149+
#[cfg(a)] Bar,
150+
//^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
151+
}
152+
153+
struct Baz {
154+
#[cfg(a)] baz: String,
155+
//^^^^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
156+
}
157+
158+
struct Qux(#[cfg(a)] String);
159+
//^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
160+
161+
union FooBar {
162+
#[cfg(a)] baz: u32,
163+
//^^^^^^^^^^^^^^^^^^ weak: code is inactive due to #[cfg] directives: a is disabled
164+
}
140165
"#,
141166
);
142167
}

0 commit comments

Comments
 (0)