[clang-tools-extra] 3adaa97 - Fix ForRangeCopyCheck not triggering on iterators returning elements by value in C++17.

Dmitri Gribenko via cfe-commits cfe-commits at lists.llvm.org
Wed May 6 00:44:29 PDT 2020


Author: Dmitri Gribenko
Date: 2020-05-06T09:42:13+02:00
New Revision: 3adaa97f0157e9d274c4d4e69b733db75b963574

URL: https://github.com/llvm/llvm-project/commit/3adaa97f0157e9d274c4d4e69b733db75b963574
DIFF: https://github.com/llvm/llvm-project/commit/3adaa97f0157e9d274c4d4e69b733db75b963574.diff

LOG: Fix ForRangeCopyCheck not triggering on iterators returning elements by value in C++17.

Summary:
The AST is different in C++17 in that there is no MaterializeTemporaryExpr for in the AST for a loop variable that is initialized from an iterator that returns its elements by value.

Account for this by checking that the variable is not initialized by an operator* call that returns a value type.

Reviewers: gribozavr2

Reviewed By: gribozavr2

Subscribers: cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D79440

Added: 
    

Modified: 
    clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
    clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
index 579d4fa3d786..38dba7b89707 100644
--- a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp
@@ -37,12 +37,18 @@ void ForRangeCopyCheck::registerMatchers(MatchFinder *Finder) {
   // Match loop variables that are not references or pointers or are already
   // initialized through MaterializeTemporaryExpr which indicates a type
   // conversion.
-  auto LoopVar = varDecl(
-      hasType(qualType(
-          unless(anyOf(hasCanonicalType(anyOf(referenceType(), pointerType())),
-                       hasDeclaration(namedDecl(
-                           matchers::matchesAnyListedName(AllowedTypes))))))),
-      unless(hasInitializer(expr(hasDescendant(materializeTemporaryExpr())))));
+  auto HasReferenceOrPointerTypeOrIsAllowed = hasType(qualType(
+      unless(anyOf(hasCanonicalType(anyOf(referenceType(), pointerType())),
+                   hasDeclaration(namedDecl(
+                       matchers::matchesAnyListedName(AllowedTypes)))))));
+  auto IteratorReturnsValueType = cxxOperatorCallExpr(
+      hasOverloadedOperatorName("*"),
+      callee(
+          cxxMethodDecl(returns(unless(hasCanonicalType(referenceType()))))));
+  auto LoopVar =
+      varDecl(HasReferenceOrPointerTypeOrIsAllowed,
+              unless(hasInitializer(expr(hasDescendant(expr(anyOf(
+                  materializeTemporaryExpr(), IteratorReturnsValueType)))))));
   Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar")))
                          .bind("forRange"),
                      this);

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
index e51142161ed9..e22650e10198 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/performance-for-range-copy.cpp
@@ -28,6 +28,7 @@ struct Iterator {
 };
 template <typename T>
 struct View {
+  View() = default;
   T begin() { return T(); }
   T begin() const { return T(); }
   T end() { return T(); }
@@ -270,3 +271,28 @@ void IgnoreLoopVariableNotUsedInLoopBody() {
   for (auto _ : View<Iterator<S>>()) {
   }
 }
+
+template <typename T>
+struct ValueReturningIterator {
+  void operator++() {}
+  T operator*() { return T(); }
+  bool operator!=(const ValueReturningIterator &) { return false; }
+  typedef const T &const_reference;
+};
+
+void negativeValueIterator() {
+  // Check does not trigger for iterators that return elements by value.
+  for (const S SS : View<ValueReturningIterator<S>>()) {
+  }
+}
+
+View<Iterator<S>> createView(S) { return View<Iterator<S>>(); }
+
+void positiveValueIteratorUsedElseWhere() {
+  for (const S SS : createView(*ValueReturningIterator<S>())) {
+    // CHECK-MESSAGES: [[@LINE-1]]:16: warning: the loop variable's type is not
+    // a reference type; this creates a copy in each iteration; consider making
+    // this a reference [performance-for-range-copy] CHECK-FIXES: for (const S&
+    // SS : createView(*ValueReturningIterator<S>())) {
+  }
+}


        


More information about the cfe-commits mailing list