1//===--- ARCMT.cpp - Migration to ARC mode --------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "Internals.h" 11#include "clang/AST/Expr.h" 12#include "clang/Lex/Preprocessor.h" 13#include "clang/Basic/SourceManager.h" 14#include "llvm/ADT/DenseSet.h" 15#include <map> 16using namespace clang; 17using namespace arcmt; 18 19namespace { 20 21/// \brief Collects transformations and merges them before applying them with 22/// with applyRewrites(). E.g. if the same source range 23/// is requested to be removed twice, only one rewriter remove will be invoked. 24/// Rewrites happen in "transactions"; if one rewrite in the transaction cannot 25/// be done (e.g. it resides in a macro) all rewrites in the transaction are 26/// aborted. 27/// FIXME: "Transactional" rewrites support should be baked in the Rewriter. 28class TransformActionsImpl { 29 CapturedDiagList &CapturedDiags; 30 ASTContext &Ctx; 31 Preprocessor &PP; 32 33 bool IsInTransaction; 34 35 enum ActionKind { 36 Act_Insert, Act_InsertAfterToken, 37 Act_Remove, Act_RemoveStmt, 38 Act_Replace, Act_ReplaceText, 39 Act_IncreaseIndentation, 40 Act_ClearDiagnostic 41 }; 42 43 struct ActionData { 44 ActionKind Kind; 45 SourceLocation Loc; 46 SourceRange R1, R2; 47 StringRef Text1, Text2; 48 Stmt *S; 49 SmallVector<unsigned, 2> DiagIDs; 50 }; 51 52 std::vector<ActionData> CachedActions; 53 54 enum RangeComparison { 55 Range_Before, 56 Range_After, 57 Range_Contains, 58 Range_Contained, 59 Range_ExtendsBegin, 60 Range_ExtendsEnd 61 }; 62 63 /// \brief A range to remove. It is a character range. 64 struct CharRange { 65 FullSourceLoc Begin, End; 66 67 CharRange(CharSourceRange range, SourceManager &srcMgr, Preprocessor &PP) { 68 SourceLocation beginLoc = range.getBegin(), endLoc = range.getEnd(); 69 assert(beginLoc.isValid() && endLoc.isValid()); 70 if (range.isTokenRange()) { 71 Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr); 72 End = FullSourceLoc(getLocForEndOfToken(endLoc, srcMgr, PP), srcMgr); 73 } else { 74 Begin = FullSourceLoc(srcMgr.getExpansionLoc(beginLoc), srcMgr); 75 End = FullSourceLoc(srcMgr.getExpansionLoc(endLoc), srcMgr); 76 } 77 assert(Begin.isValid() && End.isValid()); 78 } 79 80 RangeComparison compareWith(const CharRange &RHS) const { 81 if (End.isBeforeInTranslationUnitThan(RHS.Begin)) 82 return Range_Before; 83 if (RHS.End.isBeforeInTranslationUnitThan(Begin)) 84 return Range_After; 85 if (!Begin.isBeforeInTranslationUnitThan(RHS.Begin) && 86 !RHS.End.isBeforeInTranslationUnitThan(End)) 87 return Range_Contained; 88 if (Begin.isBeforeInTranslationUnitThan(RHS.Begin) && 89 RHS.End.isBeforeInTranslationUnitThan(End)) 90 return Range_Contains; 91 if (Begin.isBeforeInTranslationUnitThan(RHS.Begin)) 92 return Range_ExtendsBegin; 93 else 94 return Range_ExtendsEnd; 95 } 96 97 static RangeComparison compare(SourceRange LHS, SourceRange RHS, 98 SourceManager &SrcMgr, Preprocessor &PP) { 99 return CharRange(CharSourceRange::getTokenRange(LHS), SrcMgr, PP) 100 .compareWith(CharRange(CharSourceRange::getTokenRange(RHS), 101 SrcMgr, PP)); 102 } 103 }; 104 105 typedef SmallVector<StringRef, 2> TextsVec; 106 typedef std::map<FullSourceLoc, TextsVec, FullSourceLoc::BeforeThanCompare> 107 InsertsMap; 108 InsertsMap Inserts; 109 /// \brief A list of ranges to remove. They are always sorted and they never 110 /// intersect with each other. 111 std::list<CharRange> Removals; 112 113 llvm::DenseSet<Stmt *> StmtRemovals; 114 115 std::vector<std::pair<CharRange, SourceLocation> > IndentationRanges; 116 117 /// \brief Keeps text passed to transformation methods. 118 llvm::StringMap<bool> UniqueText; 119 120public: 121 TransformActionsImpl(CapturedDiagList &capturedDiags, 122 ASTContext &ctx, Preprocessor &PP) 123 : CapturedDiags(capturedDiags), Ctx(ctx), PP(PP), IsInTransaction(false) { } 124 125 void startTransaction(); 126 bool commitTransaction(); 127 void abortTransaction(); 128 129 bool isInTransaction() const { return IsInTransaction; } 130 131 void insert(SourceLocation loc, StringRef text); 132 void insertAfterToken(SourceLocation loc, StringRef text); 133 void remove(SourceRange range); 134 void removeStmt(Stmt *S); 135 void replace(SourceRange range, StringRef text); 136 void replace(SourceRange range, SourceRange replacementRange); 137 void replaceStmt(Stmt *S, StringRef text); 138 void replaceText(SourceLocation loc, StringRef text, 139 StringRef replacementText); 140 void increaseIndentation(SourceRange range, 141 SourceLocation parentIndent); 142 143 bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); 144 145 void applyRewrites(TransformActions::RewriteReceiver &receiver); 146 147private: 148 bool canInsert(SourceLocation loc); 149 bool canInsertAfterToken(SourceLocation loc); 150 bool canRemoveRange(SourceRange range); 151 bool canReplaceRange(SourceRange range, SourceRange replacementRange); 152 bool canReplaceText(SourceLocation loc, StringRef text); 153 154 void commitInsert(SourceLocation loc, StringRef text); 155 void commitInsertAfterToken(SourceLocation loc, StringRef text); 156 void commitRemove(SourceRange range); 157 void commitRemoveStmt(Stmt *S); 158 void commitReplace(SourceRange range, SourceRange replacementRange); 159 void commitReplaceText(SourceLocation loc, StringRef text, 160 StringRef replacementText); 161 void commitIncreaseIndentation(SourceRange range,SourceLocation parentIndent); 162 void commitClearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); 163 164 void addRemoval(CharSourceRange range); 165 void addInsertion(SourceLocation loc, StringRef text); 166 167 /// \brief Stores text passed to the transformation methods to keep the string 168 /// "alive". Since the vast majority of text will be the same, we also unique 169 /// the strings using a StringMap. 170 StringRef getUniqueText(StringRef text); 171 172 /// \brief Computes the source location just past the end of the token at 173 /// the given source location. If the location points at a macro, the whole 174 /// macro expansion is skipped. 175 static SourceLocation getLocForEndOfToken(SourceLocation loc, 176 SourceManager &SM,Preprocessor &PP); 177}; 178 179} // anonymous namespace 180 181void TransformActionsImpl::startTransaction() { 182 assert(!IsInTransaction && 183 "Cannot start a transaction in the middle of another one"); 184 IsInTransaction = true; 185} 186 187bool TransformActionsImpl::commitTransaction() { 188 assert(IsInTransaction && "No transaction started"); 189 190 if (CachedActions.empty()) { 191 IsInTransaction = false; 192 return false; 193 } 194 195 // Verify that all actions are possible otherwise abort the whole transaction. 196 bool AllActionsPossible = true; 197 for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) { 198 ActionData &act = CachedActions[i]; 199 switch (act.Kind) { 200 case Act_Insert: 201 if (!canInsert(act.Loc)) 202 AllActionsPossible = false; 203 break; 204 case Act_InsertAfterToken: 205 if (!canInsertAfterToken(act.Loc)) 206 AllActionsPossible = false; 207 break; 208 case Act_Remove: 209 if (!canRemoveRange(act.R1)) 210 AllActionsPossible = false; 211 break; 212 case Act_RemoveStmt: 213 assert(act.S); 214 if (!canRemoveRange(act.S->getSourceRange())) 215 AllActionsPossible = false; 216 break; 217 case Act_Replace: 218 if (!canReplaceRange(act.R1, act.R2)) 219 AllActionsPossible = false; 220 break; 221 case Act_ReplaceText: 222 if (!canReplaceText(act.Loc, act.Text1)) 223 AllActionsPossible = false; 224 break; 225 case Act_IncreaseIndentation: 226 // This is not important, we don't care if it will fail. 227 break; 228 case Act_ClearDiagnostic: 229 // We are just checking source rewrites. 230 break; 231 } 232 if (!AllActionsPossible) 233 break; 234 } 235 236 if (!AllActionsPossible) { 237 abortTransaction(); 238 return true; 239 } 240 241 for (unsigned i = 0, e = CachedActions.size(); i != e; ++i) { 242 ActionData &act = CachedActions[i]; 243 switch (act.Kind) { 244 case Act_Insert: 245 commitInsert(act.Loc, act.Text1); 246 break; 247 case Act_InsertAfterToken: 248 commitInsertAfterToken(act.Loc, act.Text1); 249 break; 250 case Act_Remove: 251 commitRemove(act.R1); 252 break; 253 case Act_RemoveStmt: 254 commitRemoveStmt(act.S); 255 break; 256 case Act_Replace: 257 commitReplace(act.R1, act.R2); 258 break; 259 case Act_ReplaceText: 260 commitReplaceText(act.Loc, act.Text1, act.Text2); 261 break; 262 case Act_IncreaseIndentation: 263 commitIncreaseIndentation(act.R1, act.Loc); 264 break; 265 case Act_ClearDiagnostic: 266 commitClearDiagnostic(act.DiagIDs, act.R1); 267 break; 268 } 269 } 270 271 CachedActions.clear(); 272 IsInTransaction = false; 273 return false; 274} 275 276void TransformActionsImpl::abortTransaction() { 277 assert(IsInTransaction && "No transaction started"); 278 CachedActions.clear(); 279 IsInTransaction = false; 280} 281 282void TransformActionsImpl::insert(SourceLocation loc, StringRef text) { 283 assert(IsInTransaction && "Actions only allowed during a transaction"); 284 text = getUniqueText(text); 285 ActionData data; 286 data.Kind = Act_Insert; 287 data.Loc = loc; 288 data.Text1 = text; 289 CachedActions.push_back(data); 290} 291 292void TransformActionsImpl::insertAfterToken(SourceLocation loc, StringRef text) { 293 assert(IsInTransaction && "Actions only allowed during a transaction"); 294 text = getUniqueText(text); 295 ActionData data; 296 data.Kind = Act_InsertAfterToken; 297 data.Loc = loc; 298 data.Text1 = text; 299 CachedActions.push_back(data); 300} 301 302void TransformActionsImpl::remove(SourceRange range) { 303 assert(IsInTransaction && "Actions only allowed during a transaction"); 304 ActionData data; 305 data.Kind = Act_Remove; 306 data.R1 = range; 307 CachedActions.push_back(data); 308} 309 310void TransformActionsImpl::removeStmt(Stmt *S) { 311 assert(IsInTransaction && "Actions only allowed during a transaction"); 312 ActionData data; 313 data.Kind = Act_RemoveStmt; 314 data.S = S->IgnoreImplicit(); // important for uniquing 315 CachedActions.push_back(data); 316} 317 318void TransformActionsImpl::replace(SourceRange range, StringRef text) { 319 assert(IsInTransaction && "Actions only allowed during a transaction"); 320 text = getUniqueText(text); 321 remove(range); 322 insert(range.getBegin(), text); 323} 324 325void TransformActionsImpl::replace(SourceRange range, 326 SourceRange replacementRange) { 327 assert(IsInTransaction && "Actions only allowed during a transaction"); 328 ActionData data; 329 data.Kind = Act_Replace; 330 data.R1 = range; 331 data.R2 = replacementRange; 332 CachedActions.push_back(data); 333} 334 335void TransformActionsImpl::replaceText(SourceLocation loc, StringRef text, 336 StringRef replacementText) { 337 text = getUniqueText(text); 338 replacementText = getUniqueText(replacementText); 339 ActionData data; 340 data.Kind = Act_ReplaceText; 341 data.Loc = loc; 342 data.Text1 = text; 343 data.Text2 = replacementText; 344 CachedActions.push_back(data); 345} 346 347void TransformActionsImpl::replaceStmt(Stmt *S, StringRef text) { 348 assert(IsInTransaction && "Actions only allowed during a transaction"); 349 text = getUniqueText(text); 350 insert(S->getLocStart(), text); 351 removeStmt(S); 352} 353 354void TransformActionsImpl::increaseIndentation(SourceRange range, 355 SourceLocation parentIndent) { 356 if (range.isInvalid()) return; 357 assert(IsInTransaction && "Actions only allowed during a transaction"); 358 ActionData data; 359 data.Kind = Act_IncreaseIndentation; 360 data.R1 = range; 361 data.Loc = parentIndent; 362 CachedActions.push_back(data); 363} 364 365bool TransformActionsImpl::clearDiagnostic(ArrayRef<unsigned> IDs, 366 SourceRange range) { 367 assert(IsInTransaction && "Actions only allowed during a transaction"); 368 if (!CapturedDiags.hasDiagnostic(IDs, range)) 369 return false; 370 371 ActionData data; 372 data.Kind = Act_ClearDiagnostic; 373 data.R1 = range; 374 data.DiagIDs.append(IDs.begin(), IDs.end()); 375 CachedActions.push_back(data); 376 return true; 377} 378 379bool TransformActionsImpl::canInsert(SourceLocation loc) { 380 if (loc.isInvalid()) 381 return false; 382 383 SourceManager &SM = Ctx.getSourceManager(); 384 if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) 385 return false; 386 387 if (loc.isFileID()) 388 return true; 389 return PP.isAtStartOfMacroExpansion(loc); 390} 391 392bool TransformActionsImpl::canInsertAfterToken(SourceLocation loc) { 393 if (loc.isInvalid()) 394 return false; 395 396 SourceManager &SM = Ctx.getSourceManager(); 397 if (SM.isInSystemHeader(SM.getExpansionLoc(loc))) 398 return false; 399 400 if (loc.isFileID()) 401 return true; 402 return PP.isAtEndOfMacroExpansion(loc); 403} 404 405bool TransformActionsImpl::canRemoveRange(SourceRange range) { 406 return canInsert(range.getBegin()) && canInsertAfterToken(range.getEnd()); 407} 408 409bool TransformActionsImpl::canReplaceRange(SourceRange range, 410 SourceRange replacementRange) { 411 return canRemoveRange(range) && canRemoveRange(replacementRange); 412} 413 414bool TransformActionsImpl::canReplaceText(SourceLocation loc, StringRef text) { 415 if (!canInsert(loc)) 416 return false; 417 418 SourceManager &SM = Ctx.getSourceManager(); 419 loc = SM.getExpansionLoc(loc); 420 421 // Break down the source location. 422 std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); 423 424 // Try to load the file buffer. 425 bool invalidTemp = false; 426 StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); 427 if (invalidTemp) 428 return false; 429 430 return file.substr(locInfo.second).startswith(text); 431} 432 433void TransformActionsImpl::commitInsert(SourceLocation loc, StringRef text) { 434 addInsertion(loc, text); 435} 436 437void TransformActionsImpl::commitInsertAfterToken(SourceLocation loc, 438 StringRef text) { 439 addInsertion(getLocForEndOfToken(loc, Ctx.getSourceManager(), PP), text); 440} 441 442void TransformActionsImpl::commitRemove(SourceRange range) { 443 addRemoval(CharSourceRange::getTokenRange(range)); 444} 445 446void TransformActionsImpl::commitRemoveStmt(Stmt *S) { 447 assert(S); 448 if (StmtRemovals.count(S)) 449 return; // already removed. 450 451 if (Expr *E = dyn_cast<Expr>(S)) { 452 commitRemove(E->getSourceRange()); 453 commitInsert(E->getSourceRange().getBegin(), getARCMTMacroName()); 454 } else 455 commitRemove(S->getSourceRange()); 456 457 StmtRemovals.insert(S); 458} 459 460void TransformActionsImpl::commitReplace(SourceRange range, 461 SourceRange replacementRange) { 462 RangeComparison comp = CharRange::compare(replacementRange, range, 463 Ctx.getSourceManager(), PP); 464 assert(comp == Range_Contained); 465 if (comp != Range_Contained) 466 return; // Although we asserted, be extra safe for release build. 467 if (range.getBegin() != replacementRange.getBegin()) 468 addRemoval(CharSourceRange::getCharRange(range.getBegin(), 469 replacementRange.getBegin())); 470 if (replacementRange.getEnd() != range.getEnd()) 471 addRemoval(CharSourceRange::getTokenRange( 472 getLocForEndOfToken(replacementRange.getEnd(), 473 Ctx.getSourceManager(), PP), 474 range.getEnd())); 475} 476void TransformActionsImpl::commitReplaceText(SourceLocation loc, 477 StringRef text, 478 StringRef replacementText) { 479 SourceManager &SM = Ctx.getSourceManager(); 480 loc = SM.getExpansionLoc(loc); 481 // canReplaceText already checked if loc points at text. 482 SourceLocation afterText = loc.getLocWithOffset(text.size()); 483 484 addRemoval(CharSourceRange::getCharRange(loc, afterText)); 485 commitInsert(loc, replacementText); 486} 487 488void TransformActionsImpl::commitIncreaseIndentation(SourceRange range, 489 SourceLocation parentIndent) { 490 SourceManager &SM = Ctx.getSourceManager(); 491 IndentationRanges.push_back( 492 std::make_pair(CharRange(CharSourceRange::getTokenRange(range), 493 SM, PP), 494 SM.getExpansionLoc(parentIndent))); 495} 496 497void TransformActionsImpl::commitClearDiagnostic(ArrayRef<unsigned> IDs, 498 SourceRange range) { 499 CapturedDiags.clearDiagnostic(IDs, range); 500} 501 502void TransformActionsImpl::addInsertion(SourceLocation loc, StringRef text) { 503 SourceManager &SM = Ctx.getSourceManager(); 504 loc = SM.getExpansionLoc(loc); 505 for (std::list<CharRange>::reverse_iterator 506 I = Removals.rbegin(), E = Removals.rend(); I != E; ++I) { 507 if (!SM.isBeforeInTranslationUnit(loc, I->End)) 508 break; 509 if (I->Begin.isBeforeInTranslationUnitThan(loc)) 510 return; 511 } 512 513 Inserts[FullSourceLoc(loc, SM)].push_back(text); 514} 515 516void TransformActionsImpl::addRemoval(CharSourceRange range) { 517 CharRange newRange(range, Ctx.getSourceManager(), PP); 518 if (newRange.Begin == newRange.End) 519 return; 520 521 Inserts.erase(Inserts.upper_bound(newRange.Begin), 522 Inserts.lower_bound(newRange.End)); 523 524 std::list<CharRange>::iterator I = Removals.end(); 525 while (I != Removals.begin()) { 526 std::list<CharRange>::iterator RI = I; 527 --RI; 528 RangeComparison comp = newRange.compareWith(*RI); 529 switch (comp) { 530 case Range_Before: 531 --I; 532 break; 533 case Range_After: 534 Removals.insert(I, newRange); 535 return; 536 case Range_Contained: 537 return; 538 case Range_Contains: 539 RI->End = newRange.End; 540 case Range_ExtendsBegin: 541 newRange.End = RI->End; 542 Removals.erase(RI); 543 break; 544 case Range_ExtendsEnd: 545 RI->End = newRange.End; 546 return; 547 } 548 } 549 550 Removals.insert(Removals.begin(), newRange); 551} 552 553void TransformActionsImpl::applyRewrites( 554 TransformActions::RewriteReceiver &receiver) { 555 for (InsertsMap::iterator I = Inserts.begin(), E = Inserts.end(); I!=E; ++I) { 556 SourceLocation loc = I->first; 557 for (TextsVec::iterator 558 TI = I->second.begin(), TE = I->second.end(); TI != TE; ++TI) { 559 receiver.insert(loc, *TI); 560 } 561 } 562 563 for (std::vector<std::pair<CharRange, SourceLocation> >::iterator 564 I = IndentationRanges.begin(), E = IndentationRanges.end(); I!=E; ++I) { 565 CharSourceRange range = CharSourceRange::getCharRange(I->first.Begin, 566 I->first.End); 567 receiver.increaseIndentation(range, I->second); 568 } 569 570 for (std::list<CharRange>::iterator 571 I = Removals.begin(), E = Removals.end(); I != E; ++I) { 572 CharSourceRange range = CharSourceRange::getCharRange(I->Begin, I->End); 573 receiver.remove(range); 574 } 575} 576 577/// \brief Stores text passed to the transformation methods to keep the string 578/// "alive". Since the vast majority of text will be the same, we also unique 579/// the strings using a StringMap. 580StringRef TransformActionsImpl::getUniqueText(StringRef text) { 581 llvm::StringMapEntry<bool> &entry = UniqueText.GetOrCreateValue(text); 582 return entry.getKey(); 583} 584 585/// \brief Computes the source location just past the end of the token at 586/// the given source location. If the location points at a macro, the whole 587/// macro expansion is skipped. 588SourceLocation TransformActionsImpl::getLocForEndOfToken(SourceLocation loc, 589 SourceManager &SM, 590 Preprocessor &PP) { 591 if (loc.isMacroID()) 592 loc = SM.getExpansionRange(loc).second; 593 return PP.getLocForEndOfToken(loc); 594} 595 596TransformActions::RewriteReceiver::~RewriteReceiver() { } 597 598TransformActions::TransformActions(DiagnosticsEngine &diag, 599 CapturedDiagList &capturedDiags, 600 ASTContext &ctx, Preprocessor &PP) 601 : Diags(diag), CapturedDiags(capturedDiags), ReportedErrors(false) { 602 Impl = new TransformActionsImpl(capturedDiags, ctx, PP); 603} 604 605TransformActions::~TransformActions() { 606 delete static_cast<TransformActionsImpl*>(Impl); 607} 608 609void TransformActions::startTransaction() { 610 static_cast<TransformActionsImpl*>(Impl)->startTransaction(); 611} 612 613bool TransformActions::commitTransaction() { 614 return static_cast<TransformActionsImpl*>(Impl)->commitTransaction(); 615} 616 617void TransformActions::abortTransaction() { 618 static_cast<TransformActionsImpl*>(Impl)->abortTransaction(); 619} 620 621 622void TransformActions::insert(SourceLocation loc, StringRef text) { 623 static_cast<TransformActionsImpl*>(Impl)->insert(loc, text); 624} 625 626void TransformActions::insertAfterToken(SourceLocation loc, 627 StringRef text) { 628 static_cast<TransformActionsImpl*>(Impl)->insertAfterToken(loc, text); 629} 630 631void TransformActions::remove(SourceRange range) { 632 static_cast<TransformActionsImpl*>(Impl)->remove(range); 633} 634 635void TransformActions::removeStmt(Stmt *S) { 636 static_cast<TransformActionsImpl*>(Impl)->removeStmt(S); 637} 638 639void TransformActions::replace(SourceRange range, StringRef text) { 640 static_cast<TransformActionsImpl*>(Impl)->replace(range, text); 641} 642 643void TransformActions::replace(SourceRange range, 644 SourceRange replacementRange) { 645 static_cast<TransformActionsImpl*>(Impl)->replace(range, replacementRange); 646} 647 648void TransformActions::replaceStmt(Stmt *S, StringRef text) { 649 static_cast<TransformActionsImpl*>(Impl)->replaceStmt(S, text); 650} 651 652void TransformActions::replaceText(SourceLocation loc, StringRef text, 653 StringRef replacementText) { 654 static_cast<TransformActionsImpl*>(Impl)->replaceText(loc, text, 655 replacementText); 656} 657 658void TransformActions::increaseIndentation(SourceRange range, 659 SourceLocation parentIndent) { 660 static_cast<TransformActionsImpl*>(Impl)->increaseIndentation(range, 661 parentIndent); 662} 663 664bool TransformActions::clearDiagnostic(ArrayRef<unsigned> IDs, 665 SourceRange range) { 666 return static_cast<TransformActionsImpl*>(Impl)->clearDiagnostic(IDs, range); 667} 668 669void TransformActions::applyRewrites(RewriteReceiver &receiver) { 670 static_cast<TransformActionsImpl*>(Impl)->applyRewrites(receiver); 671} 672 673void TransformActions::reportError(StringRef error, SourceLocation loc, 674 SourceRange range) { 675 assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() && 676 "Errors should be emitted out of a transaction"); 677 // FIXME: Use a custom category name to distinguish rewriter errors. 678 std::string rewriteErr = "[rewriter] "; 679 rewriteErr += error; 680 unsigned diagID 681 = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Error, 682 rewriteErr); 683 Diags.Report(loc, diagID) << range; 684 ReportedErrors = true; 685} 686 687void TransformActions::reportNote(StringRef note, SourceLocation loc, 688 SourceRange range) { 689 assert(!static_cast<TransformActionsImpl*>(Impl)->isInTransaction() && 690 "Errors should be emitted out of a transaction"); 691 // FIXME: Use a custom category name to distinguish rewriter errors. 692 std::string rewriteNote = "[rewriter] "; 693 rewriteNote += note; 694 unsigned diagID 695 = Diags.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Note, 696 rewriteNote); 697 Diags.Report(loc, diagID) << range; 698} 699