aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Coenen <[email protected]>2020-04-07 16:58:05 +0100
committerBenjamin Coenen <[email protected]>2020-04-07 16:58:05 +0100
commitab864ed259c10ff51f7c9c3421d098eeea7b0245 (patch)
treea6451a9ddd7774d02974cc1dca6fbf76c8d4bb1c
parentf6d688d13070a54b288486900a30680d013c66ca (diff)
feat: add attributes support on struct fields #3870
Signed-off-by: Benjamin Coenen <[email protected]>
-rw-r--r--crates/ra_hir_def/src/adt.rs31
-rw-r--r--crates/ra_hir_def/src/data.rs6
-rw-r--r--crates/ra_hir_ty/src/expr.rs12
-rw-r--r--crates/ra_hir_ty/src/tests.rs29
4 files changed, 71 insertions, 7 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index de07fc952..8527a6cad 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -4,17 +4,19 @@ 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};
10use ra_arena::{map::ArenaMap, Arena}; 11use ra_arena::{map::ArenaMap, Arena};
12use ra_cfg::CfgOptions;
11use ra_prof::profile; 13use ra_prof::profile;
12use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; 14use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner};
13 15
14use crate::{ 16use crate::{
15 db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, type_ref::TypeRef, 17 attr::Attrs, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace,
16 visibility::RawVisibility, EnumId, LocalEnumVariantId, LocalStructFieldId, Lookup, StructId, 18 type_ref::TypeRef, visibility::RawVisibility, EnumId, LocalEnumVariantId, LocalStructFieldId,
17 UnionId, VariantId, 19 Lookup, StructId, UnionId, VariantId,
18}; 20};
19 21
20/// Note that we use `StructData` for unions as well! 22/// Note that we use `StructData` for unions as well!
@@ -49,11 +51,14 @@ pub struct StructFieldData {
49 pub name: Name, 51 pub name: Name,
50 pub type_ref: TypeRef, 52 pub type_ref: TypeRef,
51 pub visibility: RawVisibility, 53 pub visibility: RawVisibility,
54 pub attrs: Attrs,
55 // TODO: add attributes
52} 56}
53 57
54impl StructData { 58impl StructData {
55 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { 59 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
56 let src = id.lookup(db).source(db); 60 let src = id.lookup(db).source(db);
61
57 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 62 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
58 let variant_data = VariantData::new(db, src.map(|s| s.kind())); 63 let variant_data = VariantData::new(db, src.map(|s| s.kind()));
59 let variant_data = Arc::new(variant_data); 64 let variant_data = Arc::new(variant_data);
@@ -181,6 +186,10 @@ pub enum StructKind {
181 Unit, 186 Unit,
182} 187}
183 188
189fn is_cfg_enabled(cfg_options: &CfgOptions, attrs: &Attrs) -> bool {
190 attrs.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false))
191}
192
184fn lower_struct( 193fn lower_struct(
185 db: &dyn DefDatabase, 194 db: &dyn DefDatabase,
186 trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, 195 trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>,
@@ -189,12 +198,21 @@ fn lower_struct(
189 match &ast.value { 198 match &ast.value {
190 ast::StructKind::Tuple(fl) => { 199 ast::StructKind::Tuple(fl) => {
191 for (i, fd) in fl.fields().enumerate() { 200 for (i, fd) in fl.fields().enumerate() {
201 let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id));
202
203 // Need verification about parent cfg_options and current with current attributes
204 // If it is we are in a case where the cfg is not enabled then we don't have to add this field to check
205 // if !is_cfg_enabled(&crate_graph[module_id.krate].cfg_options, &attrs) {
206 // continue;
207 // }
208
192 trace.alloc( 209 trace.alloc(
193 || Either::Left(fd.clone()), 210 || Either::Left(fd.clone()),
194 || StructFieldData { 211 || StructFieldData {
195 name: Name::new_tuple_field(i), 212 name: Name::new_tuple_field(i),
196 type_ref: TypeRef::from_ast_opt(fd.type_ref()), 213 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
197 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), 214 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
215 attrs: Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id)),
198 }, 216 },
199 ); 217 );
200 } 218 }
@@ -202,12 +220,19 @@ fn lower_struct(
202 } 220 }
203 ast::StructKind::Record(fl) => { 221 ast::StructKind::Record(fl) => {
204 for fd in fl.fields() { 222 for fd in fl.fields() {
223 let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id));
224 // Need verification about parent cfg_options and current with current attributes
225 // If it is we are in a case where the cfg is not enabled then we don't have to add this field to check
226 // if !is_cfg_enabled(&crate_graph[module_id.krate].cfg_options, &attrs) {
227 // continue;
228 // }
205 trace.alloc( 229 trace.alloc(
206 || Either::Right(fd.clone()), 230 || Either::Right(fd.clone()),
207 || StructFieldData { 231 || StructFieldData {
208 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), 232 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
209 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()), 233 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
210 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), 234 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
235 attrs: Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id)),
211 }, 236 },
212 ); 237 );
213 } 238 }
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index 04bd4a305..934c3b94e 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -3,6 +3,7 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_expand::{ 5use hir_expand::{
6 hygiene::Hygiene,
6 name::{name, AsName, Name}, 7 name::{name, AsName, Name},
7 AstId, InFile, 8 AstId, InFile,
8}; 9};
@@ -12,6 +13,7 @@ use ra_syntax::ast::{
12}; 13};
13 14
14use crate::{ 15use crate::{
16 attr::Attrs,
15 db::DefDatabase, 17 db::DefDatabase,
16 path::{path, GenericArgs, Path}, 18 path::{path, GenericArgs, Path},
17 src::HasSource, 19 src::HasSource,
@@ -26,6 +28,7 @@ pub struct FunctionData {
26 pub name: Name, 28 pub name: Name,
27 pub params: Vec<TypeRef>, 29 pub params: Vec<TypeRef>,
28 pub ret_type: TypeRef, 30 pub ret_type: TypeRef,
31 pub attrs: Attrs,
29 /// True if the first param is `self`. This is relevant to decide whether this 32 /// True if the first param is `self`. This is relevant to decide whether this
30 /// can be called as a method. 33 /// can be called as a method.
31 pub has_self_param: bool, 34 pub has_self_param: bool,
@@ -63,6 +66,7 @@ impl FunctionData {
63 params.push(type_ref); 66 params.push(type_ref);
64 } 67 }
65 } 68 }
69 let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id));
66 let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) { 70 let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
67 TypeRef::from_ast(type_ref) 71 TypeRef::from_ast(type_ref)
68 } else { 72 } else {
@@ -81,7 +85,7 @@ impl FunctionData {
81 let visibility = 85 let visibility =
82 RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); 86 RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility()));
83 87
84 let sig = FunctionData { name, params, ret_type, has_self_param, visibility }; 88 let sig = FunctionData { name, params, ret_type, has_self_param, visibility, attrs };
85 Arc::new(sig) 89 Arc::new(sig)
86 } 90 }
87} 91}
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index b7b476b4c..eb1209d08 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -8,8 +8,7 @@ use hir_def::{
8 AdtId, FunctionId, 8 AdtId, FunctionId,
9}; 9};
10use hir_expand::{diagnostics::DiagnosticSink, name::Name}; 10use hir_expand::{diagnostics::DiagnosticSink, name::Name};
11use ra_syntax::ast; 11use ra_syntax::{ast, AstPtr};
12use ra_syntax::AstPtr;
13use rustc_hash::FxHashSet; 12use rustc_hash::FxHashSet;
14 13
15use crate::{ 14use crate::{
@@ -82,7 +81,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
82 81
83 let variant_data = variant_data(db.upcast(), variant_def); 82 let variant_data = variant_data(db.upcast(), variant_def);
84 83
85 let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); 84 let lit_fields: FxHashSet<_> = fields
85 .iter()
86 .filter_map(|f| {
87 // TODO: check if cfg_is_enabled with .attrs ?
88
89 Some(&f.name)
90 })
91 .collect();
86 let missed_fields: Vec<Name> = variant_data 92 let missed_fields: Vec<Name> = variant_data
87 .fields() 93 .fields()
88 .iter() 94 .iter()
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 027e5a8f8..c3d793cc2 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -318,3 +318,32 @@ fn no_such_field_diagnostics() {
318 "### 318 "###
319 ); 319 );
320} 320}
321
322#[test]
323fn no_such_field_with_feature_flag_diagnostics() {
324 let diagnostics = TestDB::with_files(
325 r#"
326 //- /lib.rs
327 struct MyStruct {
328 my_val: usize,
329 #[cfg(feature = "foo")]
330 bar: bool,
331 }
332
333 impl MyStruct {
334 #[cfg(feature = "foo")]
335 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
336 Self { my_val, bar }
337 }
338
339 #[cfg(not(feature = "foo"))]
340 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
341 Self { my_val }
342 }
343 }
344 "#,
345 )
346 .diagnostics();
347
348 assert_snapshot!(diagnostics, "");
349}