void (@NotNull PsiConditionalLoopStatement statement) { final PsiExpression condition = statement.getCondition(); final List<PsiExpression> notUpdated = new SmartList<>(); PsiStatement body = statement.getBody(); if (body == null || condition == null || SideEffectChecker.mayHaveSideEffects(condition)) return; if (ignorePossibleNonLocalChanges && !ExpressionUtils.isLocallyDefinedExpression(condition)) { if (SideEffectChecker.mayHaveNonLocalSideEffects(body)) return; if (statement instanceof PsiForStatement) { PsiStatement update = ((PsiForStatement)statement).getUpdate(); if (update != null && SideEffectChecker.mayHaveNonLocalSideEffects(update)) return; } } if (isConditionNotUpdated(condition, statement, notUpdated)) { if (!ControlFlowUtils.statementMayCompleteNormally(body) && !ControlFlowUtils.statementIsContinueTarget(statement)) { // Such loop is reported by LoopStatementsThatDontLoopInspection, so no need to report // "Loop condition is not updated" if it's checked only once anyways. // Sometimes people write while(flag) {...; break;} // instead of if(flag) {...} just to be able to use break inside (though the 'if' could be labeled instead) return; } if (notUpdated.isEmpty()) { // condition involves only final variables and/or constants, // flag the whole condition if (!BoolUtils.isBooleanLiteral(condition)) { registerError(condition, Boolean.TRUE); } } else { for (PsiExpression expression : notUpdated) { registerError(expression, Boolean.FALSE); } } } }