28 auto NegatedString = unaryOperator(
29 hasOperatorName(
"!"), hasUnaryOperand(ignoringImpCasts(stringLiteral())));
31 expr(anyOf(cxxBoolLiteral(equals(
false)), integerLiteral(equals(0)),
32 cxxNullPtrLiteralExpr(), gnuNullExpr(), NegatedString))
33 .bind(
"isAlwaysFalse");
34 auto IsAlwaysFalseWithCast = ignoringParenImpCasts(anyOf(
35 IsAlwaysFalse, cStyleCastExpr(has(ignoringParenImpCasts(IsAlwaysFalse)))
37 auto AssertExprRoot = anyOf(
39 hasAnyOperatorName(
"&&",
"=="),
40 hasEitherOperand(ignoringImpCasts(stringLiteral().bind(
"assertMSG"))),
41 optionally(binaryOperator(hasEitherOperand(IsAlwaysFalseWithCast))))
42 .bind(
"assertExprRoot"),
44 auto NonConstexprFunctionCall =
45 callExpr(hasDeclaration(functionDecl(unless(isConstexpr()))));
46 auto NonConstexprVariableReference =
47 declRefExpr(to(varDecl(unless(isConstexpr()))),
48 unless(hasAncestor(expr(matchers::hasUnevaluatedContext()))),
49 unless(hasAncestor(typeLoc())));
51 auto NonConstexprCode =
52 expr(anyOf(NonConstexprFunctionCall, NonConstexprVariableReference));
53 auto AssertCondition =
54 expr(optionally(expr(ignoringParenCasts(anyOf(
55 AssertExprRoot, unaryOperator(hasUnaryOperand(
56 ignoringParenCasts(AssertExprRoot))))))),
57 unless(NonConstexprCode), unless(hasDescendant(NonConstexprCode)))
60 anyOf(ignoringParenImpCasts(callExpr(
61 hasDeclaration(functionDecl(hasName(
"__builtin_expect"))),
62 hasArgument(0, AssertCondition))),
65 Finder->addMatcher(conditionalOperator(hasCondition(Condition),
66 unless(isInTemplateInstantiation()))
71 ifStmt(hasCondition(Condition), unless(isInTemplateInstantiation()))
77 const ASTContext *ASTCtx = Result.Context;
78 const LangOptions &Opts = ASTCtx->getLangOpts();
79 const SourceManager &SM = ASTCtx->getSourceManager();
80 const auto *CondStmt = Result.Nodes.getNodeAs<Stmt>(
"condStmt");
81 const auto *Condition = Result.Nodes.getNodeAs<Expr>(
"condition");
82 const auto *IsAlwaysFalse = Result.Nodes.getNodeAs<Expr>(
"isAlwaysFalse");
83 const auto *AssertMSG = Result.Nodes.getNodeAs<StringLiteral>(
"assertMSG");
84 const auto *AssertExprRoot =
85 Result.Nodes.getNodeAs<BinaryOperator>(
"assertExprRoot");
86 const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>(
"castExpr");
87 SourceLocation AssertExpansionLoc = CondStmt->getBeginLoc();
89 if (!AssertExpansionLoc.isValid() || !AssertExpansionLoc.isMacroID())
93 Lexer::getImmediateMacroName(AssertExpansionLoc, SM, Opts);
95 if (MacroName !=
"assert" || Condition->isValueDependent() ||
96 Condition->isTypeDependent() || Condition->isInstantiationDependent() ||
97 !Condition->isEvaluatable(*ASTCtx))
101 if (IsAlwaysFalse && (!CastExpr || CastExpr->getType()->isPointerType())) {
102 SourceLocation FalseLiteralLoc =
103 SM.getImmediateSpellingLoc(IsAlwaysFalse->getExprLoc());
104 if (!FalseLiteralLoc.isMacroID())
107 StringRef FalseMacroName =
108 Lexer::getImmediateMacroName(FalseLiteralLoc, SM, Opts);
109 if (FalseMacroName.compare_insensitive(
"false") == 0 ||
110 FalseMacroName.compare_insensitive(
"null") == 0)
114 SourceLocation AssertLoc = SM.getImmediateMacroCallerLoc(AssertExpansionLoc);
116 SmallVector<FixItHint, 4> FixItHints;
117 SourceLocation LastParenLoc;
118 if (AssertLoc.isValid() && !AssertLoc.isMacroID() &&
119 (LastParenLoc = getLastParenLoc(ASTCtx, AssertLoc)).isValid()) {
120 FixItHints.push_back(
121 FixItHint::CreateReplacement(SourceRange(AssertLoc),
"static_assert"));
123 if (AssertExprRoot) {
124 FixItHints.push_back(FixItHint::CreateRemoval(
125 SourceRange(AssertExprRoot->getOperatorLoc())));
126 FixItHints.push_back(FixItHint::CreateRemoval(
127 SourceRange(AssertMSG->getBeginLoc(), AssertMSG->getEndLoc())));
128 FixItHints.push_back(FixItHint::CreateInsertion(
129 LastParenLoc, (Twine(
", \"") + AssertMSG->getString() +
"\"").str()));
130 }
else if (!Opts.CPlusPlus17) {
131 FixItHints.push_back(FixItHint::CreateInsertion(LastParenLoc,
", \"\""));
135 diag(AssertLoc,
"found assert() that could be replaced by static_assert()")
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.