11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Lex/Lexer.h"
18namespace ast_matchers {
22namespace tidy::llvm_check {
25 MatchFinder *Finder) {
26 auto Condition = hasCondition(implicitCastExpr(has(
27 callExpr(unless(isMacroID()), unless(cxxMemberCallExpr()),
28 anyOf(callee(namedDecl(hasName(
"cast"))),
29 callee(namedDecl(hasName(
"dyn_cast")).bind(
"dyn_cast"))))
33 has(declStmt(containsDeclaration(
34 0, varDecl(hasInitializer(callExpr(unless(isMacroID()),
35 unless(cxxMemberCallExpr()),
36 callee(namedDecl(hasName(
"cast"))))
43 unless(isMacroID()), unless(cxxMemberCallExpr()),
44 callee(namedDecl(hasAnyName(
"isa",
"cast",
"cast_or_null",
"dyn_cast",
47 hasArgument(0, mapAnyOf(declRefExpr, cxxMemberCallExpr).bind(
"arg")))
54 ifStmt(Any), whileStmt(Any), doStmt(
Condition),
55 binaryOperator(unless(isExpansionInFileMatching(
56 "llvm/include/llvm/Support/Casting.h")),
57 hasOperatorName(
"&&"),
58 hasLHS(implicitCastExpr().bind(
"lhs")),
59 hasRHS(anyOf(implicitCastExpr(has(CallExpression)),
66 const MatchFinder::MatchResult &Result) {
67 if (
const auto *MatchedDecl = Result.Nodes.getNodeAs<CallExpr>(
"assign")) {
68 SourceLocation StartLoc = MatchedDecl->getCallee()->getExprLoc();
69 SourceLocation EndLoc =
70 StartLoc.getLocWithOffset(StringRef(
"cast").size() - 1);
72 diag(MatchedDecl->getBeginLoc(),
73 "cast<> in conditional will assert rather than return a null pointer")
74 << FixItHint::CreateReplacement(SourceRange(StartLoc, EndLoc),
76 }
else if (
const auto *MatchedDecl =
77 Result.Nodes.getNodeAs<CallExpr>(
"call")) {
78 SourceLocation StartLoc = MatchedDecl->getCallee()->getExprLoc();
79 SourceLocation EndLoc =
80 StartLoc.getLocWithOffset(StringRef(
"cast").size() - 1);
83 "cast<> in conditional will assert rather than return a null pointer";
84 if (Result.Nodes.getNodeAs<NamedDecl>(
"dyn_cast"))
85 Message =
"return value from dyn_cast<> not used";
87 diag(MatchedDecl->getBeginLoc(), Message)
88 << FixItHint::CreateReplacement(SourceRange(StartLoc, EndLoc),
"isa");
89 }
else if (
const auto *MatchedDecl =
90 Result.Nodes.getNodeAs<BinaryOperator>(
"and")) {
91 const auto *LHS = Result.Nodes.getNodeAs<ImplicitCastExpr>(
"lhs");
92 const auto *RHS = Result.Nodes.getNodeAs<CallExpr>(
"rhs");
93 const auto *Arg = Result.Nodes.getNodeAs<Expr>(
"arg");
94 const auto *Func = Result.Nodes.getNodeAs<NamedDecl>(
"func");
96 assert(LHS &&
"LHS is null");
97 assert(RHS &&
"RHS is null");
98 assert(Arg &&
"Arg is null");
99 assert(Func &&
"Func is null");
101 StringRef LHSString(Lexer::getSourceText(
102 CharSourceRange::getTokenRange(LHS->getSourceRange()),
105 StringRef ArgString(Lexer::getSourceText(
106 CharSourceRange::getTokenRange(Arg->getSourceRange()),
109 if (ArgString != LHSString)
112 StringRef RHSString(Lexer::getSourceText(
113 CharSourceRange::getTokenRange(RHS->getSourceRange()),
116 std::string Replacement(
"isa_and_nonnull");
117 Replacement += RHSString.substr(Func->getName().size());
119 diag(MatchedDecl->getBeginLoc(),
120 "isa_and_nonnull<> is preferred over an explicit test for null "
121 "followed by calling isa<>")
122 << FixItHint::CreateReplacement(SourceRange(MatchedDecl->getBeginLoc(),
123 MatchedDecl->getEndLoc()),
std::string Condition
Condition used after the preprocessor directive.
::clang::DynTypedNode Node
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
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.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
AST_MATCHER(Decl, declHasNoReturnAttr)
matches a Decl if it has a "no return" attribute of any kind
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//