Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -1883,7 +1883,16 @@ -Matcher<CXXBoolLiteralExpr>equalsValueT Value +Matcher<BinaryOperator>isAssignmentOperator +
Matches all kinds of assignment operators.
+
+Example matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+  if (a == b)
+    a += b;
+
+ + + Matcher<CXXBoolLiteralExpr>equalsValueT Value
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 (Optional BE = 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