10#include "clang/AST/ASTTypeTraits.h"
11#include "clang/AST/Decl.h"
12#include "clang/AST/DeclCXX.h"
13#include "clang/AST/Expr.h"
14#include "clang/AST/ExprCXX.h"
15#include "clang/AST/NestedNameSpecifierBase.h"
16#include "clang/AST/ParentMapContext.h"
17#include "clang/AST/TemplateBase.h"
18#include "clang/AST/TypeBase.h"
19#include "clang/ASTMatchers/ASTMatchFinder.h"
20#include "clang/ASTMatchers/ASTMatchers.h"
21#include "clang/Lex/Lexer.h"
22#include "clang/Tooling/FixIt.h"
23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/SmallVector.h"
25#include "llvm/Support/ErrorHandling.h"
32AST_MATCHER(Expr, isMacroID) {
return Node.getExprLoc().isMacroID(); }
33AST_MATCHER_P(OverloadExpr, hasAnyUnresolvedName, ArrayRef<StringRef>, Names) {
34 const DeclarationName DeclName = Node.getName();
35 if (!DeclName.isIdentifier())
37 const IdentifierInfo *II = DeclName.getAsIdentifierInfo();
38 return llvm::any_of(Names, [II](StringRef Name) {
return II->isStr(Name); });
43 "cast",
"cast_or_null",
"cast_if_present",
44 "dyn_cast",
"dyn_cast_or_null",
"dyn_cast_if_present"};
50 auto IsInLLVMNamespace = hasDeclContext(
51 namespaceDecl(hasName(
"llvm"), hasDeclContext(translationUnitDecl())));
52 auto AnyCastCalleeName =
53 allOf(unless(isMacroID()), unless(cxxMemberCallExpr()),
56 templateArgumentLocCountIs(1))
58 auto AnyCastCalleeNameInUninstantiatedTemplate = allOf(
59 unless(isMacroID()), unless(cxxMemberCallExpr()),
61 templateArgumentLocCountIs(1))
64 callExpr(AnyCastCalleeName, argumentCountIs(1),
66 hasParent(callExpr(AnyCastCalleeName).bind(
"parent_cast"))))
70 auto AnyIsaCalleeName =
71 allOf(unless(isMacroID()), unless(cxxMemberCallExpr()),
74 hasAnyTemplateArgumentLoc(anything()))
77 callExpr(AnyIsaCalleeName, argumentCountIs(1)).bind(
"call"),
this);
79 auto AnyIsaCalleeNameInUninstantiatedTemplate = allOf(
80 unless(isMacroID()), unless(cxxMemberCallExpr()),
82 hasAnyTemplateArgumentLoc(anything()))
86 anyOf(AnyCastCalleeNameInUninstantiatedTemplate,
87 AnyIsaCalleeNameInUninstantiatedTemplate),
89 optionally(hasAncestor(
90 namespaceDecl(hasName(
"llvm"), hasParent(translationUnitDecl()))
97 QualType Pointee = Ty->getPointeeType();
104 if (NNS.getKind() != NestedNameSpecifier::Kind::Namespace)
106 auto Pair = NNS.getAsNamespaceAndPrefix();
107 if (Pair.Namespace->getNamespace()->getName() !=
"llvm")
109 const NestedNameSpecifier::Kind Kind = Pair.Prefix.getKind();
110 return Kind == NestedNameSpecifier::Kind::Null ||
111 Kind == NestedNameSpecifier::Kind::Global;
115 const BoundNodes &Nodes = Result.Nodes;
116 const auto *Call = Nodes.getNodeAs<CallExpr>(
"call");
118 ArrayRef<TemplateArgumentLoc> TArgLocs;
119 std::string FuncName;
120 if (
const auto *ResolvedCallee = Nodes.getNodeAs<DeclRefExpr>(
"callee")) {
121 TArgLocs = ResolvedCallee->template_arguments();
122 const auto *F = cast<FunctionDecl>(ResolvedCallee->getDecl());
123 FuncName = F->getName();
124 }
else if (
const auto *UnresolvedCallee =
125 Nodes.getNodeAs<UnresolvedLookupExpr>(
"callee")) {
126 const bool IsExplicitlyLLVM =
128 const auto *CallerNS = Nodes.getNodeAs<NamedDecl>(
"llvm_ns");
129 if (!IsExplicitlyLLVM && !CallerNS)
132 TArgLocs = UnresolvedCallee->template_arguments();
133 FuncName = UnresolvedCallee->getName().getAsString();
135 llvm_unreachable(
"unexpected callee kind");
138 llvm::SmallVector<CanQualType, 4> TargetTypes;
139 for (
const TemplateArgumentLoc &TArgLoc : TArgLocs) {
140 const TemplateArgument TArg = TArgLoc.getArgument();
141 if (TArg.getKind() == TemplateArgument::Type) {
142 const CanQualType TargetTy =
143 TArg.getAsType()->getCanonicalTypeUnqualified();
144 TargetTypes.emplace_back(TargetTy);
145 }
else if (TArg.getKind() == TemplateArgument::Pack) {
146 for (
const TemplateArgument &E : TArg.pack_elements()) {
147 if (E.getKind() != TemplateArgument::Type)
149 TargetTypes.emplace_back(E.getAsType()->getCanonicalTypeUnqualified());
152 llvm_unreachable(
"unexpected template argument");
156 const Expr *Arg =
Call->getArg(0);
157 const QualType ArgTy = Arg->getType();
159 const CanQualType FromTy = ArgPointeeTy->getCanonicalTypeUnqualified();
160 const auto *FromDecl = FromTy->getAsCXXRecordDecl();
161 const bool IsIsa = StringRef(FuncName).starts_with(
"isa");
162 if (!IsIsa && TargetTypes.size() != 1)
165 for (
const CanQualType TargetTy : TargetTypes) {
166 const auto *RetDecl = TargetTy->getAsCXXRecordDecl();
167 const bool IsDerived =
168 FromDecl && RetDecl && FromDecl->isDerivedFrom(RetDecl);
169 if (FromTy != TargetTy && !IsDerived)
173 diag(
Call->getExprLoc(),
"call to '%0' always succeeds") << FuncName;
176 if (
const auto *ParentCast = Nodes.getNodeAs<Expr>(
"parent_cast")) {
177 ParentTy = ParentCast->getType();
180 const TraversalKindScope TmpTraversalKind(*Result.Context, TK_AsIs);
181 for (
const DynTypedNode Parent : Result.Context->getParents(*Call)) {
182 if (
const auto *ParentCastExpr = Parent.get<CastExpr>()) {
183 ParentTy = ParentCastExpr->getType();
188 if (!ParentTy.isNull()) {
189 const CXXRecordDecl *ParentDecl = ParentTy->getAsCXXRecordDecl();
190 if (FromDecl && ParentDecl) {
191 CXXBasePaths Paths(
true,
194 const bool IsDerivedFromParent =
195 FromDecl && ParentDecl &&
196 FromDecl->isDerivedFrom(ParentDecl, Paths);
203 if (IsDerivedFromParent &&
204 Paths.isAmbiguous(ParentTy->getCanonicalTypeUnqualified()))
209 diag(
Call->getExprLoc(),
"redundant use of '%0'")
211 << tooling::fixit::createReplacement(*Call, *Arg, *Result.Context);
215 const QualType DiagFromTy(ArgPointeeTy->getUnqualifiedDesugaredType(), 0);
218 "source expression has%select{| pointee}0 type %1%select{|, which is a "
221 << Arg->getSourceRange() << ArgTy->isPointerType() << DiagFromTy
222 << (FromTy != TargetTy) << TargetTy;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
static constexpr StringRef CastFunctionNames[]
static bool isLLVMNamespace(NestedNameSpecifier NNS)
static constexpr StringRef IsaFunctionNames[]
static QualType stripPointerOrReference(QualType Ty)
AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID)
AST_MATCHER(BinaryOperator, isRelationalOperator)