Skip to content

Commit ebbd9c5

Browse files
committed
C++: Handle C++17 if initializers
1 parent 0a78927 commit ebbd9c5

18 files changed

Lines changed: 692 additions & 13 deletions

File tree

cpp/ql/lib/semmle/code/cpp/PrintAST.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,12 +663,16 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
663663
or
664664
s.(ComputedGotoStmt).getExpr() = e and pred = "getExpr()"
665665
or
666+
s.(ConstexprIfStmt).getInitialization() = e and pred = "getInitialization()"
667+
or
666668
s.(ConstexprIfStmt).getCondition() = e and pred = "getCondition()"
667669
or
668670
s.(ConstexprIfStmt).getThen() = e and pred = "getThen()"
669671
or
670672
s.(ConstexprIfStmt).getElse() = e and pred = "getElse()"
671673
or
674+
s.(IfStmt).getInitialization() = e and pred = "getInitialization()"
675+
or
672676
s.(IfStmt).getCondition() = e and pred = "getCondition()"
673677
or
674678
s.(IfStmt).getThen() = e and pred = "getThen()"

cpp/ql/lib/semmle/code/cpp/controlflow/internal/CFG.qll

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -836,8 +836,15 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) {
836836
p2.nodeAt(n2, f)
837837
)
838838
or
839-
// IfStmt -> condition ; { then, else } ->
839+
// IfStmt -> [ init -> ] condition ; { then, else } ->
840840
exists(IfStmt s |
841+
p1.nodeAt(n1, s) and
842+
p2.nodeBefore(n2, s.getInitialization())
843+
or
844+
p1.nodeAfter(n1, s.getInitialization()) and
845+
p2.nodeBefore(n2, s.getCondition())
846+
or
847+
not exists(s.getInitialization()) and
841848
p1.nodeAt(n1, s) and
842849
p2.nodeBefore(n2, s.getCondition())
843850
or
@@ -851,8 +858,15 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) {
851858
p2.nodeAfter(n2, s)
852859
)
853860
or
854-
// ConstexprIfStmt -> condition ; { then, else } -> // same as IfStmt
861+
// ConstexprIfStmt -> [ init -> ] condition ; { then, else } -> // same as IfStmt
855862
exists(ConstexprIfStmt s |
863+
p1.nodeAt(n1, s) and
864+
p2.nodeBefore(n2, s.getInitialization())
865+
or
866+
p1.nodeAfter(n1, s.getInitialization()) and
867+
p2.nodeBefore(n2, s.getCondition())
868+
or
869+
not exists(s.getInitialization()) and
856870
p1.nodeAt(n1, s) and
857871
p2.nodeBefore(n2, s.getCondition())
858872
or

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedStmt.qll

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -421,20 +421,36 @@ class TranslatedCatchAnyHandler extends TranslatedHandler {
421421
class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
422422
override IfStmt stmt;
423423

424-
override Instruction getFirstInstruction() { result = getCondition().getFirstInstruction() }
424+
override Instruction getFirstInstruction() {
425+
if hasInitialization()
426+
then result = getInitialization().getFirstInstruction()
427+
else result = getFirstConditionInstruction()
428+
}
425429

426430
override TranslatedElement getChild(int id) {
427-
id = 0 and result = getCondition()
431+
id = 0 and result = getInitialization()
432+
or
433+
id = 1 and result = getCondition()
428434
or
429-
id = 1 and result = getThen()
435+
id = 2 and result = getThen()
430436
or
431-
id = 2 and result = getElse()
437+
id = 3 and result = getElse()
438+
}
439+
440+
private predicate hasInitialization() { exists(stmt.getInitialization()) }
441+
442+
private TranslatedStmt getInitialization() {
443+
result = getTranslatedStmt(stmt.getInitialization())
432444
}
433445

434446
private TranslatedCondition getCondition() {
435447
result = getTranslatedCondition(stmt.getCondition().getFullyConverted())
436448
}
437449

450+
private Instruction getFirstConditionInstruction() {
451+
result = getCondition().getFirstInstruction()
452+
}
453+
438454
private TranslatedStmt getThen() { result = getTranslatedStmt(stmt.getThen()) }
439455

440456
private TranslatedStmt getElse() { result = getTranslatedStmt(stmt.getElse()) }
@@ -456,6 +472,9 @@ class TranslatedIfStmt extends TranslatedStmt, ConditionContext {
456472
}
457473

458474
override Instruction getChildSuccessor(TranslatedElement child) {
475+
child = getInitialization() and
476+
result = getFirstConditionInstruction()
477+
or
459478
(child = getThen() or child = getElse()) and
460479
result = getParent().getChildSuccessor(this)
461480
}

cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,26 @@ class ConditionalStmt extends ControlStructure, TConditionalStmt { }
213213
class IfStmt extends ConditionalStmt, @stmt_if {
214214
override string getAPrimaryQlClass() { result = "IfStmt" }
215215

216+
/**
217+
* Gets the initialization statement of this 'if' statement.
218+
*
219+
* For example, for
220+
* ```
221+
* if (x = y; b) { f(); }
222+
* ```
223+
* the result is `x = y;`.
224+
*
225+
* Does not hold if the initialization statement is missing or an empty statement, as in
226+
* ```
227+
* if (b) { f(); }
228+
* ```
229+
* or
230+
* ```
231+
* if (; b) { f(); }
232+
* ```
233+
*/
234+
Stmt getInitialization() { if_initialization(underlyingElement(this), unresolveElement(result)) }
235+
216236
/**
217237
* Gets the condition expression of this 'if' statement.
218238
*
@@ -222,7 +242,7 @@ class IfStmt extends ConditionalStmt, @stmt_if {
222242
* ```
223243
* the result is `b`.
224244
*/
225-
Expr getCondition() { result = this.getChild(0) }
245+
Expr getCondition() { result = this.getChild(1) }
226246

227247
override Expr getControllingExpr() { result = this.getCondition() }
228248

@@ -299,6 +319,28 @@ class IfStmt extends ConditionalStmt, @stmt_if {
299319
class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if {
300320
override string getAPrimaryQlClass() { result = "ConstexprIfStmt" }
301321

322+
/**
323+
* Gets the initialization statement of this 'constexpr if' statement.
324+
*
325+
* For example, for
326+
* ```
327+
* if constexpr (x = y; b) { f(); }
328+
* ```
329+
* the result is `x = y;`.
330+
*
331+
* Does not hold if the initialization statement is missing or an empty statement, as in
332+
* ```
333+
* if constexpr (b) { f(); }
334+
* ```
335+
* or
336+
* ```
337+
* if constexpr (; b) { f(); }
338+
* ```
339+
*/
340+
Stmt getInitialization() {
341+
constexpr_if_initialization(underlyingElement(this), unresolveElement(result))
342+
}
343+
302344
/**
303345
* Gets the condition expression of this 'constexpr if' statement.
304346
*
@@ -308,7 +350,7 @@ class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if {
308350
* ```
309351
* the result is `b`.
310352
*/
311-
Expr getCondition() { result = this.getChild(0) }
353+
Expr getCondition() { result = this.getChild(1) }
312354

313355
override Expr getControllingExpr() { result = this.getCondition() }
314356

@@ -926,7 +968,7 @@ class ForStmt extends Loop, @stmt_for {
926968
*
927969
* Does not hold if the initialization statement is an empty statement, as in
928970
* ```
929-
* for (; i < 10; i++) { j++ }
971+
* for (; i < 10; i++) { j++; }
930972
* ```
931973
*/
932974
Stmt getInitialization() { for_initialization(underlyingElement(this), unresolveElement(result)) }

cpp/ql/lib/semmlecode.cpp.dbscheme

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,6 +1863,11 @@ variable_vla(
18631863
int decl: @stmt_vla_decl ref
18641864
);
18651865

1866+
if_initialization(
1867+
unique int if_stmt: @stmt_if ref,
1868+
int init_id: @stmt ref
1869+
);
1870+
18661871
if_then(
18671872
unique int if_stmt: @stmt_if ref,
18681873
int then_id: @stmt ref
@@ -1873,6 +1878,11 @@ if_else(
18731878
int else_id: @stmt ref
18741879
);
18751880

1881+
constexpr_if_initialization(
1882+
unique int constexpr_if_stmt: @stmt_constexpr_if ref,
1883+
int init_id: @stmt ref
1884+
);
1885+
18761886
constexpr_if_then(
18771887
unique int constexpr_if_stmt: @stmt_constexpr_if ref,
18781888
int then_id: @stmt ref

cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,5 @@ where
5757
not declarationHasSideEffects(v) and
5858
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
5959
not v.getAnAttribute().getName() = "unused" and
60-
not any(ErrorExpr e).getEnclosingFunction() = f and // unextracted expr may use `v`
61-
not any(ConditionDeclExpr cde).getEnclosingFunction() = f // this case can be removed when the `if (a = b; a)` and `switch (a = b; a)` test cases don't depend on this exclusion
60+
not any(ErrorExpr e).getEnclosingFunction() = f // unextracted expr may use `v`
6261
select v, "Variable " + v.getName() + " is not used"

0 commit comments

Comments
 (0)