Hi revane,

Check if the dereference operator for the iterator returns a const
element and use 'auto const &' in such cases.

Fixes: 15601

http://llvm-reviews.chandlerc.com/D641

Files:
  cpp11-migrate/LoopConvert/LoopActions.cpp
  cpp11-migrate/LoopConvert/LoopActions.h
  cpp11-migrate/LoopConvert/LoopMatchers.cpp
  cpp11-migrate/LoopConvert/LoopMatchers.h
  test/cpp11-migrate/LoopConvert/iterator.cpp
  test/cpp11-migrate/LoopConvert/naming-conflict.cpp
  test/cpp11-migrate/LoopConvert/single-iterator.cpp
Index: cpp11-migrate/LoopConvert/LoopActions.cpp
===================================================================
--- cpp11-migrate/LoopConvert/LoopActions.cpp
+++ cpp11-migrate/LoopConvert/LoopActions.cpp
@@ -735,7 +735,8 @@
                              const UsageResult &Usages,
                              const DeclStmt *AliasDecl, const ForStmt *TheLoop,
                              bool ContainerNeedsDereference,
-                             bool DerefByValue) {
+                             bool DerefByValue,
+                             bool IteratorPointsToConst) {
   std::string VarName;
   bool VarNameFromAlias = Usages.size() == 1 && AliasDecl;
   bool AliasVarIsRef = false;
@@ -783,8 +784,12 @@
     // to 'T&&'.
     if (DerefByValue)
       AutoRefType = Context->getRValueReferenceType(AutoRefType);
-    else
+    else {
+      if (IteratorPointsToConst)
+        AutoRefType = Context->getConstType(AutoRefType);
+
       AutoRefType = Context->getLValueReferenceType(AutoRefType);
+    }
   }
 
   std::string MaybeDereference = ContainerNeedsDereference ? "*" : "";
@@ -913,6 +918,7 @@
                                     const Expr *BoundExpr,
                                     bool ContainerNeedsDereference,
                                     bool DerefByValue,
+                                    bool IteratorPointsToConst,
                                     const ForStmt *TheLoop,
                                     Confidence ConfidenceLevel) {
   ForLoopIndexUseVisitor Finder(Context, LoopVar, EndVar, ContainerExpr,
@@ -947,7 +953,7 @@
   doConversion(Context, LoopVar, getReferencedVariable(ContainerExpr),
                ContainerString, Finder.getUsages(),
                Finder.getAliasDecl(), TheLoop, ContainerNeedsDereference,
-               DerefByValue);
+               DerefByValue, IteratorPointsToConst);
   ++*AcceptedChanges;
 }
 
@@ -986,12 +992,38 @@
 
   const Expr *ContainerExpr = NULL;
   bool ContainerNeedsDereference = false;
+  bool DerefByValue = false;
+  bool IteratorPointsToConst = false;
   // FIXME: Try to put most of this logic inside a matcher. Currently, matchers
   // don't allow the right-recursive checks in digThroughConstructors.
-  if (FixerKind == LFK_Iterator)
+  if (FixerKind == LFK_Iterator) {
     ContainerExpr = findContainer(Context, LoopVar->getInit(),
                                   EndVar ? EndVar->getInit() : EndCall,
                                   &ContainerNeedsDereference);
+
+    DerefByValue = Nodes.getNodeAs<QualType>(DerefByValueResultName) != 0;
+    if (!DerefByValue) {
+      // If the iterator dereference operator returns by reference, check if it
+      // returns a const reference or not.
+      const QualType *IteratorType =
+          Nodes.getNodeAs<QualType>(DerefByRefResultName);
+      if (IteratorType) {
+        const ReferenceType *IteratorReferenceType =
+            IteratorType->getTypePtr()->getAs<ReferenceType>();
+        IteratorPointsToConst =
+            IteratorReferenceType->getPointeeType().isConstQualified();
+      } else {
+        // For non-class iterator types, check if the pointee type is const or
+        // not.
+        QualType PointerType = InitVar->getType();
+        assert(PointerType.getTypePtr()->isPointerType() &&
+               "Non-class iterator type is not a pointer type.");
+        QualType CanonicalPointerType = PointerType.getCanonicalType();
+        IteratorPointsToConst = CanonicalPointerType.getTypePtr()
+            ->getPointeeType().isConstQualified();
+      }
+    }
+  }
   else if (FixerKind == LFK_PseudoArray) {
     if (!EndCall)
       return;
@@ -1005,9 +1037,8 @@
   if (!ContainerExpr && !BoundExpr)
     return;
 
-  bool DerefByValue = Nodes.getNodeAs<QualType>(DerefByValueResultName) != 0;
 
   findAndVerifyUsages(Context, LoopVar, EndVar, ContainerExpr, BoundExpr,
-                      ContainerNeedsDereference, DerefByValue, TheLoop,
+                      ContainerNeedsDereference, DerefByValue, IteratorPointsToConst, TheLoop,
                       ConfidenceLevel);
 }
