10 #include "clang/AST/ASTContext.h" 11 #include "clang/AST/Expr.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "clang/Frontend/CompilerInstance.h" 14 #include "clang/Lex/Lexer.h" 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/Support/Casting.h" 35 auto NegatedString = unaryOperator(
36 hasOperatorName(
"!"), hasUnaryOperand(ignoringImpCasts(stringLiteral())));
38 expr(anyOf(cxxBoolLiteral(equals(
false)), integerLiteral(equals(0)),
39 cxxNullPtrLiteralExpr(), gnuNullExpr(), NegatedString))
40 .bind(
"isAlwaysFalse");
41 auto IsAlwaysFalseWithCast = ignoringParenImpCasts(anyOf(
42 IsAlwaysFalse, cStyleCastExpr(has(ignoringParenImpCasts(IsAlwaysFalse)))
44 auto AssertExprRoot = anyOf(
46 anyOf(hasOperatorName(
"&&"), hasOperatorName(
"==")),
47 hasEitherOperand(ignoringImpCasts(stringLiteral().bind(
"assertMSG"))),
48 anyOf(binaryOperator(hasEitherOperand(IsAlwaysFalseWithCast)),
50 .bind(
"assertExprRoot"),
52 auto NonConstexprFunctionCall =
53 callExpr(hasDeclaration(functionDecl(unless(isConstexpr()))));
54 auto AssertCondition =
56 anyOf(expr(ignoringParenCasts(anyOf(
57 AssertExprRoot, unaryOperator(hasUnaryOperand(
58 ignoringParenCasts(AssertExprRoot)))))),
60 unless(findAll(NonConstexprFunctionCall)))
63 anyOf(ignoringParenImpCasts(callExpr(
64 hasDeclaration(functionDecl(hasName(
"__builtin_expect"))),
65 hasArgument(0, AssertCondition))),
68 Finder->addMatcher(conditionalOperator(hasCondition(
Condition),
69 unless(isInTemplateInstantiation()))
74 ifStmt(hasCondition(
Condition), unless(isInTemplateInstantiation()))
80 const ASTContext *ASTCtx = Result.Context;
81 const LangOptions &Opts = ASTCtx->getLangOpts();
82 const SourceManager &SM = ASTCtx->getSourceManager();
83 const auto *CondStmt = Result.Nodes.getNodeAs<Stmt>(
"condStmt");
84 const auto *
Condition = Result.Nodes.getNodeAs<Expr>(
"condition");
85 const auto *IsAlwaysFalse = Result.Nodes.getNodeAs<Expr>(
"isAlwaysFalse");
86 const auto *AssertMSG = Result.Nodes.getNodeAs<StringLiteral>(
"assertMSG");
87 const auto *AssertExprRoot =
88 Result.Nodes.getNodeAs<BinaryOperator>(
"assertExprRoot");
89 const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>(
"castExpr");
90 SourceLocation AssertExpansionLoc = CondStmt->getBeginLoc();
92 if (!AssertExpansionLoc.isValid() || !AssertExpansionLoc.isMacroID())
96 Lexer::getImmediateMacroName(AssertExpansionLoc, SM, Opts);
98 if (MacroName !=
"assert" || Condition->isValueDependent() ||
99 Condition->isTypeDependent() || Condition->isInstantiationDependent() ||
100 !Condition->isEvaluatable(*ASTCtx))
104 if (IsAlwaysFalse && (!CastExpr || CastExpr->getType()->isPointerType())) {
105 SourceLocation FalseLiteralLoc =
106 SM.getImmediateSpellingLoc(IsAlwaysFalse->getExprLoc());
107 if (!FalseLiteralLoc.isMacroID())
110 StringRef FalseMacroName =
111 Lexer::getImmediateMacroName(FalseLiteralLoc, SM, Opts);
112 if (FalseMacroName.compare_lower(
"false") == 0 ||
113 FalseMacroName.compare_lower(
"null") == 0)
117 SourceLocation AssertLoc = SM.getImmediateMacroCallerLoc(AssertExpansionLoc);
119 SmallVector<FixItHint, 4> FixItHints;
120 SourceLocation LastParenLoc;
121 if (AssertLoc.isValid() && !AssertLoc.isMacroID() &&
122 (LastParenLoc = getLastParenLoc(ASTCtx, AssertLoc)).isValid()) {
123 FixItHints.push_back(
124 FixItHint::CreateReplacement(SourceRange(AssertLoc),
"static_assert"));
126 std::string StaticAssertMSG =
", \"\"";
127 if (AssertExprRoot) {
128 FixItHints.push_back(FixItHint::CreateRemoval(
129 SourceRange(AssertExprRoot->getOperatorLoc())));
130 FixItHints.push_back(FixItHint::CreateRemoval(
131 SourceRange(AssertMSG->getBeginLoc(), AssertMSG->getEndLoc())));
132 StaticAssertMSG = (Twine(
", \"") + AssertMSG->getString() +
"\"").str();
135 FixItHints.push_back(
136 FixItHint::CreateInsertion(LastParenLoc, StaticAssertMSG));
139 diag(AssertLoc,
"found assert() that could be replaced by static_assert()")
143 SourceLocation StaticAssertCheck::getLastParenLoc(
const ASTContext *ASTCtx,
144 SourceLocation AssertLoc) {
145 const LangOptions &Opts = ASTCtx->getLangOpts();
146 const SourceManager &SM = ASTCtx->getSourceManager();
148 const llvm::MemoryBuffer *Buffer = SM.getBuffer(SM.getFileID(AssertLoc));
150 return SourceLocation();
152 const char *BufferPos = SM.getCharacterData(AssertLoc);
155 Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(AssertLoc)), Opts,
156 Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
159 if (Lexer.LexFromRawLexer(Token) || Lexer.LexFromRawLexer(Token) ||
160 !Token.is(tok::l_paren))
161 return SourceLocation();
163 unsigned int ParenCount = 1;
164 while (ParenCount && !Lexer.LexFromRawLexer(Token)) {
165 if (Token.is(tok::l_paren))
167 else if (Token.is(tok::r_paren))
171 return Token.getLocation();
Base class for all clang-tidy checks.
const LangOptions & getLangOpts() const
Returns the language options from the context.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
static constexpr llvm::StringLiteral Name
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::string Condition
Condition used after the preprocessor directive.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.