Skip to content

Commit 49183bb

Browse files
committed
C++: add predicate to distinguish between array/field designators
1 parent e05c030 commit 49183bb

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

cpp/ql/lib/semmle/code/cpp/exprs/Literal.qll

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,27 @@ class ClassAggregateLiteral extends AggregateLiteral {
213213
Expr getFieldExpr(Field field, int position) {
214214
field = classType.getAField() and
215215
aggregate_field_init(underlyingElement(this), unresolveElement(result), unresolveElement(field),
216-
position)
216+
position, _)
217+
}
218+
219+
/**
220+
* Holds if the `position`-th initialization of `field` in this aggregate initializer
221+
* uses a designator (e.g., `.x =`, `[42] =`) rather than a positional initializer.
222+
*
223+
* This can be used to distinguish explicitly designated initializations from
224+
* implicit positional ones.
225+
*
226+
* For example, in the initializer:
227+
* ```c
228+
* struct S { int x, y; };
229+
* struct S s = { .x = 1, 2 };
230+
* ```
231+
* - `.x = 1` is a designator init, therefore `isDesignatorInit(x, 0)` holds.
232+
* - `2` is a positional init for `.y`, therefore `isDesignatorInit(y, 1)` does **not** hold.
233+
*/
234+
predicate isDesignatorInit(Field field, int position) {
235+
field = classType.getAField() and
236+
aggregate_field_init(underlyingElement(this), _, unresolveElement(field), position, true)
217237
}
218238

219239
/**
@@ -304,7 +324,24 @@ class ArrayOrVectorAggregateLiteral extends AggregateLiteral {
304324
* - `a.getElementExpr(0, 2)` gives `789`.
305325
*/
306326
Expr getElementExpr(int elementIndex, int position) {
307-
aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex, position)
327+
aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex, position,
328+
_)
329+
}
330+
331+
/**
332+
* Holds if the `position`-th initialization of the array element at `elementIndex`
333+
* in this aggregate initializer uses a designator (e.g., `[0] = ...`) rather than
334+
* an implicit positional initializer.
335+
*
336+
* For example, in:
337+
* ```c
338+
* int x[] = { [0] = 1, 2 };
339+
* ```
340+
* - `[0] = 1` is a designator init, therefore `isDesignatorInit(0, 0)` holds.
341+
* - `2` is a positional init for `x[1]`, therefore `isDesignatorInit(1, 1)` does **not** hold.
342+
*/
343+
predicate isDesignatorInit(int elementIndex, int position) {
344+
aggregate_array_init(underlyingElement(this), _, elementIndex, position, true)
308345
}
309346

310347
/**

cpp/ql/lib/semmlecode.cpp.dbscheme

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,7 +2039,8 @@ aggregate_field_init(
20392039
int aggregate: @aggregateliteral ref,
20402040
int initializer: @expr ref,
20412041
int field: @membervariable ref,
2042-
int position: int ref
2042+
int position: int ref,
2043+
boolean is_designated: boolean ref
20432044
);
20442045

20452046
/**
@@ -2051,7 +2052,8 @@ aggregate_array_init(
20512052
int aggregate: @aggregateliteral ref,
20522053
int initializer: @expr ref,
20532054
int element_index: int ref,
2054-
int position: int ref
2055+
int position: int ref,
2056+
boolean is_designated: boolean ref
20552057
);
20562058

20572059
@ctorinit = @ctordirectinit

0 commit comments

Comments
 (0)