aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_def/src/adt.rs57
-rw-r--r--crates/ra_hir_def/src/attr.rs5
-rw-r--r--crates/ra_hir_def/src/body/lower.rs51
-rw-r--r--crates/ra_hir_def/src/data.rs14
-rw-r--r--crates/ra_hir_ty/src/tests.rs60
-rw-r--r--crates/ra_syntax/src/ast/generated.rs1
6 files changed, 143 insertions, 45 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 7fc4cd76e..be4b0accb 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -4,6 +4,7 @@ use std::sync::Arc;
4 4
5use either::Either; 5use either::Either;
6use hir_expand::{ 6use hir_expand::{
7 hygiene::Hygiene,
7 name::{AsName, Name}, 8 name::{AsName, Name},
8 InFile, 9 InFile,
9}; 10};
@@ -12,9 +13,9 @@ use ra_prof::profile;
12use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; 13use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner};
13 14
14use crate::{ 15use crate::{
15 db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, type_ref::TypeRef, 16 attr::Attrs, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace,
16 visibility::RawVisibility, EnumId, LocalEnumVariantId, LocalStructFieldId, Lookup, StructId, 17 type_ref::TypeRef, visibility::RawVisibility, EnumId, HasModule, LocalEnumVariantId,
17 UnionId, VariantId, 18 LocalStructFieldId, Lookup, ModuleId, StructId, UnionId, VariantId,
18}; 19};
19 20
20/// Note that we use `StructData` for unions as well! 21/// Note that we use `StructData` for unions as well!
@@ -56,7 +57,8 @@ impl StructData {
56 let src = id.lookup(db).source(db); 57 let src = id.lookup(db).source(db);
57 58
58 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 59 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
59 let variant_data = VariantData::new(db, src.map(|s| s.kind())); 60 let variant_data =
61 VariantData::new(db, src.map(|s| s.kind()), id.lookup(db).container.module(db));
60 let variant_data = Arc::new(variant_data); 62 let variant_data = Arc::new(variant_data);
61 Arc::new(StructData { name, variant_data }) 63 Arc::new(StructData { name, variant_data })
62 } 64 }
@@ -70,6 +72,7 @@ impl StructData {
70 .map(ast::StructKind::Record) 72 .map(ast::StructKind::Record)
71 .unwrap_or(ast::StructKind::Unit) 73 .unwrap_or(ast::StructKind::Unit)
72 }), 74 }),
75 id.lookup(db).container.module(db),
73 ); 76 );
74 let variant_data = Arc::new(variant_data); 77 let variant_data = Arc::new(variant_data);
75 Arc::new(StructData { name, variant_data }) 78 Arc::new(StructData { name, variant_data })
@@ -82,7 +85,7 @@ impl EnumData {
82 let src = e.lookup(db).source(db); 85 let src = e.lookup(db).source(db);
83 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 86 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
84 let mut trace = Trace::new_for_arena(); 87 let mut trace = Trace::new_for_arena();
85 lower_enum(db, &mut trace, &src); 88 lower_enum(db, &mut trace, &src, e.lookup(db).container.module(db));
86 Arc::new(EnumData { name, variants: trace.into_arena() }) 89 Arc::new(EnumData { name, variants: trace.into_arena() })
87 } 90 }
88 91
@@ -98,7 +101,7 @@ impl HasChildSource for EnumId {
98 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { 101 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
99 let src = self.lookup(db).source(db); 102 let src = self.lookup(db).source(db);
100 let mut trace = Trace::new_for_map(); 103 let mut trace = Trace::new_for_map();
101 lower_enum(db, &mut trace, &src); 104 lower_enum(db, &mut trace, &src, self.lookup(db).container.module(db));
102 src.with_value(trace.into_map()) 105 src.with_value(trace.into_map())
103 } 106 }
104} 107}
@@ -107,22 +110,23 @@ fn lower_enum(
107 db: &dyn DefDatabase, 110 db: &dyn DefDatabase,
108 trace: &mut Trace<EnumVariantData, ast::EnumVariant>, 111 trace: &mut Trace<EnumVariantData, ast::EnumVariant>,
109 ast: &InFile<ast::EnumDef>, 112 ast: &InFile<ast::EnumDef>,
113 module_id: ModuleId,
110) { 114) {
111 for var in ast.value.variant_list().into_iter().flat_map(|it| it.variants()) { 115 for var in ast.value.variant_list().into_iter().flat_map(|it| it.variants()) {
112 trace.alloc( 116 trace.alloc(
113 || var.clone(), 117 || var.clone(),
114 || EnumVariantData { 118 || EnumVariantData {
115 name: var.name().map_or_else(Name::missing, |it| it.as_name()), 119 name: var.name().map_or_else(Name::missing, |it| it.as_name()),
116 variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()))), 120 variant_data: Arc::new(VariantData::new(db, ast.with_value(var.kind()), module_id)),
117 }, 121 },
118 ); 122 );
119 } 123 }
120} 124}
121 125
122impl VariantData { 126impl VariantData {
123 fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>) -> Self { 127 fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self {
124 let mut trace = Trace::new_for_arena(); 128 let mut trace = Trace::new_for_arena();
125 match lower_struct(db, &mut trace, &flavor) { 129 match lower_struct(db, &mut trace, &flavor, module_id) {
126 StructKind::Tuple => VariantData::Tuple(trace.into_arena()), 130 StructKind::Tuple => VariantData::Tuple(trace.into_arena()),
127 StructKind::Record => VariantData::Record(trace.into_arena()), 131 StructKind::Record => VariantData::Record(trace.into_arena()),
128 StructKind::Unit => VariantData::Unit, 132 StructKind::Unit => VariantData::Unit,
@@ -155,22 +159,27 @@ impl HasChildSource for VariantId {
155 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>; 159 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>;
156 160
157 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> { 161 fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
158 let src = match self { 162 let (src, module_id) = match self {
159 VariantId::EnumVariantId(it) => { 163 VariantId::EnumVariantId(it) => {
160 // I don't really like the fact that we call into parent source 164 // I don't really like the fact that we call into parent source
161 // here, this might add to more queries then necessary. 165 // here, this might add to more queries then necessary.
162 let src = it.parent.child_source(db); 166 let src = it.parent.child_source(db);
163 src.map(|map| map[it.local_id].kind()) 167 (src.map(|map| map[it.local_id].kind()), it.parent.lookup(db).container.module(db))
164 } 168 }
165 VariantId::StructId(it) => it.lookup(db).source(db).map(|it| it.kind()), 169 VariantId::StructId(it) => {
166 VariantId::UnionId(it) => it.lookup(db).source(db).map(|it| { 170 (it.lookup(db).source(db).map(|it| it.kind()), it.lookup(db).container.module(db))
167 it.record_field_def_list() 171 }
168 .map(ast::StructKind::Record) 172 VariantId::UnionId(it) => (
169 .unwrap_or(ast::StructKind::Unit) 173 it.lookup(db).source(db).map(|it| {
170 }), 174 it.record_field_def_list()
175 .map(ast::StructKind::Record)
176 .unwrap_or(ast::StructKind::Unit)
177 }),
178 it.lookup(db).container.module(db),
179 ),
171 }; 180 };
172 let mut trace = Trace::new_for_map(); 181 let mut trace = Trace::new_for_map();
173 lower_struct(db, &mut trace, &src); 182 lower_struct(db, &mut trace, &src, module_id);
174 src.with_value(trace.into_map()) 183 src.with_value(trace.into_map())
175 } 184 }
176} 185}
@@ -186,10 +195,17 @@ fn lower_struct(
186 db: &dyn DefDatabase, 195 db: &dyn DefDatabase,
187 trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, 196 trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>,
188 ast: &InFile<ast::StructKind>, 197 ast: &InFile<ast::StructKind>,
198 module_id: ModuleId,
189) -> StructKind { 199) -> StructKind {
200 let crate_graph = db.crate_graph();
190 match &ast.value { 201 match &ast.value {
191 ast::StructKind::Tuple(fl) => { 202 ast::StructKind::Tuple(fl) => {
192 for (i, fd) in fl.fields().enumerate() { 203 for (i, fd) in fl.fields().enumerate() {
204 let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id));
205 if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) {
206 continue;
207 }
208
193 trace.alloc( 209 trace.alloc(
194 || Either::Left(fd.clone()), 210 || Either::Left(fd.clone()),
195 || StructFieldData { 211 || StructFieldData {
@@ -203,6 +219,11 @@ fn lower_struct(
203 } 219 }
204 ast::StructKind::Record(fl) => { 220 ast::StructKind::Record(fl) => {
205 for fd in fl.fields() { 221 for fd in fl.fields() {
222 let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id));
223 if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) {
224 continue;
225 }
226
206 trace.alloc( 227 trace.alloc(
207 || Either::Right(fd.clone()), 228 || Either::Right(fd.clone()),
208 || StructFieldData { 229 || StructFieldData {
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index 71a18f5e1..7b0c506b1 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -5,6 +5,7 @@ use std::{ops, sync::Arc};
5use either::Either; 5use either::Either;
6use hir_expand::{hygiene::Hygiene, AstId, InFile}; 6use hir_expand::{hygiene::Hygiene, AstId, InFile};
7use mbe::ast_to_token_tree; 7use mbe::ast_to_token_tree;
8use ra_cfg::CfgOptions;
8use ra_syntax::{ 9use ra_syntax::{
9 ast::{self, AstNode, AttrsOwner}, 10 ast::{self, AstNode, AttrsOwner},
10 SmolStr, 11 SmolStr,
@@ -90,6 +91,10 @@ impl Attrs {
90 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { 91 pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
91 AttrQuery { attrs: self, key } 92 AttrQuery { attrs: self, key }
92 } 93 }
94
95 pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
96 self.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false))
97 }
93} 98}
94 99
95#[derive(Debug, Clone, PartialEq, Eq)] 100#[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 8d4b8b0f0..06145e92a 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -4,6 +4,7 @@
4use either::Either; 4use either::Either;
5 5
6use hir_expand::{ 6use hir_expand::{
7 hygiene::Hygiene,
7 name::{name, AsName, Name}, 8 name::{name, AsName, Name},
8 MacroDefId, MacroDefKind, 9 MacroDefId, MacroDefKind,
9}; 10};
@@ -20,6 +21,7 @@ use test_utils::tested_by;
20use super::{ExprSource, PatSource}; 21use super::{ExprSource, PatSource};
21use crate::{ 22use crate::{
22 adt::StructKind, 23 adt::StructKind,
24 attr::Attrs,
23 body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax}, 25 body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax},
24 builtin_type::{BuiltinFloat, BuiltinInt}, 26 builtin_type::{BuiltinFloat, BuiltinInt},
25 db::DefDatabase, 27 db::DefDatabase,
@@ -31,8 +33,8 @@ use crate::{
31 path::GenericArgs, 33 path::GenericArgs,
32 path::Path, 34 path::Path,
33 type_ref::{Mutability, TypeRef}, 35 type_ref::{Mutability, TypeRef},
34 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, 36 AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, HasModule, Intern,
35 StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, 37 ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
36}; 38};
37 39
38pub(super) fn lower( 40pub(super) fn lower(
@@ -298,28 +300,41 @@ impl ExprCollector<'_> {
298 self.alloc_expr(Expr::Return { expr }, syntax_ptr) 300 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
299 } 301 }
300 ast::Expr::RecordLit(e) => { 302 ast::Expr::RecordLit(e) => {
303 let crate_graph = self.db.crate_graph();
301 let path = e.path().and_then(|path| self.expander.parse_path(path)); 304 let path = e.path().and_then(|path| self.expander.parse_path(path));
302 let mut field_ptrs = Vec::new(); 305 let mut field_ptrs = Vec::new();
303 let record_lit = if let Some(nfl) = e.record_field_list() { 306 let record_lit = if let Some(nfl) = e.record_field_list() {
304 let fields = nfl 307 let fields = nfl
305 .fields() 308 .fields()
306 .inspect(|field| field_ptrs.push(AstPtr::new(field))) 309 .inspect(|field| field_ptrs.push(AstPtr::new(field)))
307 .map(|field| RecordLitField { 310 .filter_map(|field| {
308 name: field 311 let module_id = ContainerId::DefWithBodyId(self.def).module(self.db);
309 .name_ref() 312 let attrs = Attrs::new(
310 .map(|nr| nr.as_name()) 313 &field,
311 .unwrap_or_else(Name::missing), 314 &Hygiene::new(self.db.upcast(), self.expander.current_file_id),
312 expr: if let Some(e) = field.expr() { 315 );
313 self.collect_expr(e) 316
314 } else if let Some(nr) = field.name_ref() { 317 if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) {
315 // field shorthand 318 return None;
316 self.alloc_expr_field_shorthand( 319 }
317 Expr::Path(Path::from_name_ref(&nr)), 320
318 AstPtr::new(&field), 321 Some(RecordLitField {
319 ) 322 name: field
320 } else { 323 .name_ref()
321 self.missing_expr() 324 .map(|nr| nr.as_name())
322 }, 325 .unwrap_or_else(Name::missing),
326 expr: if let Some(e) = field.expr() {
327 self.collect_expr(e)
328 } else if let Some(nr) = field.name_ref() {
329 // field shorthand
330 self.alloc_expr_field_shorthand(
331 Expr::Path(Path::from_name_ref(&nr)),
332 AstPtr::new(&field),
333 )
334 } else {
335 self.missing_expr()
336 },
337 })
323 }) 338 })
324 .collect(); 339 .collect();
325 let spread = nfl.spread().map(|s| self.collect_expr(s)); 340 let spread = nfl.spread().map(|s| self.collect_expr(s));
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 606ec48b0..e793ad874 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -7,7 +7,6 @@ use hir_expand::{
7 name::{name, AsName, Name}, 7 name::{name, AsName, Name},
8 AstId, InFile, 8 AstId, InFile,
9}; 9};
10use ra_cfg::CfgOptions;
11use ra_prof::profile; 10use ra_prof::profile;
12use ra_syntax::ast::{ 11use ra_syntax::ast::{
13 self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, VisibilityOwner, 12 self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, VisibilityOwner,
@@ -318,10 +317,6 @@ fn collect_impl_items_in_macro(
318 } 317 }
319} 318}
320 319
321fn is_cfg_enabled(cfg_options: &CfgOptions, attrs: &Attrs) -> bool {
322 attrs.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false))
323}
324
325fn collect_impl_items( 320fn collect_impl_items(
326 db: &dyn DefDatabase, 321 db: &dyn DefDatabase,
327 impl_items: impl Iterator<Item = ImplItem>, 322 impl_items: impl Iterator<Item = ImplItem>,
@@ -341,10 +336,11 @@ fn collect_impl_items(
341 } 336 }
342 .intern(db); 337 .intern(db);
343 338
344 if !is_cfg_enabled( 339 if !db
345 &crate_graph[module_id.krate].cfg_options, 340 .function_data(def)
346 &db.function_data(def).attrs, 341 .attrs
347 ) { 342 .is_cfg_enabled(&crate_graph[module_id.krate].cfg_options)
343 {
348 None 344 None
349 } else { 345 } else {
350 Some(def.into()) 346 Some(def.into())
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 608408d88..02f2e5de0 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -349,3 +349,63 @@ fn no_such_field_with_feature_flag_diagnostics() {
349 349
350 assert_snapshot!(diagnostics, @r###""###); 350 assert_snapshot!(diagnostics, @r###""###);
351} 351}
352
353#[test]
354fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
355 let diagnostics = TestDB::with_files(
356 r#"
357 //- /lib.rs crate:foo cfg:feature=foo
358 struct S {
359 #[cfg(feature = "foo")]
360 foo: u32,
361 #[cfg(not(feature = "foo"))]
362 bar: u32,
363 }
364
365 impl S {
366 #[cfg(feature = "foo")]
367 fn new(foo: u32) -> Self {
368 Self { foo }
369 }
370 #[cfg(not(feature = "foo"))]
371 fn new(bar: u32) -> Self {
372 Self { bar }
373 }
374 }
375 "#,
376 )
377 .diagnostics()
378 .0;
379
380 assert_snapshot!(diagnostics, @r###""###);
381}
382
383#[test]
384fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() {
385 let diagnostics = TestDB::with_files(
386 r#"
387 //- /lib.rs crate:foo cfg:feature=foo
388 struct S {
389 #[cfg(feature = "foo")]
390 foo: u32,
391 #[cfg(not(feature = "foo"))]
392 bar: u32,
393 }
394
395 impl S {
396 fn new(val: u32) -> Self {
397 Self {
398 #[cfg(feature = "foo")]
399 foo: val,
400 #[cfg(not(feature = "foo"))]
401 bar: val,
402 }
403 }
404 }
405 "#,
406 )
407 .diagnostics()
408 .0;
409
410 assert_snapshot!(diagnostics, @r###""###);
411}
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 385fddc89..d2b055b0a 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -5216,6 +5216,7 @@ impl RecordFieldList {
5216pub struct RecordField { 5216pub struct RecordField {
5217 pub(crate) syntax: SyntaxNode, 5217 pub(crate) syntax: SyntaxNode,
5218} 5218}
5219impl ast::AttrsOwner for RecordField {}
5219impl std::fmt::Display for RecordField { 5220impl std::fmt::Display for RecordField {
5220 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 5221 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
5221 std::fmt::Display::fmt(self.syntax(), f) 5222 std::fmt::Display::fmt(self.syntax(), f)