Skip to content

Commit 412eda7

Browse files
bors[bot]bnjjj
andauthored
Merge #3880
3880: Add support for attributes for struct fields r=matklad a=bnjjj Hello I try to solve this example: ```rust struct MyStruct { my_val: usize, #[cfg(feature = "foo")] bar: bool, } impl MyStruct { #[cfg(feature = "foo")] pub(crate) fn new(my_val: usize, bar: bool) -> Self { Self { my_val, bar } } #[cfg(not(feature = "foo"))] pub(crate) fn new(my_val: usize, _bar: bool) -> Self { Self { my_val } } } ``` Here is a draft PR to try to solve this issue. In fact for now when i have this kind of example, rust-analyzer tells me that my second Self {} miss the bar field. Which is a bug. I have some difficulties to add this features. Here in my draft I share my work about adding attributes support on struct field data. But I'm stuck when I have to fetch attributes from parent expressions. I don't really know how to do that. For the first iteration I just want to solve my issue without solving on all different expressions. And then after I will try to implement that on different kind of expression. I think I have to fetch my FunctionId and then I will be able to find attributes with myFunction.attrs() But I don't know if it's the right way. @matklad (or anyone else) if you can help me it would be great :D Co-authored-by: Benjamin Coenen <[email protected]>
2 parents 01e5bd5 + 585bb83 commit 412eda7

File tree

4 files changed

+58
-7
lines changed

4 files changed

+58
-7
lines changed

crates/ra_hir_def/src/adt.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ pub struct StructFieldData {
5454
impl StructData {
5555
pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
5656
let src = id.lookup(db).source(db);
57+
5758
let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
5859
let variant_data = VariantData::new(db, src.map(|s| s.kind()));
5960
let variant_data = Arc::new(variant_data);

crates/ra_hir_def/src/data.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@
33
use std::sync::Arc;
44

55
use hir_expand::{
6+
hygiene::Hygiene,
67
name::{name, AsName, Name},
78
AstId, InFile,
89
};
10+
use ra_cfg::CfgOptions;
911
use ra_prof::profile;
1012
use ra_syntax::ast::{
1113
self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, VisibilityOwner,
1214
};
1315

1416
use crate::{
17+
attr::Attrs,
1518
db::DefDatabase,
1619
path::{path, GenericArgs, Path},
1720
src::HasSource,
@@ -26,6 +29,7 @@ pub struct FunctionData {
2629
pub name: Name,
2730
pub params: Vec<TypeRef>,
2831
pub ret_type: TypeRef,
32+
pub attrs: Attrs,
2933
/// True if the first param is `self`. This is relevant to decide whether this
3034
/// can be called as a method.
3135
pub has_self_param: bool,
@@ -63,6 +67,8 @@ impl FunctionData {
6367
params.push(type_ref);
6468
}
6569
}
70+
let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id));
71+
6672
let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
6773
TypeRef::from_ast(type_ref)
6874
} else {
@@ -81,7 +87,7 @@ impl FunctionData {
8187
let visibility =
8288
RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility()));
8389

84-
let sig = FunctionData { name, params, ret_type, has_self_param, visibility };
90+
let sig = FunctionData { name, params, ret_type, has_self_param, visibility, attrs };
8591
Arc::new(sig)
8692
}
8793
}
@@ -211,6 +217,7 @@ impl ImplData {
211217
let module_id = impl_loc.container.module(db);
212218

213219
let mut items = Vec::new();
220+
214221
if let Some(item_list) = src.value.item_list() {
215222
items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id));
216223
items.extend(collect_impl_items_in_macros(
@@ -311,39 +318,53 @@ fn collect_impl_items_in_macro(
311318
}
312319
}
313320

321+
fn 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+
314325
fn collect_impl_items(
315326
db: &dyn DefDatabase,
316327
impl_items: impl Iterator<Item = ImplItem>,
317328
file_id: crate::HirFileId,
318329
id: ImplId,
319330
) -> Vec<AssocItemId> {
320331
let items = db.ast_id_map(file_id);
332+
let crate_graph = db.crate_graph();
333+
let module_id = id.lookup(db).container.module(db);
321334

322335
impl_items
323-
.map(|item_node| match item_node {
336+
.filter_map(|item_node| match item_node {
324337
ast::ImplItem::FnDef(it) => {
325338
let def = FunctionLoc {
326339
container: AssocContainerId::ImplId(id),
327340
ast_id: AstId::new(file_id, items.ast_id(&it)),
328341
}
329342
.intern(db);
330-
def.into()
343+
344+
if !is_cfg_enabled(
345+
&crate_graph[module_id.krate].cfg_options,
346+
&db.function_data(def).attrs,
347+
) {
348+
None
349+
} else {
350+
Some(def.into())
351+
}
331352
}
332353
ast::ImplItem::ConstDef(it) => {
333354
let def = ConstLoc {
334355
container: AssocContainerId::ImplId(id),
335356
ast_id: AstId::new(file_id, items.ast_id(&it)),
336357
}
337358
.intern(db);
338-
def.into()
359+
Some(def.into())
339360
}
340361
ast::ImplItem::TypeAliasDef(it) => {
341362
let def = TypeAliasLoc {
342363
container: AssocContainerId::ImplId(id),
343364
ast_id: AstId::new(file_id, items.ast_id(&it)),
344365
}
345366
.intern(db);
346-
def.into()
367+
Some(def.into())
347368
}
348369
})
349370
.collect()

crates/ra_hir_ty/src/expr.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ use std::sync::Arc;
44

55
use hir_def::{path::path, resolver::HasResolver, AdtId, FunctionId};
66
use hir_expand::diagnostics::DiagnosticSink;
7-
use ra_syntax::ast;
8-
use ra_syntax::AstPtr;
7+
use ra_syntax::{ast, AstPtr};
98
use rustc_hash::FxHashSet;
109

1110
use crate::{

crates/ra_hir_ty/src/tests.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,33 @@ fn no_such_field_diagnostics() {
319319
"###
320320
);
321321
}
322+
323+
#[test]
324+
fn no_such_field_with_feature_flag_diagnostics() {
325+
let diagnostics = TestDB::with_files(
326+
r#"
327+
//- /lib.rs crate:foo cfg:feature=foo
328+
struct MyStruct {
329+
my_val: usize,
330+
#[cfg(feature = "foo")]
331+
bar: bool,
332+
}
333+
334+
impl MyStruct {
335+
#[cfg(feature = "foo")]
336+
pub(crate) fn new(my_val: usize, bar: bool) -> Self {
337+
Self { my_val, bar }
338+
}
339+
340+
#[cfg(not(feature = "foo"))]
341+
pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
342+
Self { my_val }
343+
}
344+
}
345+
"#,
346+
)
347+
.diagnostics()
348+
.0;
349+
350+
assert_snapshot!(diagnostics, @r###""###);
351+
}

0 commit comments

Comments
 (0)