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