djtodoro created this revision.
djtodoro added reviewers: shuaiwang, lebedev.ri.
Herald added subscribers: Charusso, jdoerfert, dkrupp, donat.nagy, Szelethus, 
mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.

We should track mutation of a variable within a comma operator expression.
Current code in `ExprMutationAnalyzer `does not handle it.

This will handle cases like:

`(a, b) ++`  < == `b `is modified
`(a, b) = c` < == `b `is modifed


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,24 @@
   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, 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
@@ -14,6 +14,42 @@
 
 namespace {
 
+// Assignment on an expression with comma operator.
+// Match situations like:
+//     '(a, b) = c', '(c, (a, b)) = c', etc.
+AST_MATCHER_P(BinaryOperator, isAssigmentWithCommma, const Expr *, E) {
+  if (Node.isAssignmentOp()) {
+    const Expr* LHSResult = Node.getLHS();
+    while (const auto *BOComma =
+                 dyn_cast_or_null<BinaryOperator>(LHSResult->IgnoreParens())) {
+      if (!BOComma->isCommaOp())
+        break;
+      LHSResult = BOComma->getRHS();
+    }
+    if (LHSResult == E)
+      return true;
+  }
+  return false;
+}
+
+// Increment/Decrement on an expression with comma operator.
+// Match situations like:
+//     '(a, b)++', '(c, (a, b))++', '(a, b)--', etc.
+AST_MATCHER_P(UnaryOperator, isIncDecOperandWithComma, const Expr *, E) {
+  if (Node.isIncrementDecrementOp()) {
+    const Expr* Result = Node.getSubExpr()->IgnoreParens();
+    while (const auto *BOComma =
+                 dyn_cast_or_null<BinaryOperator>(Result->IgnoreParens())) {
+      if (!BOComma->isCommaOp())
+        break;
+      Result = BOComma->getRHS();
+    }
+    if (Result == E)
+      return true;
+  }
+  return false;
+}
+
 AST_MATCHER_P(LambdaExpr, hasCaptureInit, const Expr *, E) {
   return llvm::is_contained(Node.capture_inits(), E);
 }
@@ -195,11 +231,20 @@
   const auto AsAssignmentLhs =
       binaryOperator(isAssignmentOperator(), hasLHS(equalsNode(Exp)));
 
+  // LHS of assignment is an expression with comma operator.
+  const auto AsAssignmentCommaLhs =
+      binaryOperator(isAssigmentWithCommma(Exp));
+
   // Operand of increment/decrement operators.
   const auto AsIncDecOperand =
       unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--")),
                     hasUnaryOperand(equalsNode(Exp)));
 
+  // Operand of increment/decrement operators is an expression
+  // with comma operator.
+  const auto AsIncDecOperandWithComma =
+      unaryOperator(isIncDecOperandWithComma(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()));
@@ -264,10 +309,12 @@
   const auto AsNonConstRefReturn = returnStmt(hasReturnValue(equalsNode(Exp)));
 
   const auto Matches =
-      match(findAll(stmt(anyOf(AsAssignmentLhs, AsIncDecOperand, AsNonConstThis,
-                               AsAmpersandOperand, AsPointerFromArrayDecay,
-                               AsOperatorArrowThis, AsNonConstRefArg,
-                               AsLambdaRefCaptureInit, AsNonConstRefReturn))
+      match(findAll(stmt(anyOf(AsAssignmentLhs, AsAssignmentCommaLhs,
+                               AsIncDecOperand, AsIncDecOperandWithComma,
+                               AsNonConstThis, AsAmpersandOperand,
+                               AsPointerFromArrayDecay, AsOperatorArrowThis,
+                               AsNonConstRefArg, AsLambdaRefCaptureInit,
+                               AsNonConstRefReturn))
                         .bind("stmt")),
             Stm, Context);
   return selectFirst<Stmt>("stmt", Matches);
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -3403,6 +3403,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