1224135Sdim//===--- ARCMT.cpp - Migration to ARC mode --------------------------------===// 2224135Sdim// 3224135Sdim// The LLVM Compiler Infrastructure 4224135Sdim// 5224135Sdim// This file is distributed under the University of Illinois Open Source 6224135Sdim// License. See LICENSE.TXT for details. 7224135Sdim// 8224135Sdim//===----------------------------------------------------------------------===// 9224135Sdim 10224135Sdim#include "Internals.h" 11239462Sdim#include "clang/AST/ASTContext.h" 12224135Sdim#include "clang/AST/Expr.h" 13249423Sdim#include "clang/Basic/SourceManager.h" 14224135Sdim#include "clang/Lex/Preprocessor.h" 15224135Sdim#include "llvm/ADT/DenseSet.h" 16224135Sdim#include <map> 17224135Sdimusing namespace clang; 18224135Sdimusing namespace arcmt; 19224135Sdim 20224135Sdimnamespace { 21224135Sdim 22224135Sdim/// \brief Collects transformations and merges them before applying them with 23224135Sdim/// with applyRewrites(). E.g. if the same source range 24224135Sdim/// is requested to be removed twice, only one rewriter remove will be invoked. 25224135Sdim/// Rewrites happen in "transactions"; if one rewrite in the transaction cannot 26224135Sdim/// be done (e.g. it resides in a macro) all rewrites in the transaction are 27224135Sdim/// aborted. 28224135Sdim/// FIXME: "Transactional" rewrites support should be baked in the Rewriter. 29224135Sdimclass TransformActionsImpl { 30224135Sdim CapturedDiagList &CapturedDiags; 31224135Sdim ASTContext &Ctx; 32224135Sdim Preprocessor &PP; 33224135Sdim 34224135Sdim bool IsInTransaction; 35224135Sdim 36224135Sdim enum ActionKind { 37224135Sdim Act_Insert, Act_InsertAfterToken, 38224135Sdim Act_Remove, Act_RemoveStmt, 39224135Sdim Act_Replace, Act_ReplaceText, 40224135Sdim Act_IncreaseIndentation, 41224135Sdim Act_ClearDiagnostic 42224135Sdim }; 43224135Sdim 44224135Sdim struct ActionData { 45224135Sdim ActionKind Kind; 46224135Sdim SourceLocation Loc; 47224135Sdim SourceRange R1, R2; 48226633Sdim StringRef Text1, Text2; 49224135Sdim Stmt *S; 50226633Sdim SmallVector<unsigned, 2> DiagIDs; 51224135Sdim }; 52224135Sdim 53224135Sdim std::vector<ActionData> CachedActions; 54224135Sdim 55224135Sdim enum RangeComparison { 56224135Sdim Range_Before, 57224135Sdim Range_After, 58224135Sdim Range_Contains, 59224135Sdim Range_Contained, 60224135Sdim Range_ExtendsBegin, 61224135Sdim Range_ExtendsEnd 62224135Sdim }; 63224135Sdim 64224135Sdim /// \brief A range to remove. It is a character range. 65224135Sdim struct CharRange { 66224135Sdim FullSourceLoc Begin, End; 67224135Sdim 68224135Sdim CharRange(CharSourceRange range, SourceManager &srcMgr, Preprocessor &PP) { 69224135Sdim SourceLocation beginLoc = range.getBegin(), endLoc = range.getEnd(); 70224135Sdim assert(beginLoc.isValid() && endLoc.isValid()); 71224135Sdim if (range.isTokenRange()) { 72226633Sdim Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr); 73224135Sdim End = FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr); 74224135Sdim } else { 75226633Sdim Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr); 76226633Sdim End = FullSourceLoc(srcMgr.getExpansionLoc(endLoc), srcMgr); 77224135Sdim } 78224135Sdim assert(Begin.isValid() && End.isValid()); 79224135Sdim } 80224135Sdim 81224135Sdim RangeComparison compareWith(const CharRange &RHS) const { 82224135Sdim if (End.isBeforeInTranslationUnitThan(RHS.Begin)) 83224135Sdim return Range_Before; 84224135Sdim if (RHS.End.isBeforeInTranslationUnitThan(Begin)) 85224135Sdim return Range_After; 86224135Sdim if (!Begin.isBeforeInTranslationUnitThan(RHS.Begin) && 87224135Sdim !RHS.End.isBeforeInTranslationUnitThan(End)) 88224135Sdim return Range_Contained; 89224135Sdim if (Begin.isBeforeInTranslationUnitThan(RHS.Begin) && 90224135Sdim RHS.End.isBeforeInTranslationUnitThan(End)) 91224135Sdim return Range_Contains; 92224135Sdim if (Begin.isBeforeInTranslationUnitThan(RHS.Begin)) 93224135Sdim return Range_ExtendsBegin; 94224135Sdim else 95224135Sdim return Range_ExtendsEnd; 96224135Sdim } 97224135Sdim 98224135Sdim static RangeComparison compare(SourceRange LHS, SourceRange RHS, 99224135Sdim SourceManager &SrcMgr, Preprocessor &PP) { 100224135Sdim return CharRange(CharSourceRange::getTokenRange(LHS), SrcMgr, PP) 101224135Sdim .compareWith(CharRange(CharSourceRange::getTokenRange(RHS), 102224135Sdim SrcMgr, PP)); 103224135Sdim } 104224135Sdim }; 105224135Sdim 106226633Sdim typedef SmallVector<StringRef, 2> TextsVec; 107224135Sdim typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare> 108224135Sdim InsertsMap; 109224135Sdim InsertsMap Inserts; 110224135Sdim /// \brief A list of ranges to remove. They are always sorted and they never 111224135Sdim /// intersect with each other. 112224135Sdim std::list<CharRange> Removals; 113224135Sdim 114224135Sdim llvm::DenseSet<Stmt *> StmtRemovals; 115224135Sdim 116224135Sdim std::vector<std::pair<CharRange, SourceLocation> > IndentationRanges; 117224135Sdim 118224135Sdim /// \brief Keeps text passed to transformation methods. 119224135Sdim llvm::StringMap<bool> UniqueText; 120224135Sdim 121224135Sdimpublic: 122224135Sdim TransformActionsImpl(CapturedDiagList &capturedDiags, 123224135Sdim ASTContext &ctx, Preprocessor &PP) 124224135Sdim : CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(false) { } 125224135Sdim 126234353Sdim ASTContext &getASTContext() { return Ctx; } 127234353Sdim 128224135Sdim void startTransaction(); 129224135Sdim bool commitTransaction(); 130224135Sdim void abortTransaction(); 131224135Sdim 132224135Sdim bool isInTransaction() const { return IsInTransaction; } 133224135Sdim 134226633Sdim void insert(SourceLocation loc, StringRef text); 135226633Sdim void insertAfterToken(SourceLocation loc, StringRef text); 136224135Sdim void remove(SourceRange range); 137224135Sdim void removeStmt(Stmt *S); 138226633Sdim void replace(SourceRange range, StringRef text); 139224135Sdim void replace(SourceRange range, SourceRange replacementRange); 140226633Sdim void replaceStmt(Stmt *S, StringRef text); 141226633Sdim void replaceText(SourceLocation loc, StringRef text, 142226633Sdim StringRef replacementText); 143224135Sdim void increaseIndentation(SourceRange range, 144224135Sdim SourceLocation parentIndent); 145224135Sdim 146226633Sdim bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); 147224135Sdim 148224135Sdim void applyRewrites(TransformActions::RewriteReceiver &receiver); 149224135Sdim 150224135Sdimprivate: 151224135Sdim bool canInsert(SourceLocation loc); 152224135Sdim bool canInsertAfterToken(SourceLocation loc); 153224135Sdim bool canRemoveRange(SourceRange range); 154224135Sdim bool canReplaceRange(SourceRange range, SourceRange replacementRange); 155226633Sdim bool canReplaceText(SourceLocation loc, StringRef text); 156224135Sdim 157224135Sdim void commitInsert(SourceLocation loc, StringRef text); 158224135Sdim void commitInsertAfterToken(SourceLocation loc, StringRef text); 159224135Sdim void commitRemove(SourceRange range); 160224135Sdim void commitRemoveStmt(Stmt *S); 161224135Sdim void commitReplace(SourceRange range, SourceRange replacementRange); 162226633Sdim void commitReplaceText(SourceLocation loc, StringRef text, 163226633Sdim StringRef replacementText); 164224135Sdim void commitIncreaseIndentation(SourceRange range,SourceLocation parentIndent); 165226633Sdim void commitClearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); 166224135Sdim 167224135Sdim void addRemoval(CharSourceRange range); 168224135Sdim void addInsertion(SourceLocation loc, StringRef text); 169224135Sdim 170224135Sdim /// \brief Stores text passed to the transformation methods to keep the string 171224135Sdim /// "alive". Since the vast majority of text will be the same, we also unique 172224135Sdim /// the strings using a StringMap. 173224135Sdim StringRef getUniqueText(StringRef text); 174224135Sdim 175224135Sdim /// \brief Computes the source location just past the end of the token at 176224135Sdim /// the given source location. If the location points at a macro, the whole 177224135Sdim /// macro expansion is skipped. 178224135Sdim static SourceLocation getLocForEndOfToken(SourceLocation loc, 179224135Sdim SourceManager &SM,Preprocessor &PP); 180224135Sdim}; 181224135Sdim 182224135Sdim} // anonymous namespace 183224135Sdim 184224135Sdimvoid TransformActionsImpl::startTransaction() { 185224135Sdim assert(!IsInTransaction && 186224135Sdim "Cannot start a transaction in the middle of another one"); 187224135Sdim IsInTransaction = true; 188224135Sdim} 189224135Sdim 190224135Sdimbool TransformActionsImpl::commitTransaction() { 191224135Sdim assert(IsInTransaction && "No transaction started"); 192224135Sdim 193224135Sdim if (CachedActions.empty()) { 194224135Sdim IsInTransaction = false; 195224135Sdim return false; 196224135Sdim } 197224135Sdim 198224135Sdim // Verify that all actions are possible otherwise abort the whole transaction. 199224135Sdim bool AllActionsPossible = true; 200224135Sdim for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) { 201224135Sdim ActionData &act = CachedActions[i]; 202224135Sdim switch (act.Kind) { 203224135Sdim case Act_Insert: 204224135Sdim if (!canInsert(act.Loc)) 205224135Sdim AllActionsPossible = false; 206224135Sdim break; 207224135Sdim case Act_InsertAfterToken: 208224135Sdim if (!canInsertAfterToken(act.Loc)) 209224135Sdim AllActionsPossible = false; 210224135Sdim break; 211224135Sdim case Act_Remove: 212224135Sdim if (!canRemoveRange(act.R1)) 213224135Sdim AllActionsPossible = false; 214224135Sdim break; 215224135Sdim case Act_RemoveStmt: 216224135Sdim assert(act.S); 217224135Sdim if (!canRemoveRange(act.S->getSourceRange())) 218224135Sdim AllActionsPossible = false; 219224135Sdim break; 220224135Sdim case Act_Replace: 221224135Sdim if (!canReplaceRange(act.R1, act.R2)) 222224135Sdim AllActionsPossible = false; 223224135Sdim break; 224224135Sdim case Act_ReplaceText: 225224135Sdim if (!canReplaceText(act.Loc, act.Text1)) 226224135Sdim AllActionsPossible = false; 227224135Sdim break; 228224135Sdim case Act_IncreaseIndentation: 229224135Sdim // This is not important, we don't care if it will fail. 230224135Sdim break; 231224135Sdim case Act_ClearDiagnostic: 232224135Sdim // We are just checking source rewrites. 233224135Sdim break; 234224135Sdim } 235224135Sdim if (!AllActionsPossible) 236224135Sdim break; 237224135Sdim } 238224135Sdim 239224135Sdim if (!AllActionsPossible) { 240224135Sdim abortTransaction(); 241224135Sdim return true; 242224135Sdim } 243224135Sdim 244224135Sdim for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) { 245224135Sdim ActionData &act = CachedActions[i]; 246224135Sdim switch (act.Kind) { 247224135Sdim case Act_Insert: 248224135Sdim commitInsert(act.Loc, act.Text1); 249224135Sdim break; 250224135Sdim case Act_InsertAfterToken: 251224135Sdim commitInsertAfterToken(act.Loc, act.Text1); 252224135Sdim break; 253224135Sdim case Act_Remove: 254224135Sdim commitRemove(act.R1); 255224135Sdim break; 256224135Sdim case Act_RemoveStmt: 257224135Sdim commitRemoveStmt(act.S); 258224135Sdim break; 259224135Sdim case Act_Replace: 260224135Sdim commitReplace(act.R1, act.R2); 261224135Sdim break; 262224135Sdim case Act_ReplaceText: 263224135Sdim commitReplaceText(act.Loc, act.Text1, act.Text2); 264224135Sdim break; 265224135Sdim case Act_IncreaseIndentation: 266224135Sdim commitIncreaseIndentation(act.R1, act.Loc); 267224135Sdim break; 268224135Sdim case Act_ClearDiagnostic: 269224135Sdim commitClearDiagnostic(act.DiagIDs, act.R1); 270224135Sdim break; 271224135Sdim } 272224135Sdim } 273224135Sdim 274224135Sdim CachedActions.clear(); 275224135Sdim IsInTransaction = false; 276224135Sdim return false; 277224135Sdim} 278224135Sdim 279224135Sdimvoid TransformActionsImpl::abortTransaction() { 280224135Sdim assert(IsInTransaction && "No transaction started"); 281224135Sdim CachedActions.clear(); 282224135Sdim IsInTransaction = false; 283224135Sdim} 284224135Sdim 285224135Sdimvoid TransformActionsImpl::insert(SourceLocation loc, StringRef text) { 286224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 287224135Sdim text = getUniqueText(text); 288224135Sdim ActionData data; 289224135Sdim data.Kind = Act_Insert; 290224135Sdim data.Loc = loc; 291224135Sdim data.Text1 = text; 292224135Sdim CachedActions.push_back(data); 293224135Sdim} 294224135Sdim 295224135Sdimvoid TransformActionsImpl::insertAfterToken(SourceLocation loc, StringRef text) { 296224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 297224135Sdim text = getUniqueText(text); 298224135Sdim ActionData data; 299224135Sdim data.Kind = Act_InsertAfterToken; 300224135Sdim data.Loc = loc; 301224135Sdim data.Text1 = text; 302224135Sdim CachedActions.push_back(data); 303224135Sdim} 304224135Sdim 305224135Sdimvoid TransformActionsImpl::remove(SourceRange range) { 306224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 307224135Sdim ActionData data; 308224135Sdim data.Kind = Act_Remove; 309224135Sdim data.R1 = range; 310224135Sdim CachedActions.push_back(data); 311224135Sdim} 312224135Sdim 313224135Sdimvoid TransformActionsImpl::removeStmt(Stmt *S) { 314224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 315224135Sdim ActionData data; 316224135Sdim data.Kind = Act_RemoveStmt; 317224135Sdim data.S = S->IgnoreImplicit(); // important for uniquing 318224135Sdim CachedActions.push_back(data); 319224135Sdim} 320224135Sdim 321224135Sdimvoid TransformActionsImpl::replace(SourceRange range, StringRef text) { 322224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 323224135Sdim text = getUniqueText(text); 324224135Sdim remove(range); 325224135Sdim insert(range.getBegin(), text); 326224135Sdim} 327224135Sdim 328224135Sdimvoid TransformActionsImpl::replace(SourceRange range, 329224135Sdim SourceRange replacementRange) { 330224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 331224135Sdim ActionData data; 332224135Sdim data.Kind = Act_Replace; 333224135Sdim data.R1 = range; 334224135Sdim data.R2 = replacementRange; 335224135Sdim CachedActions.push_back(data); 336224135Sdim} 337224135Sdim 338224135Sdimvoid TransformActionsImpl::replaceText(SourceLocation loc, StringRef text, 339224135Sdim StringRef replacementText) { 340224135Sdim text = getUniqueText(text); 341224135Sdim replacementText = getUniqueText(replacementText); 342224135Sdim ActionData data; 343224135Sdim data.Kind = Act_ReplaceText; 344224135Sdim data.Loc = loc; 345224135Sdim data.Text1 = text; 346224135Sdim data.Text2 = replacementText; 347224135Sdim CachedActions.push_back(data); 348224135Sdim} 349224135Sdim 350224135Sdimvoid TransformActionsImpl::replaceStmt(Stmt *S, StringRef text) { 351224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 352224135Sdim text = getUniqueText(text); 353224135Sdim insert(S->getLocStart(), text); 354224135Sdim removeStmt(S); 355224135Sdim} 356224135Sdim 357224135Sdimvoid TransformActionsImpl::increaseIndentation(SourceRange range, 358224135Sdim SourceLocation parentIndent) { 359224135Sdim if (range.isInvalid()) return; 360224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 361224135Sdim ActionData data; 362224135Sdim data.Kind = Act_IncreaseIndentation; 363224135Sdim data.R1 = range; 364224135Sdim data.Loc = parentIndent; 365224135Sdim CachedActions.push_back(data); 366224135Sdim} 367224135Sdim 368226633Sdimbool TransformActionsImpl::clearDiagnostic(ArrayRef<unsigned> IDs, 369224135Sdim SourceRange range) { 370224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 371224135Sdim if (!CapturedDiags.hasDiagnostic(IDs, range)) 372224135Sdim return false; 373224135Sdim 374224135Sdim ActionData data; 375224135Sdim data.Kind = Act_ClearDiagnostic; 376224135Sdim data.R1 = range; 377224135Sdim data.DiagIDs.append(IDs.begin(), IDs.end()); 378224135Sdim CachedActions.push_back(data); 379224135Sdim return true; 380224135Sdim} 381224135Sdim 382224135Sdimbool TransformActionsImpl::canInsert(SourceLocation loc) { 383224135Sdim if (loc.isInvalid()) 384224135Sdim return false; 385224135Sdim 386224135Sdim SourceManager &SM = Ctx.getSourceManager(); 387226633Sdim if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) 388224135Sdim return false; 389224135Sdim 390224135Sdim if (loc.isFileID()) 391224135Sdim return true; 392224135Sdim return PP.isAtStartOfMacroExpansion(loc); 393224135Sdim} 394224135Sdim 395224135Sdimbool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) { 396224135Sdim if (loc.isInvalid()) 397224135Sdim return false; 398224135Sdim 399224135Sdim SourceManager &SM = Ctx.getSourceManager(); 400226633Sdim if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) 401224135Sdim return false; 402224135Sdim 403224135Sdim if (loc.isFileID()) 404224135Sdim return true; 405224135Sdim return PP.isAtEndOfMacroExpansion(loc); 406224135Sdim} 407224135Sdim 408224135Sdimbool TransformActionsImpl::canRemoveRange(SourceRange range) { 409224135Sdim return canInsert(range.getBegin()) && canInsertAfterToken(range.getEnd()); 410224135Sdim} 411224135Sdim 412224135Sdimbool TransformActionsImpl::canReplaceRange(SourceRange range, 413224135Sdim SourceRange replacementRange) { 414224135Sdim return canRemoveRange(range) && canRemoveRange(replacementRange); 415224135Sdim} 416224135Sdim 417224135Sdimbool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) { 418224135Sdim if (!canInsert(loc)) 419224135Sdim return false; 420224135Sdim 421224135Sdim SourceManager &SM = Ctx.getSourceManager(); 422226633Sdim loc = SM.getExpansionLoc(loc); 423224135Sdim 424224135Sdim // Break down the source location. 425224135Sdim std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); 426224135Sdim 427224135Sdim // Try to load the file buffer. 428224135Sdim bool invalidTemp = false; 429226633Sdim StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 430224135Sdim if (invalidTemp) 431224135Sdim return false; 432224135Sdim 433224135Sdim return file.substr(locInfo.second).startswith(text); 434224135Sdim} 435224135Sdim 436224135Sdimvoid TransformActionsImpl::commitInsert(SourceLocation loc, StringRef text) { 437224135Sdim addInsertion(loc, text); 438224135Sdim} 439224135Sdim 440224135Sdimvoid TransformActionsImpl::commitInsertAfterToken(SourceLocation loc, 441224135Sdim StringRef text) { 442224135Sdim addInsertion(getLocForEndOfToken(loc, Ctx.getSourceManager(), PP), text); 443224135Sdim} 444224135Sdim 445224135Sdimvoid TransformActionsImpl::commitRemove(SourceRange range) { 446224135Sdim addRemoval(CharSourceRange::getTokenRange(range)); 447224135Sdim} 448224135Sdim 449224135Sdimvoid TransformActionsImpl::commitRemoveStmt(Stmt *S) { 450224135Sdim assert(S); 451224135Sdim if (StmtRemovals.count(S)) 452224135Sdim return; // already removed. 453224135Sdim 454224135Sdim if (Expr *E = dyn_cast<Expr>(S)) { 455224135Sdim commitRemove(E->getSourceRange()); 456224135Sdim commitInsert(E->getSourceRange().getBegin(), getARCMTMacroName()); 457224135Sdim } else 458224135Sdim commitRemove(S->getSourceRange()); 459224135Sdim 460224135Sdim StmtRemovals.insert(S); 461224135Sdim} 462224135Sdim 463224135Sdimvoid TransformActionsImpl::commitReplace(SourceRange range, 464224135Sdim SourceRange replacementRange) { 465224135Sdim RangeComparison comp = CharRange::compare(replacementRange, range, 466224135Sdim Ctx.getSourceManager(), PP); 467224135Sdim assert(comp == Range_Contained); 468224135Sdim if (comp != Range_Contained) 469224135Sdim return; // Although we asserted, be extra safe for release build. 470224135Sdim if (range.getBegin() != replacementRange.getBegin()) 471224135Sdim addRemoval(CharSourceRange::getCharRange(range.getBegin(), 472224135Sdim replacementRange.getBegin())); 473224135Sdim if (replacementRange.getEnd() != range.getEnd()) 474224135Sdim addRemoval(CharSourceRange::getTokenRange( 475224135Sdim getLocForEndOfToken(replacementRange.getEnd(), 476224135Sdim Ctx.getSourceManager(), PP), 477224135Sdim range.getEnd())); 478224135Sdim} 479224135Sdimvoid TransformActionsImpl::commitReplaceText(SourceLocation loc, 480224135Sdim StringRef text, 481224135Sdim StringRef replacementText) { 482224135Sdim SourceManager &SM = Ctx.getSourceManager(); 483226633Sdim loc = SM.getExpansionLoc(loc); 484224135Sdim // canReplaceText already checked if loc points at text. 485226633Sdim SourceLocation afterText = loc.getLocWithOffset(text.size()); 486224135Sdim 487224135Sdim addRemoval(CharSourceRange::getCharRange(loc, afterText)); 488224135Sdim commitInsert(loc, replacementText); 489224135Sdim} 490224135Sdim 491224135Sdimvoid TransformActionsImpl::commitIncreaseIndentation(SourceRange range, 492224135Sdim SourceLocation parentIndent) { 493224135Sdim SourceManager &SM = Ctx.getSourceManager(); 494224135Sdim IndentationRanges.push_back( 495224135Sdim std::make_pair(CharRange(CharSourceRange::getTokenRange(range), 496224135Sdim SM, PP), 497226633Sdim SM.getExpansionLoc(parentIndent))); 498224135Sdim} 499224135Sdim 500226633Sdimvoid TransformActionsImpl::commitClearDiagnostic(ArrayRef<unsigned> IDs, 501224135Sdim SourceRange range) { 502224135Sdim CapturedDiags.clearDiagnostic(IDs, range); 503224135Sdim} 504224135Sdim 505224135Sdimvoid TransformActionsImpl::addInsertion(SourceLocation loc, StringRef text) { 506224135Sdim SourceManager &SM = Ctx.getSourceManager(); 507226633Sdim loc = SM.getExpansionLoc(loc); 508224135Sdim for (std::list<CharRange>::reverse_iterator 509224135Sdim I = Removals.rbegin(), E = Removals.rend(); I != E; ++I) { 510224135Sdim if (!SM.isBeforeInTranslationUnit(loc, I->End)) 511224135Sdim break; 512224135Sdim if (I->Begin.isBeforeInTranslationUnitThan(loc)) 513224135Sdim return; 514224135Sdim } 515224135Sdim 516224135Sdim Inserts[FullSourceLoc(loc, SM)].push_back(text); 517224135Sdim} 518224135Sdim 519224135Sdimvoid TransformActionsImpl::addRemoval(CharSourceRange range) { 520224135Sdim CharRange newRange(range, Ctx.getSourceManager(), PP); 521224135Sdim if (newRange.Begin == newRange.End) 522224135Sdim return; 523224135Sdim 524224135Sdim Inserts.erase(Inserts.upper_bound(newRange.Begin), 525224135Sdim Inserts.lower_bound(newRange.End)); 526224135Sdim 527224135Sdim std::list<CharRange>::iterator I = Removals.end(); 528224135Sdim while (I != Removals.begin()) { 529224135Sdim std::list<CharRange>::iterator RI = I; 530224135Sdim --RI; 531224135Sdim RangeComparison comp = newRange.compareWith(*RI); 532224135Sdim switch (comp) { 533224135Sdim case Range_Before: 534224135Sdim --I; 535224135Sdim break; 536224135Sdim case Range_After: 537224135Sdim Removals.insert(I, newRange); 538224135Sdim return; 539224135Sdim case Range_Contained: 540224135Sdim return; 541224135Sdim case Range_Contains: 542224135Sdim RI->End = newRange.End; 543224135Sdim case Range_ExtendsBegin: 544224135Sdim newRange.End = RI->End; 545224135Sdim Removals.erase(RI); 546224135Sdim break; 547224135Sdim case Range_ExtendsEnd: 548224135Sdim RI->End = newRange.End; 549224135Sdim return; 550224135Sdim } 551224135Sdim } 552224135Sdim 553224135Sdim Removals.insert(Removals.begin(), newRange); 554224135Sdim} 555224135Sdim 556224135Sdimvoid TransformActionsImpl::applyRewrites( 557224135Sdim TransformActions::RewriteReceiver &receiver) { 558224135Sdim for (InsertsMap::iterator I = Inserts.begin(), E = Inserts.end(); I!=E; ++I) { 559224135Sdim SourceLocation loc = I->first; 560224135Sdim for (TextsVec::iterator 561224135Sdim TI = I->second.begin(), TE = I->second.end(); TI != TE; ++TI) { 562224135Sdim receiver.insert(loc, *TI); 563224135Sdim } 564224135Sdim } 565224135Sdim 566224135Sdim for (std::vector<std::pair<CharRange, SourceLocation> >::iterator 567224135Sdim I = IndentationRanges.begin(), E = IndentationRanges.end(); I!=E; ++I) { 568224135Sdim CharSourceRange range = CharSourceRange::getCharRange(I->first.Begin, 569224135Sdim I->first.End); 570224135Sdim receiver.increaseIndentation(range, I->second); 571224135Sdim } 572224135Sdim 573224135Sdim for (std::list<CharRange>::iterator 574224135Sdim I = Removals.begin(), E = Removals.end(); I != E; ++I) { 575224135Sdim CharSourceRange range = CharSourceRange::getCharRange(I->Begin, I->End); 576224135Sdim receiver.remove(range); 577224135Sdim } 578224135Sdim} 579224135Sdim 580224135Sdim/// \brief Stores text passed to the transformation methods to keep the string 581224135Sdim/// "alive". Since the vast majority of text will be the same, we also unique 582224135Sdim/// the strings using a StringMap. 583224135SdimStringRef TransformActionsImpl::getUniqueText(StringRef text) { 584224135Sdim llvm::StringMapEntry<bool> &entry = UniqueText.GetOrCreateValue(text); 585224135Sdim return entry.getKey(); 586224135Sdim} 587224135Sdim 588224135Sdim/// \brief Computes the source location just past the end of the token at 589224135Sdim/// the given source location. If the location points at a macro, the whole 590224135Sdim/// macro expansion is skipped. 591224135SdimSourceLocation TransformActionsImpl::getLocForEndOfToken(SourceLocation loc, 592224135Sdim SourceManager &SM, 593224135Sdim Preprocessor &PP) { 594224135Sdim if (loc.isMacroID()) 595226633Sdim loc = SM.getExpansionRange(loc).second; 596224135Sdim return PP.getLocForEndOfToken(loc); 597224135Sdim} 598224135Sdim 599224135SdimTransformActions::RewriteReceiver::~RewriteReceiver() { } 600224135Sdim 601226633SdimTransformActions::TransformActions(DiagnosticsEngine &diag, 602224135Sdim CapturedDiagList &capturedDiags, 603224135Sdim ASTContext &ctx, Preprocessor &PP) 604226633Sdim : Diags(diag), CapturedDiags(capturedDiags), ReportedErrors(false) { 605224135Sdim Impl = new TransformActionsImpl(capturedDiags, ctx, PP); 606224135Sdim} 607224135Sdim 608224135SdimTransformActions::~TransformActions() { 609224135Sdim delete static_cast<TransformActionsImpl*>(Impl); 610224135Sdim} 611224135Sdim 612224135Sdimvoid TransformActions::startTransaction() { 613224135Sdim static_cast<TransformActionsImpl*>(Impl)->startTransaction(); 614224135Sdim} 615224135Sdim 616224135Sdimbool TransformActions::commitTransaction() { 617224135Sdim return static_cast<TransformActionsImpl*>(Impl)->commitTransaction(); 618224135Sdim} 619224135Sdim 620224135Sdimvoid TransformActions::abortTransaction() { 621224135Sdim static_cast<TransformActionsImpl*>(Impl)->abortTransaction(); 622224135Sdim} 623224135Sdim 624224135Sdim 625226633Sdimvoid TransformActions::insert(SourceLocation loc, StringRef text) { 626224135Sdim static_cast<TransformActionsImpl*>(Impl)->insert(loc, text); 627224135Sdim} 628224135Sdim 629224135Sdimvoid TransformActions::insertAfterToken(SourceLocation loc, 630226633Sdim StringRef text) { 631224135Sdim static_cast<TransformActionsImpl*>(Impl)->insertAfterToken(loc, text); 632224135Sdim} 633224135Sdim 634224135Sdimvoid TransformActions::remove(SourceRange range) { 635224135Sdim static_cast<TransformActionsImpl*>(Impl)->remove(range); 636224135Sdim} 637224135Sdim 638224135Sdimvoid TransformActions::removeStmt(Stmt *S) { 639224135Sdim static_cast<TransformActionsImpl*>(Impl)->removeStmt(S); 640224135Sdim} 641224135Sdim 642226633Sdimvoid TransformActions::replace(SourceRange range, StringRef text) { 643224135Sdim static_cast<TransformActionsImpl*>(Impl)->replace(range, text); 644224135Sdim} 645224135Sdim 646224135Sdimvoid TransformActions::replace(SourceRange range, 647224135Sdim SourceRange replacementRange) { 648224135Sdim static_cast<TransformActionsImpl*>(Impl)->replace(range, replacementRange); 649224135Sdim} 650224135Sdim 651226633Sdimvoid TransformActions::replaceStmt(Stmt *S, StringRef text) { 652224135Sdim static_cast<TransformActionsImpl*>(Impl)->replaceStmt(S, text); 653224135Sdim} 654224135Sdim 655226633Sdimvoid TransformActions::replaceText(SourceLocation loc, StringRef text, 656226633Sdim StringRef replacementText) { 657224135Sdim static_cast<TransformActionsImpl*>(Impl)->replaceText(loc, text, 658224135Sdim replacementText); 659224135Sdim} 660224135Sdim 661224135Sdimvoid TransformActions::increaseIndentation(SourceRange range, 662224135Sdim SourceLocation parentIndent) { 663224135Sdim static_cast<TransformActionsImpl*>(Impl)->increaseIndentation(range, 664224135Sdim parentIndent); 665224135Sdim} 666224135Sdim 667226633Sdimbool TransformActions::clearDiagnostic(ArrayRef<unsigned> IDs, 668224135Sdim SourceRange range) { 669224135Sdim return static_cast<TransformActionsImpl*>(Impl)->clearDiagnostic(IDs, range); 670224135Sdim} 671224135Sdim 672224135Sdimvoid TransformActions::applyRewrites(RewriteReceiver &receiver) { 673224135Sdim static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver); 674224135Sdim} 675224135Sdim 676226633Sdimvoid TransformActions::reportError(StringRef error, SourceLocation loc, 677224135Sdim SourceRange range) { 678224135Sdim assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() && 679224135Sdim "Errors should be emitted out of a transaction"); 680234353Sdim 681234353Sdim SourceManager &SM = static_cast<TransformActionsImpl*>(Impl)-> 682234353Sdim getASTContext().getSourceManager(); 683234353Sdim if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) 684234353Sdim return; 685234353Sdim 686224135Sdim // FIXME: Use a custom category name to distinguish rewriter errors. 687224135Sdim std::string rewriteErr = "[rewriter] "; 688224135Sdim rewriteErr += error; 689224135Sdim unsigned diagID 690224135Sdim = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error, 691224135Sdim rewriteErr); 692224135Sdim Diags.Report(loc, diagID) << range; 693226633Sdim ReportedErrors = true; 694224135Sdim} 695224135Sdim 696234353Sdimvoid TransformActions::reportWarning(StringRef warning, SourceLocation loc, 697234353Sdim SourceRange range) { 698234353Sdim assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() && 699234353Sdim "Warning should be emitted out of a transaction"); 700234353Sdim 701234353Sdim SourceManager &SM = static_cast<TransformActionsImpl*>(Impl)-> 702234353Sdim getASTContext().getSourceManager(); 703234353Sdim if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) 704234353Sdim return; 705234353Sdim 706234353Sdim // FIXME: Use a custom category name to distinguish rewriter errors. 707234353Sdim std::string rewriterWarn = "[rewriter] "; 708234353Sdim rewriterWarn += warning; 709234353Sdim unsigned diagID 710234353Sdim = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Warning, 711234353Sdim rewriterWarn); 712234353Sdim Diags.Report(loc, diagID) << range; 713234353Sdim} 714234353Sdim 715226633Sdimvoid TransformActions::reportNote(StringRef note, SourceLocation loc, 716224135Sdim SourceRange range) { 717224135Sdim assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() && 718224135Sdim "Errors should be emitted out of a transaction"); 719234353Sdim 720234353Sdim SourceManager &SM = static_cast<TransformActionsImpl*>(Impl)-> 721234353Sdim getASTContext().getSourceManager(); 722234353Sdim if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) 723234353Sdim return; 724234353Sdim 725224135Sdim // FIXME: Use a custom category name to distinguish rewriter errors. 726224135Sdim std::string rewriteNote = "[rewriter] "; 727224135Sdim rewriteNote += note; 728224135Sdim unsigned diagID 729224135Sdim = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note, 730224135Sdim rewriteNote); 731224135Sdim Diags.Report(loc, diagID) << range; 732224135Sdim} 733