Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -1883,7 +1883,16 @@ -
Matches all kinds of assignment operators. + +Example matches a += b (matcher = binaryOperator(isAssignmentOperator())) + if (a == b) + a += b; +
Matches literals that are equal to the given value of type ValueT. Given Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -3927,6 +3927,19 @@ return Name == Node.getOpcodeStr(Node.getOpcode()); } + +/// \brief Matches all kinds of assignment operators. +/// +/// Example matches a += b (matcher = binaryOperator(isAssignmentOperator())) +/// \code +/// if (a == b) +/// a += b; +/// \endcode +AST_MATCHER(BinaryOperator, isAssignmentOperator) { + return Node.isAssignmentOp(); +} + + /// \brief Matches the left hand side of binary operator expressions. /// /// Example matches a (matcher = binaryOperator(hasLHS())) Index: lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- lib/ASTMatchers/Dynamic/Registry.cpp +++ lib/ASTMatchers/Dynamic/Registry.cpp @@ -302,6 +302,7 @@ REGISTER_MATCHER(isAnyCharacter); REGISTER_MATCHER(isAnyPointer); REGISTER_MATCHER(isArrow); + REGISTER_MATCHER(isAssignmentOperator); REGISTER_MATCHER(isBaseInitializer); REGISTER_MATCHER(isBitField); REGISTER_MATCHER(isCatchAll); Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp =================================================================== --- lib/StaticAnalyzer/Core/LoopUnrolling.cpp +++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -97,9 +97,7 @@ unaryOperator(anyOf(hasOperatorName("--"), hasOperatorName("++")), hasUnaryOperand(ignoringParenImpCasts( declRefExpr(to(varDecl(VarNodeMatcher)))))), - binaryOperator(anyOf(hasOperatorName("="), hasOperatorName("+="), - hasOperatorName("/="), hasOperatorName("*="), - hasOperatorName("-=")), + binaryOperator(isAssignmentOperator(), hasLHS(ignoringParenImpCasts( declRefExpr(to(varDecl(VarNodeMatcher))))))); } Index: lib/StaticAnalyzer/Core/PathDiagnostic.cpp =================================================================== --- lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -690,6 +690,8 @@ return getLocationForCaller(CEE->getCalleeContext(), CEE->getLocationContext(), SMng); + } else if (OptionalBE = P.getAs ()) { + S = BE->getBlock()->getTerminatorCondition(); } else { llvm_unreachable("Unexpected ProgramPoint"); } Index: test/Analysis/loop-unrolling.cpp =================================================================== --- test/Analysis/loop-unrolling.cpp +++ test/Analysis/loop-unrolling.cpp @@ -98,13 +98,101 @@ return 0; } +int no_unroll_assignment() { + for (int i = 0; i < 9; i++) { + i = i + 1; + clang_analyzer_numTimesReached(); // expected-warning {{4}} + } + return 0; +} + +int no_unroll_assignment2() { + for (int i = 0; i < 9; i++) { + i *= 2; + clang_analyzer_numTimesReached(); // expected-warning {{4}} + } + return 0; +} + +int no_unroll_assignment3() { + for (int i = 128; i > 0; i--) { + i /= 2; + clang_analyzer_numTimesReached(); // expected-warning {{4}} + } + return 0; +} + +int no_unroll_assignment4() { + for (int i = 0; i < 9; i++) { + i -= 2; + clang_analyzer_numTimesReached(); // expected-warning {{4}} + } + return 0; +} + +int no_unroll_assignment5() { + for (int i = 0; i < 9; i++) { + i += 1; + clang_analyzer_numTimesReached(); // expected-warning {{4}} + } + return 0; +} + +int no_unroll_assignment6() { + for (int i = 128; i > 0; i--) { + i >>= 1; + clang_analyzer_numTimesReached(); // expected-warning {{4}} + } + return 0; +} + +int no_unroll_assignment7() { + for (int i = 0; i < 512; i++) { + i <<= 1; + clang_analyzer_numTimesReached(); // expected-warning {{4}} + } + return 0; +} + +int no_unroll_assignment8() { + for (int i = 0; i < 9; i++) { + i %= 8; + clang_analyzer_numTimesReached(); // expected-warning {{4}} + } + return 0; +} + +int no_unroll_assignment9() { + for (int i = 0; i < 9; i++) { + i &= 31; + clang_analyzer_numTimesReached(); // expected-warning {{4}} + } + return 0; +} + +int no_unroll_assignment10() { + for (int i = 0; i < 9; i++) { + i |= 2; + clang_analyzer_numTimesReached(); // expected-warning {{4}} + } + return 0; +} + +int no_unroll_assignment11() { + for (int i = 0; i < 9; i++) { + i ^= 2; + clang_analyzer_numTimesReached(); // expected-warning {{4}} + } + return 0; +} + int make_new_branches_loop_cached() { for (int i = 0; i < 8; i++) { clang_analyzer_numTimesReached(); // expected-warning {{4}} - if(getNum()){ - (void) i; // Since this Stmt does not change the State the analyzer - // won't make a new execution path but reuse the earlier nodes. - } + if (getNum()) { + (void)i; // Since this Stmt does not change the State the analyzer + // won't make a new execution path but reuse the earlier nodes. + } } clang_analyzer_warnIfReached(); // no-warning return 0; @@ -114,7 +202,7 @@ int l = 2; for (int i = 0; i < 8; i++) { clang_analyzer_numTimesReached(); // expected-warning {{10}} - if(getNum()){ + if (getNum()) { ++l; } } @@ -126,7 +214,7 @@ int l = 2; for (int i = 0; i < 8; i++) { clang_analyzer_numTimesReached(); // expected-warning {{10}} - if(getNum()){ + if (getNum()) { ++l; } (void)&i; // This ensures that the loop won't be unrolled. @@ -184,7 +272,7 @@ for (j = 0; j < 9; ++j) { clang_analyzer_numTimesReached(); // expected-warning {{4}} a[j] = 22; - (void) &j; // ensures that the inner loop won't be unrolled + (void)&j; // ensures that the inner loop won't be unrolled } a[i] = 42; } @@ -263,8 +351,8 @@ int k = 2; for (int i = 0; i < 5; i++) { clang_analyzer_numTimesReached(); // expected-warning {{13}} - if(i == 0 && b) // Splits the state in the first iteration but the recursion - // call will be unrolled anyway since the condition is known there. + if (i == 0 && b) // Splits the state in the first iteration but the recursion + // call will be unrolled anyway since the condition is known there. recursion_unroll1(false); clang_analyzer_numTimesReached(); // expected-warning {{14}} } @@ -276,7 +364,7 @@ int k = 0; for (int i = 0; i < 5; i++) { clang_analyzer_numTimesReached(); // expected-warning {{9}} - if(i == 0 && b) + if (i == 0 && b) recursion_unroll2(false); clang_analyzer_numTimesReached(); // expected-warning {{9}} } @@ -302,7 +390,7 @@ int k = 2; for (int i = 0; i < 5; i++) { clang_analyzer_numTimesReached(); // expected-warning {{13}} - if(i == 0 && b) { + if (i == 0 && b) { recursion_unroll4(false); continue; } Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -1983,5 +1983,15 @@ namedDecl(hasExternalFormalLinkage()))); } +TEST(IsAssignmentOperator, Basic) { + StatementMatcher AsOperator = binaryOperator(isAssignmentOperator()); + + EXPECT_TRUE(matches("void x() { int a; a += 1; }", AsOperator)); + EXPECT_TRUE(matches("void x() { int a; a = 2; }", AsOperator)); + EXPECT_TRUE(matches("void x() { int a; a &= 3; }", AsOperator)); + EXPECT_TRUE(notMatches("void x() { int a; if(a == 0) return; }", AsOperator)); +} + + } // namespace ast_matchers } // namespace clang