diff --git a/cpp/ql/lib/semmle/code/cpp/exprs/Literal.qll b/cpp/ql/lib/semmle/code/cpp/exprs/Literal.qll index a36758417bb..fb79988c10f 100644 --- a/cpp/ql/lib/semmle/code/cpp/exprs/Literal.qll +++ b/cpp/ql/lib/semmle/code/cpp/exprs/Literal.qll @@ -213,7 +213,27 @@ class ClassAggregateLiteral extends AggregateLiteral { Expr getFieldExpr(Field field, int position) { field = classType.getAField() and aggregate_field_init(underlyingElement(this), unresolveElement(result), unresolveElement(field), - position) + position, _) + } + + /** + * Holds if the `position`-th initialization of `field` in this aggregate initializer + * uses a designator (e.g., `.x =`, `[42] =`) rather than a positional initializer. + * + * This can be used to distinguish explicitly designated initializations from + * implicit positional ones. + * + * For example, in the initializer: + * ```c + * struct S { int x, y; }; + * struct S s = { .x = 1, 2 }; + * ``` + * - `.x = 1` is a designator init, therefore `isDesignatorInit(x, 0)` holds. + * - `2` is a positional init for `.y`, therefore `isDesignatorInit(y, 1)` does **not** hold. + */ + predicate isDesignatorInit(Field field, int position) { + field = classType.getAField() and + aggregate_field_init(underlyingElement(this), _, unresolveElement(field), position, true) } /** @@ -304,7 +324,24 @@ class ArrayOrVectorAggregateLiteral extends AggregateLiteral { * - `a.getElementExpr(0, 2)` gives `789`. */ Expr getElementExpr(int elementIndex, int position) { - aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex, position) + aggregate_array_init(underlyingElement(this), unresolveElement(result), elementIndex, position, + _) + } + + /** + * Holds if the `position`-th initialization of the array element at `elementIndex` + * in this aggregate initializer uses a designator (e.g., `[0] = ...`) rather than + * an implicit positional initializer. + * + * For example, in: + * ```c + * int x[] = { [0] = 1, 2 }; + * ``` + * - `[0] = 1` is a designator init, therefore `isDesignatorInit(0, 0)` holds. + * - `2` is a positional init for `x[1]`, therefore `isDesignatorInit(1, 1)` does **not** hold. + */ + predicate isDesignatorInit(int elementIndex, int position) { + aggregate_array_init(underlyingElement(this), _, elementIndex, position, true) } /** diff --git a/cpp/ql/lib/semmlecode.cpp.dbscheme b/cpp/ql/lib/semmlecode.cpp.dbscheme index 0f0a390468a..5923d7e8351 100644 --- a/cpp/ql/lib/semmlecode.cpp.dbscheme +++ b/cpp/ql/lib/semmlecode.cpp.dbscheme @@ -2039,7 +2039,8 @@ aggregate_field_init( int aggregate: @aggregateliteral ref, int initializer: @expr ref, int field: @membervariable ref, - int position: int ref + int position: int ref, + boolean designated: boolean ref ); /** @@ -2051,7 +2052,8 @@ aggregate_array_init( int aggregate: @aggregateliteral ref, int initializer: @expr ref, int element_index: int ref, - int position: int ref + int position: int ref, + boolean designated: boolean ref ); @ctorinit = @ctordirectinit