Transform for loops over pseudo-arrays only if begin/end members exist

For loops using pseudo-arrays, classes that can be used like arrays from
the Loop Convert Transform's point of view, should only get transformed
if the pseudo-array class has begin()/end() members for the
range-based for-loop to call.

Free versions of begin()/end() should also be allowed but this is an
enhancement for another revision.

llvm-svn: 181539
diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.cpp b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.cpp
index a7ca15f..d69f2a8 100644
--- a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.cpp
+++ b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.cpp
@@ -258,10 +258,57 @@
 ///   - If the end iterator variable 'g' is defined, it is the same as 'j'
 ///   - The container's iterators would not be invalidated during the loop
 StatementMatcher makePseudoArrayLoopMatcher() {
+  // Test that the incoming type has a record declaration that has methods
+  // called 'begin' and 'end'. If the incoming type is const, then make sure
+  // these methods are also marked const.
+  // 
+  // FIXME: To be completely thorough this matcher should also ensure the
+  // return type of begin/end is an iterator that dereferences to the same as
+  // what operator[] or at() returns. Such a test isn't likely to fail except
+  // for pathological cases.
+  //
+  // FIXME: Also, a record doesn't necessarily need begin() and end(). Free
+  // functions called begin() and end() taking the container as an argument
+  // are also allowed.
+  TypeMatcher RecordWithBeginEnd = 
+    qualType(anyOf(
+      qualType(
+        isConstQualified(),
+        hasDeclaration(
+          recordDecl(
+            hasMethod(
+              methodDecl(
+                hasName("begin"),
+                isConst()
+              )
+            ),
+            hasMethod(
+              methodDecl(
+                hasName("end"),
+                isConst()
+              )
+            )
+          )
+        ) // hasDeclaration
+      ), // qualType
+      qualType(
+        unless(isConstQualified()),
+        hasDeclaration(
+          recordDecl(
+            hasMethod(hasName("begin")),
+            hasMethod(hasName("end"))
+          )
+        )
+      ) // qualType
+    )
+  );
+
   StatementMatcher SizeCallMatcher =
       memberCallExpr(argumentCountIs(0),
                      callee(methodDecl(anyOf(hasName("size"),
-                                             hasName("length")))));
+                                             hasName("length")))),
+                     on(anyOf(hasType(pointsTo(RecordWithBeginEnd)),
+                              hasType(RecordWithBeginEnd))));
 
   StatementMatcher EndInitMatcher =
       expr(anyOf(