From d2f21a2bf5bfc5f89034fa3696fc661e5ceec6c8 Mon Sep 17 00:00:00 2001 From: Peter Szecsi Date: Tue, 27 Mar 2018 12:11:46 +0000 Subject: [PATCH] [ASTMatchers] Add isAssignmentOperator matcher Adding a matcher for BinaryOperator and cxxOperatorCallExpr to be able to decide whether it is any kind of assignment operator or not. This would be useful since allows us to easily detect assignments via matchers for static analysis (Tidy, SA) purposes. Differential Revision: https://reviews.llvm.org/D44893 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@328618 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LibASTMatchersReference.html | 26 +++++++++++++++++++ include/clang/ASTMatchers/ASTMatchers.h | 20 ++++++++++++++ lib/ASTMatchers/Dynamic/Registry.cpp | 1 + .../ASTMatchers/ASTMatchersNarrowingTest.cpp | 15 +++++++++++ 4 files changed, 62 insertions(+) diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index 8775314afc..9c55e8214d 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -1926,6 +1926,19 @@ Example matches a || b (matcher = binaryOperator(hasOperatorName("||"))) +Matcher<BinaryOperator>isAssignmentOperator +
Matches all kinds of assignment operators.
+
+Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+  if (a == b)
+    a += b;
+
+Example 2: matches s1 = s2 (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+  struct S { S& operator=(const S&); };
+  void x() { S s1, s2; s1 = s2; })
+
+ + Matcher<CXXBoolLiteralExpr>equalsbool Value

 
@@ -2306,6 +2319,19 @@ Usable as: Matcher<CXXOperatorCallExpr>isAssignmentOperator
+
Matches all kinds of assignment operators.
+
+Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+  if (a == b)
+    a += b;
+
+Example 2: matches s1 = s2 (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+  struct S { S& operator=(const S&); };
+  void x() { S s1, s2; s1 = s2; })
+
+ + Matcher<CXXRecordDecl>hasDefinition
Matches a class declaration that is defined.
 
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 31620de85f..65f1524223 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -4003,6 +4003,26 @@ AST_POLYMORPHIC_MATCHER_P(hasOperatorName,
   return Name == Node.getOpcodeStr(Node.getOpcode());
 }
 
+/// \brief Matches on all kinds of assignment operators.
+///
+/// Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator()))
+/// \code
+///   if (a == b)
+///     a += b;
+/// \endcode
+///
+/// Example 2: matches s1 = s2
+///            (matcher = cxxOperatorCallExpr(isAssignmentOperator()))
+/// \code
+///   struct S { S& operator=(const S&); };
+///   void x() { S s1, s2; s1 = s2; })
+/// \endcode
+AST_POLYMORPHIC_MATCHER(isAssignmentOperator,
+                        AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator,
+                                                        CXXOperatorCallExpr)) {
+  return Node.isAssignmentOp();
+}
+
 /// \brief Matches the left hand side of binary operator expressions.
 ///
 /// Example matches a (matcher = binaryOperator(hasLHS()))
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index 79aa4e667b..fd373bca56 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -322,6 +322,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(isAnyPointer);
   REGISTER_MATCHER(isArray);
   REGISTER_MATCHER(isArrow);
+  REGISTER_MATCHER(isAssignmentOperator);
   REGISTER_MATCHER(isBaseInitializer);
   REGISTER_MATCHER(isBitField);
   REGISTER_MATCHER(isCatchAll);
diff --git a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 3e27948db7..ad90f75409 100644
--- a/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2139,5 +2139,20 @@ TEST(HasTrailingReturn, MatchesLambdaTrailingReturn) {
           functionDecl(hasTrailingReturn())));
 }
 
+TEST(IsAssignmentOperator, Basic) {
+  StatementMatcher BinAsgmtOperator = binaryOperator(isAssignmentOperator());
+  StatementMatcher CXXAsgmtOperator =
+      cxxOperatorCallExpr(isAssignmentOperator());
+
+  EXPECT_TRUE(matches("void x() { int a; a += 1; }", BinAsgmtOperator));
+  EXPECT_TRUE(matches("void x() { int a; a = 2; }", BinAsgmtOperator));
+  EXPECT_TRUE(matches("void x() { int a; a &= 3; }", BinAsgmtOperator));
+  EXPECT_TRUE(matches("struct S { S& operator=(const S&); };"
+                      "void x() { S s1, s2; s1 = s2; }",
+                      CXXAsgmtOperator));
+  EXPECT_TRUE(
+      notMatches("void x() { int a; if(a == 0) return; }", BinAsgmtOperator));
+}
+
 } // namespace ast_matchers
 } // namespace clang
-- 
2.40.0