/// \brief If we encounter a reference to IndexVar in an unpruned branch of the /// traversal, mark this loop as unconvertible. /// /// This implements the whitelist for convertible loops: any usages of IndexVar /// not explicitly considered convertible by this traversal will be caught by /// this function. /// /// Additionally, if the container expression is more complex than just a /// DeclRefExpr, and some part of it is appears elsewhere in the loop, lower /// our confidence in the transformation. /// /// For example, these are not permitted: /// \code /// for (int i = 0; i < N; ++i) { printf("arr[%d] = %d", i, arr[i]); } /// for (vector<int>::iterator i = container.begin(), e = container.end(); /// i != e; ++i) /// i.insert(0); /// for (vector<int>::iterator i = container.begin(), e = container.end(); /// i != e; ++i) /// i.insert(0); /// for (vector<int>::iterator i = container.begin(), e = container.end(); /// i != e; ++i) /// if (i + 1 != e) /// printf("%d", *i); /// \endcode /// /// And these will raise the risk level: /// \code /// int arr[10][20]; /// int l = 5; /// for (int j = 0; j < 20; ++j) /// int k = arr[l][j] + l; // using l outside arr[l] is considered risky /// for (int i = 0; i < obj.getVector().size(); ++i) /// obj.foo(10); // using `obj` is considered risky /// \endcode bool ForLoopIndexUseVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { const ValueDecl *TheDecl = DRE->getDecl(); if (areSameVariable(IndexVar, TheDecl) || areSameVariable(EndVar, TheDecl)) OnlyUsedAsIndex = false; if (containsExpr(Context, &DependentExprs, DRE)) ConfidenceLevel.lowerTo(TCK_Risky); return true; }
/// \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, bool DerefByConstRef, const ForStmt *TheLoop, Confidence ConfidenceLevel) { ForLoopIndexUseVisitor Finder(Context, LoopVar, EndVar, ContainerExpr, BoundExpr, ContainerNeedsDereference); if (ContainerExpr) { ComponentFinderASTVisitor ComponentFinder; ComponentFinder.findExprComponents(ContainerExpr->IgnoreParenImpCasts()); Finder.addComponents(ComponentFinder.getComponents()); } if (!Finder.findAndVerifyUsages(TheLoop->getBody())) return; ConfidenceLevel.lowerTo(Finder.getRiskLevel()); if (FixerKind == LFK_Array) { // The array being indexed by IndexVar was discovered during traversal. ContainerExpr = Finder.getContainerIndexed()->IgnoreParenImpCasts(); // Very few loops are over expressions that generate arrays rather than // array variables. Consider loops over arrays that aren't just represented // by a variable to be risky conversions. if (!getReferencedVariable(ContainerExpr) && !isDirectMemberExpr(ContainerExpr)) ConfidenceLevel.lowerTo(RL_Risky); } 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, DerefByConstRef); ++*AcceptedChanges; }
/// \brief If a member function call is the at() accessor on the container with /// IndexVar as the single argument, include it as a valid usage and prune /// the traversal. /// /// Member calls on other objects will not be permitted. /// Calls on the iterator object are not permitted, unless done through /// operator->(). The one exception is allowing vector::at() for pseudoarrays. bool ForLoopIndexUseVisitor::TraverseCXXMemberCallExpr( CXXMemberCallExpr *MemberCall) { MemberExpr *Member = dyn_cast<MemberExpr>(MemberCall->getCallee()->IgnoreParenImpCasts()); if (!Member) return VisitorBase::TraverseCXXMemberCallExpr(MemberCall); // We specifically allow an accessor named "at" to let STL in, though // this is restricted to pseudo-arrays by requiring a single, integer // argument. const IdentifierInfo *Ident = Member->getMemberDecl()->getIdentifier(); if (Ident && Ident->isStr("at") && MemberCall->getNumArgs() == 1) { if (isIndexInSubscriptExpr(Context, MemberCall->getArg(0), IndexVar, Member->getBase(), ContainerExpr, ContainerNeedsDereference)) { Usages.push_back(Usage(MemberCall)); return true; } } if (containsExpr(Context, &DependentExprs, Member->getBase())) ConfidenceLevel.lowerTo(TCK_Risky); return VisitorBase::TraverseCXXMemberCallExpr(MemberCall); }