Index: cpp11-migrate/LoopConvert/LoopActions.h
===================================================================
--- cpp11-migrate/LoopConvert/LoopActions.h
+++ cpp11-migrate/LoopConvert/LoopActions.h
@@ -75,7 +75,8 @@
                     const clang::DeclStmt *AliasDecl,
                     const clang::ForStmt *TheLoop,
                     bool ContainerNeedsDereference,
-                    bool DerefByValue);
+                    bool DerefByValue,
+                    bool IteratorPointsToConst);
 
   /// \brief Given a loop header that would be convertible, discover all usages
   /// of the index variable and convert the loop if possible.
@@ -86,6 +87,7 @@
                            const clang::Expr *BoundExpr,
                            bool ContainerNeedsDereference,
                            bool DerefByValue,
+                           bool IteratorPointsToConst,
                            const clang::ForStmt *TheLoop,
                            Confidence ConfidenceLevel);
 
Index: cpp11-migrate/LoopConvert/LoopMatchers.cpp
===================================================================
--- cpp11-migrate/LoopConvert/LoopMatchers.cpp
+++ cpp11-migrate/LoopConvert/LoopMatchers.cpp
@@ -26,6 +26,7 @@
 const char ConditionEndVarName[] = "conditionEndVar";
 const char EndVarName[] = "endVar";
 const char DerefByValueResultName[] = "derefByValueResult";
+const char DerefByRefResultName[] = "derefByRefResult";
 
 // shared matchers
 static const TypeMatcher AnyType = anything();
@@ -157,7 +158,8 @@
                 returns(
                   // Skip loops where the iterator's operator* returns an
                   // rvalue reference. This is just weird.
-                  qualType(unless(hasCanonicalType(rValueReferenceType())))
+                  qualType(unless(hasCanonicalType(rValueReferenceType()))
+                  ).bind(DerefByRefResultName)
                 )
               )
             )
Index: cpp11-migrate/LoopConvert/LoopMatchers.h
===================================================================
--- cpp11-migrate/LoopConvert/LoopMatchers.h
+++ cpp11-migrate/LoopConvert/LoopMatchers.h
@@ -31,6 +31,7 @@
 extern const char EndCallName[];
 extern const char EndVarName[];
 extern const char DerefByValueResultName[];
+extern const char DerefByRefResultName[];
 
 clang::ast_matchers::StatementMatcher makeArrayLoopMatcher();
 clang::ast_matchers::StatementMatcher makeIteratorLoopMatcher();
Index: test/cpp11-migrate/LoopConvert/iterator.cpp
===================================================================
--- test/cpp11-migrate/LoopConvert/iterator.cpp
+++ test/cpp11-migrate/LoopConvert/iterator.cpp
@@ -26,20 +26,20 @@
   for (S::const_iterator it = s.begin(), e = s.end(); it != e; ++it) {
     printf("s has value %d\n", (*it).x);
   }
-  // CHECK: for (auto & elem : s)
+  // CHECK: for (auto const & elem : s)
   // CHECK-NEXT: printf("s has value %d\n", (elem).x);
 
   S *ps;
   for (S::const_iterator it = ps->begin(), e = ps->end(); it != e; ++it) {
     printf("s has value %d\n", (*it).x);
   }
-  // CHECK: for (auto & p : *ps)
+  // CHECK: for (auto const & p : *ps)
   // CHECK-NEXT: printf("s has value %d\n", (p).x);
 
   for (S::const_iterator it = s.begin(), e = s.end(); it != e; ++it) {
     printf("s has value %d\n", it->x);
   }
