//// \brief Apply the source transformations necessary to migrate the loop! void LoopFixer::doConversion(ASTContext *Context, const VarDecl *IndexVar, const VarDecl *MaybeContainer, StringRef ContainerString, const UsageResult &Usages, const DeclStmt *AliasDecl, const ForStmt *TheLoop, bool ContainerNeedsDereference) { std::string VarName; if (Usages.size() == 1 && AliasDecl) { const VarDecl *AliasVar = cast<VarDecl>(AliasDecl->getSingleDecl()); VarName = AliasVar->getName().str(); // We keep along the entire DeclStmt to keep the correct range here. const SourceRange &ReplaceRange = AliasDecl->getSourceRange(); if (!CountOnly) Replace->insert( Replacement(Context->getSourceManager(), CharSourceRange::getTokenRange(ReplaceRange), "")); // No further replacements are made to the loop, since the iterator or index // was used exactly once - in the initialization of AliasVar. } else { VariableNamer Namer(GeneratedDecls, &ParentFinder->getStmtToParentStmtMap(), TheLoop, IndexVar, MaybeContainer); VarName = Namer.createIndexName(); // First, replace all usages of the array subscript expression with our new // variable. for (UsageResult::const_iterator I = Usages.begin(), E = Usages.end(); I != E; ++I) { std::string ReplaceText = I->IsArrow ? VarName + "." : VarName; ReplacedVarRanges->insert(std::make_pair(TheLoop, IndexVar)); if (!CountOnly) Replace->insert( Replacement(Context->getSourceManager(), CharSourceRange::getTokenRange(I->Range), ReplaceText)); } } // Now, we need to construct the new range expresion. SourceRange ParenRange(TheLoop->getLParenLoc(), TheLoop->getRParenLoc()); QualType AutoRefType = Context->getLValueReferenceType(Context->getAutoDeductType()); std::string MaybeDereference = ContainerNeedsDereference ? "*" : ""; std::string TypeString = AutoRefType.getAsString(); std::string Range = ("(" + TypeString + " " + VarName + " : " + MaybeDereference + ContainerString + ")").str(); if (!CountOnly) Replace->insert(Replacement(Context->getSourceManager(), CharSourceRange::getTokenRange(ParenRange), Range)); GeneratedDecls->insert(make_pair(TheLoop, VarName)); }
//// \brief Apply the source transformations necessary to migrate the loop! 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, bool DerefByConstRef) { std::string VarName; bool VarNameFromAlias = Usages.size() == 1 && AliasDecl; bool AliasVarIsRef = false; if (VarNameFromAlias) { const VarDecl *AliasVar = cast<VarDecl>(AliasDecl->getSingleDecl()); VarName = AliasVar->getName().str(); AliasVarIsRef = AliasVar->getType()->isReferenceType(); // We keep along the entire DeclStmt to keep the correct range here. const SourceRange &ReplaceRange = AliasDecl->getSourceRange(); std::string ReplacementText; if (AliasUseRequired) ReplacementText = VarName; else if (AliasFromForInit) // FIXME: Clang includes the location of the ';' but only for DeclStmt's // in a for loop's init clause. Need to put this ';' back while removing // the declaration of the alias variable. This is probably a bug. ReplacementText = ";"; Owner.addReplacementForCurrentTU(Replacement( Context->getSourceManager(), CharSourceRange::getTokenRange(ReplaceRange), ReplacementText)); // No further replacements are made to the loop, since the iterator or index // was used exactly once - in the initialization of AliasVar. } else { VariableNamer Namer(&TUInfo.getGeneratedDecls(), &TUInfo.getParentFinder().getStmtToParentStmtMap(), TheLoop, IndexVar, MaybeContainer, Context); VarName = Namer.createIndexName(); // First, replace all usages of the array subscript expression with our new // variable. for (UsageResult::const_iterator I = Usages.begin(), E = Usages.end(); I != E; ++I) { std::string ReplaceText = I->IsArrow ? VarName + "." : VarName; TUInfo.getReplacedVars().insert(std::make_pair(TheLoop, IndexVar)); Owner.addReplacementForCurrentTU( Replacement(Context->getSourceManager(), CharSourceRange::getTokenRange(I->Range), ReplaceText)); } } // Now, we need to construct the new range expresion. SourceRange ParenRange(TheLoop->getLParenLoc(), TheLoop->getRParenLoc()); QualType AutoRefType = Context->getAutoDeductType(); // If the new variable name is from the aliased variable, then the reference // type for the new variable should only be used if the aliased variable was // declared as a reference. if (!VarNameFromAlias || AliasVarIsRef) { // If an iterator's operator*() returns a 'T&' we can bind that to 'auto&'. // If operator*() returns 'T' we can bind that to 'auto&&' which will deduce // to 'T&&'. if (DerefByValue) AutoRefType = Context->getRValueReferenceType(AutoRefType); 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(); Owner.addReplacementForCurrentTU( Replacement(Context->getSourceManager(), CharSourceRange::getTokenRange(ParenRange), Range)); TUInfo.getGeneratedDecls().insert(make_pair(TheLoop, VarName)); }