Skip to content

Commit 7fe9396

Browse files
committed
Add isInvalidLoop predicate that provides a reason
1 parent b0014ca commit 7fe9396

File tree

1 file changed

+74
-27
lines changed

1 file changed

+74
-27
lines changed

cpp/common/src/codingstandards/cpp/Loops.qll

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,14 @@ predicate isForLoopWithFloatingPointCounters(ForStmt forLoop, Variable v) {
3737
* Holds if for loop `forLoop` contains an invalid for loop incrementation.
3838
* M6-5-2
3939
*/
40-
predicate isInvalidForLoopIncrementation(ForStmt forLoop, LoopControlVariable v) {
41-
v.getAnAccess() = forLoop.getCondition().getAChild*() and
42-
exists(VariableAccess va |
43-
va = v.getAnAccess() and
44-
va = forLoop.getUpdate().getAChild*() and
45-
not exists(CrementOperation cop | cop.getOperand() = va) and
46-
not exists(Call c | c.getQualifier() = va and c.getTarget() instanceof UserCrementOperator)
40+
predicate isInvalidForLoopIncrementation(ForStmt forLoop, Variable v, VariableAccess modification) {
41+
v = getAnIterationVariable(forLoop) and
42+
modification = v.getAnAccess() and
43+
modification = forLoop.getUpdate().getAChild*() and
44+
modification.isModified() and
45+
not exists(CrementOperation cop | cop.getOperand() = modification) and
46+
not exists(Call c |
47+
c.getQualifier() = modification and c.getTarget() instanceof UserCrementOperator
4748
) and
4849
exists(VariableAccess va | va = forLoop.getCondition().getAChild*() and va = v.getAnAccess() |
4950
exists(EqualityOperation eop | eop.getAnOperand() = va)
@@ -163,26 +164,72 @@ predicate isLoopControlVarModifiedInLoopExpr(
163164
predicate isNonBoolLoopControlVar(
164165
ForStmt forLoop, LoopControlVariable loopControlVariable, VariableAccess loopControlVariableAccess
165166
) {
166-
// get a loop control variable that is not a loop counter
167-
loopControlVariableAccess = loopControlVariable.getVariableAccessInLoop(forLoop) and
168-
not loopControlVariable = getAnIterationVariable(forLoop) and
169-
loopControlVariableAccess.getEnclosingStmt() = forLoop.getStmt().getAChild*() and
170-
// filter only loop control variables that are modified
171-
(
172-
loopControlVariableAccess.isModified() or
173-
loopControlVariableAccess.isAddressOfAccess()
174-
) and
175-
// check if the variable type is anything but bool
176-
not loopControlVariable.getType() instanceof BoolType
167+
exists(Variable loopCounter, ComparisonOperation terminationCheck |
168+
loopCounter = getAnIterationVariable(forLoop) and
169+
forLoop.getCondition() = terminationCheck.getParent*()
170+
|
171+
// get a loop control variable that is not a loop counter
172+
loopControlVariableAccess = loopControlVariable.getVariableAccessInLoop(forLoop) and
173+
not loopControlVariable = getAnIterationVariable(forLoop) and
174+
// filter only loop control variables that are modified
175+
(
176+
loopControlVariableAccess.isModified() or
177+
loopControlVariableAccess.isAddressOfAccess()
178+
) and
179+
// check if the variable type is anything but bool
180+
not loopControlVariable.getType() instanceof BoolType and
181+
// check if the control variable is part of the termination check, but is not compared to the loop counter
182+
terminationCheck.getAnOperand() = loopControlVariable.getAnAccess().getParent*() and
183+
not terminationCheck.getAnOperand() = loopCounter.getAnAccess().getParent*()
184+
)
177185
}
178186

179-
predicate isInvalidLoop(ForStmt forLoop) {
180-
isInvalidForLoopIncrementation(forLoop, _) or
181-
isForLoopWithMulipleCounters(forLoop) or
182-
isForLoopWithFloatingPointCounters(forLoop, _) or
183-
isLoopCounterModifiedInCondition(forLoop, _) or
184-
isLoopCounterModifiedInStatement(forLoop, _, _) or
185-
isIrregularLoopCounterModification(forLoop, _, _) or
186-
isLoopControlVarModifiedInLoopExpr(forLoop, _, _) or
187-
isNonBoolLoopControlVar(forLoop, _, _)
187+
predicate isInvalidLoop(ForStmt forLoop) { isInvalidLoop(forLoop, _, _, _) }
188+
189+
predicate isInvalidLoop(ForStmt forLoop, string reason, Locatable reasonLocation, string reasonLabel) {
190+
exists(Variable loopCounter |
191+
isInvalidForLoopIncrementation(forLoop, loopCounter, reasonLocation) and
192+
reason =
193+
"it $@ its loop counter '" + loopCounter.getName() +
194+
"' with an operation that is not an increment or decrement" and
195+
reasonLabel = "updates"
196+
)
197+
or
198+
isForLoopWithMulipleCounters(forLoop) and
199+
reason = "it uses multiple loop counters$@" and
200+
reasonLabel = "" and
201+
reasonLocation.getLocation() instanceof UnknownExprLocation
202+
or
203+
isForLoopWithFloatingPointCounters(forLoop, reasonLocation) and
204+
reason = "it uses a loop counter '$@' of type floating-point" and
205+
reasonLabel = reasonLocation.(Variable).getName()
206+
or
207+
isLoopCounterModifiedInCondition(forLoop, reasonLocation) and
208+
reason =
209+
"it $@ the loop counter '" + reasonLocation.(VariableAccess).getTarget().getName() +
210+
"' in the condition" and
211+
reasonLabel = "updates"
212+
or
213+
exists(Variable loopCounter |
214+
isLoopCounterModifiedInStatement(forLoop, loopCounter, reasonLocation) and
215+
reason = "it $@ the loop counter '" + loopCounter.getName() + "' in the body of the loop" and
216+
reasonLabel = "updates"
217+
)
218+
or
219+
exists(Variable loopCounter |
220+
isIrregularLoopCounterModification(forLoop, loopCounter, reasonLocation) and
221+
reason = "it $@ the loop counter '" + loopCounter.getName() + "' irregularly" and
222+
reasonLabel = "updates"
223+
)
224+
or
225+
exists(Variable loopControlVariable |
226+
isLoopControlVarModifiedInLoopExpr(forLoop, loopControlVariable, reasonLocation) and
227+
reason =
228+
"it updates $@, a loop control variable other than the loop counter, in the update expression of the loop" and
229+
reasonLabel = loopControlVariable.getName()
230+
)
231+
or
232+
isNonBoolLoopControlVar(forLoop, reasonLocation, _) and
233+
reason = "its $@ is not a boolean" and
234+
reasonLabel = "loop control variable"
188235
}

0 commit comments

Comments
 (0)