Skip to content

Commit edeeb7a

Browse files
committed
Find references to end-identifiers and end-labels
1 parent a9ba97b commit edeeb7a

19 files changed

+1046
-461
lines changed

vhdl_lang/src/analysis/concurrent.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ impl<'a> AnalyzeContext<'a> {
8080
sensitivity_list,
8181
decl,
8282
statements,
83+
end_label_pos: _,
8384
} = process;
8485
if let Some(sensitivity_list) = sensitivity_list {
8586
match sensitivity_list {
@@ -104,6 +105,7 @@ impl<'a> AnalyzeContext<'a> {
104105
index_name,
105106
discrete_range,
106107
body,
108+
end_label_pos: _,
107109
} = gen;
108110
let typ = as_fatal(self.drange_type(scope, discrete_range, diagnostics))?;
109111
let nested = scope.nested();
@@ -117,7 +119,7 @@ impl<'a> AnalyzeContext<'a> {
117119
let Conditionals {
118120
conditionals,
119121
else_item,
120-
} = gen;
122+
} = &mut gen.conds;
121123
for conditional in conditionals.iter_mut() {
122124
let Conditional { condition, item } = conditional;
123125
self.boolean_expr(scope, condition, diagnostics)?;
@@ -130,7 +132,7 @@ impl<'a> AnalyzeContext<'a> {
130132
}
131133
}
132134
ConcurrentStatement::CaseGenerate(ref mut gen) => {
133-
for alternative in gen.alternatives.iter_mut() {
135+
for alternative in gen.sels.alternatives.iter_mut() {
134136
let nested = scope.nested();
135137
self.analyze_generate_body(&nested, &mut alternative.item, diagnostics)?;
136138
}
@@ -185,6 +187,7 @@ impl<'a> AnalyzeContext<'a> {
185187
alternative_label,
186188
decl,
187189
statements,
190+
end_label_pos: _,
188191
} = body;
189192
if let Some(label) = alternative_label {
190193
scope.add(label.define(self.arena, AnyEntKind::Label), diagnostics);

vhdl_lang/src/analysis/named_entity.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,14 @@ impl<'a> AnyEnt<'a> {
210210
self.id
211211
}
212212

213+
pub fn declaration(&'a self) -> EntRef<'a> {
214+
if let Related::DeclaredBy(other) = self.related {
215+
other
216+
} else {
217+
self
218+
}
219+
}
220+
213221
pub fn is_implicit(&self) -> bool {
214222
match self.related {
215223
Related::ImplicitOf(_) => true,

vhdl_lang/src/analysis/root.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,8 @@ impl DesignRoot {
369369
let mut searcher = ItemAtCursor::new(source, cursor);
370370
let _ = self.search(&mut searcher);
371371
let id = searcher.result?;
372-
Some(self.get_ent(id))
372+
let ent = self.get_ent(id);
373+
Some(ent)
373374
}
374375

375376
pub fn find_definition_of<'a>(&'a self, decl: EntRef<'a>) -> Option<EntRef<'a>> {

vhdl_lang/src/analysis/sequential.rs

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ impl<'a> AnalyzeContext<'a> {
2929

3030
match statement.statement {
3131
SequentialStatement::If(ref mut ifstmt) => {
32-
let IfStatement {
32+
let Conditionals {
3333
conditionals,
3434
else_item,
35-
} = ifstmt;
35+
} = &mut ifstmt.conds;
3636

3737
for conditional in conditionals {
3838
self.define_labels_for_sequential_part(
@@ -143,30 +143,36 @@ impl<'a> AnalyzeContext<'a> {
143143
SequentialStatement::Exit(ref mut exit_stmt) => {
144144
let ExitStatement {
145145
condition,
146-
// @TODO loop label
147-
..
146+
loop_label,
148147
} = exit_stmt;
149148

149+
if let Some(ref mut loop_label) = loop_label {
150+
self.check_loop_label(scope, loop_label, diagnostics);
151+
}
152+
150153
if let Some(expr) = condition {
151154
self.boolean_expr(scope, expr, diagnostics)?;
152155
}
153156
}
154157
SequentialStatement::Next(ref mut next_stmt) => {
155158
let NextStatement {
156159
condition,
157-
// @TODO loop label
158-
..
160+
loop_label,
159161
} = next_stmt;
160162

163+
if let Some(ref mut loop_label) = loop_label {
164+
self.check_loop_label(scope, loop_label, diagnostics);
165+
}
166+
161167
if let Some(expr) = condition {
162168
self.boolean_expr(scope, expr, diagnostics)?;
163169
}
164170
}
165171
SequentialStatement::If(ref mut ifstmt) => {
166-
let IfStatement {
172+
let Conditionals {
167173
conditionals,
168174
else_item,
169-
} = ifstmt;
175+
} = &mut ifstmt.conds;
170176

171177
// @TODO write generic function for this
172178
for conditional in conditionals {
@@ -183,6 +189,7 @@ impl<'a> AnalyzeContext<'a> {
183189
is_matching: _,
184190
expression,
185191
alternatives,
192+
end_label_pos: _,
186193
} = case_stmt;
187194
let ctyp = as_fatal(self.expr_unambiguous_type(scope, expression, diagnostics))?;
188195
for alternative in alternatives.iter_mut() {
@@ -195,6 +202,7 @@ impl<'a> AnalyzeContext<'a> {
195202
let LoopStatement {
196203
iteration_scheme,
197204
statements,
205+
end_label_pos: _,
198206
} = loop_stmt;
199207
match iteration_scheme {
200208
Some(IterationScheme::For(ref mut index, ref mut drange)) => {
@@ -265,6 +273,39 @@ impl<'a> AnalyzeContext<'a> {
265273
Ok(())
266274
}
267275

276+
fn check_loop_label(
277+
&self,
278+
scope: &Scope<'a>,
279+
label: &mut WithRef<Ident>,
280+
diagnostics: &mut dyn DiagnosticHandler,
281+
) {
282+
match scope.lookup(
283+
&label.item.pos,
284+
&Designator::Identifier(label.item.item.clone()),
285+
) {
286+
Ok(NamedEntities::Single(ent)) => {
287+
label.set_unique_reference(ent);
288+
if !matches!(ent.kind(), AnyEntKind::Label) {
289+
// @TODO check that is actually a loop label and that we are inside the loop
290+
diagnostics.error(
291+
&label.item.pos,
292+
format!("Expected loop label, got {}", ent.describe()),
293+
);
294+
}
295+
}
296+
Ok(NamedEntities::Overloaded(_)) => diagnostics.error(
297+
&label.item.pos,
298+
format!(
299+
"Expected loop label, got overloaded name {}",
300+
&label.item.item
301+
),
302+
),
303+
Err(diag) => {
304+
diagnostics.push(diag);
305+
}
306+
}
307+
}
308+
268309
pub fn analyze_sequential_part(
269310
&self,
270311
scope: &Scope<'a>,

vhdl_lang/src/analysis/tests/resolves_names.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,9 @@ package body pkg is
516516
517517
proc2(i); -- Index is defined
518518
missing;
519+
520+
exit missing;
521+
next missing;
519522
end loop;
520523
521524
@@ -1900,3 +1903,133 @@ end architecture;
19001903
Some(&code.s("a2", 1).pos())
19011904
);
19021905
}
1906+
1907+
#[test]
1908+
fn find_end_identifier_references_of_declarations() {
1909+
for name in [
1910+
"ent1", "a1", "rec_t", "prot_t", "phys_t", "fun1", "proc1", "comp1", "pkg", "cfg1", "ctx1",
1911+
] {
1912+
check_search_reference_with_name(
1913+
name,
1914+
"
1915+
entity ent1 is
1916+
end entity ent1;
1917+
1918+
architecture a1 of ent1 is
1919+
1920+
type rec_t is record
1921+
field: natural;
1922+
end record rec_t;
1923+
1924+
type prot_t is protected
1925+
end protected prot_t;
1926+
1927+
type prot_t is protected body
1928+
end protected body prot_t;
1929+
1930+
type phys_t is range 0 to 10
1931+
units
1932+
bangs;
1933+
bugs = 10 bangs;
1934+
end units phys_t;
1935+
1936+
function fun1 return integer is
1937+
begin
1938+
end function fun1;
1939+
1940+
procedure proc1 is
1941+
begin
1942+
end procedure proc1;
1943+
1944+
component comp1 is
1945+
end component comp1;
1946+
begin
1947+
end architecture a1;
1948+
1949+
package pkg is
1950+
end package pkg;
1951+
1952+
package body pkg is
1953+
end package body pkg;
1954+
1955+
configuration cfg1 of ent1 is
1956+
for rtl(0)
1957+
end for;
1958+
end configuration cfg1;
1959+
1960+
context ctx1 is
1961+
end context ctx1;
1962+
",
1963+
);
1964+
}
1965+
}
1966+
1967+
#[test]
1968+
fn find_end_identifier_references_of_concurrent() {
1969+
for name in ["b1", "p1", "fg1", "ig1", "ialt1", "cg1", "cgalt1"] {
1970+
check_search_reference_with_name(
1971+
name,
1972+
"
1973+
entity ent1 is
1974+
end entity ent1;
1975+
1976+
architecture a1 of ent1 is
1977+
begin
1978+
b1: block
1979+
begin
1980+
end block b1;
1981+
1982+
p1: process
1983+
begin
1984+
end process p1;
1985+
1986+
fg1: for i in 0 to 10 generate
1987+
end generate fg1;
1988+
1989+
ig1: if true generate
1990+
else ialt1: generate
1991+
end ialt1;
1992+
end generate ig1;
1993+
1994+
cg1: case 0 generate
1995+
when cgalt1: 0 =>
1996+
assert false;
1997+
end cgalt1;
1998+
end generate cg1;
1999+
2000+
end architecture;
2001+
",
2002+
);
2003+
}
2004+
}
2005+
2006+
#[test]
2007+
fn find_end_identifier_references_of_sequential() {
2008+
for name in ["if0", "loop0", "c0"] {
2009+
check_search_reference_with_name(
2010+
name,
2011+
"
2012+
entity ent1 is
2013+
end entity ent1;
2014+
2015+
architecture a1 of ent1 is
2016+
begin
2017+
process
2018+
begin
2019+
if0: if true then
2020+
end if if0;
2021+
2022+
loop0: for i in 0 to 1 loop
2023+
next loop0;
2024+
exit loop0;
2025+
end loop loop0;
2026+
2027+
c0: case 0 is
2028+
when others =>
2029+
end case c0;
2030+
end process;
2031+
end architecture;
2032+
",
2033+
);
2034+
}
2035+
}

vhdl_lang/src/analysis/tests/util.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,10 @@ pub fn check_search_reference_with_name(decl_name: &str, contents: &str) {
224224
let mut references = Vec::new();
225225
for idx in 1..=occurences {
226226
assert_eq!(
227-
root.search_reference_pos(code.source(), code.s(decl_name, idx).end()),
227+
root.search_reference(code.source(), code.s(decl_name, idx).end())
228+
.and_then(|ent| ent.declaration().decl_pos().cloned()),
228229
Some(code.s(decl_name, 1).pos()),
229-
"{}",
230+
"{decl_name}, occurence {}",
230231
idx
231232
);
232233
references.push(code.s(decl_name, idx).pos());

0 commit comments

Comments
 (0)