clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ARCMT.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/lib/ARCMigrate -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/lib/ARCMigrate -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/lib/ARCMigrate -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/include -D NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/lib/ARCMigrate -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e=. -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2021-09-04-040900-46481-1 -x c++ /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/lib/ARCMigrate/ARCMT.cpp
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "Internals.h" |
10 | #include "clang/ARCMigrate/ARCMT.h" |
11 | #include "clang/AST/ASTConsumer.h" |
12 | #include "clang/Basic/DiagnosticCategories.h" |
13 | #include "clang/Frontend/ASTUnit.h" |
14 | #include "clang/Frontend/CompilerInstance.h" |
15 | #include "clang/Frontend/FrontendAction.h" |
16 | #include "clang/Frontend/TextDiagnosticPrinter.h" |
17 | #include "clang/Frontend/Utils.h" |
18 | #include "clang/Lex/Preprocessor.h" |
19 | #include "clang/Lex/PreprocessorOptions.h" |
20 | #include "clang/Rewrite/Core/Rewriter.h" |
21 | #include "clang/Sema/SemaDiagnostic.h" |
22 | #include "clang/Serialization/ASTReader.h" |
23 | #include "llvm/ADT/Triple.h" |
24 | #include "llvm/Support/MemoryBuffer.h" |
25 | #include <utility> |
26 | using namespace clang; |
27 | using namespace arcmt; |
28 | |
29 | bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs, |
30 | SourceRange range) { |
31 | if (range.isInvalid()) |
32 | return false; |
33 | |
34 | bool cleared = false; |
35 | ListTy::iterator I = List.begin(); |
36 | while (I != List.end()) { |
37 | FullSourceLoc diagLoc = I->getLocation(); |
38 | if ((IDs.empty() || |
39 | llvm::is_contained(IDs, I->getID())) && |
40 | !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && |
41 | (diagLoc == range.getEnd() || |
42 | diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { |
43 | cleared = true; |
44 | ListTy::iterator eraseS = I++; |
45 | if (eraseS->getLevel() != DiagnosticsEngine::Note) |
46 | while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note) |
47 | ++I; |
48 | |
49 | I = List.erase(eraseS, I); |
50 | continue; |
51 | } |
52 | |
53 | ++I; |
54 | } |
55 | |
56 | return cleared; |
57 | } |
58 | |
59 | bool CapturedDiagList::hasDiagnostic(ArrayRef<unsigned> IDs, |
60 | SourceRange range) const { |
61 | if (range.isInvalid()) |
62 | return false; |
63 | |
64 | ListTy::const_iterator I = List.begin(); |
65 | while (I != List.end()) { |
66 | FullSourceLoc diagLoc = I->getLocation(); |
67 | if ((IDs.empty() || |
68 | llvm::find(IDs, I->getID()) != IDs.end()) && |
69 | !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && |
70 | (diagLoc == range.getEnd() || |
71 | diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { |
72 | return true; |
73 | } |
74 | |
75 | ++I; |
76 | } |
77 | |
78 | return false; |
79 | } |
80 | |
81 | void CapturedDiagList::reportDiagnostics(DiagnosticsEngine &Diags) const { |
82 | for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) |
83 | Diags.Report(*I); |
84 | } |
85 | |
86 | bool CapturedDiagList::hasErrors() const { |
87 | for (ListTy::const_iterator I = List.begin(), E = List.end(); I != E; ++I) |
88 | if (I->getLevel() >= DiagnosticsEngine::Error) |
89 | return true; |
90 | |
91 | return false; |
92 | } |
93 | |
94 | namespace { |
95 | |
96 | class CaptureDiagnosticConsumer : public DiagnosticConsumer { |
97 | DiagnosticsEngine &Diags; |
98 | DiagnosticConsumer &DiagClient; |
99 | CapturedDiagList &CapturedDiags; |
100 | bool HasBegunSourceFile; |
101 | public: |
102 | CaptureDiagnosticConsumer(DiagnosticsEngine &diags, |
103 | DiagnosticConsumer &client, |
104 | CapturedDiagList &capturedDiags) |
105 | : Diags(diags), DiagClient(client), CapturedDiags(capturedDiags), |
106 | HasBegunSourceFile(false) { } |
107 | |
108 | void BeginSourceFile(const LangOptions &Opts, |
109 | const Preprocessor *PP) override { |
110 | |
111 | |
112 | |
113 | if (!HasBegunSourceFile) { |
114 | DiagClient.BeginSourceFile(Opts, PP); |
115 | HasBegunSourceFile = true; |
116 | } |
117 | } |
118 | |
119 | void FinishCapture() { |
120 | |
121 | |
122 | |
123 | if (HasBegunSourceFile) { |
124 | DiagClient.EndSourceFile(); |
125 | HasBegunSourceFile = false; |
126 | } |
127 | } |
128 | |
129 | ~CaptureDiagnosticConsumer() override { |
130 | assert(!HasBegunSourceFile && "FinishCapture not called!"); |
131 | } |
132 | |
133 | void HandleDiagnostic(DiagnosticsEngine::Level level, |
134 | const Diagnostic &Info) override { |
135 | if (DiagnosticIDs::isARCDiagnostic(Info.getID()) || |
136 | level >= DiagnosticsEngine::Error || level == DiagnosticsEngine::Note) { |
137 | if (Info.getLocation().isValid()) |
138 | CapturedDiags.push_back(StoredDiagnostic(level, Info)); |
139 | return; |
140 | } |
141 | |
142 | |
143 | Diags.setLastDiagnosticIgnored(true); |
144 | } |
145 | }; |
146 | |
147 | } |
148 | |
149 | static bool HasARCRuntime(CompilerInvocation &origCI) { |
150 | |
151 | |
152 | |
153 | llvm::Triple triple(origCI.getTargetOpts().Triple); |
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 | unsigned Major, Minor, Micro; |
166 | triple.getOSVersion(Major, Minor, Micro); |
167 | return Major > 10 || (Major == 10 && Minor >= 7); |
168 | } |
169 | |
170 | return false; |
171 | } |
172 | |
173 | static CompilerInvocation * |
174 | createInvocationForMigration(CompilerInvocation &origCI, |
175 | const PCHContainerReader &PCHContainerRdr) { |
176 | std::unique_ptr<CompilerInvocation> CInvok; |
177 | CInvok.reset(new CompilerInvocation(origCI)); |
178 | PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); |
179 | if (!PPOpts.ImplicitPCHInclude.empty()) { |
180 | |
181 | |
182 | FileManager FileMgr(origCI.getFileSystemOpts()); |
183 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
184 | IntrusiveRefCntPtr<DiagnosticsEngine> Diags( |
185 | new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), |
186 | new IgnoringDiagConsumer())); |
187 | std::string OriginalFile = ASTReader::getOriginalSourceFile( |
188 | PPOpts.ImplicitPCHInclude, FileMgr, PCHContainerRdr, *Diags); |
189 | if (!OriginalFile.empty()) |
190 | PPOpts.Includes.insert(PPOpts.Includes.begin(), OriginalFile); |
191 | PPOpts.ImplicitPCHInclude.clear(); |
192 | } |
193 | std::string define = std::string(getARCMTMacroName()); |
194 | define += '='; |
195 | CInvok->getPreprocessorOpts().addMacroDef(define); |
196 | CInvok->getLangOpts()->ObjCAutoRefCount = true; |
197 | CInvok->getLangOpts()->setGC(LangOptions::NonGC); |
198 | CInvok->getDiagnosticOpts().ErrorLimit = 0; |
199 | CInvok->getDiagnosticOpts().PedanticErrors = 0; |
200 | |
201 | |
202 | std::vector<std::string> WarnOpts; |
203 | for (std::vector<std::string>::iterator |
204 | I = CInvok->getDiagnosticOpts().Warnings.begin(), |
205 | E = CInvok->getDiagnosticOpts().Warnings.end(); I != E; ++I) { |
206 | if (!StringRef(*I).startswith("error")) |
207 | WarnOpts.push_back(*I); |
208 | } |
209 | WarnOpts.push_back("error=arc-unsafe-retained-assign"); |
210 | CInvok->getDiagnosticOpts().Warnings = std::move(WarnOpts); |
211 | |
212 | CInvok->getLangOpts()->ObjCWeakRuntime = HasARCRuntime(origCI); |
213 | CInvok->getLangOpts()->ObjCWeak = CInvok->getLangOpts()->ObjCWeakRuntime; |
214 | |
215 | return CInvok.release(); |
216 | } |
217 | |
218 | static void emitPremigrationErrors(const CapturedDiagList &arcDiags, |
219 | DiagnosticOptions *diagOpts, |
220 | Preprocessor &PP) { |
221 | TextDiagnosticPrinter printer(llvm::errs(), diagOpts); |
222 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
223 | IntrusiveRefCntPtr<DiagnosticsEngine> Diags( |
224 | new DiagnosticsEngine(DiagID, diagOpts, &printer, |
| |
225 | false)); |
226 | Diags->setSourceManager(&PP.getSourceManager()); |
227 | |
228 | printer.BeginSourceFile(PP.getLangOpts(), &PP); |
229 | arcDiags.reportDiagnostics(*Diags); |
230 | printer.EndSourceFile(); |
231 | } |
| 14 | | Potential leak of memory pointed to by 'Diags.Obj' |
|
232 | |
233 | |
234 | |
235 | |
236 | |
237 | bool arcmt::checkForManualIssues( |
238 | CompilerInvocation &origCI, const FrontendInputFile &Input, |
239 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, |
240 | DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors, |
241 | StringRef plistOut) { |
242 | if (!origCI.getLangOpts()->ObjC) |
| 5 | | Assuming field 'ObjC' is not equal to 0 | |
|
| |
243 | return false; |
244 | |
245 | LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); |
246 | bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError; |
247 | bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; |
248 | |
249 | std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, |
250 | NoFinalizeRemoval); |
251 | assert(!transforms.empty()); |
252 | |
253 | std::unique_ptr<CompilerInvocation> CInvok; |
254 | CInvok.reset( |
255 | createInvocationForMigration(origCI, PCHContainerOps->getRawReader())); |
256 | CInvok->getFrontendOpts().Inputs.clear(); |
257 | CInvok->getFrontendOpts().Inputs.push_back(Input); |
258 | |
259 | CapturedDiagList capturedDiags; |
260 | |
261 | assert(DiagClient); |
262 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
263 | IntrusiveRefCntPtr<DiagnosticsEngine> Diags( |
264 | new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), |
265 | DiagClient, false)); |
266 | |
267 | |
268 | CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); |
269 | Diags->setClient(&errRec, false); |
270 | |
271 | std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction( |
272 | std::move(CInvok), PCHContainerOps, Diags)); |
273 | if (!Unit) { |
| |
274 | errRec.FinishCapture(); |
275 | return true; |
276 | } |
277 | |
278 | |
279 | Diags->setClient(DiagClient, false); |
280 | |
281 | ASTContext &Ctx = Unit->getASTContext(); |
282 | |
283 | if (Diags->hasFatalErrorOccurred()) { |
| 8 | | Assuming the condition is false | |
|
| |
284 | Diags->Reset(); |
285 | DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); |
286 | capturedDiags.reportDiagnostics(*Diags); |
287 | DiagClient->EndSourceFile(); |
288 | errRec.FinishCapture(); |
289 | return true; |
290 | } |
291 | |
292 | if (emitPremigrationARCErrors) |
| 10 | | Assuming 'emitPremigrationARCErrors' is true | |
|
| |
293 | emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(), |
| 12 | | Calling 'emitPremigrationErrors' | |
|
294 | Unit->getPreprocessor()); |
295 | if (!plistOut.empty()) { |
296 | SmallVector<StoredDiagnostic, 8> arcDiags; |
297 | for (CapturedDiagList::iterator |
298 | I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I) |
299 | arcDiags.push_back(*I); |
300 | writeARCDiagsToPlist(std::string(plistOut), arcDiags, |
301 | Ctx.getSourceManager(), Ctx.getLangOpts()); |
302 | } |
303 | |
304 | |
305 | |
306 | |
307 | |
308 | |
309 | DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); |
310 | |
311 | |
312 | |
313 | std::vector<SourceLocation> ARCMTMacroLocs; |
314 | |
315 | TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); |
316 | MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, capturedDiags, |
317 | ARCMTMacroLocs); |
318 | pass.setNoFinalizeRemoval(NoFinalizeRemoval); |
319 | if (!NoNSAllocReallocError) |
320 | Diags->setSeverity(diag::warn_arcmt_nsalloc_realloc, diag::Severity::Error, |
321 | SourceLocation()); |
322 | |
323 | for (unsigned i=0, e = transforms.size(); i != e; ++i) |
324 | transforms[i](pass); |
325 | |
326 | capturedDiags.reportDiagnostics(*Diags); |
327 | |
328 | DiagClient->EndSourceFile(); |
329 | errRec.FinishCapture(); |
330 | |
331 | return capturedDiags.hasErrors() || testAct.hasReportedErrors(); |
332 | } |
333 | |
334 | |
335 | |
336 | |
337 | |
338 | static bool |
339 | applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input, |
340 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, |
341 | DiagnosticConsumer *DiagClient, StringRef outputDir, |
342 | bool emitPremigrationARCErrors, StringRef plistOut) { |
343 | if (!origCI.getLangOpts()->ObjC) |
| 2 | | Assuming field 'ObjC' is not equal to 0 | |
|
| |
344 | return false; |
345 | |
346 | LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); |
347 | |
348 | |
349 | CompilerInvocation CInvokForCheck(origCI); |
350 | if (arcmt::checkForManualIssues(CInvokForCheck, Input, PCHContainerOps, |
| 4 | | Calling 'checkForManualIssues' | |
|
351 | DiagClient, emitPremigrationARCErrors, |
352 | plistOut)) |
353 | return true; |
354 | |
355 | CompilerInvocation CInvok(origCI); |
356 | CInvok.getFrontendOpts().Inputs.clear(); |
357 | CInvok.getFrontendOpts().Inputs.push_back(Input); |
358 | |
359 | MigrationProcess migration(CInvok, PCHContainerOps, DiagClient, outputDir); |
360 | bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; |
361 | |
362 | std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, |
363 | NoFinalizeRemoval); |
364 | assert(!transforms.empty()); |
365 | |
366 | for (unsigned i=0, e = transforms.size(); i != e; ++i) { |
367 | bool err = migration.applyTransform(transforms[i]); |
368 | if (err) return true; |
369 | } |
370 | |
371 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
372 | IntrusiveRefCntPtr<DiagnosticsEngine> Diags( |
373 | new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), |
374 | DiagClient, false)); |
375 | |
376 | if (outputDir.empty()) { |
377 | origCI.getLangOpts()->ObjCAutoRefCount = true; |
378 | return migration.getRemapper().overwriteOriginal(*Diags); |
379 | } else { |
380 | return migration.getRemapper().flushToDisk(outputDir, *Diags); |
381 | } |
382 | } |
383 | |
384 | bool arcmt::applyTransformations( |
385 | CompilerInvocation &origCI, const FrontendInputFile &Input, |
386 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, |
387 | DiagnosticConsumer *DiagClient) { |
388 | return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, |
389 | StringRef(), false, StringRef()); |
390 | } |
391 | |
392 | bool arcmt::migrateWithTemporaryFiles( |
393 | CompilerInvocation &origCI, const FrontendInputFile &Input, |
394 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, |
395 | DiagnosticConsumer *DiagClient, StringRef outputDir, |
396 | bool emitPremigrationARCErrors, StringRef plistOut) { |
397 | assert(!outputDir.empty() && "Expected output directory path"); |
398 | return applyTransforms(origCI, Input, PCHContainerOps, DiagClient, outputDir, |
| 1 | Calling 'applyTransforms' | |
|
399 | emitPremigrationARCErrors, plistOut); |
400 | } |
401 | |
402 | bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > & |
403 | remap, |
404 | StringRef outputDir, |
405 | DiagnosticConsumer *DiagClient) { |
406 | assert(!outputDir.empty()); |
407 | |
408 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
409 | IntrusiveRefCntPtr<DiagnosticsEngine> Diags( |
410 | new DiagnosticsEngine(DiagID, new DiagnosticOptions, |
411 | DiagClient, false)); |
412 | |
413 | FileRemapper remapper; |
414 | bool err = remapper.initFromDisk(outputDir, *Diags, |
415 | true); |
416 | if (err) |
417 | return true; |
418 | |
419 | remapper.forEachMapping( |
420 | [&](StringRef From, StringRef To) { |
421 | remap.push_back(std::make_pair(From.str(), To.str())); |
422 | }, |
423 | [](StringRef, const llvm::MemoryBufferRef &) {}); |
424 | |
425 | return false; |
426 | } |
427 | |
428 | |
429 | |
430 | |
431 | |
432 | |
433 | namespace { |
434 | |
435 | class ARCMTMacroTrackerPPCallbacks : public PPCallbacks { |
436 | std::vector<SourceLocation> &ARCMTMacroLocs; |
437 | |
438 | public: |
439 | ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs) |
440 | : ARCMTMacroLocs(ARCMTMacroLocs) { } |
441 | |
442 | void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, |
443 | SourceRange Range, const MacroArgs *Args) override { |
444 | if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) |
445 | ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); |
446 | } |
447 | }; |
448 | |
449 | class ARCMTMacroTrackerAction : public ASTFrontendAction { |
450 | std::vector<SourceLocation> &ARCMTMacroLocs; |
451 | |
452 | public: |
453 | ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs) |
454 | : ARCMTMacroLocs(ARCMTMacroLocs) { } |
455 | |
456 | std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, |
457 | StringRef InFile) override { |
458 | CI.getPreprocessor().addPPCallbacks( |
459 | std::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs)); |
460 | return std::make_unique<ASTConsumer>(); |
461 | } |
462 | }; |
463 | |
464 | class RewritesApplicator : public TransformActions::RewriteReceiver { |
465 | Rewriter &rewriter; |
466 | MigrationProcess::RewriteListener *Listener; |
467 | |
468 | public: |
469 | RewritesApplicator(Rewriter &rewriter, ASTContext &ctx, |
470 | MigrationProcess::RewriteListener *listener) |
471 | : rewriter(rewriter), Listener(listener) { |
472 | if (Listener) |
473 | Listener->start(ctx); |
474 | } |
475 | ~RewritesApplicator() override { |
476 | if (Listener) |
477 | Listener->finish(); |
478 | } |
479 | |
480 | void insert(SourceLocation loc, StringRef text) override { |
481 | bool err = rewriter.InsertText(loc, text, true, |
482 | true); |
483 | if (!err && Listener) |
484 | Listener->insert(loc, text); |
485 | } |
486 | |
487 | void remove(CharSourceRange range) override { |
488 | Rewriter::RewriteOptions removeOpts; |
489 | removeOpts.IncludeInsertsAtBeginOfRange = false; |
490 | removeOpts.IncludeInsertsAtEndOfRange = false; |
491 | removeOpts.RemoveLineIfEmpty = true; |
492 | |
493 | bool err = rewriter.RemoveText(range, removeOpts); |
494 | if (!err && Listener) |
495 | Listener->remove(range); |
496 | } |
497 | |
498 | void increaseIndentation(CharSourceRange range, |
499 | SourceLocation parentIndent) override { |
500 | rewriter.IncreaseIndentation(range, parentIndent); |
501 | } |
502 | }; |
503 | |
504 | } |
505 | |
506 | |
507 | MigrationProcess::RewriteListener::~RewriteListener() { } |
508 | |
509 | MigrationProcess::MigrationProcess( |
510 | const CompilerInvocation &CI, |
511 | std::shared_ptr<PCHContainerOperations> PCHContainerOps, |
512 | DiagnosticConsumer *diagClient, StringRef outputDir) |
513 | : OrigCI(CI), PCHContainerOps(std::move(PCHContainerOps)), |
514 | DiagClient(diagClient), HadARCErrors(false) { |
515 | if (!outputDir.empty()) { |
516 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
517 | IntrusiveRefCntPtr<DiagnosticsEngine> Diags( |
518 | new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), |
519 | DiagClient, false)); |
520 | Remapper.initFromDisk(outputDir, *Diags, true); |
521 | } |
522 | } |
523 | |
524 | bool MigrationProcess::applyTransform(TransformFn trans, |
525 | RewriteListener *listener) { |
526 | std::unique_ptr<CompilerInvocation> CInvok; |
527 | CInvok.reset( |
528 | createInvocationForMigration(OrigCI, PCHContainerOps->getRawReader())); |
529 | CInvok->getDiagnosticOpts().IgnoreWarnings = true; |
530 | |
531 | Remapper.applyMappings(CInvok->getPreprocessorOpts()); |
532 | |
533 | CapturedDiagList capturedDiags; |
534 | std::vector<SourceLocation> ARCMTMacroLocs; |
535 | |
536 | assert(DiagClient); |
537 | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
538 | IntrusiveRefCntPtr<DiagnosticsEngine> Diags( |
539 | new DiagnosticsEngine(DiagID, new DiagnosticOptions, |
540 | DiagClient, false)); |
541 | |
542 | |
543 | CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); |
544 | Diags->setClient(&errRec, false); |
545 | |
546 | std::unique_ptr<ARCMTMacroTrackerAction> ASTAction; |
547 | ASTAction.reset(new ARCMTMacroTrackerAction(ARCMTMacroLocs)); |
548 | |
549 | std::unique_ptr<ASTUnit> Unit(ASTUnit::LoadFromCompilerInvocationAction( |
550 | std::move(CInvok), PCHContainerOps, Diags, ASTAction.get())); |
551 | if (!Unit) { |
552 | errRec.FinishCapture(); |
553 | return true; |
554 | } |
555 | Unit->setOwnsRemappedFileBuffers(false); |
556 | |
557 | HadARCErrors = HadARCErrors || capturedDiags.hasErrors(); |
558 | |
559 | |
560 | Diags->setClient(DiagClient, false); |
561 | |
562 | ASTContext &Ctx = Unit->getASTContext(); |
563 | |
564 | if (Diags->hasFatalErrorOccurred()) { |
565 | Diags->Reset(); |
566 | DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); |
567 | capturedDiags.reportDiagnostics(*Diags); |
568 | DiagClient->EndSourceFile(); |
569 | errRec.FinishCapture(); |
570 | return true; |
571 | } |
572 | |
573 | |
574 | |
575 | |
576 | |
577 | |
578 | DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); |
579 | |
580 | Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); |
581 | TransformActions TA(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); |
582 | MigrationPass pass(Ctx, OrigCI.getLangOpts()->getGC(), |
583 | Unit->getSema(), TA, capturedDiags, ARCMTMacroLocs); |
584 | |
585 | trans(pass); |
586 | |
587 | { |
588 | RewritesApplicator applicator(rewriter, Ctx, listener); |
589 | TA.applyRewrites(applicator); |
590 | } |
591 | |
592 | DiagClient->EndSourceFile(); |
593 | errRec.FinishCapture(); |
594 | |
595 | if (DiagClient->getNumErrors()) |
596 | return true; |
597 | |
598 | for (Rewriter::buffer_iterator |
599 | I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { |
600 | FileID FID = I->first; |
601 | RewriteBuffer &buf = I->second; |
602 | const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); |
603 | assert(file); |
604 | std::string newFname = std::string(file->getName()); |
605 | newFname += "-trans"; |
606 | SmallString<512> newText; |
607 | llvm::raw_svector_ostream vecOS(newText); |
608 | buf.write(vecOS); |
609 | std::unique_ptr<llvm::MemoryBuffer> memBuf( |
610 | llvm::MemoryBuffer::getMemBufferCopy( |
611 | StringRef(newText.data(), newText.size()), newFname)); |
612 | SmallString<64> filePath(file->getName()); |
613 | Unit->getFileManager().FixupRelativePath(filePath); |
614 | Remapper.remap(filePath.str(), std::move(memBuf)); |
615 | } |
616 | |
617 | return false; |
618 | } |