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 "llvm/ADT/STLExtras.h"
29AST_MATCHER(Expr, isMacroID) {
return Node.getExprLoc().isMacroID(); }
30AST_MATCHER_P(OverloadExpr, hasAnyUnresolvedName, ArrayRef<StringRef>, Names) {
31 auto DeclName = Node.getName();
32 if (!DeclName.isIdentifier())
34 const IdentifierInfo *II = DeclName.getAsIdentifierInfo();
35 return llvm::any_of(Names, [II](StringRef Name) {
return II->isStr(Name); });
40 "cast",
"cast_or_null",
"cast_if_present",
41 "dyn_cast",
"dyn_cast_or_null",
"dyn_cast_if_present"};
44 auto IsInLLVMNamespace = hasDeclContext(
45 namespaceDecl(hasName(
"llvm"), hasDeclContext(translationUnitDecl())));
47 allOf(unless(isMacroID()), unless(cxxMemberCallExpr()),
48 callee(expr(ignoringImpCasts(
51 templateArgumentLocCountIs(1))
53 auto AnyCalleeNameInUninstantiatedTemplate =
54 allOf(unless(isMacroID()), unless(cxxMemberCallExpr()),
55 callee(expr(ignoringImpCasts(
57 templateArgumentLocCountIs(1))
59 Finder->addMatcher(callExpr(AnyCalleeName, argumentCountIs(1),
61 callExpr(AnyCalleeName).bind(
"parent_cast"))))
66 AnyCalleeNameInUninstantiatedTemplate, argumentCountIs(1),
67 optionally(hasAncestor(
68 namespaceDecl(hasName(
"llvm"), hasParent(translationUnitDecl()))
75 QualType Pointee = Ty->getPointeeType();
82 if (NNS.getKind() != NestedNameSpecifier::Kind::Namespace)
84 auto Pair = NNS.getAsNamespaceAndPrefix();
85 if (Pair.Namespace->getNamespace()->getName() !=
"llvm")
87 const NestedNameSpecifier::Kind Kind = Pair.Prefix.getKind();
88 return Kind == NestedNameSpecifier::Kind::Null ||
89 Kind == NestedNameSpecifier::Kind::Global;
93 const auto &Nodes = Result.Nodes;
94 const auto *Call = Nodes.getNodeAs<CallExpr>(
"call");
98 if (
const auto *ResolvedCallee = Nodes.getNodeAs<DeclRefExpr>(
"callee")) {
99 const auto *F = cast<FunctionDecl>(ResolvedCallee->getDecl());
101 ->getCanonicalTypeUnqualified();
102 FuncName = F->getName();
103 }
else if (
const auto *UnresolvedCallee =
104 Nodes.getNodeAs<UnresolvedLookupExpr>(
"callee")) {
105 const bool IsExplicitlyLLVM =
107 const auto *CallerNS = Nodes.getNodeAs<NamedDecl>(
"llvm_ns");
108 if (!IsExplicitlyLLVM && !CallerNS)
110 auto TArg = UnresolvedCallee->template_arguments()[0].getArgument();
111 if (TArg.getKind() != TemplateArgument::Type)
114 RetTy = TArg.getAsType()->getCanonicalTypeUnqualified();
115 FuncName = UnresolvedCallee->getName().getAsString();
117 llvm_unreachable(
"");
120 const auto *Arg =
Call->getArg(0);
121 const QualType ArgTy = Arg->getType();
123 const CanQualType FromTy = ArgPointeeTy->getCanonicalTypeUnqualified();
124 const auto *FromDecl = FromTy->getAsCXXRecordDecl();
125 const auto *RetDecl = RetTy->getAsCXXRecordDecl();
126 const bool IsDerived =
127 FromDecl && RetDecl && FromDecl->isDerivedFrom(RetDecl);
128 if (FromTy != RetTy && !IsDerived)
132 if (
const auto *ParentCast = Nodes.getNodeAs<Expr>(
"parent_cast")) {
133 ParentTy = ParentCast->getType();
136 const TraversalKindScope TmpTraversalKind(*Result.Context, TK_AsIs);
137 for (
const DynTypedNode Parent : Result.Context->getParents(*Call)) {
138 if (
const auto *ParentCastExpr = Parent.get<CastExpr>()) {
139 ParentTy = ParentCastExpr->getType();
144 if (!ParentTy.isNull()) {
145 const CXXRecordDecl *ParentDecl = ParentTy->getAsCXXRecordDecl();
146 if (FromDecl && ParentDecl) {
147 CXXBasePaths Paths(
true,
150 const bool IsDerivedFromParent =
151 FromDecl && ParentDecl && FromDecl->isDerivedFrom(ParentDecl, Paths);
158 if (IsDerivedFromParent &&
159 Paths.isAmbiguous(ParentTy->getCanonicalTypeUnqualified()))
164 auto GetText = [&](SourceRange R) {
165 return Lexer::getSourceText(CharSourceRange::getTokenRange(R),
166 *Result.SourceManager, getLangOpts());
168 StringRef ArgText = GetText(Arg->getSourceRange());
169 diag(
Call->getExprLoc(),
"redundant use of '%0'")
171 << FixItHint::CreateReplacement(
Call->getSourceRange(), ArgText);
174 const QualType DiagFromTy(ArgPointeeTy->getUnqualifiedDesugaredType(), 0);
175 diag(Arg->getExprLoc(),
176 "source expression has%select{| pointee}0 type %1%select{|, which is a "
179 << Arg->getSourceRange() << ArgTy->isPointerType() << DiagFromTy
180 << (FromTy != RetTy) << RetTy;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
static bool isLLVMNamespace(NestedNameSpecifier NNS)
static QualType stripPointerOrReference(QualType Ty)
static constexpr StringRef FunctionNames[]
AST_MATCHER_P(Stmt, isStatementIdenticalToBoundNode, std::string, ID)
AST_MATCHER(BinaryOperator, isRelationalOperator)