- Fixed comments
- Used clang-format on the code
- Added asserts
Hi revane,
http://llvm-reviews.chandlerc.com/D759
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D759?vs=1862&id=1884#toc
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/Inputs/structures.h
test/cpp11-migrate/LoopConvert/iterator.cpp
test/cpp11-migrate/LoopConvert/naming-conflict.cpp
test/cpp11-migrate/LoopConvert/nesting.cpp
test/cpp11-migrate/LoopConvert/single-iterator.cpp
Index: cpp11-migrate/LoopConvert/LoopActions.cpp
===================================================================
--- cpp11-migrate/LoopConvert/LoopActions.cpp
+++ cpp11-migrate/LoopConvert/LoopActions.cpp
@@ -29,9 +29,9 @@
SourceRange Range;
explicit Usage(const Expr *E)
- : E(E), IsArrow(false), Range(E->getSourceRange()) { }
+ : E(E), IsArrow(false), Range(E->getSourceRange()) {}
Usage(const Expr *E, bool IsArrow, SourceRange Range)
- : E(E), IsArrow(IsArrow), Range(Range) { }
+ : E(E), IsArrow(IsArrow), Range(Range) {}
};
/// \brief A class to encapsulate lowering of the tool's confidence level.
@@ -42,8 +42,7 @@
class Confidence {
public:
/// \brief Initialize confidence level.
- explicit Confidence(RiskLevel Level) :
- CurrentLevel(Level) {}
+ explicit Confidence(RiskLevel Level) : CurrentLevel(Level) {}
/// \brief Lower the internal confidence level to Level, but do not raise it.
void lowerTo(RiskLevel Level) {
@@ -62,25 +61,25 @@
///
/// Given an index variable, recursively crawls a for loop to discover if the
/// index variable is used in a way consistent with range-based for loop access.
-class ForLoopIndexUseVisitor
- : public RecursiveASTVisitor<ForLoopIndexUseVisitor> {
- public:
+class ForLoopIndexUseVisitor :
+ public RecursiveASTVisitor<ForLoopIndexUseVisitor> {
+public:
ForLoopIndexUseVisitor(ASTContext *Context, const VarDecl *IndexVar,
const VarDecl *EndVar, const Expr *ContainerExpr,
const Expr *ArrayBoundExpr,
- bool ContainerNeedsDereference) :
- Context(Context), IndexVar(IndexVar), EndVar(EndVar),
- ContainerExpr(ContainerExpr), ArrayBoundExpr(ArrayBoundExpr),
- ContainerNeedsDereference(ContainerNeedsDereference),
- OnlyUsedAsIndex(true), AliasDecl(NULL), ConfidenceLevel(RL_Safe),
- NextStmtParent(NULL), CurrStmtParent(NULL), ReplaceWithAliasUse(false),
- AliasFromForInit(false) {
- if (ContainerExpr) {
- addComponent(ContainerExpr);
- llvm::FoldingSetNodeID ID;
- const Expr *E = ContainerExpr->IgnoreParenImpCasts();
- E->Profile(ID, *Context, true);
- }
+ bool ContainerNeedsDereference)
+ : Context(Context), IndexVar(IndexVar), EndVar(EndVar),
+ ContainerExpr(ContainerExpr), ArrayBoundExpr(ArrayBoundExpr),
+ ContainerNeedsDereference(ContainerNeedsDereference),
+ OnlyUsedAsIndex(true), AliasDecl(NULL), ConfidenceLevel(RL_Safe),
+ NextStmtParent(NULL), CurrStmtParent(NULL), ReplaceWithAliasUse(false),
+ AliasFromForInit(false) {
+ if (ContainerExpr) {
+ addComponent(ContainerExpr);
+ llvm::FoldingSetNodeID ID;
+ const Expr *E = ContainerExpr->IgnoreParenImpCasts();
+ E->Profile(ID, *Context, true);
+ }
}
/// \brief Finds all uses of IndexVar in Body, placing all usages in Usages,
@@ -104,26 +103,23 @@
void addComponents(const ComponentVector &Components) {
// FIXME: add sort(on ID)+unique to avoid extra work.
for (ComponentVector::const_iterator I = Components.begin(),
- E = Components.end(); I != E; ++I)
+ E = Components.end();
+ I != E; ++I)
addComponent(*I);
}
/// \brief Accessor for Usages.
const UsageResult &getUsages() const { return Usages; }
/// \brief Get the container indexed by IndexVar, if any.
- const Expr *getContainerIndexed() const {
- return ContainerExpr;
- }
+ const Expr *getContainerIndexed() const { return ContainerExpr; }
/// \brief Returns the statement declaring the variable created as an alias
/// for the loop element, if any.
const DeclStmt *getAliasDecl() const { return AliasDecl; }
/// \brief Accessor for ConfidenceLevel.
- RiskLevel getRiskLevel() const {
- return ConfidenceLevel.getRiskLevel();
- }
+ RiskLevel getRiskLevel() const { return ConfidenceLevel.getRiskLevel(); }
/// \brief Indicates if the alias declaration was in a place where it cannot
/// simply be removed but rather replaced with a use of the alias variable.
@@ -136,7 +132,7 @@
/// case need to be adjusted.
bool aliasFromForInit() const { return AliasFromForInit; }
- private:
+private:
/// Typedef used in CRTP functions.
typedef RecursiveASTVisitor<ForLoopIndexUseVisitor> VisitorBase;
friend class RecursiveASTVisitor<ForLoopIndexUseVisitor>;
@@ -184,8 +180,8 @@
///
/// If any of these expressions are encountered outside of an acceptable usage
/// of the loop element, lower our confidence level.
- llvm::SmallVector<
- std::pair<const Expr *, llvm::FoldingSetNodeID>, 16> DependentExprs;
+ llvm::SmallVector<std::pair<const Expr *, llvm::FoldingSetNodeID>, 16>
+ DependentExprs;
/// The parent-in-waiting. Will become the real parent once we traverse down
/// one level in the AST.
@@ -286,7 +282,7 @@
return NULL;
E = ConstructExpr->getArg(0);
if (const MaterializeTemporaryExpr *Temp =
- dyn_cast<MaterializeTemporaryExpr>(E))
+ dyn_cast<MaterializeTemporaryExpr>(E))
E = Temp->GetTemporaryExpr();
return digThroughConstructors(E);
}
@@ -300,20 +296,22 @@
return Uop->getOpcode() == UO_Deref ? Uop->getSubExpr() : NULL;
if (const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(E))
- return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1 ?
- OpCall->getArg(0) : NULL;
+ return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1
+ ? OpCall->getArg(0)
+ : NULL;
return NULL;
}
/// \brief Returns true when the Container contains an Expr equivalent to E.
-template<typename ContainerT>
+template <typename ContainerT>
static bool containsExpr(ASTContext *Context, const ContainerT *Container,
const Expr *E) {
llvm::FoldingSetNodeID ID;
E->Profile(ID, *Context, true);
for (typename ContainerT::const_iterator I = Container->begin(),
- End = Container->end(); I != End; ++I)
+ End = Container->end();
+ I != End; ++I)
if (ID == I->second)
return true;
return false;
@@ -330,8 +328,8 @@
static bool isIndexInSubscriptExpr(const Expr *IndexExpr,
const VarDecl *IndexVar) {
const DeclRefExpr *Idx = getDeclRef(IndexExpr);
- return Idx && Idx->getType()->isIntegerType()
- && areSameVariable(IndexVar, Idx->getDecl());
+ return Idx && Idx->getType()->isIntegerType() &&
+ areSameVariable(IndexVar, Idx->getDecl());
}
/// \brief Returns true when the index expression is a declaration reference to
@@ -403,7 +401,7 @@
static bool isDereferenceOfUop(const UnaryOperator *Uop,
const VarDecl *IndexVar) {
return Uop->getOpcode() == UO_Deref &&
- exprReferencesVariable(IndexVar, Uop->getSubExpr());
+ exprReferencesVariable(IndexVar, Uop->getSubExpr());
}
/// \brief Determines whether the given Decl defines a variable initialized to
@@ -446,10 +444,10 @@
return isDereferenceOfUop(cast<UnaryOperator>(Init), IndexVar);
case Stmt::CXXOperatorCallExprClass: {
- const CXXOperatorCallExpr *OpCall = cast<CXXOperatorCallExpr>(Init);
- if (OpCall->getOperator() == OO_Star)
- return isDereferenceOfOpCall(OpCall, IndexVar);
- break;
+ const CXXOperatorCallExpr *OpCall = cast<CXXOperatorCallExpr>(Init);
+ if (OpCall->getOperator() == OO_Star)
+ return isDereferenceOfOpCall(OpCall, IndexVar);
+ break;
}
default:
@@ -477,7 +475,7 @@
if (!ConditionExpr || ConditionExpr->isValueDependent())
return false;
const ConstantArrayType *ConstType =
- Context->getAsConstantArrayType(ArrayType);
+ Context->getAsConstantArrayType(ArrayType);
if (!ConstType)
return false;
llvm::APSInt ConditionSize;
@@ -540,15 +538,15 @@
const Expr *ResultExpr = Member;
QualType ExprType;
if (const CXXOperatorCallExpr *Call =
- dyn_cast<CXXOperatorCallExpr>(Base->IgnoreParenImpCasts())) {
+ dyn_cast<CXXOperatorCallExpr>(Base->IgnoreParenImpCasts())) {
// If operator->() is a MemberExpr containing a CXXOperatorCallExpr, then
// the MemberExpr does not have the expression we want. We therefore catch
// that instance here.
// For example, if vector<Foo>::iterator defines operator->(), then the
// example `i->bar()` at the top of this function is a CXXMemberCallExpr
// referring to `i->` as the member function called. We want just `i`, so
// we take the argument to operator->() as the base object.
- if(Call->getOperator() == OO_Arrow) {
+ if (Call->getOperator() == OO_Arrow) {
assert(Call->getNumArgs() == 1 &&
"Operator-> takes more than one argument");
Obj = getDeclRef(Call->getArg(0));
@@ -564,14 +562,13 @@
assert(ExprType->isPointerType() && "Operator-> returned non-pointer type");
// FIXME: This works around not having the location of the arrow operator.
// Consider adding OperatorLoc to MemberExpr?
- SourceLocation ArrowLoc =
- Lexer::getLocForEndOfToken(Base->getExprLoc(), 0,
- Context->getSourceManager(),
- Context->getLangOpts());
+ SourceLocation ArrowLoc = Lexer::getLocForEndOfToken(
+ Base->getExprLoc(), 0, Context->getSourceManager(),
+ Context->getLangOpts());
// If something complicated is happening (i.e. the next token isn't an
// arrow), give up on making this work.
if (!ArrowLoc.isInvalid()) {
- Usages.push_back(Usage(ResultExpr, /*IsArrow=*/true,
+ Usages.push_back(Usage(ResultExpr, /*IsArrow=*/ true,
SourceRange(Base->getExprLoc(), ArrowLoc)));
return true;
}
@@ -676,16 +673,15 @@
/// \endcode
/// and further checking needs to be done later to ensure that exactly one array
/// is referenced.
-bool ForLoopIndexUseVisitor::TraverseArraySubscriptExpr(
- ArraySubscriptExpr *E) {
+bool ForLoopIndexUseVisitor::TraverseArraySubscriptExpr(ArraySubscriptExpr *E) {
Expr *Arr = E->getBase();
if (!isIndexInSubscriptExpr(E->getIdx(), IndexVar))
return VisitorBase::TraverseArraySubscriptExpr(E);
if ((ContainerExpr && !areSameExpr(Context, Arr->IgnoreParenImpCasts(),
- ContainerExpr->IgnoreParenImpCasts()))
- || !arrayMatchesBoundExpr(Context, Arr->IgnoreImpCasts()->getType(),
- ArrayBoundExpr)) {
+ ContainerExpr->IgnoreParenImpCasts())) ||
+ !arrayMatchesBoundExpr(Context, Arr->IgnoreImpCasts()->getType(),
+ ArrayBoundExpr)) {
// If we have already discovered the array being indexed and this isn't it
// or this array doesn't match, mark this loop as unconvertible.
OnlyUsedAsIndex = false;
@@ -752,8 +748,7 @@
isAliasDecl(S->getSingleDecl(), IndexVar)) {
AliasDecl = S;
if (CurrStmtParent) {
- if (isa<IfStmt>(CurrStmtParent) ||
- isa<WhileStmt>(CurrStmtParent) ||
+ if (isa<IfStmt>(CurrStmtParent) || isa<WhileStmt>(CurrStmtParent) ||
isa<SwitchStmt>(CurrStmtParent))
ReplaceWithAliasUse = true;
else if (isa<ForStmt>(CurrStmtParent)) {
@@ -781,17 +776,14 @@
}
//// \brief Apply the source transformations necessary to migrate the loop!
-void LoopFixer::doConversion(ASTContext *Context,
- const VarDecl *IndexVar,
+void LoopFixer::doConversion(ASTContext *Context, const VarDecl *IndexVar,
const VarDecl *MaybeContainer,
StringRef ContainerString,
const UsageResult &Usages,
- const DeclStmt *AliasDecl,
- bool AliasUseRequired,
- bool AliasFromForInit,
- const ForStmt *TheLoop,
- bool ContainerNeedsDereference,
- bool DerefByValue) {
+ const DeclStmt *AliasDecl, bool AliasUseRequired,
+ bool AliasFromForInit, const ForStmt *TheLoop,
+ bool ContainerNeedsDereference, bool DerefByValue,
+ bool DerefByConstRef) {
std::string VarName;
bool VarNameFromAlias = Usages.size() == 1 && AliasDecl;
bool AliasVarIsRef = false;
@@ -830,8 +822,7 @@
ReplacedVarRanges->insert(std::make_pair(TheLoop, IndexVar));
Replace->insert(
Replacement(Context->getSourceManager(),
- CharSourceRange::getTokenRange(I->Range),
- ReplaceText));
+ CharSourceRange::getTokenRange(I->Range), ReplaceText));
}
}
@@ -849,17 +840,20 @@
// to 'T&&'.
if (DerefByValue)
AutoRefType = Context->getRValueReferenceType(AutoRefType);
- else
+ else {
+ if (DerefByConstRef)
+ AutoRefType = Context->getConstType(AutoRefType);
AutoRefType = Context->getLValueReferenceType(AutoRefType);
+ }
}
std::string MaybeDereference = ContainerNeedsDereference ? "*" : "";
std::string TypeString = AutoRefType.getAsString();
- std::string Range = ("(" + TypeString + " " + VarName + " : "
- + MaybeDereference + ContainerString + ")").str();
- Replace->insert(Replacement(Context->getSourceManager(),
- CharSourceRange::getTokenRange(ParenRange),
- Range));
+ std::string Range = ("(" + TypeString + " " + VarName + " : " +
+ MaybeDereference + ContainerString + ")").str();
+ Replace->insert(
+ Replacement(Context->getSourceManager(),
+ CharSourceRange::getTokenRange(ParenRange), Range));
GeneratedDecls->insert(make_pair(TheLoop, VarName));
}
@@ -874,7 +868,7 @@
const CXXMemberCallExpr *TheCall =
dyn_cast_or_null<CXXMemberCallExpr>(digThroughConstructors(Init));
if (!TheCall || TheCall->getNumArgs() != 0)
- return NULL;
+ return NULL;
const MemberExpr *Member = dyn_cast<MemberExpr>(TheCall->getCallee());
if (!Member)
@@ -905,12 +899,12 @@
bool BeginIsArrow = false;
bool EndIsArrow = false;
const Expr *BeginContainerExpr =
- getContainerFromBeginEndCall(BeginExpr, /*IsBegin=*/true, &BeginIsArrow);
+ getContainerFromBeginEndCall(BeginExpr, /*IsBegin=*/ true, &BeginIsArrow);
if (!BeginContainerExpr)
- return NULL;
+ return NULL;
const Expr *EndContainerExpr =
- getContainerFromBeginEndCall(EndExpr, /*IsBegin=*/false, &EndIsArrow);
+ getContainerFromBeginEndCall(EndExpr, /*IsBegin=*/ false, &EndIsArrow);
// Disallow loops that try evil things like this (note the dot and arrow):
// for (IteratorType It = Obj.begin(), E = Obj->end(); It != E; ++It) { }
if (!EndContainerExpr || BeginIsArrow != EndIsArrow ||
@@ -937,10 +931,9 @@
ParentFinder->gatherAncestors(Context->getTranslationUnitDecl());
// Ensure that we do not try to move an expression dependent on a local
// variable declared inside the loop outside of it!
- DependencyFinderASTVisitor
- DependencyFinder(&ParentFinder->getStmtToParentStmtMap(),
- &ParentFinder->getDeclToParentStmtMap(),
- ReplacedVarRanges, TheLoop);
+ DependencyFinderASTVisitor DependencyFinder(
+ &ParentFinder->getStmtToParentStmtMap(),
+ &ParentFinder->getDeclToParentStmtMap(), ReplacedVarRanges, TheLoop);
// Not all of these are actually deferred changes.
// FIXME: Determine when the external dependency isn't an expression converted
@@ -958,9 +951,9 @@
if (isa<CXXThisExpr>(ContainerExpr->IgnoreParenImpCasts())) {
ContainerString = "this";
} else {
- ContainerString = getStringFromRange(Context->getSourceManager(),
- Context->getLangOpts(),
- ContainerExpr->getSourceRange());
+ ContainerString =
+ getStringFromRange(Context->getSourceManager(), Context->getLangOpts(),
+ ContainerExpr->getSourceRange());
}
// In case someone is using an evil macro, reject this change.
@@ -972,15 +965,11 @@
/// \brief Given that we have verified that the loop's header appears to be
/// convertible, run the complete analysis on the loop to determine if the
/// loop's body is convertible.
-void LoopFixer::findAndVerifyUsages(ASTContext *Context,
- const VarDecl *LoopVar,
- const VarDecl *EndVar,
- const Expr *ContainerExpr,
- const Expr *BoundExpr,
- bool ContainerNeedsDereference,
- bool DerefByValue,
- const ForStmt *TheLoop,
- Confidence ConfidenceLevel) {
+void LoopFixer::findAndVerifyUsages(
+ ASTContext *Context, const VarDecl *LoopVar, const VarDecl *EndVar,
+ const Expr *ContainerExpr, const Expr *BoundExpr,
+ bool ContainerNeedsDereference, bool DerefByValue, bool DerefByConstRef,
+ const ForStmt *TheLoop, Confidence ConfidenceLevel) {
ForLoopIndexUseVisitor Finder(Context, LoopVar, EndVar, ContainerExpr,
BoundExpr, ContainerNeedsDereference);
if (ContainerExpr) {
@@ -1004,16 +993,15 @@
ConfidenceLevel.lowerTo(RL_Risky);
}
- std::string ContainerString =
- checkDeferralsAndRejections(Context, ContainerExpr,
- ConfidenceLevel, TheLoop);
+ std::string ContainerString = checkDeferralsAndRejections(
+ Context, ContainerExpr, ConfidenceLevel, TheLoop);
if (ContainerString.empty())
return;
doConversion(Context, LoopVar, getReferencedVariable(ContainerExpr),
ContainerString, Finder.getUsages(), Finder.getAliasDecl(),
Finder.aliasUseRequired(), Finder.aliasFromForInit(), TheLoop,
- ContainerNeedsDereference, DerefByValue);
+ ContainerNeedsDereference, DerefByValue, DerefByConstRef);
++*AcceptedChanges;
}
@@ -1034,6 +1022,7 @@
const VarDecl *InitVar = Nodes.getDeclAs<VarDecl>(InitVarName);
if (!areSameVariable(LoopVar, CondVar) || !areSameVariable(LoopVar, InitVar))
return;
+
const VarDecl *EndVar = Nodes.getDeclAs<VarDecl>(EndVarName);
const VarDecl *ConditionEndVar =
Nodes.getDeclAs<VarDecl>(ConditionEndVarName);
@@ -1051,14 +1040,64 @@
ConfidenceLevel.lowerTo(RL_Reasonable);
const Expr *ContainerExpr = NULL;
+ bool DerefByValue = false;
+ bool DerefByConstRef = false;
bool ContainerNeedsDereference = 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);
- else if (FixerKind == LFK_PseudoArray) {
+
+ QualType InitVarType = InitVar->getType();
+ QualType CanonicalInitVarType = InitVarType.getCanonicalType();
+
+ const CXXMemberCallExpr *BeginCall =
+ Nodes.getNodeAs<CXXMemberCallExpr>(BeginCallName);
+ assert(BeginCall != 0 && "Bad Callback. No begin call expression.");
+ QualType CanonicalBeginType =
+ BeginCall->getMethodDecl()->getResultType().getCanonicalType();
+
+ if (CanonicalBeginType->isPointerType() &&
+ CanonicalInitVarType->isPointerType()) {
+ QualType BeginPointeeType = CanonicalBeginType->getPointeeType();
+ QualType InitPointeeType = CanonicalInitVarType->getPointeeType();
+ // If the initializer and the variable are both pointers check if the
+ // un-qualified pointee types match otherwise we don't use auto.
+ if (!Context->hasSameUnqualifiedType(InitPointeeType, BeginPointeeType))
+ return;
+ } else {
+ // Check for qualified types to avoid conversions from non-const to const
+ // iterator types.
+ if (!Context->hasSameType(CanonicalInitVarType, CanonicalBeginType))
+ return;
+ }
+
+ DerefByValue = Nodes.getNodeAs<QualType>(DerefByValueResultName) != 0;
+ if (!DerefByValue) {
+ if (const QualType *DerefType =
+ Nodes.getNodeAs<QualType>(DerefByRefResultName)) {
+ // A node will only be bound with DerefByRefResultName if we're dealing
+ // with a user-defined iterator type. Test the const qualification of
+ // the reference type.
+ DerefByConstRef = (*DerefType)->getAs<ReferenceType>()->getPointeeType()
+ .isConstQualified();
+ } else {
+ // By nature of the matcher this case is triggered only for built-in
+ // iterator types (i.e. pointers). Test for const qualification of the
+ // pointed-at type.
+ QualType InitPointeeType = CanonicalInitVarType->getPointeeType();
+ assert(isa<PointerType>(CanonicalInitVarType) &&
+ "Non-class iterator type is not a pointer type");
+ DerefByConstRef = InitPointeeType.isConstQualified();
+ }
+ } else {
+ // If the de-referece operator return by value then test for the canonical
+ // const qualification of the init variable type.
+ DerefByConstRef = CanonicalInitVarType.isConstQualified();
+ }
+ } else if (FixerKind == LFK_PseudoArray) {
if (!EndCall)
return;
ContainerExpr = EndCall->getImplicitObjectArgument();
@@ -1071,9 +1110,7 @@
if (!ContainerExpr && !BoundExpr)
return;
- bool DerefByValue = Nodes.getNodeAs<QualType>(DerefByValueResultName) != 0;
-
findAndVerifyUsages(Context, LoopVar, EndVar, ContainerExpr, BoundExpr,
- ContainerNeedsDereference, DerefByValue, TheLoop,
- ConfidenceLevel);
+ ContainerNeedsDereference, DerefByValue, DerefByConstRef,
+ TheLoop, ConfidenceLevel);
}
Index: cpp11-migrate/LoopConvert/LoopActions.h
===================================================================
--- cpp11-migrate/LoopConvert/LoopActions.h
+++ cpp11-migrate/LoopConvert/LoopActions.h
@@ -77,7 +77,8 @@
bool AliasFromForInit,
const clang::ForStmt *TheLoop,
bool ContainerNeedsDereference,
- bool DerefByValue);
+ bool DerefByValue,
+ bool DerefByConstRef);
/// \brief Given a loop header that would be convertible, discover all usages
/// of the index variable and convert the loop if possible.
@@ -88,6 +89,7 @@
const clang::Expr *BoundExpr,
bool ContainerNeedsDereference,
bool DerefByValue,
+ bool DerefByConstRef,
const clang::ForStmt *TheLoop,
Confidence ConfidenceLevel);
Index: cpp11-migrate/LoopConvert/LoopMatchers.cpp
===================================================================
--- cpp11-migrate/LoopConvert/LoopMatchers.cpp
+++ cpp11-migrate/LoopConvert/LoopMatchers.cpp
@@ -22,10 +22,12 @@
const char ConditionVarName[] = "conditionVar";
const char IncrementVarName[] = "incrementVar";
const char InitVarName[] = "initVar";
+const char BeginCallName[] = "beginCall";
const char EndCallName[] = "endCall";
const char ConditionEndVarName[] = "conditionEndVar";
const char EndVarName[] = "endVar";
const char DerefByValueResultName[] = "derefByValueResult";
+const char DerefByRefResultName[] = "derefByRefResult";
// shared matchers
static const TypeMatcher AnyType = anything();
@@ -109,10 +111,23 @@
/// - If the end iterator variable 'g' is defined, it is the same as 'f'
StatementMatcher makeIteratorLoopMatcher() {
StatementMatcher BeginCallMatcher =
- memberCallExpr(argumentCountIs(0), callee(methodDecl(hasName("begin"))));
+ memberCallExpr(
+ argumentCountIs(0),
+ callee(
+ methodDecl(hasName("begin"))
+ )
+ ).bind(BeginCallName);
DeclarationMatcher InitDeclMatcher =
- varDecl(hasInitializer(anything())).bind(InitVarName);
+ varDecl(
+ hasInitializer(
+ anyOf(
+ ignoringParenImpCasts(BeginCallMatcher),
+ materializeTemporaryExpr(ignoringParenImpCasts(BeginCallMatcher)),
+ hasDescendant(BeginCallMatcher)
+ )
+ )
+ ).bind(InitVarName);
DeclarationMatcher EndDeclMatcher =
varDecl(hasInitializer(anything())).bind(EndVarName);
@@ -157,14 +172,19 @@
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)
)
)
)
)
)
);
+
return
forStmt(
hasLoopInit(anyOf(
Index: cpp11-migrate/LoopConvert/LoopMatchers.h
===================================================================
--- cpp11-migrate/LoopConvert/LoopMatchers.h
+++ cpp11-migrate/LoopConvert/LoopMatchers.h
@@ -27,10 +27,12 @@
extern const char ConditionEndVarName[];
extern const char IncrementVarName[];
extern const char InitVarName[];
+extern const char BeginCallName[];
extern const char EndExprName[];
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/Inputs/structures.h
===================================================================
--- test/cpp11-migrate/LoopConvert/Inputs/structures.h
+++ test/cpp11-migrate/LoopConvert/Inputs/structures.h
@@ -131,10 +131,13 @@
template<typename IteratorType>
struct Nested {
typedef IteratorType* iterator;
+ typedef const IteratorType* const_iterator;
IteratorType *operator->();
IteratorType operator*();
iterator begin();
iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
};
// Like llvm::SmallPtrSet, the iterator has a dereference operator that returns
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,15 +84,17 @@
it != e; ++it) {
printf("Fibonacci number is %d\n", *it);
}
- // CHECK: for (auto & elem : v)
- // CHECK-NEXT: printf("Fibonacci number is %d\n", elem);
+ // CHECK: for (dependent<int>::const_iterator it = v.begin(), e = v.end();
+ // CHECK-NEXT: it != e; ++it) {
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", *it);
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-NEXT: printf("Fibonacci number is %d\n", elem);
+ // CHECK: for (dependent<int>::const_iterator it(v.begin()), e = v.end();
+ // CHECK-NEXT: it != e; ++it) {
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", *it);
doublyDependent<int,int> intmap;
for (doublyDependent<int,int>::iterator it = intmap.begin(), e = intmap.end();
@@ -174,14 +176,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();
}
}
@@ -201,4 +203,4 @@
// CHECK: for (auto & elem : *this) {
}
}
-};
+};
\ No newline at end of file
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/nesting.cpp
===================================================================
--- test/cpp11-migrate/LoopConvert/nesting.cpp
+++ test/cpp11-migrate/LoopConvert/nesting.cpp
@@ -54,4 +54,16 @@
// CHECK: for (auto & elem : NestT) {
// CHECK-NEXT: for (T::iterator TI = (elem).begin(), TE = (elem).end(); TI != TE; ++TI) {
// CHECK-NEXT: printf("%d", *TI);
+
+ Nested<S> NestS;
+ for (Nested<S>::const_iterator I = NestS.begin(), E = NestS.end(); I != E; ++I) {
+ for (S::const_iterator SI = (*I).begin(), SE = (*I).end(); SI != SE; ++SI) {
+ printf("%d", *SI);
+ }
+ }
+ // The inner loop is also convertible, but doesn't need to be converted
+ // immediately. Update this test when that changes!
+ // CHECK: for (auto const & elem : NestS) {
+ // CHECK-NEXT: for (S::const_iterator SI = (elem).begin(), SE = (elem).end(); SI != SE; ++SI) {
+ // CHECK-NEXT: printf("%d", *SI);
}
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,21 +95,23 @@
it != v.end(); ++it) {
printf("Fibonacci number is %d\n", *it);
}
- // CHECK: for (auto & elem : v)
- // CHECK-NEXT: printf("Fibonacci number is %d\n", elem);
+ // CHECK: for (dependent<int>::const_iterator it = v.begin();
+ // CHECK-NEXT: it != v.end(); ++it) {
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", *it);
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-NEXT: printf("Fibonacci number is %d\n", elem);
+ // CHECK: for (dependent<int>::const_iterator it(v.begin());
+ // CHECK-NEXT: it != v.end(); ++it) {
+ // CHECK-NEXT: printf("Fibonacci number is %d\n", *it);
doublyDependent<int,int> intmap;
for (doublyDependent<int,int>::iterator it = intmap.begin();
it != intmap.end(); ++it) {
printf("intmap[%d] = %d", it->first, it->second);
}
// CHECK: for (auto & elem : intmap)
// CHECK-NEXT: printf("intmap[%d] = %d", elem.first, elem.second);
-}
+}
\ No newline at end of file
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits