1353358Sdim//===-- TransformActions.cpp - Migration to ARC mode ----------------------===// 2224135Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6224135Sdim// 7224135Sdim//===----------------------------------------------------------------------===// 8224135Sdim 9224135Sdim#include "Internals.h" 10239462Sdim#include "clang/AST/ASTContext.h" 11224135Sdim#include "clang/AST/Expr.h" 12249423Sdim#include "clang/Basic/SourceManager.h" 13224135Sdim#include "clang/Lex/Preprocessor.h" 14224135Sdim#include "llvm/ADT/DenseSet.h" 15224135Sdim#include <map> 16224135Sdimusing namespace clang; 17224135Sdimusing namespace arcmt; 18224135Sdim 19224135Sdimnamespace { 20224135Sdim 21341825Sdim/// Collects transformations and merges them before applying them with 22224135Sdim/// with applyRewrites(). E.g. if the same source range 23224135Sdim/// is requested to be removed twice, only one rewriter remove will be invoked. 24224135Sdim/// Rewrites happen in "transactions"; if one rewrite in the transaction cannot 25224135Sdim/// be done (e.g. it resides in a macro) all rewrites in the transaction are 26224135Sdim/// aborted. 27224135Sdim/// FIXME: "Transactional" rewrites support should be baked in the Rewriter. 28224135Sdimclass TransformActionsImpl { 29224135Sdim CapturedDiagList &CapturedDiags; 30224135Sdim ASTContext &Ctx; 31224135Sdim Preprocessor &PP; 32224135Sdim 33224135Sdim bool IsInTransaction; 34224135Sdim 35224135Sdim enum ActionKind { 36224135Sdim Act_Insert, Act_InsertAfterToken, 37224135Sdim Act_Remove, Act_RemoveStmt, 38224135Sdim Act_Replace, Act_ReplaceText, 39224135Sdim Act_IncreaseIndentation, 40224135Sdim Act_ClearDiagnostic 41224135Sdim }; 42224135Sdim 43224135Sdim struct ActionData { 44224135Sdim ActionKind Kind; 45224135Sdim SourceLocation Loc; 46224135Sdim SourceRange R1, R2; 47226633Sdim StringRef Text1, Text2; 48224135Sdim Stmt *S; 49226633Sdim SmallVector<unsigned, 2> DiagIDs; 50224135Sdim }; 51224135Sdim 52224135Sdim std::vector<ActionData> CachedActions; 53224135Sdim 54224135Sdim enum RangeComparison { 55224135Sdim Range_Before, 56224135Sdim Range_After, 57224135Sdim Range_Contains, 58224135Sdim Range_Contained, 59224135Sdim Range_ExtendsBegin, 60224135Sdim Range_ExtendsEnd 61224135Sdim }; 62224135Sdim 63341825Sdim /// A range to remove. It is a character range. 64224135Sdim struct CharRange { 65224135Sdim FullSourceLoc Begin, End; 66224135Sdim 67224135Sdim CharRange(CharSourceRange range, SourceManager &srcMgr, Preprocessor &PP) { 68224135Sdim SourceLocation beginLoc = range.getBegin(), endLoc = range.getEnd(); 69224135Sdim assert(beginLoc.isValid() && endLoc.isValid()); 70224135Sdim if (range.isTokenRange()) { 71226633Sdim Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr); 72224135Sdim End = FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr); 73224135Sdim } else { 74226633Sdim Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr); 75226633Sdim End = FullSourceLoc(srcMgr.getExpansionLoc(endLoc), srcMgr); 76224135Sdim } 77224135Sdim assert(Begin.isValid() && End.isValid()); 78341825Sdim } 79224135Sdim 80224135Sdim RangeComparison compareWith(const CharRange &RHS) const { 81224135Sdim if (End.isBeforeInTranslationUnitThan(RHS.Begin)) 82224135Sdim return Range_Before; 83224135Sdim if (RHS.End.isBeforeInTranslationUnitThan(Begin)) 84224135Sdim return Range_After; 85224135Sdim if (!Begin.isBeforeInTranslationUnitThan(RHS.Begin) && 86224135Sdim !RHS.End.isBeforeInTranslationUnitThan(End)) 87224135Sdim return Range_Contained; 88224135Sdim if (Begin.isBeforeInTranslationUnitThan(RHS.Begin) && 89224135Sdim RHS.End.isBeforeInTranslationUnitThan(End)) 90224135Sdim return Range_Contains; 91224135Sdim if (Begin.isBeforeInTranslationUnitThan(RHS.Begin)) 92224135Sdim return Range_ExtendsBegin; 93224135Sdim else 94224135Sdim return Range_ExtendsEnd; 95224135Sdim } 96341825Sdim 97224135Sdim static RangeComparison compare(SourceRange LHS, SourceRange RHS, 98224135Sdim SourceManager &SrcMgr, Preprocessor &PP) { 99224135Sdim return CharRange(CharSourceRange::getTokenRange(LHS), SrcMgr, PP) 100224135Sdim .compareWith(CharRange(CharSourceRange::getTokenRange(RHS), 101224135Sdim SrcMgr, PP)); 102224135Sdim } 103224135Sdim }; 104224135Sdim 105226633Sdim typedef SmallVector<StringRef, 2> TextsVec; 106224135Sdim typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare> 107224135Sdim InsertsMap; 108224135Sdim InsertsMap Inserts; 109341825Sdim /// A list of ranges to remove. They are always sorted and they never 110224135Sdim /// intersect with each other. 111224135Sdim std::list<CharRange> Removals; 112224135Sdim 113224135Sdim llvm::DenseSet<Stmt *> StmtRemovals; 114224135Sdim 115224135Sdim std::vector<std::pair<CharRange, SourceLocation> > IndentationRanges; 116224135Sdim 117341825Sdim /// Keeps text passed to transformation methods. 118224135Sdim llvm::StringMap<bool> UniqueText; 119224135Sdim 120224135Sdimpublic: 121224135Sdim TransformActionsImpl(CapturedDiagList &capturedDiags, 122224135Sdim ASTContext &ctx, Preprocessor &PP) 123224135Sdim : CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(false) { } 124224135Sdim 125234353Sdim ASTContext &getASTContext() { return Ctx; } 126234353Sdim 127224135Sdim void startTransaction(); 128224135Sdim bool commitTransaction(); 129224135Sdim void abortTransaction(); 130224135Sdim 131224135Sdim bool isInTransaction() const { return IsInTransaction; } 132224135Sdim 133226633Sdim void insert(SourceLocation loc, StringRef text); 134226633Sdim void insertAfterToken(SourceLocation loc, StringRef text); 135224135Sdim void remove(SourceRange range); 136224135Sdim void removeStmt(Stmt *S); 137226633Sdim void replace(SourceRange range, StringRef text); 138224135Sdim void replace(SourceRange range, SourceRange replacementRange); 139226633Sdim void replaceStmt(Stmt *S, StringRef text); 140226633Sdim void replaceText(SourceLocation loc, StringRef text, 141226633Sdim StringRef replacementText); 142224135Sdim void increaseIndentation(SourceRange range, 143224135Sdim SourceLocation parentIndent); 144224135Sdim 145226633Sdim bool clearDiagnostic(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); 154226633Sdim bool canReplaceText(SourceLocation loc, 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); 161226633Sdim void commitReplaceText(SourceLocation loc, StringRef text, 162226633Sdim StringRef replacementText); 163224135Sdim void commitIncreaseIndentation(SourceRange range,SourceLocation parentIndent); 164226633Sdim void commitClearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); 165224135Sdim 166224135Sdim void addRemoval(CharSourceRange range); 167224135Sdim void addInsertion(SourceLocation loc, StringRef text); 168224135Sdim 169341825Sdim /// 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 174341825Sdim /// 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; 316353358Sdim if (auto *E = dyn_cast<Expr>(S)) 317353358Sdim S = E->IgnoreImplicit(); // important for uniquing 318353358Sdim data.S = S; 319224135Sdim CachedActions.push_back(data); 320224135Sdim} 321224135Sdim 322224135Sdimvoid TransformActionsImpl::replace(SourceRange range, StringRef text) { 323224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 324224135Sdim text = getUniqueText(text); 325224135Sdim remove(range); 326224135Sdim insert(range.getBegin(), text); 327224135Sdim} 328224135Sdim 329224135Sdimvoid TransformActionsImpl::replace(SourceRange range, 330224135Sdim SourceRange replacementRange) { 331224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 332224135Sdim ActionData data; 333224135Sdim data.Kind = Act_Replace; 334224135Sdim data.R1 = range; 335224135Sdim data.R2 = replacementRange; 336224135Sdim CachedActions.push_back(data); 337224135Sdim} 338224135Sdim 339224135Sdimvoid TransformActionsImpl::replaceText(SourceLocation loc, StringRef text, 340224135Sdim StringRef replacementText) { 341224135Sdim text = getUniqueText(text); 342224135Sdim replacementText = getUniqueText(replacementText); 343224135Sdim ActionData data; 344224135Sdim data.Kind = Act_ReplaceText; 345224135Sdim data.Loc = loc; 346224135Sdim data.Text1 = text; 347224135Sdim data.Text2 = replacementText; 348224135Sdim CachedActions.push_back(data); 349224135Sdim} 350224135Sdim 351224135Sdimvoid TransformActionsImpl::replaceStmt(Stmt *S, StringRef text) { 352224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 353224135Sdim text = getUniqueText(text); 354344779Sdim insert(S->getBeginLoc(), text); 355224135Sdim removeStmt(S); 356224135Sdim} 357224135Sdim 358224135Sdimvoid TransformActionsImpl::increaseIndentation(SourceRange range, 359224135Sdim SourceLocation parentIndent) { 360224135Sdim if (range.isInvalid()) return; 361224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 362224135Sdim ActionData data; 363224135Sdim data.Kind = Act_IncreaseIndentation; 364224135Sdim data.R1 = range; 365224135Sdim data.Loc = parentIndent; 366224135Sdim CachedActions.push_back(data); 367224135Sdim} 368224135Sdim 369226633Sdimbool TransformActionsImpl::clearDiagnostic(ArrayRef<unsigned> IDs, 370224135Sdim SourceRange range) { 371224135Sdim assert(IsInTransaction && "Actions only allowed during a transaction"); 372224135Sdim if (!CapturedDiags.hasDiagnostic(IDs, range)) 373224135Sdim return false; 374224135Sdim 375224135Sdim ActionData data; 376224135Sdim data.Kind = Act_ClearDiagnostic; 377224135Sdim data.R1 = range; 378224135Sdim data.DiagIDs.append(IDs.begin(), IDs.end()); 379224135Sdim CachedActions.push_back(data); 380224135Sdim return true; 381224135Sdim} 382224135Sdim 383224135Sdimbool TransformActionsImpl::canInsert(SourceLocation loc) { 384224135Sdim if (loc.isInvalid()) 385224135Sdim return false; 386224135Sdim 387224135Sdim SourceManager &SM = Ctx.getSourceManager(); 388226633Sdim if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) 389224135Sdim return false; 390224135Sdim 391224135Sdim if (loc.isFileID()) 392224135Sdim return true; 393224135Sdim return PP.isAtStartOfMacroExpansion(loc); 394224135Sdim} 395224135Sdim 396224135Sdimbool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) { 397224135Sdim if (loc.isInvalid()) 398224135Sdim return false; 399224135Sdim 400224135Sdim SourceManager &SM = Ctx.getSourceManager(); 401226633Sdim if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) 402224135Sdim return false; 403224135Sdim 404224135Sdim if (loc.isFileID()) 405224135Sdim return true; 406224135Sdim return PP.isAtEndOfMacroExpansion(loc); 407224135Sdim} 408224135Sdim 409224135Sdimbool TransformActionsImpl::canRemoveRange(SourceRange range) { 410224135Sdim return canInsert(range.getBegin()) && canInsertAfterToken(range.getEnd()); 411224135Sdim} 412224135Sdim 413224135Sdimbool TransformActionsImpl::canReplaceRange(SourceRange range, 414224135Sdim SourceRange replacementRange) { 415224135Sdim return canRemoveRange(range) && canRemoveRange(replacementRange); 416224135Sdim} 417224135Sdim 418224135Sdimbool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) { 419224135Sdim if (!canInsert(loc)) 420224135Sdim return false; 421224135Sdim 422224135Sdim SourceManager &SM = Ctx.getSourceManager(); 423226633Sdim loc = SM.getExpansionLoc(loc); 424224135Sdim 425224135Sdim // Break down the source location. 426224135Sdim std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); 427224135Sdim 428224135Sdim // Try to load the file buffer. 429224135Sdim bool invalidTemp = false; 430226633Sdim StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 431224135Sdim if (invalidTemp) 432224135Sdim return false; 433224135Sdim 434224135Sdim return file.substr(locInfo.second).startswith(text); 435224135Sdim} 436224135Sdim 437224135Sdimvoid TransformActionsImpl::commitInsert(SourceLocation loc, StringRef text) { 438224135Sdim addInsertion(loc, text); 439224135Sdim} 440224135Sdim 441224135Sdimvoid TransformActionsImpl::commitInsertAfterToken(SourceLocation loc, 442224135Sdim StringRef text) { 443224135Sdim addInsertion(getLocForEndOfToken(loc, Ctx.getSourceManager(), PP), text); 444224135Sdim} 445224135Sdim 446224135Sdimvoid TransformActionsImpl::commitRemove(SourceRange range) { 447224135Sdim addRemoval(CharSourceRange::getTokenRange(range)); 448224135Sdim} 449224135Sdim 450224135Sdimvoid TransformActionsImpl::commitRemoveStmt(Stmt *S) { 451224135Sdim assert(S); 452224135Sdim if (StmtRemovals.count(S)) 453224135Sdim return; // already removed. 454224135Sdim 455224135Sdim if (Expr *E = dyn_cast<Expr>(S)) { 456224135Sdim commitRemove(E->getSourceRange()); 457224135Sdim commitInsert(E->getSourceRange().getBegin(), getARCMTMacroName()); 458224135Sdim } else 459224135Sdim commitRemove(S->getSourceRange()); 460224135Sdim 461224135Sdim StmtRemovals.insert(S); 462224135Sdim} 463224135Sdim 464224135Sdimvoid TransformActionsImpl::commitReplace(SourceRange range, 465224135Sdim SourceRange replacementRange) { 466224135Sdim RangeComparison comp = CharRange::compare(replacementRange, range, 467224135Sdim Ctx.getSourceManager(), PP); 468224135Sdim assert(comp == Range_Contained); 469224135Sdim if (comp != Range_Contained) 470224135Sdim return; // Although we asserted, be extra safe for release build. 471224135Sdim if (range.getBegin() != replacementRange.getBegin()) 472224135Sdim addRemoval(CharSourceRange::getCharRange(range.getBegin(), 473224135Sdim replacementRange.getBegin())); 474224135Sdim if (replacementRange.getEnd() != range.getEnd()) 475224135Sdim addRemoval(CharSourceRange::getTokenRange( 476224135Sdim getLocForEndOfToken(replacementRange.getEnd(), 477224135Sdim Ctx.getSourceManager(), PP), 478224135Sdim range.getEnd())); 479224135Sdim} 480224135Sdimvoid TransformActionsImpl::commitReplaceText(SourceLocation loc, 481224135Sdim StringRef text, 482224135Sdim StringRef replacementText) { 483224135Sdim SourceManager &SM = Ctx.getSourceManager(); 484226633Sdim loc = SM.getExpansionLoc(loc); 485224135Sdim // canReplaceText already checked if loc points at text. 486226633Sdim SourceLocation afterText = loc.getLocWithOffset(text.size()); 487224135Sdim 488224135Sdim addRemoval(CharSourceRange::getCharRange(loc, afterText)); 489341825Sdim commitInsert(loc, replacementText); 490224135Sdim} 491224135Sdim 492224135Sdimvoid TransformActionsImpl::commitIncreaseIndentation(SourceRange range, 493224135Sdim SourceLocation parentIndent) { 494224135Sdim SourceManager &SM = Ctx.getSourceManager(); 495224135Sdim IndentationRanges.push_back( 496224135Sdim std::make_pair(CharRange(CharSourceRange::getTokenRange(range), 497224135Sdim SM, PP), 498226633Sdim SM.getExpansionLoc(parentIndent))); 499224135Sdim} 500224135Sdim 501226633Sdimvoid TransformActionsImpl::commitClearDiagnostic(ArrayRef<unsigned> IDs, 502224135Sdim SourceRange range) { 503224135Sdim CapturedDiags.clearDiagnostic(IDs, range); 504224135Sdim} 505224135Sdim 506224135Sdimvoid TransformActionsImpl::addInsertion(SourceLocation loc, StringRef text) { 507224135Sdim SourceManager &SM = Ctx.getSourceManager(); 508226633Sdim loc = SM.getExpansionLoc(loc); 509296417Sdim for (const CharRange &I : llvm::reverse(Removals)) { 510296417Sdim if (!SM.isBeforeInTranslationUnit(loc, I.End)) 511224135Sdim break; 512296417Sdim 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; 543321369Sdim LLVM_FALLTHROUGH; 544224135Sdim case Range_ExtendsBegin: 545224135Sdim newRange.End = RI->End; 546224135Sdim Removals.erase(RI); 547224135Sdim break; 548224135Sdim case Range_ExtendsEnd: 549224135Sdim RI->End = newRange.End; 550224135Sdim return; 551224135Sdim } 552224135Sdim } 553224135Sdim 554224135Sdim Removals.insert(Removals.begin(), newRange); 555224135Sdim} 556224135Sdim 557224135Sdimvoid TransformActionsImpl::applyRewrites( 558224135Sdim TransformActions::RewriteReceiver &receiver) { 559224135Sdim for (InsertsMap::iterator I = Inserts.begin(), E = Inserts.end(); I!=E; ++I) { 560224135Sdim SourceLocation loc = I->first; 561224135Sdim for (TextsVec::iterator 562224135Sdim TI = I->second.begin(), TE = I->second.end(); TI != TE; ++TI) { 563224135Sdim receiver.insert(loc, *TI); 564224135Sdim } 565224135Sdim } 566224135Sdim 567224135Sdim for (std::vector<std::pair<CharRange, SourceLocation> >::iterator 568224135Sdim I = IndentationRanges.begin(), E = IndentationRanges.end(); I!=E; ++I) { 569224135Sdim CharSourceRange range = CharSourceRange::getCharRange(I->first.Begin, 570224135Sdim I->first.End); 571224135Sdim receiver.increaseIndentation(range, I->second); 572224135Sdim } 573224135Sdim 574224135Sdim for (std::list<CharRange>::iterator 575224135Sdim I = Removals.begin(), E = Removals.end(); I != E; ++I) { 576224135Sdim CharSourceRange range = CharSourceRange::getCharRange(I->Begin, I->End); 577224135Sdim receiver.remove(range); 578224135Sdim } 579224135Sdim} 580224135Sdim 581341825Sdim/// Stores text passed to the transformation methods to keep the string 582224135Sdim/// "alive". Since the vast majority of text will be the same, we also unique 583224135Sdim/// the strings using a StringMap. 584224135SdimStringRef TransformActionsImpl::getUniqueText(StringRef text) { 585280031Sdim return UniqueText.insert(std::make_pair(text, false)).first->first(); 586224135Sdim} 587224135Sdim 588341825Sdim/// 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) { 594341825Sdim if (loc.isMacroID()) { 595341825Sdim CharSourceRange Exp = SM.getExpansionRange(loc); 596341825Sdim if (Exp.isCharRange()) 597341825Sdim return Exp.getEnd(); 598341825Sdim loc = Exp.getEnd(); 599341825Sdim } 600224135Sdim return PP.getLocForEndOfToken(loc); 601224135Sdim} 602224135Sdim 603224135SdimTransformActions::RewriteReceiver::~RewriteReceiver() { } 604224135Sdim 605226633SdimTransformActions::TransformActions(DiagnosticsEngine &diag, 606224135Sdim CapturedDiagList &capturedDiags, 607224135Sdim ASTContext &ctx, Preprocessor &PP) 608276479Sdim : Diags(diag), CapturedDiags(capturedDiags) { 609224135Sdim Impl = new TransformActionsImpl(capturedDiags, ctx, PP); 610224135Sdim} 611224135Sdim 612224135SdimTransformActions::~TransformActions() { 613224135Sdim delete static_cast<TransformActionsImpl*>(Impl); 614224135Sdim} 615224135Sdim 616224135Sdimvoid TransformActions::startTransaction() { 617224135Sdim static_cast<TransformActionsImpl*>(Impl)->startTransaction(); 618224135Sdim} 619224135Sdim 620224135Sdimbool TransformActions::commitTransaction() { 621224135Sdim return static_cast<TransformActionsImpl*>(Impl)->commitTransaction(); 622224135Sdim} 623224135Sdim 624224135Sdimvoid TransformActions::abortTransaction() { 625224135Sdim static_cast<TransformActionsImpl*>(Impl)->abortTransaction(); 626224135Sdim} 627224135Sdim 628224135Sdim 629226633Sdimvoid TransformActions::insert(SourceLocation loc, StringRef text) { 630224135Sdim static_cast<TransformActionsImpl*>(Impl)->insert(loc, text); 631224135Sdim} 632224135Sdim 633224135Sdimvoid TransformActions::insertAfterToken(SourceLocation loc, 634226633Sdim StringRef text) { 635224135Sdim static_cast<TransformActionsImpl*>(Impl)->insertAfterToken(loc, text); 636224135Sdim} 637224135Sdim 638224135Sdimvoid TransformActions::remove(SourceRange range) { 639224135Sdim static_cast<TransformActionsImpl*>(Impl)->remove(range); 640224135Sdim} 641224135Sdim 642224135Sdimvoid TransformActions::removeStmt(Stmt *S) { 643224135Sdim static_cast<TransformActionsImpl*>(Impl)->removeStmt(S); 644224135Sdim} 645224135Sdim 646226633Sdimvoid TransformActions::replace(SourceRange range, StringRef text) { 647224135Sdim static_cast<TransformActionsImpl*>(Impl)->replace(range, text); 648224135Sdim} 649224135Sdim 650224135Sdimvoid TransformActions::replace(SourceRange range, 651224135Sdim SourceRange replacementRange) { 652224135Sdim static_cast<TransformActionsImpl*>(Impl)->replace(range, replacementRange); 653224135Sdim} 654224135Sdim 655226633Sdimvoid TransformActions::replaceStmt(Stmt *S, StringRef text) { 656224135Sdim static_cast<TransformActionsImpl*>(Impl)->replaceStmt(S, text); 657224135Sdim} 658224135Sdim 659226633Sdimvoid TransformActions::replaceText(SourceLocation loc, StringRef text, 660226633Sdim StringRef replacementText) { 661224135Sdim static_cast<TransformActionsImpl*>(Impl)->replaceText(loc, text, 662224135Sdim replacementText); 663224135Sdim} 664224135Sdim 665224135Sdimvoid TransformActions::increaseIndentation(SourceRange range, 666224135Sdim SourceLocation parentIndent) { 667224135Sdim static_cast<TransformActionsImpl*>(Impl)->increaseIndentation(range, 668224135Sdim parentIndent); 669224135Sdim} 670224135Sdim 671226633Sdimbool TransformActions::clearDiagnostic(ArrayRef<unsigned> IDs, 672224135Sdim SourceRange range) { 673224135Sdim return static_cast<TransformActionsImpl*>(Impl)->clearDiagnostic(IDs, range); 674224135Sdim} 675224135Sdim 676224135Sdimvoid TransformActions::applyRewrites(RewriteReceiver &receiver) { 677224135Sdim static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver); 678224135Sdim} 679224135Sdim 680276479SdimDiagnosticBuilder TransformActions::report(SourceLocation loc, unsigned diagId, 681276479Sdim SourceRange range) { 682276479Sdim assert(!static_cast<TransformActionsImpl *>(Impl)->isInTransaction() && 683224135Sdim "Errors should be emitted out of a transaction"); 684276479Sdim return Diags.Report(loc, diagId) << range; 685224135Sdim} 686224135Sdim 687276479Sdimvoid TransformActions::reportError(StringRef message, SourceLocation loc, 688234353Sdim SourceRange range) { 689276479Sdim report(loc, diag::err_mt_message, range) << message; 690234353Sdim} 691234353Sdim 692276479Sdimvoid TransformActions::reportWarning(StringRef message, SourceLocation loc, 693276479Sdim SourceRange range) { 694276479Sdim report(loc, diag::warn_mt_message, range) << message; 695276479Sdim} 696276479Sdim 697276479Sdimvoid TransformActions::reportNote(StringRef message, SourceLocation loc, 698224135Sdim SourceRange range) { 699276479Sdim report(loc, diag::note_mt_message, range) << message; 700224135Sdim} 701