10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/Frontend/CompilerInstance.h"
13 #include "clang/Lex/Lexer.h"
14 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/Casting.h"
28 AST_MATCHER_P(Expr, hasSideEffect,
bool, CheckFunctionCalls) {
29 const Expr *
E = &Node;
31 if (
const auto *Op = dyn_cast<UnaryOperator>(
E)) {
32 UnaryOperator::Opcode OC = Op->getOpcode();
33 return OC == UO_PostInc || OC == UO_PostDec || OC == UO_PreInc ||
37 if (
const auto *Op = dyn_cast<BinaryOperator>(
E)) {
38 return Op->isAssignmentOp();
41 if (
const auto *OpCallExpr = dyn_cast<CXXOperatorCallExpr>(
E)) {
42 OverloadedOperatorKind OpKind = OpCallExpr->getOperator();
43 return OpKind == OO_Equal || OpKind == OO_PlusEqual ||
44 OpKind == OO_MinusEqual || OpKind == OO_StarEqual ||
45 OpKind == OO_SlashEqual || OpKind == OO_AmpEqual ||
46 OpKind == OO_PipeEqual || OpKind == OO_CaretEqual ||
47 OpKind == OO_LessLessEqual || OpKind == OO_GreaterGreaterEqual ||
48 OpKind == OO_PlusPlus || OpKind == OO_MinusMinus ||
49 OpKind == OO_PercentEqual || OpKind == OO_New ||
50 OpKind == OO_Delete || OpKind == OO_Array_New ||
51 OpKind == OO_Array_Delete;
54 if (
const auto *CExpr = dyn_cast<CallExpr>(
E)) {
55 bool Result = CheckFunctionCalls;
56 if (
const auto *FuncDecl = CExpr->getDirectCallee()) {
57 if (FuncDecl->getDeclName().isIdentifier() &&
58 FuncDecl->getName() ==
"__builtin_expect")
60 else if (
const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FuncDecl))
61 Result &= !MethodDecl->isConst();
66 return isa<CXXNewExpr>(
E) || isa<CXXDeleteExpr>(
E) || isa<CXXThrowExpr>(
E);
71 AssertSideEffectCheck::AssertSideEffectCheck(StringRef
Name,
74 CheckFunctionCalls(Options.get(
"CheckFunctionCalls", false)),
75 RawAssertList(Options.get(
"AssertMacros",
"assert")) {
76 StringRef(RawAssertList).split(AssertMacros,
",", -1,
false);
81 Options.
store(Opts,
"CheckFunctionCalls", CheckFunctionCalls);
86 auto DescendantWithSideEffect =
87 traverse(ast_type_traits::TK_AsIs,
88 hasDescendant(expr(hasSideEffect(CheckFunctionCalls))));
89 auto ConditionWithSideEffect = hasCondition(DescendantWithSideEffect);
92 anyOf(conditionalOperator(ConditionWithSideEffect),
93 ifStmt(ConditionWithSideEffect),
94 unaryOperator(hasOperatorName(
"!"),
95 hasUnaryOperand(unaryOperator(
97 hasUnaryOperand(DescendantWithSideEffect))))))
103 const SourceManager &SM = *Result.SourceManager;
105 SourceLocation
Loc = Result.Nodes.getNodeAs<Stmt>(
"condStmt")->getBeginLoc();
107 StringRef AssertMacroName;
108 while (
Loc.isValid() &&
Loc.isMacroID()) {
109 StringRef MacroName = Lexer::getImmediateMacroName(
Loc, SM, LangOpts);
112 if (llvm::is_contained(AssertMacros, MacroName)) {
113 AssertMacroName = MacroName;
116 Loc = SM.getImmediateMacroCallerLoc(
Loc);
118 if (AssertMacroName.empty())
121 diag(
Loc,
"found %0() with side effect") << AssertMacroName;