10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/Lex/Lexer.h" 18 namespace performance {
21 if (
const auto *LeftRefType = Left->getAs<ReferenceType>())
22 Left = LeftRefType->getPointeeType();
23 if (
const auto *RightRefType = Right->getAs<ReferenceType>())
24 Right = RightRefType->getPointeeType();
25 return Left->getCanonicalTypeUnqualified() ==
26 Right->getCanonicalTypeUnqualified();
29 void InefficientAlgorithmCheck::registerMatchers(MatchFinder *Finder) {
32 if (!getLangOpts().CPlusPlus)
35 const auto Algorithms =
36 hasAnyName(
"::std::find",
"::std::count",
"::std::equal_range",
37 "::std::lower_bound",
"::std::upper_bound");
38 const auto ContainerMatcher = classTemplateSpecializationDecl(hasAnyName(
39 "::std::set",
"::std::map",
"::std::multiset",
"::std::multimap",
40 "::std::unordered_set",
"::std::unordered_map",
41 "::std::unordered_multiset",
"::std::unordered_multimap"));
45 callee(functionDecl(Algorithms)),
47 0, cxxConstructExpr(has(ignoringParenImpCasts(cxxMemberCallExpr(
48 callee(cxxMethodDecl(hasName(
"begin"))),
50 hasDeclaration(decl().bind(
"IneffContObj")),
51 anyOf(hasType(ContainerMatcher.bind(
"IneffCont")),
53 ContainerMatcher.bind(
"IneffContPtr")))))
54 .bind(
"IneffContExpr"))))))),
56 1, cxxConstructExpr(has(ignoringParenImpCasts(cxxMemberCallExpr(
57 callee(cxxMethodDecl(hasName(
"end"))),
59 hasDeclaration(equalsBoundNode(
"IneffContObj"))))))))),
60 hasArgument(2, expr().bind(
"AlgParam")),
61 unless(isInTemplateInstantiation()))
64 Finder->addMatcher(Matcher,
this);
67 void InefficientAlgorithmCheck::check(
const MatchFinder::MatchResult &Result) {
68 const auto *AlgCall = Result.Nodes.getNodeAs<CallExpr>(
"IneffAlg");
69 const auto *IneffCont =
70 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(
"IneffCont");
71 bool PtrToContainer =
false;
74 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>(
"IneffContPtr");
75 PtrToContainer =
true;
77 const llvm::StringRef IneffContName = IneffCont->getName();
78 const bool Unordered =
79 IneffContName.find(
"unordered") != llvm::StringRef::npos;
80 const bool Maplike = IneffContName.find(
"map") != llvm::StringRef::npos;
84 QualType ValueType = AlgCall->getArg(2)->getType();
86 IneffCont->getTemplateArgs()[0].getAsType().getCanonicalType();
90 if (AlgCall->getNumArgs() == 4 && !Unordered) {
91 const Expr *Arg = AlgCall->getArg(3);
92 const QualType AlgCmp =
93 Arg->getType().getUnqualifiedType().getCanonicalType();
94 const unsigned CmpPosition =
95 (IneffContName.find(
"map") == llvm::StringRef::npos) ? 1 : 2;
96 const QualType ContainerCmp = IneffCont->getTemplateArgs()[CmpPosition]
100 if (AlgCmp != ContainerCmp) {
101 diag(Arg->getBeginLoc(),
102 "different comparers used in the algorithm and the container");
107 const auto *AlgDecl = AlgCall->getDirectCallee();
111 if (Unordered && AlgDecl->getName().find(
"bound") != llvm::StringRef::npos)
114 const auto *AlgParam = Result.Nodes.getNodeAs<Expr>(
"AlgParam");
115 const auto *IneffContExpr = Result.Nodes.getNodeAs<Expr>(
"IneffContExpr");
118 SourceManager &SM = *Result.SourceManager;
119 LangOptions LangOpts = getLangOpts();
121 CharSourceRange CallRange =
135 if (SM.isMacroArgExpansion(CallRange.getBegin()) &&
136 SM.isMacroArgExpansion(CallRange.getEnd())) {
137 CallRange.setBegin(SM.getSpellingLoc(CallRange.getBegin()));
138 CallRange.setEnd(SM.getSpellingLoc(CallRange.getEnd()));
141 if (!CallRange.getBegin().isMacroID() && !Maplike && CompatibleTypes) {
142 StringRef ContainerText = Lexer::getSourceText(
145 StringRef ParamText = Lexer::getSourceText(
148 std::string ReplacementText =
149 (llvm::Twine(ContainerText) + (PtrToContainer ?
"->" :
".") +
150 AlgDecl->getName() +
"(" + ParamText +
")")
152 Hint = FixItHint::CreateReplacement(CallRange, ReplacementText);
155 diag(AlgCall->getBeginLoc(),
156 "this STL algorithm call should be replaced with a container method")
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//