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