blob: cf1be0e7b30276fa06517687dd994843daf123f8 [file] [log] [blame]
Gabor Horvathd4637fb2015-02-10 09:14:26 +00001//===--- InaccurateEraseCheck.cpp - clang-tidy-----------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "InaccurateEraseCheck.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Lex/Lexer.h"
14
15using namespace clang::ast_matchers;
16
17namespace clang {
18namespace tidy {
Alexander Kornienkod4ac4af2017-11-24 14:16:29 +000019namespace bugprone {
Gabor Horvathd4637fb2015-02-10 09:14:26 +000020
Alexander Kornienko0bdd8a12017-06-06 17:49:45 +000021namespace {
22AST_MATCHER(Decl, isInStdNamespace) { return Node.isInStdNamespace(); }
23}
24
Gabor Horvathd4637fb2015-02-10 09:14:26 +000025void InaccurateEraseCheck::registerMatchers(MatchFinder *Finder) {
Aaron Ballman327e97b2015-08-28 19:27:19 +000026 // Only register the matchers for C++; the functionality currently does not
27 // provide any benefit to other languages, despite being benign.
Aaron Ballmanbf891092015-08-31 15:28:57 +000028 if (!getLangOpts().CPlusPlus)
29 return;
Gabor Horvathd4637fb2015-02-10 09:14:26 +000030
Alexander Kornienkof1dc12e2017-06-07 08:25:51 +000031 const auto EndCall =
32 callExpr(
33 callee(functionDecl(hasAnyName("remove", "remove_if", "unique"))),
34 hasArgument(
35 1,
36 anyOf(cxxConstructExpr(has(ignoringImplicit(
37 cxxMemberCallExpr(callee(cxxMethodDecl(hasName("end"))))
38 .bind("end")))),
39 anything())))
40 .bind("alg");
Aaron Ballmanbf891092015-08-31 15:28:57 +000041
Manuel Klimek7b9c1172017-08-02 13:13:11 +000042 const auto DeclInStd = type(hasUnqualifiedDesugaredType(
43 tagType(hasDeclaration(decl(isInStdNamespace())))));
Aaron Ballmanbf891092015-08-31 15:28:57 +000044 Finder->addMatcher(
Aaron Ballmanb9ea09c2015-09-17 13:31:25 +000045 cxxMemberCallExpr(
Alexander Kornienko0bdd8a12017-06-06 17:49:45 +000046 on(anyOf(hasType(DeclInStd), hasType(pointsTo(DeclInStd)))),
Aaron Ballmanb9ea09c2015-09-17 13:31:25 +000047 callee(cxxMethodDecl(hasName("erase"))), argumentCountIs(1),
Alexander Kornienkof1dc12e2017-06-07 08:25:51 +000048 hasArgument(0, has(ignoringImplicit(
49 anyOf(EndCall, has(ignoringImplicit(EndCall)))))),
Aaron Ballmanbf891092015-08-31 15:28:57 +000050 unless(isInTemplateInstantiation()))
Alexander Kornienkof1dc12e2017-06-07 08:25:51 +000051 .bind("erase"),
Aaron Ballmanbf891092015-08-31 15:28:57 +000052 this);
Gabor Horvathd4637fb2015-02-10 09:14:26 +000053}
54
55void InaccurateEraseCheck::check(const MatchFinder::MatchResult &Result) {
56 const auto *MemberCall =
Alexander Kornienkof1dc12e2017-06-07 08:25:51 +000057 Result.Nodes.getNodeAs<CXXMemberCallExpr>("erase");
Gabor Horvathd4637fb2015-02-10 09:14:26 +000058 const auto *EndExpr =
Alexander Kornienkof1dc12e2017-06-07 08:25:51 +000059 Result.Nodes.getNodeAs<CXXMemberCallExpr>("end");
Gabor Horvathd4637fb2015-02-10 09:14:26 +000060 const SourceLocation Loc = MemberCall->getLocStart();
61
62 FixItHint Hint;
63
64 if (!Loc.isMacroID() && EndExpr) {
Alexander Kornienkof1dc12e2017-06-07 08:25:51 +000065 const auto *AlgCall = Result.Nodes.getNodeAs<CallExpr>("alg");
Gabor Horvathd4637fb2015-02-10 09:14:26 +000066 std::string ReplacementText = Lexer::getSourceText(
67 CharSourceRange::getTokenRange(EndExpr->getSourceRange()),
Gabor Horvathafad84c2016-09-24 02:13:45 +000068 *Result.SourceManager, getLangOpts());
Gabor Horvathd4637fb2015-02-10 09:14:26 +000069 const SourceLocation EndLoc = Lexer::getLocForEndOfToken(
Gabor Horvathafad84c2016-09-24 02:13:45 +000070 AlgCall->getLocEnd(), 0, *Result.SourceManager, getLangOpts());
Gabor Horvathd4637fb2015-02-10 09:14:26 +000071 Hint = FixItHint::CreateInsertion(EndLoc, ", " + ReplacementText);
72 }
73
74 diag(Loc, "this call will remove at most one item even when multiple items "
75 "should be removed")
76 << Hint;
77}
78
Alexander Kornienkod4ac4af2017-11-24 14:16:29 +000079} // namespace bugprone
Gabor Horvathd4637fb2015-02-10 09:14:26 +000080} // namespace tidy
81} // namespace clang