Skip to content

Commit 9105fee

Browse files
committed
Find references of user defined attribute
1 parent 4932d11 commit 9105fee

File tree

8 files changed

+67
-10
lines changed

8 files changed

+67
-10
lines changed

vhdl_lang/src/analysis/named_entity/attribute.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,9 @@ impl<'a> AttributeEnt<'a> {
4242
}
4343
}
4444
}
45+
46+
impl<'a> From<AttributeEnt<'a>> for EntRef<'a> {
47+
fn from(value: AttributeEnt<'a>) -> Self {
48+
value.ent
49+
}
50+
}

vhdl_lang/src/analysis/names.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -944,9 +944,10 @@ impl<'a> AnalyzeContext<'a> {
944944
}
945945
}
946946

947-
AttributeDesignator::Ident(ref sym) => {
947+
AttributeDesignator::Ident(ref mut sym) => {
948948
if let Some(actual) = prefix.as_actual_entity() {
949-
if let Some(attr) = actual.get_attribute(sym) {
949+
if let Some(attr) = actual.get_attribute(&sym.item) {
950+
sym.set_unique_reference(attr.into());
950951
Ok(AttrResolveResult::Value(attr.typ().base()))
951952
} else {
952953
diagnostics.error(

vhdl_lang/src/analysis/tests/custom_attributes.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//
55
// Copyright (c) 2023, Olof Kraigher olof.kraigher@gmail.com
66

7+
use itertools::Itertools;
8+
79
use super::*;
810

911
#[test]
@@ -126,6 +128,40 @@ end architecture;
126128
check_no_diagnostics(&diagnostics);
127129
}
128130

131+
#[test]
132+
fn finds_references_of_custom_attributes() {
133+
let mut builder = LibraryBuilder::new();
134+
let code = builder.code(
135+
"libname",
136+
"
137+
entity ent is
138+
attribute myattr : boolean;
139+
attribute myattr of ent : entity is false;
140+
end entity;
141+
142+
architecture a of ent is
143+
constant c0 : boolean := ent'myattr;
144+
begin
145+
end architecture;
146+
",
147+
);
148+
149+
let (root, diagnostics) = builder.get_analyzed_root();
150+
check_no_diagnostics(&diagnostics);
151+
152+
assert_eq!(
153+
root.find_all_references_pos(&code.s1("myattr").pos()),
154+
vec![
155+
code.s1("attribute myattr : boolean"),
156+
code.s1("myattr of ent"),
157+
code.s1("ent'myattr"),
158+
]
159+
.into_iter()
160+
.map(|c| c.s1("myattr").pos())
161+
.collect_vec()
162+
);
163+
}
164+
129165
#[test]
130166
fn invalid_prefix_for_custom_attribute() {
131167
let mut builder = LibraryBuilder::new();

vhdl_lang/src/ast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub enum RangeAttribute {
111111
pub enum AttributeDesignator {
112112
Type(TypeAttribute),
113113
Range(RangeAttribute),
114-
Ident(Symbol),
114+
Ident(WithRef<Symbol>),
115115
Ascending,
116116
Descending,
117117
Left,
@@ -436,7 +436,7 @@ pub enum Designator {
436436
pub type Reference = Option<EntityId>;
437437

438438
/// An item which has a reference to a declaration
439-
#[derive(PartialEq, Debug, Clone)]
439+
#[derive(PartialEq, Eq, Debug, Clone)]
440440
pub struct WithRef<T> {
441441
pub item: T,
442442
pub reference: Reference,

vhdl_lang/src/ast/search.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,8 +628,17 @@ fn search_pos_name(
628628
Name::CallOrIndexed(ref mut fcall) => fcall.search(ctx, searcher),
629629
Name::Attribute(ref mut attr) => {
630630
// @TODO more
631-
let AttributeName { name, expr, .. } = attr.as_mut();
631+
let AttributeName {
632+
name, expr, attr, ..
633+
} = attr.as_mut();
632634
return_if_found!(name.search(ctx, searcher));
635+
if let AttributeDesignator::Ident(ref mut user_attr) = attr.item {
636+
return_if_finished!(searcher.search_pos_with_ref(
637+
ctx,
638+
&attr.pos,
639+
&mut user_attr.reference
640+
));
641+
}
633642
if let Some(expr) = expr {
634643
return_if_found!(expr.search(ctx, searcher));
635644
}

vhdl_lang/src/syntax/names.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ mod tests {
724724
let attr = WithPos {
725725
item: Name::Attribute(Box::new(AttributeName {
726726
name: prefix,
727-
attr: code.s1("foo").ident().map_into(AttributeDesignator::Ident),
727+
attr: code.s1("foo").attr_ident(),
728728
signature: None,
729729
expr: None,
730730
})),
@@ -855,7 +855,7 @@ mod tests {
855855
let attr = WithPos {
856856
item: Name::Attribute(Box::new(AttributeName {
857857
name: prefix,
858-
attr: code.s1("foo").ident().map_into(AttributeDesignator::Ident),
858+
attr: code.s1("foo").attr_ident(),
859859
signature: None,
860860
expr: Some(Box::new(code.s1("expr+1").expr())),
861861
})),
@@ -874,7 +874,7 @@ mod tests {
874874
let attr = WithPos {
875875
item: Name::Attribute(Box::new(AttributeName {
876876
name: prefix,
877-
attr: code.s1("foo").ident().map_into(AttributeDesignator::Ident),
877+
attr: code.s1("foo").attr_ident(),
878878
signature: Some(code.s1("[return natural]").signature()),
879879
expr: Some(Box::new(code.s1("expr+1").expr())),
880880
})),

vhdl_lang/src/syntax/test.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,11 @@ impl Code {
459459
self.parse_ok(|stream: &TokenStream| stream.expect_ident())
460460
}
461461

462+
pub fn attr_ident(&self) -> WithPos<AttributeDesignator> {
463+
self.parse_ok(|stream: &TokenStream| stream.expect_ident())
464+
.map_into(|i| AttributeDesignator::Ident(WithRef::new(i)))
465+
}
466+
462467
pub fn decl_ident(&self) -> WithDecl<Ident> {
463468
WithDecl::new(self.parse_ok(|stream: &TokenStream| stream.expect_ident()))
464469
}

vhdl_lang/src/syntax/tokens/tokenizer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use fnv::FnvHashMap;
88

9-
use crate::ast::{self, AttributeDesignator, Operator};
9+
use crate::ast::{self, AttributeDesignator, Operator, WithRef};
1010
use crate::ast::{BaseSpecifier, Ident};
1111
use crate::data::*;
1212

@@ -1668,7 +1668,7 @@ impl<'a> Tokenizer<'a> {
16681668
.attributes
16691669
.get(&sym)
16701670
.cloned()
1671-
.unwrap_or_else(|| AttributeDesignator::Ident(sym))
1671+
.unwrap_or_else(|| AttributeDesignator::Ident(WithRef::new(sym)))
16721672
}
16731673

16741674
fn parse_token(&mut self) -> Result<Option<(Kind, Value)>, TokenError> {

0 commit comments

Comments
 (0)