djtodoro updated this revision to Diff 189461.
djtodoro added a comment.

-add AST matcher that skips operands in comma expression
-add unit tests for extended support


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58894/new/

https://reviews.llvm.org/D58894

Files:
  include/clang/AST/Expr.h
  lib/Analysis/ExprMutationAnalyzer.cpp
  unittests/Analysis/ExprMutationAnalyzerTest.cpp

Index: unittests/Analysis/ExprMutationAnalyzerTest.cpp
===================================================================
--- unittests/Analysis/ExprMutationAnalyzerTest.cpp
+++ unittests/Analysis/ExprMutationAnalyzerTest.cpp
@@ -881,6 +881,65 @@
   EXPECT_FALSE(isMutated(Results, AST.get()));
 }
 
+TEST(ExprMutationAnalyzerTest, CommaExprWithAnAssigment) {
+  const auto AST =
+      buildASTFromCodeWithArgs("void f() { int x; int y; (x, y) = 5; }",
+                               {"-Wno-unused-value"});
+  const auto Results =
+      match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
+  EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprWithDecOp) {
+  const auto AST =
+      buildASTFromCodeWithArgs("void f() { int x; int y; (x, y)++; }",
+                               {"-Wno-unused-value"});
+  const auto Results =
+      match(withEnclosingCompound(declRefTo("y")), AST->getASTContext());
+  EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprWithNonConstMemberCall) {
+  const auto AST =
+      buildASTFromCodeWithArgs("class A { public: int mem; void f() { mem ++; } };"
+                               "void fn() { A o1, o2; (o1, o2).f(); }",
+                               {"-Wno-unused-value"});
+  const auto Results =
+      match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext());
+  EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprWithConstMemberCall) {
+  const auto AST =
+      buildASTFromCodeWithArgs("class A { public: int mem; void f() const  { } };"
+                               "void fn() { A o1, o2; (o1, o2).f(); }",
+                               {"-Wno-unused-value"});
+  const auto Results =
+      match(withEnclosingCompound(declRefTo("o2")), AST->getASTContext());
+  EXPECT_FALSE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprParmRef) {
+  const auto AST =
+      buildASTFromCodeWithArgs("class A { public: int mem;};"
+                               "extern void fn(A &o1);"
+                               "void fn2 () { A o1, o2; fn((o2, o1)); } ",
+                               {"-Wno-unused-value"});
+  const auto Results =
+      match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext());
+  EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
+TEST(ExprMutationAnalyzerTest, CommaExprWithAmpersandOp) {
+  const auto AST =
+      buildASTFromCodeWithArgs("class A { public: int mem;};"
+                               "void fn () { A o1, o2; void *addr = &(o2, o1); } ",
+                               {"-Wno-unused-value"});
+  const auto Results =
+      match(withEnclosingCompound(declRefTo("o1")), AST->getASTContext());
+  EXPECT_TRUE(isMutated(Results, AST.get()));
+}
+
 TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) {
   const auto AST = buildASTFromCode("void f() { int x; [=]() { x; }; }");
   const auto Results =
Index: lib/Analysis/ExprMutationAnalyzer.cpp
===================================================================
--- lib/Analysis/ExprMutationAnalyzer.cpp
+++ lib/Analysis/ExprMutationAnalyzer.cpp
@@ -24,6 +24,18 @@
   return InnerMatcher.matches(*Range, Finder, Builder);
 }
 
+AST_MATCHER_P(Expr, skipCommaOps,
+             ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
+  const Expr* Result = &Node;
+  while (const auto *BOComma =
+               dyn_cast_or_null<BinaryOperator>(Result->IgnoreParens())) {
+    if (!BOComma->isCommaOp())
+      break;
+    Result = BOComma->getRHS();
+  }
+  return InnerMatcher.matches(*Result, Finder, Builder);
+}
+
 const ast_matchers::internal::VariadicDynCastAllOfMatcher<Stmt, CXXTypeidExpr>
     cxxTypeidExpr;
 
@@ -193,18 +205,20 @@
 const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
   // LHS of any assignment operators.
   const auto AsAssignmentLhs =
-      binaryOperator(isAssignmentOperator(), hasLHS(equalsNode(Exp)));
+      binaryOperator(isAssignmentOperator(),
+                     hasLHS(skipCommaOps(equalsNode(Exp))));
 
   // Operand of increment/decrement operators.
   const auto AsIncDecOperand =
       unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--")),
-                    hasUnaryOperand(equalsNode(Exp)));
+                    hasUnaryOperand(skipCommaOps(equalsNode(Exp))));
 
   // Invoking non-const member function.
   // A member function is assumed to be non-const when it is unresolved.
   const auto NonConstMethod = cxxMethodDecl(unless(isConst()));
   const auto AsNonConstThis =
-      expr(anyOf(cxxMemberCallExpr(callee(NonConstMethod), on(equalsNode(Exp))),
+      expr(anyOf(cxxMemberCallExpr(callee(NonConstMethod),
+                                   on(skipCommaOps(equalsNode(Exp)))),
                  cxxOperatorCallExpr(callee(NonConstMethod),
                                      hasArgument(0, equalsNode(Exp))),
                  callExpr(callee(expr(anyOf(
@@ -220,7 +234,7 @@
       unaryOperator(hasOperatorName("&"),
                     // A NoOp implicit cast is adding const.
                     unless(hasParent(implicitCastExpr(hasCastKind(CK_NoOp)))),
-                    hasUnaryOperand(equalsNode(Exp)));
+                    hasUnaryOperand(skipCommaOps(equalsNode(Exp))));
   const auto AsPointerFromArrayDecay =
       castExpr(hasCastKind(CK_ArrayToPointerDecay),
                unless(hasParent(arraySubscriptExpr())), has(equalsNode(Exp)));
@@ -239,7 +253,8 @@
   // findFunctionArgMutation which has additional smarts for handling forwarding
   // references.
   const auto NonConstRefParam = forEachArgumentWithParam(
-      equalsNode(Exp), parmVarDecl(hasType(nonConstReferenceType())));
+      skipCommaOps(equalsNode(Exp)),
+      parmVarDecl(hasType(nonConstReferenceType())));
   const auto NotInstantiated = unless(hasDeclaration(isInstantiated()));
   const auto AsNonConstRefArg = anyOf(
       callExpr(NonConstRefParam, NotInstantiated),
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -3398,6 +3398,9 @@
   static bool isComparisonOp(Opcode Opc) { return Opc >= BO_Cmp && Opc<=BO_NE; }
   bool isComparisonOp() const { return isComparisonOp(getOpcode()); }
 
+  static bool isCommaOp(Opcode Opc) { return Opc == BO_Comma; }
+  bool isCommaOp() const { return isCommaOp(getOpcode()); }
+
   static Opcode negateComparisonOp(Opcode Opc) {
     switch (Opc) {
     default:
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to