Have LoopConvert use 'auto &&' where necessary
For iterators where the dereference operator returns by value, LoopConvert
should use 'auto &&' in the range-based for loop expression.
If the dereference operator returns an rvalue reference, this is deemed too
strange and the for loop is not converted.
Moved test case from iterator_failing.cpp to iterator.cpp and added extra
tests.
Fixes PR15437.
Reviewer: gribozavr
llvm-svn: 176631
diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.cpp b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.cpp
index 1b6f59c..ffd9f79 100644
--- a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.cpp
+++ b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopMatchers.cpp
@@ -25,6 +25,7 @@
const char EndCallName[] = "endCall";
const char ConditionEndVarName[] = "conditionEndVar";
const char EndVarName[] = "endVar";
+const char DerefByValueResultName[] = "derefByValueResult";
// shared matchers
static const TypeMatcher AnyType = anything();
@@ -137,30 +138,75 @@
hasArgument(0, IteratorComparisonMatcher),
hasArgument(1, IteratorBoundMatcher));
- return forStmt(
+ // This matcher tests that a declaration is a CXXRecordDecl that has an
+ // overloaded operator*(). If the operator*() returns by value instead of by
+ // reference then the return type is tagged with DerefByValueResultName.
+ internal::Matcher<VarDecl> TestDerefReturnsByValue =
+ hasType(
+ recordDecl(
+ hasMethod(
+ allOf(
+ hasOverloadedOperatorName("*"),
+ anyOf(
+ // Tag the return type if it's by value.
+ returns(
+ qualType(
+ unless(hasCanonicalType(referenceType()))
+ ).bind(DerefByValueResultName)
+ ),
+ returns(
+ // Skip loops where the iterator's operator* returns an
+ // rvalue reference. This is just weird.
+ qualType(unless(hasCanonicalType(rValueReferenceType())))
+ )
+ )
+ )
+ )
+ )
+ );
+
+ return
+ forStmt(
hasLoopInit(anyOf(
- declStmt(declCountIs(2),
- containsDeclaration(0, InitDeclMatcher),
- containsDeclaration(1, EndDeclMatcher)),
- declStmt(hasSingleDecl(InitDeclMatcher)))),
+ declStmt(
+ declCountIs(2),
+ containsDeclaration(0, InitDeclMatcher),
+ containsDeclaration(1, EndDeclMatcher)
+ ),
+ declStmt(hasSingleDecl(InitDeclMatcher))
+ )),
hasCondition(anyOf(
- binaryOperator(hasOperatorName("!="),
- hasLHS(IteratorComparisonMatcher),
- hasRHS(IteratorBoundMatcher)),
- binaryOperator(hasOperatorName("!="),
- hasLHS(IteratorBoundMatcher),
- hasRHS(IteratorComparisonMatcher)),
- OverloadedNEQMatcher)),
+ binaryOperator(
+ hasOperatorName("!="),
+ hasLHS(IteratorComparisonMatcher),
+ hasRHS(IteratorBoundMatcher)
+ ),
+ binaryOperator(
+ hasOperatorName("!="),
+ hasLHS(IteratorBoundMatcher),
+ hasRHS(IteratorComparisonMatcher)
+ ),
+ OverloadedNEQMatcher
+ )),
hasIncrement(anyOf(
- unaryOperator(hasOperatorName("++"),
- hasUnaryOperand(declRefExpr(to(
- varDecl(hasType(pointsTo(AnyType)))
- .bind(IncrementVarName))))),
- operatorCallExpr(
- hasOverloadedOperatorName("++"),
- hasArgument(0, declRefExpr(to(
- varDecl().bind(IncrementVarName))))))))
- .bind(LoopName);
+ unaryOperator(
+ hasOperatorName("++"),
+ hasUnaryOperand(
+ declRefExpr(to(
+ varDecl(hasType(pointsTo(AnyType))).bind(IncrementVarName)
+ ))
+ )
+ ),
+ operatorCallExpr(
+ hasOverloadedOperatorName("++"),
+ hasArgument(0,
+ declRefExpr(to(
+ varDecl(TestDerefReturnsByValue).bind(IncrementVarName)
+ ))
+ )
+ )
+ ))
+ ).bind(LoopName);
}
/// \brief The matcher used for array-like containers (pseudoarrays).