mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-01 20:47:36 +00:00
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 <5719034+bnjjj@users.noreply.github.com>
This commit is contained in:
commit
412eda7387
@ -54,6 +54,7 @@ pub struct StructFieldData {
|
||||
impl StructData {
|
||||
pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
|
||||
let src = id.lookup(db).source(db);
|
||||
|
||||
let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
|
||||
let variant_data = VariantData::new(db, src.map(|s| s.kind()));
|
||||
let variant_data = Arc::new(variant_data);
|
||||
|
@ -3,15 +3,18 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use hir_expand::{
|
||||
hygiene::Hygiene,
|
||||
name::{name, AsName, Name},
|
||||
AstId, InFile,
|
||||
};
|
||||
use ra_cfg::CfgOptions;
|
||||
use ra_prof::profile;
|
||||
use ra_syntax::ast::{
|
||||
self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner, VisibilityOwner,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
attr::Attrs,
|
||||
db::DefDatabase,
|
||||
path::{path, GenericArgs, Path},
|
||||
src::HasSource,
|
||||
@ -26,6 +29,7 @@ pub struct FunctionData {
|
||||
pub name: Name,
|
||||
pub params: Vec<TypeRef>,
|
||||
pub ret_type: TypeRef,
|
||||
pub attrs: Attrs,
|
||||
/// True if the first param is `self`. This is relevant to decide whether this
|
||||
/// can be called as a method.
|
||||
pub has_self_param: bool,
|
||||
@ -63,6 +67,8 @@ impl FunctionData {
|
||||
params.push(type_ref);
|
||||
}
|
||||
}
|
||||
let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id));
|
||||
|
||||
let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
|
||||
TypeRef::from_ast(type_ref)
|
||||
} else {
|
||||
@ -81,7 +87,7 @@ impl FunctionData {
|
||||
let visibility =
|
||||
RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility()));
|
||||
|
||||
let sig = FunctionData { name, params, ret_type, has_self_param, visibility };
|
||||
let sig = FunctionData { name, params, ret_type, has_self_param, visibility, attrs };
|
||||
Arc::new(sig)
|
||||
}
|
||||
}
|
||||
@ -211,6 +217,7 @@ impl ImplData {
|
||||
let module_id = impl_loc.container.module(db);
|
||||
|
||||
let mut items = Vec::new();
|
||||
|
||||
if let Some(item_list) = src.value.item_list() {
|
||||
items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id));
|
||||
items.extend(collect_impl_items_in_macros(
|
||||
@ -311,6 +318,10 @@ fn collect_impl_items_in_macro(
|
||||
}
|
||||
}
|
||||
|
||||
fn is_cfg_enabled(cfg_options: &CfgOptions, attrs: &Attrs) -> bool {
|
||||
attrs.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false))
|
||||
}
|
||||
|
||||
fn collect_impl_items(
|
||||
db: &dyn DefDatabase,
|
||||
impl_items: impl Iterator<Item = ImplItem>,
|
||||
@ -318,16 +329,26 @@ fn collect_impl_items(
|
||||
id: ImplId,
|
||||
) -> Vec<AssocItemId> {
|
||||
let items = db.ast_id_map(file_id);
|
||||
let crate_graph = db.crate_graph();
|
||||
let module_id = id.lookup(db).container.module(db);
|
||||
|
||||
impl_items
|
||||
.map(|item_node| match item_node {
|
||||
.filter_map(|item_node| match item_node {
|
||||
ast::ImplItem::FnDef(it) => {
|
||||
let def = FunctionLoc {
|
||||
container: AssocContainerId::ImplId(id),
|
||||
ast_id: AstId::new(file_id, items.ast_id(&it)),
|
||||
}
|
||||
.intern(db);
|
||||
def.into()
|
||||
|
||||
if !is_cfg_enabled(
|
||||
&crate_graph[module_id.krate].cfg_options,
|
||||
&db.function_data(def).attrs,
|
||||
) {
|
||||
None
|
||||
} else {
|
||||
Some(def.into())
|
||||
}
|
||||
}
|
||||
ast::ImplItem::ConstDef(it) => {
|
||||
let def = ConstLoc {
|
||||
@ -335,7 +356,7 @@ fn collect_impl_items(
|
||||
ast_id: AstId::new(file_id, items.ast_id(&it)),
|
||||
}
|
||||
.intern(db);
|
||||
def.into()
|
||||
Some(def.into())
|
||||
}
|
||||
ast::ImplItem::TypeAliasDef(it) => {
|
||||
let def = TypeAliasLoc {
|
||||
@ -343,7 +364,7 @@ fn collect_impl_items(
|
||||
ast_id: AstId::new(file_id, items.ast_id(&it)),
|
||||
}
|
||||
.intern(db);
|
||||
def.into()
|
||||
Some(def.into())
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
@ -4,8 +4,7 @@ use std::sync::Arc;
|
||||
|
||||
use hir_def::{path::path, resolver::HasResolver, AdtId, FunctionId};
|
||||
use hir_expand::diagnostics::DiagnosticSink;
|
||||
use ra_syntax::ast;
|
||||
use ra_syntax::AstPtr;
|
||||
use ra_syntax::{ast, AstPtr};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::{
|
||||
|
@ -319,3 +319,33 @@ fn no_such_field_diagnostics() {
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_such_field_with_feature_flag_diagnostics() {
|
||||
let diagnostics = TestDB::with_files(
|
||||
r#"
|
||||
//- /lib.rs crate:foo cfg:feature=foo
|
||||
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 }
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
.diagnostics()
|
||||
.0;
|
||||
|
||||
assert_snapshot!(diagnostics, @r###""###);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user