Skip to content

Commit 1d32d36

Browse files
fix: validation of passing enum as var_in_out (#1521)
* fix: validation of passing enum as var_in_out * fix: ensuring variable index entry is stored in hash map if it is a pointer to an enum --------- Co-authored-by: Angus-Bethke-Bachmann <[email protected]>
1 parent efcc614 commit 1d32d36

11 files changed

+582
-4
lines changed

src/index.rs

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,9 +1628,21 @@ impl Index {
16281628

16291629
/// Returns all enum variants of the given variable.
16301630
pub fn get_enum_variants_by_variable(&self, variable: &VariableIndexEntry) -> Vec<&VariableIndexEntry> {
1631-
let Some(var) = self.type_index.find_type(&variable.data_type_name) else { return vec![] };
1632-
let DataTypeInformation::Enum { variants, .. } = var.get_type_information() else { return vec![] };
1633-
variants.iter().collect()
1631+
let Some(datatype) = self.type_index.find_type(&variable.data_type_name) else { return vec![] };
1632+
1633+
self.get_enum_variants(datatype)
1634+
}
1635+
1636+
fn get_enum_variants<'a>(&'a self, datatype: &'a DataType) -> Vec<&'a VariableIndexEntry> {
1637+
match datatype.get_type_information() {
1638+
DataTypeInformation::Enum { variants, .. } => variants.iter().collect(),
1639+
DataTypeInformation::Pointer { name: _, inner_type_name, auto_deref: Some(_), .. } => {
1640+
let Some(inner_type) = self.type_index.find_type(inner_type_name) else { return vec![] };
1641+
1642+
self.get_enum_variants(inner_type)
1643+
}
1644+
_ => vec![],
1645+
}
16341646
}
16351647

16361648
/// Tries to return an enum variant defined within a POU
@@ -1645,7 +1657,18 @@ impl Index {
16451657
pub fn get_enum_variants_in_pou(&self, pou: &str) -> Vec<&VariableIndexEntry> {
16461658
let mut hs: FxHashSet<&VariableIndexEntry> = FxHashSet::default();
16471659
for member in self.get_pou_members(pou) {
1648-
if self.type_index.find_type(member.get_type_name()).is_some_and(|it| it.is_enum()) {
1660+
let Some(data_type) = self.type_index.find_type(member.get_type_name()) else {
1661+
continue;
1662+
};
1663+
let is_enum = match data_type.get_type_information() {
1664+
DataTypeInformation::Enum { .. } => true,
1665+
DataTypeInformation::Pointer { inner_type_name, auto_deref: Some(_), .. } => {
1666+
self.type_index.find_type(inner_type_name).is_some_and(|it| it.is_enum())
1667+
}
1668+
_ => false,
1669+
};
1670+
1671+
if is_enum {
16491672
hs.insert(member);
16501673
}
16511674
}

src/index/tests/index_tests.rs

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2273,3 +2273,271 @@ fn fixed_order() {
22732273
let methods_d = index.get_methods_in_fixed_order("D").iter().map(|p| p.get_name()).collect::<Vec<_>>();
22742274
assert_eq!(methods_d, vec!["C.foo", "A.bar", "D.baz", "D.qux", "C.whateverComesAfterQux", "D.idk"]);
22752275
}
2276+
2277+
#[test]
2278+
fn enum_ensure_standard_variable_can_be_assigned_in_function_block() {
2279+
let (_, index) = index(
2280+
r#"
2281+
TYPE EnumType : (
2282+
red,
2283+
green,
2284+
blue
2285+
);
2286+
END_TYPE
2287+
2288+
FUNCTION_BLOCK fb
2289+
VAR
2290+
myVar : EnumType;
2291+
END_VAR
2292+
myVar := red;
2293+
END_FUNCTION_BLOCK
2294+
"#,
2295+
);
2296+
2297+
let pou_type = index.find_pou_type("fb").unwrap();
2298+
assert!(pou_type.get_type_information().get_size(&index).is_ok());
2299+
2300+
assert!(index.find_local_member("fb", "myVar").is_some());
2301+
2302+
// Evaluate the enum reference
2303+
assert!(index.find_local_member("fb", "red").is_some());
2304+
assert_eq!(index.find_local_member("fb", "red").unwrap().data_type_name, "EnumType");
2305+
}
2306+
2307+
#[test]
2308+
fn enum_ensure_output_variable_can_be_assigned_in_function_block() {
2309+
let (_, index) = index(
2310+
r#"
2311+
TYPE EnumType : (
2312+
red,
2313+
green,
2314+
blue
2315+
);
2316+
END_TYPE
2317+
2318+
FUNCTION_BLOCK fb
2319+
VAR_OUTPUT
2320+
outVar : EnumType;
2321+
END_VAR
2322+
outVar := green;
2323+
END_FUNCTION_BLOCK
2324+
"#,
2325+
);
2326+
2327+
let pou_type = index.find_pou_type("fb").unwrap();
2328+
assert!(pou_type.get_type_information().get_size(&index).is_ok());
2329+
2330+
assert!(index.find_local_member("fb", "outVar").is_some());
2331+
2332+
// Evaluate the enum reference
2333+
assert!(index.find_local_member("fb", "green").is_some());
2334+
assert_eq!(index.find_local_member("fb", "green").unwrap().data_type_name, "EnumType");
2335+
}
2336+
2337+
#[test]
2338+
fn enum_ensure_in_out_variable_can_be_assigned_in_function_block() {
2339+
let (_, index) = index(
2340+
r#"
2341+
TYPE EnumType : (
2342+
red,
2343+
green,
2344+
blue
2345+
);
2346+
END_TYPE
2347+
2348+
FUNCTION_BLOCK fb
2349+
VAR_IN_OUT
2350+
inOutVar : EnumType;
2351+
END_VAR
2352+
inOutVar := blue;
2353+
END_FUNCTION_BLOCK
2354+
"#,
2355+
);
2356+
2357+
let pou_type = index.find_pou_type("fb").unwrap();
2358+
assert!(pou_type.get_type_information().get_size(&index).is_ok());
2359+
2360+
assert!(index.find_local_member("fb", "inOutVar").is_some());
2361+
2362+
// Evaluate the enum reference
2363+
assert!(index.find_local_member("fb", "blue").is_some());
2364+
assert_eq!(index.find_local_member("fb", "blue").unwrap().data_type_name, "EnumType");
2365+
}
2366+
2367+
#[test]
2368+
fn enum_ensure_a_combination_of_variables_can_be_assigned_in_function_block() {
2369+
let (_, index) = index(
2370+
r#"
2371+
TYPE EnumType : (
2372+
red,
2373+
green,
2374+
blue
2375+
);
2376+
END_TYPE
2377+
2378+
FUNCTION_BLOCK fb
2379+
VAR
2380+
myVar : EnumType;
2381+
END_VAR
2382+
VAR_OUTPUT
2383+
outVar : EnumType;
2384+
END_VAR
2385+
VAR_IN_OUT
2386+
inOutVar : EnumType;
2387+
END_VAR
2388+
myVar := red;
2389+
outVar := green;
2390+
inOutVar := blue;
2391+
END_FUNCTION_BLOCK
2392+
"#,
2393+
);
2394+
2395+
let pou_type = index.find_pou_type("fb").unwrap();
2396+
assert!(pou_type.get_type_information().get_size(&index).is_ok());
2397+
2398+
assert!(index.find_local_member("fb", "myVar").is_some());
2399+
assert!(index.find_local_member("fb", "outVar").is_some());
2400+
assert!(index.find_local_member("fb", "inOutVar").is_some());
2401+
2402+
// Evaluate the enum reference
2403+
assert!(index.find_local_member("fb", "red").is_some());
2404+
assert_eq!(index.find_local_member("fb", "red").unwrap().data_type_name, "EnumType");
2405+
assert!(index.find_local_member("fb", "green").is_some());
2406+
assert_eq!(index.find_local_member("fb", "green").unwrap().data_type_name, "EnumType");
2407+
assert!(index.find_local_member("fb", "blue").is_some());
2408+
assert_eq!(index.find_local_member("fb", "blue").unwrap().data_type_name, "EnumType");
2409+
}
2410+
2411+
#[test]
2412+
fn enum_ensure_standard_variable_can_be_assigned_in_function() {
2413+
let (_, index) = index(
2414+
r#"
2415+
TYPE EnumType : (
2416+
red,
2417+
green,
2418+
blue
2419+
);
2420+
END_TYPE
2421+
2422+
FUNCTION fn : INT
2423+
VAR
2424+
myVar : EnumType;
2425+
END_VAR
2426+
myVar := red;
2427+
END_FUNCTION
2428+
"#,
2429+
);
2430+
2431+
let pou_type = index.find_pou_type("fn").unwrap();
2432+
assert!(pou_type.get_type_information().get_size(&index).is_ok());
2433+
2434+
assert!(index.find_local_member("fn", "myVar").is_some());
2435+
2436+
// Evaluate the enum reference
2437+
assert!(index.find_local_member("fn", "red").is_some());
2438+
assert_eq!(index.find_local_member("fn", "red").unwrap().data_type_name, "EnumType");
2439+
}
2440+
2441+
#[test]
2442+
fn enum_ensure_output_variable_can_be_assigned_in_function() {
2443+
let (_, index) = index(
2444+
r#"
2445+
TYPE EnumType : (
2446+
red,
2447+
green,
2448+
blue
2449+
);
2450+
END_TYPE
2451+
2452+
FUNCTION fn : INT
2453+
VAR_OUTPUT
2454+
outVar : EnumType;
2455+
END_VAR
2456+
outVar := green;
2457+
END_FUNCTION
2458+
"#,
2459+
);
2460+
2461+
let pou_type = index.find_pou_type("fn").unwrap();
2462+
assert!(pou_type.get_type_information().get_size(&index).is_ok());
2463+
2464+
assert!(index.find_local_member("fn", "outVar").is_some());
2465+
2466+
// Evaluate the enum reference
2467+
assert!(index.find_local_member("fn", "green").is_some());
2468+
assert_eq!(index.find_local_member("fn", "green").unwrap().data_type_name, "EnumType");
2469+
}
2470+
2471+
#[test]
2472+
fn enum_ensure_in_out_variable_can_be_assigned_in_function() {
2473+
let (_, index) = index(
2474+
r#"
2475+
TYPE EnumType : (
2476+
red,
2477+
green,
2478+
blue
2479+
);
2480+
END_TYPE
2481+
2482+
FUNCTION fn : INT
2483+
VAR_IN_OUT
2484+
inOutVar : EnumType;
2485+
END_VAR
2486+
inOutVar := blue;
2487+
END_FUNCTION
2488+
"#,
2489+
);
2490+
2491+
let pou_type = index.find_pou_type("fn").unwrap();
2492+
assert!(pou_type.get_type_information().get_size(&index).is_ok());
2493+
2494+
assert!(index.find_local_member("fn", "inOutVar").is_some());
2495+
2496+
// Evaluate the enum reference
2497+
assert!(index.find_local_member("fn", "blue").is_some());
2498+
assert_eq!(index.find_local_member("fn", "blue").unwrap().data_type_name, "EnumType");
2499+
}
2500+
2501+
#[test]
2502+
fn enum_ensure_a_combination_of_variables_can_be_assigned_in_function() {
2503+
let (_, index) = index(
2504+
r#"
2505+
TYPE EnumType : (
2506+
red,
2507+
green,
2508+
blue
2509+
);
2510+
END_TYPE
2511+
2512+
FUNCTION fn : INT
2513+
VAR
2514+
myVar : EnumType;
2515+
END_VAR
2516+
VAR_OUTPUT
2517+
outVar : EnumType;
2518+
END_VAR
2519+
VAR_IN_OUT
2520+
inOutVar : EnumType;
2521+
END_VAR
2522+
myVar := red;
2523+
outVar := green;
2524+
inOutVar := blue;
2525+
END_FUNCTION
2526+
"#,
2527+
);
2528+
2529+
let pou_type = index.find_pou_type("fn").unwrap();
2530+
assert!(pou_type.get_type_information().get_size(&index).is_ok());
2531+
2532+
assert!(index.find_local_member("fn", "myVar").is_some());
2533+
assert!(index.find_local_member("fn", "outVar").is_some());
2534+
assert!(index.find_local_member("fn", "inOutVar").is_some());
2535+
2536+
// Evaluate the enum reference
2537+
assert!(index.find_local_member("fn", "red").is_some());
2538+
assert_eq!(index.find_local_member("fn", "red").unwrap().data_type_name, "EnumType");
2539+
assert!(index.find_local_member("fn", "green").is_some());
2540+
assert_eq!(index.find_local_member("fn", "green").unwrap().data_type_name, "EnumType");
2541+
assert!(index.find_local_member("fn", "blue").is_some());
2542+
assert_eq!(index.find_local_member("fn", "blue").unwrap().data_type_name, "EnumType");
2543+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: (%COMPILE %s && %RUN) | %CHECK %s
2+
3+
TYPE EnumType : (
4+
red,
5+
green,
6+
blue
7+
);
8+
END_TYPE
9+
10+
FUNCTION fn : INT
11+
VAR
12+
myVar : EnumType;
13+
END_VAR
14+
VAR_OUTPUT
15+
outVar : EnumType;
16+
END_VAR
17+
VAR_IN_OUT
18+
inOutVar : EnumType;
19+
END_VAR
20+
myVar := red;
21+
outVar := green;
22+
inOutVar := blue;
23+
END_FUNCTION
24+
25+
PROGRAM prog
26+
VAR
27+
inOutVar : EnumType;
28+
outVar: EnumType;
29+
END_VAR
30+
fn(outVar, inOutVar);
31+
32+
// CHECK: 1
33+
printf('%d$N', outVar);
34+
// CHECK: 2
35+
printf('%d$N', inOutVar);
36+
END_PROGRAM
37+
38+
FUNCTION main
39+
prog();
40+
END_FUNCTION
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: (%COMPILE %s && %RUN) | %CHECK %s
2+
3+
TYPE EnumType : (
4+
red,
5+
green,
6+
blue
7+
);
8+
END_TYPE
9+
10+
FUNCTION_BLOCK fb
11+
VAR
12+
myVar : EnumType;
13+
END_VAR
14+
VAR_OUTPUT
15+
outVar : EnumType;
16+
END_VAR
17+
VAR_IN_OUT
18+
inOutVar : EnumType;
19+
END_VAR
20+
myVar := red;
21+
outVar := green;
22+
inOutVar := blue;
23+
END_FUNCTION_BLOCK
24+
25+
PROGRAM prog
26+
VAR
27+
inOutVar : EnumType;
28+
outVar: EnumType;
29+
fb : fb;
30+
END_VAR
31+
fb(outVar, inOutVar);
32+
33+
// CHECK: 1
34+
printf('%d$N', outVar);
35+
// CHECK: 2
36+
printf('%d$N', inOutVar);
37+
END_PROGRAM
38+
39+
FUNCTION main
40+
prog();
41+
END_FUNCTION

0 commit comments

Comments
 (0)