shuaiwang created this revision.
Herald added subscribers: cfe-commits, klimek.

Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D45153

Files:
  clang-tidy/utils/ASTUtils.cpp
  clang-tidy/utils/ASTUtils.h

Index: clang-tidy/utils/ASTUtils.h
===================================================================
--- clang-tidy/utils/ASTUtils.h
+++ clang-tidy/utils/ASTUtils.h
@@ -27,6 +27,10 @@
 bool exprHasBitFlagWithSpelling(const Expr *Flags, const SourceManager &SM,
                                 const LangOptions &LangOpts,
                                 StringRef FlagName);
+
+// Checks whether `expr` is (potentially) modified within `stmt`.
+bool isModified(const Expr& expr, const Stmt& stmt, ASTContext* context);
+
 } // namespace utils
 } // namespace tidy
 } // namespace clang
Index: clang-tidy/utils/ASTUtils.cpp
===================================================================
--- clang-tidy/utils/ASTUtils.cpp
+++ clang-tidy/utils/ASTUtils.cpp
@@ -67,6 +67,83 @@
   return true;
 }
 
+bool isModified(const Expr& expr, const Stmt& stmt, ASTContext* context) {
+  // LHS of any assignment operators.
+  const auto as_assignment_lhs = binaryOperator(
+      anyOf(hasOperatorName("="), hasOperatorName("+="), hasOperatorName("-="),
+            hasOperatorName("*="), hasOperatorName("/="), hasOperatorName("%="),
+            hasOperatorName("^="), hasOperatorName("&="), hasOperatorName("|="),
+            hasOperatorName(">>="), hasOperatorName("<<=")),
+      hasLHS(equalsNode(&expr)));
+
+  // Operand of increment/decrement operators.
+  const auto as_inc_dec_operand =
+      unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--")),
+                    hasUnaryOperand(equalsNode(&expr)));
+
+  // Invoking non-const member function.
+  const auto non_const_method = cxxMethodDecl(unless(isConst()));
+  const auto as_non_const_this = ast_matchers::expr(
+      anyOf(cxxMemberCallExpr(callee(non_const_method), on(equalsNode(&expr))),
+            cxxOperatorCallExpr(callee(non_const_method),
+                                hasArgument(0, equalsNode(&expr)))));
+
+  // Used as non-const-ref argument when calling a function.
+  const auto non_const_ref_type =
+      referenceType(pointee(unless(isConstQualified())));
+  const auto non_const_ref_param = forEachArgumentWithParam(
+      equalsNode(&expr), parmVarDecl(hasType(qualType(non_const_ref_type))));
+  const auto as_non_const_ref_arg = anyOf(
+      callExpr(non_const_ref_param), cxxConstructExpr(non_const_ref_param));
+
+  // Taking address of 'exp'.
+  const auto as_ampersand_operand =
+      unaryOperator(hasOperatorName("&"), hasUnaryOperand(equalsNode(&expr)));
+  const auto as_pointer_from_array_decay =
+      castExpr(hasCastKind(CK_ArrayToPointerDecay), has(equalsNode(&expr)));
+
+  // Check whether 'exp' is directly modified as a whole.
+  MatchFinder finder;
+  bool has_match = false;
+  MatchCallbackAdaptor callback(
+      [&has_match](const MatchFinder::MatchResult&) { has_match = true; });
+  finder.addMatcher(findAll(ast_matchers::expr(anyOf(
+                        as_assignment_lhs, as_inc_dec_operand,
+                        as_non_const_this, as_non_const_ref_arg,
+                        as_ampersand_operand, as_pointer_from_array_decay))),
+                    &callback);
+  finder.match(stmt, *context);
+  if (has_match) return true;
+
+  // Check whether any member of 'exp' is modified.
+  const auto member_exprs = match(
+      findAll(memberExpr(hasObjectExpression(equalsNode(&expr))).bind("expr")),
+      stmt, *context);
+  for (const auto& node : member_exprs) {
+    if (isModified(*node.getNodeAs<Expr>("expr"), stmt, context)) return true;
+  }
+
+  // If 'exp' is bound to a non-const reference, check all declRefExpr to that.
+  const auto decls = match(
+      ast_matchers::stmt(forEachDescendant(
+          varDecl(hasType(referenceType(pointee(unless(isConstQualified())))),
+                  hasInitializer(equalsNode(&expr)))
+              .bind("decl"))),
+      stmt, *context);
+  for (const auto& decl_node : decls) {
+    const auto exprs = match(
+        findAll(declRefExpr(to(equalsNode(decl_node.getNodeAs<Decl>("decl"))))
+                    .bind("expr")),
+        stmt, *context);
+    for (const auto& expr_node : exprs) {
+      if (isModified(*expr_node.getNodeAs<Expr>("expr"), stmt, context))
+        return true;
+    }
+  }
+
+  return false;
+}
+
 } // namespace utils
 } // namespace tidy
 } // namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to