[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