-  // CHECK: for (auto & elem : s)
+  // CHECK: for (auto const & elem : s)
   // CHECK-NEXT: printf("s has value %d\n", elem.x);
 
   for (S::iterator it = s.begin(), e = s.end(); it != e; ++it) {
@@ -84,14 +84,14 @@
        it != e; ++it) {
     printf("Fibonacci number is %d\n", *it);
   }
-  // CHECK: for (auto & elem : v)
+  // CHECK: for (auto const & elem : v)
   // CHECK-NEXT: printf("Fibonacci number is %d\n", elem);
 
   for (dependent<int>::const_iterator it(v.begin()), e = v.end();
        it != e; ++it) {
     printf("Fibonacci number is %d\n", *it);
   }
-  // CHECK: for (auto & elem : v)
+  // CHECK: for (auto const & elem : v)
   // CHECK-NEXT: printf("Fibonacci number is %d\n", elem);
 
   doublyDependent<int,int> intmap;
@@ -174,14 +174,14 @@
 
   void doLoop() const {
     for (const_iterator I = begin(), E = end(); I != E; ++I) {
-      // CHECK: for (auto & elem : *this) {
+      // CHECK: for (auto const & elem : *this) {
     }
     for (const_iterator I = C::begin(), E = C::end(); I != E; ++I) {
-      // CHECK: for (auto & elem : *this) {
+      // CHECK: for (auto const & elem : *this) {
     }
     for (const_iterator I = begin(), E = end(); I != E; ++I) {
       // CHECK: for (const_iterator I = begin(), E = end(); I != E; ++I) {
-      // RISKY: for (auto & elem : *this) {
+      // RISKY: for (auto const & elem : *this) {
       doSomething();
     }
   }
Index: test/cpp11-migrate/LoopConvert/naming-conflict.cpp
===================================================================
--- test/cpp11-migrate/LoopConvert/naming-conflict.cpp
+++ test/cpp11-migrate/LoopConvert/naming-conflict.cpp
@@ -36,7 +36,7 @@
     printf("s has value %d\n", (*it).x);
     printf("Max of 3 and 5: %d\n", MAX(3,5));
   }
-  // CHECK: for (auto & MAXs_it : MAXs)
+  // CHECK: for (auto const & MAXs_it : MAXs)
   // CHECK-NEXT: printf("s has value %d\n", (MAXs_it).x);
   // CHECK-NEXT: printf("Max of 3 and 5: %d\n", MAX(3,5));
 
Index: test/cpp11-migrate/LoopConvert/single-iterator.cpp
===================================================================
--- test/cpp11-migrate/LoopConvert/single-iterator.cpp
+++ test/cpp11-migrate/LoopConvert/single-iterator.cpp
@@ -37,20 +37,20 @@
   for (S::const_iterator it = s.begin(); it != s.end(); ++it) {
     printf("s has value %d\n", (*it).x);
   }
-  // CHECK: for (auto & elem : s)
+  // CHECK: for (auto const & elem : s)
   // CHECK-NEXT: printf("s has value %d\n", (elem).x);
 
   S *ps;
   for (S::const_iterator it = ps->begin(); it != ps->end(); ++it) {
     printf("s has value %d\n", (*it).x);
   }
-  // CHECK: for (auto & p : *ps)
+  // CHECK: for (auto const & p : *ps)
   // CHECK-NEXT: printf("s has value %d\n", (p).x);
 
   for (S::const_iterator it = s.begin(); it != s.end(); ++it) {
     printf("s has value %d\n", it->x);
   }
-  // CHECK: for (auto & elem : s)
+  // CHECK: for (auto const & elem : s)
   // CHECK-NEXT: printf("s has value %d\n", elem.x);
 
   for (S::iterator it = s.begin(); it != s.end(); ++it) {
@@ -95,14 +95,14 @@
        it != v.end(); ++it) {
     printf("Fibonacci number is %d\n", *it);
   }
-  // CHECK: for (auto & elem : v)
+  // CHECK: for (auto const & elem : v)
   // CHECK-NEXT: printf("Fibonacci number is %d\n", elem);
 
   for (dependent<int>::const_iterator it(v.begin());
        it != v.end(); ++it) {
     printf("Fibonacci number is %d\n", *it);
   }
-  // CHECK: for (auto & elem : v)
+  // CHECK: for (auto const & elem : v)
   // CHECK-NEXT: printf("Fibonacci number is %d\n", elem);
 
   doublyDependent<int,int> intmap;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to