diff options
author | Benjamin Coenen <[email protected]> | 2020-04-07 16:58:05 +0100 |
---|---|---|
committer | Benjamin Coenen <[email protected]> | 2020-04-07 16:58:05 +0100 |
commit | ab864ed259c10ff51f7c9c3421d098eeea7b0245 (patch) | |
tree | a6451a9ddd7774d02974cc1dca6fbf76c8d4bb1c | |
parent | f6d688d13070a54b288486900a30680d013c66ca (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.rs | 31 | ||||
-rw-r--r-- | crates/ra_hir_def/src/data.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/expr.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 29 |
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 | ||
5 | use either::Either; | 5 | use either::Either; |
6 | use hir_expand::{ | 6 | use hir_expand::{ |
7 | hygiene::Hygiene, | ||
7 | name::{AsName, Name}, | 8 | name::{AsName, Name}, |
8 | InFile, | 9 | InFile, |
9 | }; | 10 | }; |
10 | use ra_arena::{map::ArenaMap, Arena}; | 11 | use ra_arena::{map::ArenaMap, Arena}; |
12 | use ra_cfg::CfgOptions; | ||
11 | use ra_prof::profile; | 13 | use ra_prof::profile; |
12 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; | 14 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; |
13 | 15 | ||
14 | use crate::{ | 16 | use 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 | ||
54 | impl StructData { | 58 | impl 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 | ||
189 | fn 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 | |||
184 | fn lower_struct( | 193 | fn 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 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_expand::{ | 5 | use 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 | ||
14 | use crate::{ | 15 | use 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 | }; |
10 | use hir_expand::{diagnostics::DiagnosticSink, name::Name}; | 10 | use hir_expand::{diagnostics::DiagnosticSink, name::Name}; |
11 | use ra_syntax::ast; | 11 | use ra_syntax::{ast, AstPtr}; |
12 | use ra_syntax::AstPtr; | ||
13 | use rustc_hash::FxHashSet; | 12 | use rustc_hash::FxHashSet; |
14 | 13 | ||
15 | use crate::{ | 14 | use 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] | ||
323 | fn 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 | } | ||