[clang-tools-extra] r304879 - [clang-tidy] Make misc-inaccurate-erase work with real C++11 containers.
Alexander Kornienko via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 7 01:25:51 PDT 2017
Author: alexfh
Date: Wed Jun 7 03:25:51 2017
New Revision: 304879
URL: http://llvm.org/viewvc/llvm-project?rev=304879&view=rev
Log:
[clang-tidy] Make misc-inaccurate-erase work with real C++11 containers.
The check failed to match iterator->const_iterator conversion that is happening
at least when using the libstdc++'s vector. We might want to make it match even
more flexible patterns, if we see more false negatives.
Modified:
clang-tools-extra/trunk/clang-tidy/misc/InaccurateEraseCheck.cpp
clang-tools-extra/trunk/test/clang-tidy/misc-inaccurate-erase.cpp
Modified: clang-tools-extra/trunk/clang-tidy/misc/InaccurateEraseCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/InaccurateEraseCheck.cpp?rev=304879&r1=304878&r2=304879&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/InaccurateEraseCheck.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/InaccurateEraseCheck.cpp Wed Jun 7 03:25:51 2017
@@ -28,38 +28,40 @@ void InaccurateEraseCheck::registerMatch
if (!getLangOpts().CPlusPlus)
return;
- const auto CheckForEndCall = hasArgument(
- 1, anyOf(cxxConstructExpr(has(ignoringParenImpCasts(
- cxxMemberCallExpr(callee(cxxMethodDecl(hasName("end"))))
- .bind("InaccEndCall")))),
- anything()));
+ const auto EndCall =
+ callExpr(
+ callee(functionDecl(hasAnyName("remove", "remove_if", "unique"))),
+ hasArgument(
+ 1,
+ anyOf(cxxConstructExpr(has(ignoringImplicit(
+ cxxMemberCallExpr(callee(cxxMethodDecl(hasName("end"))))
+ .bind("end")))),
+ anything())))
+ .bind("alg");
const auto DeclInStd = decl(isInStdNamespace());
Finder->addMatcher(
cxxMemberCallExpr(
on(anyOf(hasType(DeclInStd), hasType(pointsTo(DeclInStd)))),
callee(cxxMethodDecl(hasName("erase"))), argumentCountIs(1),
- hasArgument(0, has(ignoringParenImpCasts(
- callExpr(callee(functionDecl(hasAnyName(
- "remove", "remove_if", "unique"))),
- CheckForEndCall)
- .bind("InaccAlgCall")))),
+ hasArgument(0, has(ignoringImplicit(
+ anyOf(EndCall, has(ignoringImplicit(EndCall)))))),
unless(isInTemplateInstantiation()))
- .bind("InaccErase"),
+ .bind("erase"),
this);
}
void InaccurateEraseCheck::check(const MatchFinder::MatchResult &Result) {
const auto *MemberCall =
- Result.Nodes.getNodeAs<CXXMemberCallExpr>("InaccErase");
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("erase");
const auto *EndExpr =
- Result.Nodes.getNodeAs<CXXMemberCallExpr>("InaccEndCall");
+ Result.Nodes.getNodeAs<CXXMemberCallExpr>("end");
const SourceLocation Loc = MemberCall->getLocStart();
FixItHint Hint;
if (!Loc.isMacroID() && EndExpr) {
- const auto *AlgCall = Result.Nodes.getNodeAs<CallExpr>("InaccAlgCall");
+ const auto *AlgCall = Result.Nodes.getNodeAs<CallExpr>("alg");
std::string ReplacementText = Lexer::getSourceText(
CharSourceRange::getTokenRange(EndExpr->getSourceRange()),
*Result.SourceManager, getLangOpts());
Modified: clang-tools-extra/trunk/test/clang-tidy/misc-inaccurate-erase.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/misc-inaccurate-erase.cpp?rev=304879&r1=304878&r2=304879&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/misc-inaccurate-erase.cpp (original)
+++ clang-tools-extra/trunk/test/clang-tidy/misc-inaccurate-erase.cpp Wed Jun 7 03:25:51 2017
@@ -2,12 +2,15 @@
namespace std {
template <typename T> struct vec_iterator {
- T *ptr;
+ T ptr;
vec_iterator operator++(int);
+
+ template <typename X>
+ vec_iterator(const vec_iterator<X> &); // Omit enable_if<...>.
};
template <typename T> struct vector {
- typedef vec_iterator<T> iterator;
+ typedef vec_iterator<T*> iterator;
iterator begin();
iterator end();
@@ -16,6 +19,17 @@ template <typename T> struct vector {
void erase(iterator, iterator);
};
+template <typename T> struct vector_with_const_iterator {
+ typedef vec_iterator<T*> iterator;
+ typedef vec_iterator<const T*> const_iterator;
+
+ iterator begin();
+ iterator end();
+
+ void erase(const_iterator);
+ void erase(const_iterator, const_iterator);
+};
+
template <typename FwIt, typename T>
FwIt remove(FwIt begin, FwIt end, const T &val);
@@ -61,6 +75,10 @@ int main() {
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one
// CHECK-FIXES: {{^ }}p->erase(remove(p->begin(), p->end(), 11), p->end());{{$}}
+ std::vector_with_const_iterator<int> v2;
+ v2.erase(remove(v2.begin(), v2.end(), 12));
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: this call will remove at most one
+ // CHECK-FIXES: {{^ }}v2.erase(remove(v2.begin(), v2.end(), 12), v2.end());{{$}}
// Fix is not trivial.
auto it = v.end();
More information about the cfe-commits
mailing list