11#include "clang/AST/ASTTypeTraits.h"
12#include "clang/AST/Decl.h"
13#include "clang/AST/DeclCXX.h"
14#include "clang/AST/Expr.h"
15#include "clang/AST/ExprCXX.h"
16#include "clang/AST/NestedNameSpecifierBase.h"
17#include "clang/AST/ParentMapContext.h"
18#include "clang/AST/TemplateBase.h"
19#include "clang/AST/TypeBase.h"
20#include "clang/ASTMatchers/ASTMatchFinder.h"
21#include "clang/ASTMatchers/ASTMatchers.h"
22#include "clang/Lex/Lexer.h"
23#include "clang/Tooling/FixIt.h"
24#include "llvm/ADT/STLExtras.h"
25#include "llvm/ADT/SmallVector.h"
26#include "llvm/Support/ErrorHandling.h"
34AST_MATCHER_P(OverloadExpr, hasAnyUnresolvedName, ArrayRef<StringRef>, Names) {
35 const DeclarationName DeclName = Node.getName();
36 if (!DeclName.isIdentifier())
38 const IdentifierInfo *II = DeclName.getAsIdentifierInfo();
39 return llvm::any_of(Names, [II](StringRef Name) {
return II->isStr(Name); });
44 "cast",
"cast_or_null",
"cast_if_present",
45 "dyn_cast",
"dyn_cast_or_null",
"dyn_cast_if_present"};
51 const auto IsInLLVMNamespace = hasDeclContext(
52 namespaceDecl(hasName(
"llvm"), hasDeclContext(translationUnitDecl())));
53 const auto AnyCastCalleeName =
54 allOf(unless(isMacroID()), unless(cxxMemberCallExpr()),
57 templateArgumentLocCountIs(1))
59 auto AnyCastCalleeNameInUninstantiatedTemplate = allOf(
60 unless(isMacroID()), unless(cxxMemberCallExpr()),
62 templateArgumentLocCountIs(1))
65 callExpr(AnyCastCalleeName, argumentCountIs(1),
67 hasParent(callExpr(AnyCastCalleeName).bind(
"parent_cast"))))
71 const auto AnyIsaCalleeName =
72 allOf(unless(isMacroID()), unless(cxxMemberCallExpr()),
75 hasAnyTemplateArgumentLoc(anything()))
78 callExpr(AnyIsaCalleeName, argumentCountIs(1)).bind(
"call"),
this);
80 auto AnyIsaCalleeNameInUninstantiatedTemplate = allOf(
81 unless(isMacroID()), unless(cxxMemberCallExpr()),
83 hasAnyTemplateArgumentLoc(anything()))
87 anyOf(AnyCastCalleeNameInUninstantiatedTemplate,
88 AnyIsaCalleeNameInUninstantiatedTemplate),
90 optionally(hasAncestor(
91 namespaceDecl(hasName(
"llvm"), hasParent(translationUnitDecl()))
98 QualType Pointee = Ty->getPointeeType();
105 if (NNS.getKind() != NestedNameSpecifier::Kind::Namespace)
107 const auto Pair = NNS.getAsNamespaceAndPrefix();
108 if (Pair.Namespace->getNamespace()->getName() !=
"llvm")
110 const NestedNameSpecifier::Kind Kind = Pair.Prefix.getKind();
111 return Kind == NestedNameSpecifier::Kind::Null ||
112 Kind == NestedNameSpecifier::Kind::Global;
116 const BoundNodes &Nodes = Result.Nodes;
117 const auto *Call = Nodes.getNodeAs<CallExpr>(
"call");
119 ArrayRef<TemplateArgumentLoc> TArgLocs;
120 std::string FuncName;
121 if (
const auto *ResolvedCallee = Nodes.getNodeAs<DeclRefExpr>(
"callee")) {
122 TArgLocs = ResolvedCallee->template_arguments();
123 const auto *F = cast<FunctionDecl>(ResolvedCallee->getDecl());
124 FuncName = F->getName();
125 }
else if (
const auto *UnresolvedCallee =
126 Nodes.getNodeAs<UnresolvedLookupExpr>(
"callee")) {
127 const bool IsExplicitlyLLVM =
129 const auto *CallerNS = Nodes.getNodeAs<NamedDecl>(
"llvm_ns");
130 if (!IsExplicitlyLLVM && !CallerNS)
133 TArgLocs = UnresolvedCallee->template_arguments();
134 FuncName = UnresolvedCallee->getName().getAsString();
136 llvm_unreachable(
"unexpected callee kind");
139 llvm::SmallVector<CanQualType, 4> TargetTypes;
140 for (
const TemplateArgumentLoc &TArgLoc : TArgLocs) {
141 const TemplateArgument TArg = TArgLoc.getArgument();
142 if (TArg.getKind() == TemplateArgument::Type) {
143 const CanQualType TargetTy =
144 TArg.getAsType()->getCanonicalTypeUnqualified();
145 TargetTypes.emplace_back(TargetTy);
146 }
else if (TArg.getKind() == TemplateArgument::Pack) {
147 for (
const TemplateArgument &E : TArg.pack_elements()) {
148 if (E.getKind() != TemplateArgument::Type)
150 TargetTypes.emplace_back(E.getAsType()->getCanonicalTypeUnqualified());
153 llvm_unreachable(
"unexpected template argument");
157 const Expr *Arg =
Call->getArg(0);
158 const QualType ArgTy = Arg->getType();
160 const CanQualType FromTy = ArgPointeeTy->getCanonicalTypeUnqualified();
161 const auto *FromDecl = FromTy->getAsCXXRecordDecl();
162 const bool IsIsa = StringRef(FuncName).starts_with(
"isa");
163 if (!IsIsa && TargetTypes.size() != 1)
166 for (
const CanQualType TargetTy : TargetTypes) {
167 const auto *RetDecl = TargetTy->getAsCXXRecordDecl();
168 const bool IsDerived =
169 FromDecl && RetDecl && FromDecl->isDerivedFrom(RetDecl);
170 if (FromTy != TargetTy && !IsDerived)
174 diag(
Call->getExprLoc(),
"call to '%0' always succeeds") << FuncName;
177 if (
const auto *ParentCast = Nodes.getNodeAs<Expr>(
"parent_cast")) {
178 ParentTy = ParentCast->getType();
181 const TraversalKindScope TmpTraversalKind(*Result.Context, TK_AsIs);
182 for (
const DynTypedNode Parent : Result.Context->getParents(*Call)) {
183 if (
const auto *ParentCastExpr = Parent.get<CastExpr>()) {
184 ParentTy = ParentCastExpr->getType();
189 if (!ParentTy.isNull()) {
190 const CXXRecordDecl *ParentDecl = ParentTy->getAsCXXRecordDecl();
191 if (FromDecl && ParentDecl) {
192 CXXBasePaths Paths(
true,
195 const bool IsDerivedFromParent =
196 FromDecl && ParentDecl &&
197 FromDecl->isDerivedFrom(ParentDecl, Paths);
204 if (IsDerivedFromParent &&
205 Paths.isAmbiguous(ParentTy->getCanonicalTypeUnqualified()))
210 diag(
Call->getExprLoc(),
"redundant use of '%0'")
212 << tooling::fixit::createReplacement(*Call, *Arg, *Result.Context);
216 const QualType DiagFromTy(ArgPointeeTy->getUnqualifiedDesugaredType(), 0);
219 "source expression has%select{| pointee}0 type %1%select{|, which is a "
222 << Arg->getSourceRange() << ArgTy->isPointerType() << DiagFromTy
223 << (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)