clang: lib/ARCMigrate/ARCMT.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
23#include "llvm/Support/MemoryBuffer.h"
24#include "llvm/TargetParser/Triple.h"
25#include
26using namespace clang;
27using namespace arcmt;
28
31 if (range.isInvalid())
32 return false;
33
34 bool cleared = false;
35 ListTy::iterator I = List.begin();
36 while (I != List.end()) {
38 if ((IDs.empty() ||
39 llvm::is_contained(IDs, I->getID())) &&
41 (diagLoc == range.getEnd() ||
43 cleared = true;
44 ListTy::iterator eraseS = I++;
47 ++I;
48
49 I = List.erase(eraseS, I);
50 continue;
51 }
52
53 ++I;
54 }
55
56 return cleared;
57}
58
61 if (range.isInvalid())
62 return false;
63
64 ListTy::const_iterator I = List.begin();
65 while (I != List.end()) {
67 if ((IDs.empty() ||
68 llvm::is_contained(IDs, I->getID())) &&
70 (diagLoc == range.getEnd() ||
72 return true;
73 }
74
75 ++I;
76 }
77
78 return false;
79}
80
82 for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
84}
85
87 for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I)
89 return true;
90
91 return false;
92}
93
94namespace {
95
100 bool HasBegunSourceFile;
101public:
105 : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags),
106 HasBegunSourceFile(false) { }
107
108 void BeginSourceFile(const LangOptions &Opts,
110
111
112
113 if (!HasBegunSourceFile) {
115 HasBegunSourceFile = true;
116 }
117 }
118
119 void FinishCapture() {
120
121
122
123 if (HasBegunSourceFile) {
125 HasBegunSourceFile = false;
126 }
127 }
128
129 ~CaptureDiagnosticConsumer() override {
130 assert(!HasBegunSourceFile && "FinishCapture not called!");
131 }
132
139 return;
140 }
141
142
144 }
145};
146
147}
148
150
151
152
154
155 if (triple.isiOS())
156 return triple.getOSMajorVersion() >= 5;
157
158 if (triple.isWatchOS())
159 return true;
160
161 if (triple.getOS() == llvm::Triple::Darwin)
162 return triple.getOSMajorVersion() >= 11;
163
164 if (triple.getOS() == llvm::Triple::MacOSX) {
165 return triple.getOSVersion() >= VersionTuple(10, 7);
166 }
167
168 return false;
169}
170
174 std::unique_ptr CInvok;
178
179
187 if (!OriginalFile.empty())
188 PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile);
190 }
192 define += '=';
193 CInvok->getPreprocessorOpts().addMacroDef(define);
194 CInvok->getLangOpts().ObjCAutoRefCount = true;
196 CInvok->getDiagnosticOpts().ErrorLimit = 0;
197 CInvok->getDiagnosticOpts().PedanticErrors = 0;
198
199
200 std::vectorstd::string WarnOpts;
201 for (std::vectorstd::string::iterator
202 I = CInvok->getDiagnosticOpts().Warnings.begin(),
203 E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) {
204 if (!StringRef(*I).starts_with("error"))
205 WarnOpts.push_back(*I);
206 }
207 WarnOpts.push_back("error=arc-unsafe-retained-assign");
208 CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts);
209
210 CInvok->getLangOpts().ObjCWeakRuntime = HasARCRuntime(origCI);
211 CInvok->getLangOpts().ObjCWeak = CInvok->getLangOpts().ObjCWeakRuntime;
212
213 return CInvok.release();
214}
215
223 false));
225
229}
230
231
232
233
234
237 std::shared_ptr PCHContainerOps,
239 StringRef plistOut) {
241 return false;
242
246
248 NoFinalizeRemoval);
249 assert(!transforms.empty());
250
251 std::unique_ptr CInvok;
252 CInvok.reset(
254 CInvok->getFrontendOpts().Inputs.clear();
255 CInvok->getFrontendOpts().Inputs.push_back(Input);
256
258
259 assert(DiagClient);
263 DiagClient, false));
264
265
266 CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
267 Diags->setClient(&errRec, false);
268
270 std::move(CInvok), PCHContainerOps, Diags));
271 if (!Unit) {
272 errRec.FinishCapture();
273 return true;
274 }
275
276
277 Diags->setClient(DiagClient, false);
278
279 ASTContext &Ctx = Unit->getASTContext();
280
281 if (Diags->hasFatalErrorOccurred()) {
282 Diags->Reset();
286 errRec.FinishCapture();
287 return true;
288 }
289
290 if (emitPremigrationARCErrors)
292 Unit->getPreprocessor());
293 if (!plistOut.empty()) {
296 I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I)
297 arcDiags.push_back(*I);
300 }
301
302
303
304
305
306
308
309
310
311 std::vector ARCMTMacroLocs;
312
313 TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
314 MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags,
315 ARCMTMacroLocs);
317 if (!NoNSAllocReallocError)
320
321 for (unsigned i=0, e = transforms.size(); i != e; ++i)
322 transforms[i](pass);
323
325
327 errRec.FinishCapture();
328
330}
331
332
333
334
335
336static bool
338 std::shared_ptr PCHContainerOps,
340 bool emitPremigrationARCErrors, StringRef plistOut) {
342 return false;
343
345
346
349 DiagClient, emitPremigrationARCErrors,
350 plistOut))
351 return true;
352
356
357 MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir);
359
361 NoFinalizeRemoval);
362 assert(!transforms.empty());
363
364 for (unsigned i=0, e = transforms.size(); i != e; ++i) {
366 if (err) return true;
367 }
368
372 DiagClient, false));
373
374 if (outputDir.empty()) {
375 origCI.getLangOpts().ObjCAutoRefCount = true;
377 } else {
379 }
380}
381
384 std::shared_ptr PCHContainerOps,
386 return applyTransforms(origCI, Input, PCHContainerOps, DiagClient,
387 StringRef(), false, StringRef());
388}
389
392 std::shared_ptr PCHContainerOps,
394 bool emitPremigrationARCErrors, StringRef plistOut) {
395 assert(!outputDir.empty() && "Expected output directory path");
396 return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir,
397 emitPremigrationARCErrors, plistOut);
398}
399
401 remap,
402 StringRef outputDir,
404 assert(!outputDir.empty());
405
409 DiagClient, false));
410
412 bool err = remapper.initFromDisk(outputDir, *Diags,
413 true);
414 if (err)
415 return true;
416
418 [&](StringRef From, StringRef To) {
419 remap.push_back(std::make_pair(From.str(), To.str()));
420 },
421 [](StringRef, const llvm::MemoryBufferRef &) {});
422
423 return false;
424}
425
426
427
428
429
430
431namespace {
432
433class ARCMTMacroTrackerPPCallbacks : public PPCallbacks {
434 std::vector &ARCMTMacroLocs;
435
436public:
437 ARCMTMacroTrackerPPCallbacks(std::vector &ARCMTMacroLocs)
438 : ARCMTMacroLocs(ARCMTMacroLocs) { }
439
443 ARCMTMacroLocs.push_back(MacroNameTok.getLocation());
444 }
445};
446
448 std::vector &ARCMTMacroLocs;
449
450public:
451 ARCMTMacroTrackerAction(std::vector &ARCMTMacroLocs)
452 : ARCMTMacroLocs(ARCMTMacroLocs) { }
453
454 std::unique_ptr CreateASTConsumer(CompilerInstance &CI,
455 StringRef InFile) override {
457 std::make_unique(ARCMTMacroLocs));
458 return std::make_unique();
459 }
460};
461
465
466public:
469 : rewriter(rewriter), Listener(listener) {
470 if (Listener)
471 Listener->start(ctx);
472 }
473 ~RewritesApplicator() override {
474 if (Listener)
476 }
477
478 void insert(SourceLocation loc, StringRef text) override {
479 bool err = rewriter.InsertText(loc, text, true,
480 true);
481 if (!err && Listener)
482 Listener->insert(loc, text);
483 }
484
490
491 bool err = rewriter.RemoveText(range, removeOpts);
492 if (!err && Listener)
493 Listener->remove(range);
494 }
495
499 }
500};
501
502}
503
504
506
509 std::shared_ptr PCHContainerOps,
511 : OrigCI(CI), PCHContainerOps(std::move(PCHContainerOps)),
513 if (!outputDir.empty()) {
517 DiagClient, false));
518 Remapper.initFromDisk(outputDir, *Diags, true);
519 }
520}
521
524 std::unique_ptr CInvok;
525 CInvok.reset(
527 CInvok->getDiagnosticOpts().IgnoreWarnings = true;
528
529 Remapper.applyMappings(CInvok->getPreprocessorOpts());
530
532 std::vector ARCMTMacroLocs;
533
534 assert(DiagClient);
538 DiagClient, false));
539
540
541 CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags);
542 Diags->setClient(&errRec, false);
543
544 std::unique_ptr ASTAction;
545 ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs));
546
548 std::move(CInvok), PCHContainerOps, Diags, ASTAction.get()));
549 if (!Unit) {
550 errRec.FinishCapture();
551 return true;
552 }
553 Unit->setOwnsRemappedFileBuffers(false);
554
556
557
558 Diags->setClient(DiagClient, false);
559
560 ASTContext &Ctx = Unit->getASTContext();
561
562 if (Diags->hasFatalErrorOccurred()) {
563 Diags->Reset();
567 errRec.FinishCapture();
568 return true;
569 }
570
571
572
573
574
575
577
579 TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor());
581 Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs);
582
583 trans(pass);
584
585 {
586 RewritesApplicator applicator(rewriter, Ctx, listener);
588 }
589
591 errRec.FinishCapture();
592
594 return true;
595
598 FileID FID = I->first;
599 llvm::RewriteBuffer &buf = I->second;
602 assert(file);
603 std::string newFname = std::string(file->getName());
604 newFname += "-trans";
606 llvm::raw_svector_ostream vecOS(newText);
607 buf.write(vecOS);
608 std::unique_ptrllvm::MemoryBuffer memBuf(
609 llvm::MemoryBuffer::getMemBufferCopy(newText.str(), newFname));
611 Unit->getFileManager().FixupRelativePath(filePath);
612 Remapper.remap(filePath.str(), std::move(memBuf));
613 }
614
615 return false;
616}
static void emitPremigrationErrors(const CapturedDiagList &arcDiags, DiagnosticOptions *diagOpts, Preprocessor &PP)
static CompilerInvocation * createInvocationForMigration(CompilerInvocation &origCI, const PCHContainerReader &PCHContainerRdr)
static bool applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagClient, StringRef outputDir, bool emitPremigrationARCErrors, StringRef plistOut)
static bool HasARCRuntime(CompilerInvocation &origCI)
Defines the clang::FrontendAction interface and various convenience abstract classes (clang::ASTFront...
Defines the clang::Preprocessor interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SourceManager & getSourceManager()
const LangOptions & getLangOpts() const
Abstract base class to use for AST consumer-based frontend actions.
StringRef getOriginalSourceFile()
Retrieve the name of the original source file name for the primary module file.
static ASTUnit * LoadFromCompilerInvocationAction(std::shared_ptr< CompilerInvocation > CI, std::shared_ptr< PCHContainerOperations > PCHContainerOps, IntrusiveRefCntPtr< DiagnosticsEngine > Diags, FrontendAction *Action=nullptr, ASTUnit *Unit=nullptr, bool Persistent=true, StringRef ResourceFilesPath=StringRef(), bool OnlyLocalDecls=false, CaptureDiagsKind CaptureDiagnostics=CaptureDiagsKind::None, unsigned PrecompilePreambleAfterNParses=0, bool CacheCodeCompletionResults=false, bool UserFilesAreVolatile=false, std::unique_ptr< ASTUnit > *ErrAST=nullptr)
Create an ASTUnit from a source file, via a CompilerInvocation object, by invoking the optionally pro...
Represents a character-granular source range.
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
Helper class for holding the data necessary to invoke the compiler.
MigratorOptions & getMigratorOpts()
LangOptions & getLangOpts()
Mutable getters.
FrontendOptions & getFrontendOpts()
FileSystemOptions & getFileSystemOpts()
TargetOptions & getTargetOpts()
DiagnosticOptions & getDiagnosticOpts()
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
virtual void EndSourceFile()
Callback to inform the diagnostic client that processing of a source file has ended.
unsigned getNumErrors() const
virtual void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP=nullptr)
Callback to inform the diagnostic client that processing of a source file is beginning.
Used for handling and querying diagnostic IDs.
static bool isARCDiagnostic(unsigned DiagID)
Return true if a given diagnostic falls into an ARC diagnostic category.
Options for controlling the compiler diagnostics engine.
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine a...
const SourceLocation & getLocation() const
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
void setLastDiagnosticIgnored(bool Ignored)
Pretend that the last diagnostic issued was ignored, so any subsequent notes will be suppressed,...
Level
The level of the diagnostic, after it has been through mapping.
StringRef getName() const
The name of this FileEntry.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Implements support for file system lookup, file system caching, and directory search management.
An input file for the front end.
SmallVector< FrontendInputFile, 0 > Inputs
The input files and their types.
A SourceLocation and its associated SourceManager.
bool isBeforeInTranslationUnitThan(SourceLocation Loc) const
Determines the order of 2 source locations in the translation unit.
StringRef getName() const
Return the actual identifier string.
A diagnostic client that ignores all diagnostics.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
MacroArgs - An instance of this class captures information about the formal arguments specified to a ...
A description of the current definition of a macro.
unsigned NoNSAllocReallocError
unsigned NoFinalizeRemoval
This abstract interface provides operations for unwrapping containers for serialized ASTs (precompile...
This interface provides a way to observe the actions of the preprocessor as it does its thing.
PreprocessorOptions - This class is used for passing the various options used in preprocessor initial...
std::vector< std::string > Includes
std::string ImplicitPCHInclude
The implicit PCH included at the start of the translation unit, or empty.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
void addPPCallbacks(std::unique_ptr< PPCallbacks > C)
SourceManager & getSourceManager() const
const LangOptions & getLangOpts() const
Rewriter - This is the main interface to the rewrite buffers.
std::map< FileID, llvm::RewriteBuffer >::iterator buffer_iterator
bool InsertText(SourceLocation Loc, StringRef Str, bool InsertAfter=true, bool indentNewLines=false)
InsertText - Insert the specified string at the specified location in the original buffer.
bool RemoveText(SourceLocation Start, unsigned Length, RewriteOptions opts=RewriteOptions())
RemoveText - Remove the specified text region.
buffer_iterator buffer_end()
buffer_iterator buffer_begin()
bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent)
Increase indentation for the lines between the given source range.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
OptionalFileEntryRef getFileEntryRefForID(FileID FID) const
Returns the FileEntryRef for the provided FileID.
A trivial tuple used to represent a source range.
Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...
std::string Triple
The name of the target triple to compile for.
void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override
Callback to inform the diagnostic client that processing of a source file is beginning.
void EndSourceFile() override
Callback to inform the diagnostic client that processing of a source file has ended.
Token - This structure provides full information about a lexed token.
IdentifierInfo * getIdentifierInfo() const
SourceLocation getLocation() const
Return a source location identifier for the specified offset in the current file.
bool clearDiagnostic(ArrayRef< unsigned > IDs, SourceRange range)
void push_back(const StoredDiagnostic &diag)
bool hasDiagnostic(ArrayRef< unsigned > IDs, SourceRange range) const
ListTy::const_iterator iterator
void reportDiagnostics(DiagnosticsEngine &diags) const
void forEachMapping(llvm::function_ref< void(StringRef, StringRef)> CaptureFile, llvm::function_ref< void(StringRef, const llvm::MemoryBufferRef &)> CaptureBuffer) const
Iterate through all the mappings.
bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag)
void remap(StringRef filePath, std::unique_ptr< llvm::MemoryBuffer > memBuf)
void applyMappings(PreprocessorOptions &PPOpts) const
bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag, bool ignoreIfFilesChanged)
bool overwriteOriginal(DiagnosticsEngine &Diag, StringRef outputDir=StringRef())
void setNoFinalizeRemoval(bool val)
virtual void start(ASTContext &Ctx)
virtual void remove(CharSourceRange range)
virtual ~RewriteListener()
Anchor for VTable.
virtual void insert(SourceLocation loc, StringRef text)
FileRemapper & getRemapper()
MigrationProcess(CompilerInvocation &CI, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *diagClient, StringRef outputDir=StringRef())
bool applyTransform(TransformFn trans, RewriteListener *listener=nullptr)
void applyRewrites(RewriteReceiver &receiver)
bool hasReportedErrors() const
bool getFileRemappings(std::vector< std::pair< std::string, std::string > > &remap, StringRef outputDir, DiagnosticConsumer *DiagClient)
Get the set of file remappings from the outputDir path that migrateWithTemporaryFiles produced.
static StringRef getARCMTMacroName()
std::vector< TransformFn > getAllTransformations(LangOptions::GCMode OrigGCMode, bool NoFinalizeRemoval)
void writeARCDiagsToPlist(const std::string &outPath, ArrayRef< StoredDiagnostic > diags, SourceManager &SM, const LangOptions &LangOpts)
bool migrateWithTemporaryFiles(CompilerInvocation &origCI, const FrontendInputFile &Input, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagClient, StringRef outputDir, bool emitPremigrationARCErrors, StringRef plistOut)
Applies automatic modifications and produces temporary files and metadata into the outputDir path.
void(* TransformFn)(MigrationPass &pass)
bool applyTransformations(CompilerInvocation &origCI, const FrontendInputFile &Input, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagClient)
Works similar to checkForManualIssues but instead of checking, it applies automatic modifications to ...
bool checkForManualIssues(CompilerInvocation &CI, const FrontendInputFile &Input, std::shared_ptr< PCHContainerOperations > PCHContainerOps, DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors=false, StringRef plistOut=StringRef())
Creates an AST with the provided CompilerInvocation but with these changes: -if a PCH/PTH is set,...
@ Error
Present this diagnostic as an error.
ASTEdit remove(RangeSelector S)
Removes the source selected by S.
The JSON file list parser is used to communicate input to InstallAPI.
bool IncludeInsertsAtBeginOfRange
Given a source range, true to include previous inserts at the beginning of the range as part of the r...
bool IncludeInsertsAtEndOfRange
Given a source range, true to include previous inserts at the end of the range as part of the range i...
bool RemoveLineIfEmpty
If true and removing some text leaves a blank line also remove the empty line (false by default).