feat: add attributes support on struct fields #3870
Signed-off-by: Benjamin Coenen <5719034+bnjjj@users.noreply.github.com>
This commit is contained in:
parent
f6d688d130
commit
ab864ed259
@ -4,17 +4,19 @@ use std::sync::Arc;
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::{
|
||||
hygiene::Hygiene,
|
||||
name::{AsName, Name},
|
||||
InFile,
|
||||
};
|
||||
use ra_arena::{map::ArenaMap, Arena};
|
||||
use ra_cfg::CfgOptions;
|
||||
use ra_prof::profile;
|
||||
use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner};
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, type_ref::TypeRef,
|
||||
visibility::RawVisibility, EnumId, LocalEnumVariantId, LocalStructFieldId, Lookup, StructId,
|
||||
UnionId, VariantId,
|
||||
attr::Attrs, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace,
|
||||
type_ref::TypeRef, visibility::RawVisibility, EnumId, LocalEnumVariantId, LocalStructFieldId,
|
||||
Lookup, StructId, UnionId, VariantId,
|
||||
};
|
||||
|
||||
/// Note that we use `StructData` for unions as well!
|
||||
@ -49,11 +51,14 @@ pub struct StructFieldData {
|
||||
pub name: Name,
|
||||
pub type_ref: TypeRef,
|
||||
pub visibility: RawVisibility,
|
||||
pub attrs: Attrs,
|
||||
// TODO: add attributes
|
||||
}
|
||||
|
||||
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);
|
||||
@ -181,6 +186,10 @@ pub enum StructKind {
|
||||
Unit,
|
||||
}
|
||||
|
||||
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 lower_struct(
|
||||
db: &dyn DefDatabase,
|
||||
trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>,
|
||||
@ -189,12 +198,21 @@ fn lower_struct(
|
||||
match &ast.value {
|
||||
ast::StructKind::Tuple(fl) => {
|
||||
for (i, fd) in fl.fields().enumerate() {
|
||||
let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id));
|
||||
|
||||
// Need verification about parent cfg_options and current with current attributes
|
||||
// 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
|
||||
// if !is_cfg_enabled(&crate_graph[module_id.krate].cfg_options, &attrs) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
trace.alloc(
|
||||
|| Either::Left(fd.clone()),
|
||||
|| StructFieldData {
|
||||
name: Name::new_tuple_field(i),
|
||||
type_ref: TypeRef::from_ast_opt(fd.type_ref()),
|
||||
visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
|
||||
attrs: Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id)),
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -202,12 +220,19 @@ fn lower_struct(
|
||||
}
|
||||
ast::StructKind::Record(fl) => {
|
||||
for fd in fl.fields() {
|
||||
let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id));
|
||||
// Need verification about parent cfg_options and current with current attributes
|
||||
// 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
|
||||
// if !is_cfg_enabled(&crate_graph[module_id.krate].cfg_options, &attrs) {
|
||||
// continue;
|
||||
// }
|
||||
trace.alloc(
|
||||
|| Either::Right(fd.clone()),
|
||||
|| StructFieldData {
|
||||
name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
|
||||
type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
|
||||
visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
|
||||
attrs: Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id)),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use hir_expand::{
|
||||
hygiene::Hygiene,
|
||||
name::{name, AsName, Name},
|
||||
AstId, InFile,
|
||||
};
|
||||
@ -12,6 +13,7 @@ use ra_syntax::ast::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
attr::Attrs,
|
||||
db::DefDatabase,
|
||||
path::{path, GenericArgs, Path},
|
||||
src::HasSource,
|
||||
@ -26,6 +28,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 +66,7 @@ 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 +85,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)
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,7 @@ use hir_def::{
|
||||
AdtId, FunctionId,
|
||||
};
|
||||
use hir_expand::{diagnostics::DiagnosticSink, name::Name};
|
||||
use ra_syntax::ast;
|
||||
use ra_syntax::AstPtr;
|
||||
use ra_syntax::{ast, AstPtr};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
use crate::{
|
||||
@ -82,7 +81,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
|
||||
|
||||
let variant_data = variant_data(db.upcast(), variant_def);
|
||||
|
||||
let lit_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
|
||||
let lit_fields: FxHashSet<_> = fields
|
||||
.iter()
|
||||
.filter_map(|f| {
|
||||
// TODO: check if cfg_is_enabled with .attrs ?
|
||||
|
||||
Some(&f.name)
|
||||
})
|
||||
.collect();
|
||||
let missed_fields: Vec<Name> = variant_data
|
||||
.fields()
|
||||
.iter()
|
||||
|
@ -318,3 +318,32 @@ fn no_such_field_diagnostics() {
|
||||
"###
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_such_field_with_feature_flag_diagnostics() {
|
||||
let diagnostics = TestDB::with_files(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
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();
|
||||
|
||||
assert_snapshot!(diagnostics, "");
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user