Skip to content

Commit 0d632be

Browse files
committed
C++: add predicate to distinguish between array/field designators
1 parent 8631371 commit 0d632be

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

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

+43-2
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,29 @@ 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+
* @param field The field being initialized.
235+
*/
236+
predicate isDesignatorInit(Field field, int position) {
237+
field = classType.getAField() and
238+
aggregate_field_init(underlyingElement(this), _, unresolveElement(field), position, true)
217239
}
218240

219241
/**
@@ -304,7 +326,26 @@ class ArrayOrVectorAggregateLiteral extends AggregateLiteral {
304326
* - `a.getElementExpr(0, 2)` gives `789`.
305327
*/
306328
Expr getElementExpr(int elementIndex, int position) {
307-
aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex, position)
329+
aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex, position,
330+
_)
331+
}
332+
333+
/**
334+
* Holds if the `position`-th initialization of the array element at `elementIndex`
335+
* in this aggregate initializer uses a designator (e.g., `[0] = ...`) rather than
336+
* an implicit positional initializer.
337+
*
338+
* For example, in:
339+
* ```c
340+
* int x[] = { [0] = 1, 2 };
341+
* ```
342+
* - `[0] = 1` is a designator init, therefore `isDesignatorInit(0, 0)` holds.
343+
* - `2` is a positional init for `x[1]`, therefore `isDesignatorInit(1, 1)` does **not** hold.
344+
*
345+
* @param elementIndex The index of the array element.
346+
*/
347+
predicate isDesignatorInit(int elementIndex, int position) {
348+
aggregate_array_init(underlyingElement(this), _, elementIndex, position, true)
308349
}
309350

310351
/**

cpp/ql/lib/semmlecode.cpp.dbscheme

+4-2
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 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 designated: boolean ref
20552057
);
20562058

20572059
@ctorinit = @ctordirectinit

0 commit comments

Comments
 (0)