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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits