static bool performTransformations(StringRef resourcesPath, ArrayRef<const char *> Args) { // Check first. if (checkForMigration(resourcesPath, Args)) return true; IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); DiagnosticConsumer *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> TopDiags( new DiagnosticsEngine(DiagID, &*DiagOpts, &*DiagClient)); CompilerInvocation origCI; if (!CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(), *TopDiags)) return true; if (origCI.getFrontendOpts().Inputs.empty()) { llvm::errs() << "error: no input files\n"; return true; } if (!origCI.getLangOpts()->ObjC1) return false; MigrationProcess migration(origCI, std::make_shared<PCHContainerOperations>(), DiagClient); std::vector<TransformFn> transforms = arcmt::getAllTransformations(origCI.getLangOpts()->getGC(), origCI.getMigratorOpts().NoFinalizeRemoval); assert(!transforms.empty()); std::unique_ptr<PrintTransforms> transformPrinter; if (OutputTransformations) transformPrinter.reset(new PrintTransforms(llvm::outs())); for (unsigned i=0, e = transforms.size(); i != e; ++i) { bool err = migration.applyTransform(transforms[i], transformPrinter.get()); if (err) return true; if (VerboseOpt) { if (i == e-1) llvm::errs() << "\n##### FINAL RESULT #####\n"; else llvm::errs() << "\n##### OUTPUT AFTER "<< i+1 <<". TRANSFORMATION #####\n"; printResult(migration.getRemapper(), llvm::errs()); llvm::errs() << "\n##########################\n\n"; } } if (!OutputTransformations) printResult(migration.getRemapper(), llvm::outs()); // FIXME: TestResultForARC return false; }
static bool applyTransforms(CompilerInvocation &origCI, const FrontendInputFile &Input, DiagnosticConsumer *DiagClient, StringRef outputDir, bool emitPremigrationARCErrors, StringRef plistOut) { if (!origCI.getLangOpts()->ObjC1) return false; LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); // Make sure checking is successful first. CompilerInvocation CInvokForCheck(origCI); if (arcmt::checkForManualIssues(CInvokForCheck, Input, DiagClient, emitPremigrationARCErrors, plistOut)) return true; CompilerInvocation CInvok(origCI); CInvok.getFrontendOpts().Inputs.clear(); CInvok.getFrontendOpts().Inputs.push_back(Input); MigrationProcess migration(CInvok, DiagClient, outputDir); bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, NoFinalizeRemoval); assert(!transforms.empty()); for (unsigned i=0, e = transforms.size(); i != e; ++i) { bool err = migration.applyTransform(transforms[i]); if (err) return true; } IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), DiagClient, /*ShouldOwnClient=*/false)); if (outputDir.empty()) { origCI.getLangOpts()->ObjCAutoRefCount = true; return migration.getRemapper().overwriteOriginal(*Diags); } else { // If we are migrating code that gets the '-fobjc-arc' flag, make sure // to remove it so that we don't get errors from normal compilation. origCI.getLangOpts()->ObjCAutoRefCount = false; return migration.getRemapper().flushToDisk(outputDir, *Diags); } }
static bool checkForMigration(StringRef resourcesPath, ArrayRef<const char *> Args) { IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); DiagnosticConsumer *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient)); // Chain in -verify checker, if requested. VerifyDiagnosticConsumer *verifyDiag = nullptr; if (VerifyDiags) { verifyDiag = new VerifyDiagnosticConsumer(*Diags); Diags->setClient(verifyDiag); } CompilerInvocation CI; if (!CompilerInvocation::CreateFromArgs(CI, Args.begin(), Args.end(), *Diags)) return true; if (CI.getFrontendOpts().Inputs.empty()) { llvm::errs() << "error: no input files\n"; return true; } if (!CI.getLangOpts()->ObjC1) return false; arcmt::checkForManualIssues(CI, CI.getFrontendOpts().Inputs[0], std::make_shared<PCHContainerOperations>(), Diags->getClient()); return Diags->getClient()->getNumErrors() > 0; }
void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, const char **ArgBegin, const char **ArgEnd, Diagnostic &Diags) { // Parse the arguments. llvm::OwningPtr<OptTable> Opts(createCC1OptTable()); unsigned MissingArgIndex, MissingArgCount; llvm::OwningPtr<InputArgList> Args( Opts->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount)); // Check for missing argument error. if (MissingArgCount) Diags.Report(diag::err_drv_missing_argument) << Args->getArgString(MissingArgIndex) << MissingArgCount; // Issue errors on unknown arguments. for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN), ie = Args->filtered_end(); it != ie; ++it) Diags.Report(diag::err_drv_unknown_argument) << it->getAsString(*Args); ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags); ParseCodeGenArgs(Res.getCodeGenOpts(), *Args, Diags); ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, Diags); FrontendOptions::InputKind DashX = ParseFrontendArgs(Res.getFrontendOpts(), *Args, Diags); ParseHeaderSearchArgs(Res.getHeaderSearchOpts(), *Args); if (DashX != FrontendOptions::IK_AST) ParseLangArgs(Res.getLangOpts(), *Args, DashX, Diags); ParsePreprocessorArgs(Res.getPreprocessorOpts(), *Args, Diags); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), *Args); ParseTargetArgs(Res.getTargetOpts(), *Args); }
static bool applyTransforms(CompilerInvocation &origCI, llvm::StringRef Filename, InputKind Kind, DiagnosticClient *DiagClient, llvm::StringRef outputDir) { if (!origCI.getLangOpts().ObjC1) return false; // Make sure checking is successful first. CompilerInvocation CInvokForCheck(origCI); if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient)) return true; CompilerInvocation CInvok(origCI); CInvok.getFrontendOpts().Inputs.clear(); CInvok.getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename)); MigrationProcess migration(CInvok, DiagClient, outputDir); std::vector<TransformFn> transforms = arcmt::getAllTransformations(); assert(!transforms.empty()); for (unsigned i=0, e = transforms.size(); i != e; ++i) { bool err = migration.applyTransform(transforms[i]); if (err) return true; } llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); llvm::IntrusiveRefCntPtr<Diagnostic> Diags( new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); if (outputDir.empty()) { origCI.getLangOpts().ObjCAutoRefCount = true; return migration.getRemapper().overwriteOriginal(*Diags); } else { // If we are migrating code that gets the '-fobjc-arc' flag, make sure // to remove it so that we don't get errors from normal compilation. origCI.getLangOpts().ObjCAutoRefCount = false; return migration.getRemapper().flushToDisk(outputDir, *Diags); } }
bool arcmt::checkForManualIssues(CompilerInvocation &origCI, const FrontendInputFile &Input, DiagnosticConsumer *DiagClient, bool emitPremigrationARCErrors, StringRef plistOut) { if (!origCI.getLangOpts()->ObjC1) return false; LangOptions::GCMode OrigGCMode = origCI.getLangOpts()->getGC(); bool NoNSAllocReallocError = origCI.getMigratorOpts().NoNSAllocReallocError; bool NoFinalizeRemoval = origCI.getMigratorOpts().NoFinalizeRemoval; std::vector<TransformFn> transforms = arcmt::getAllTransformations(OrigGCMode, NoFinalizeRemoval); assert(!transforms.empty()); OwningPtr<CompilerInvocation> CInvok; CInvok.reset(createInvocationForMigration(origCI)); CInvok->getFrontendOpts().Inputs.clear(); CInvok->getFrontendOpts().Inputs.push_back(Input); CapturedDiagList capturedDiags; assert(DiagClient); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); // Filter of all diagnostics. CaptureDiagnosticConsumer errRec(*Diags, capturedDiags); Diags->setClient(&errRec, /*ShouldOwnClient=*/false); OwningPtr<ASTUnit> Unit( ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags)); if (!Unit) return true; // Don't filter diagnostics anymore. Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); ASTContext &Ctx = Unit->getASTContext(); if (Diags->hasFatalErrorOccurred()) { Diags->Reset(); DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); capturedDiags.reportDiagnostics(*Diags); DiagClient->EndSourceFile(); return true; } if (emitPremigrationARCErrors) emitPremigrationErrors(capturedDiags, origCI.getDiagnosticOpts(), Unit->getPreprocessor()); if (!plistOut.empty()) { SmallVector<StoredDiagnostic, 8> arcDiags; for (CapturedDiagList::iterator I = capturedDiags.begin(), E = capturedDiags.end(); I != E; ++I) arcDiags.push_back(*I); writeARCDiagsToPlist(plistOut, arcDiags, Ctx.getSourceManager(), Ctx.getLangOpts()); } // After parsing of source files ended, we want to reuse the // diagnostics objects to emit further diagnostics. // We call BeginSourceFile because DiagnosticConsumer requires that // diagnostics with source range information are emitted only in between // BeginSourceFile() and EndSourceFile(). DiagClient->BeginSourceFile(Ctx.getLangOpts(), &Unit->getPreprocessor()); // No macros will be added since we are just checking and we won't modify // source code. std::vector<SourceLocation> ARCMTMacroLocs; TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); MigrationPass pass(Ctx, OrigGCMode, Unit->getSema(), testAct, ARCMTMacroLocs); pass.setNSAllocReallocError(NoNSAllocReallocError); pass.setNoFinalizeRemoval(NoFinalizeRemoval); for (unsigned i=0, e = transforms.size(); i != e; ++i) transforms[i](pass); capturedDiags.reportDiagnostics(*Diags); DiagClient->EndSourceFile(); // If we are migrating code that gets the '-fobjc-arc' flag, make sure // to remove it so that we don't get errors from normal compilation. origCI.getLangOpts()->ObjCAutoRefCount = false; return capturedDiags.hasErrors() || testAct.hasReportedErrors(); }
bool arcmt::checkForManualIssues(CompilerInvocation &origCI, llvm::StringRef Filename, InputKind Kind, DiagnosticClient *DiagClient) { if (!origCI.getLangOpts().ObjC1) return false; std::vector<TransformFn> transforms = arcmt::getAllTransformations(); assert(!transforms.empty()); llvm::OwningPtr<CompilerInvocation> CInvok; CInvok.reset(createInvocationForMigration(origCI)); CInvok->getFrontendOpts().Inputs.clear(); CInvok->getFrontendOpts().Inputs.push_back(std::make_pair(Kind, Filename)); CapturedDiagList capturedDiags; assert(DiagClient); llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); llvm::IntrusiveRefCntPtr<Diagnostic> Diags( new Diagnostic(DiagID, DiagClient, /*ShouldOwnClient=*/false)); // Filter of all diagnostics. CaptureDiagnosticClient errRec(*Diags, capturedDiags); Diags->setClient(&errRec, /*ShouldOwnClient=*/false); llvm::OwningPtr<ASTUnit> Unit( ASTUnit::LoadFromCompilerInvocationAction(CInvok.take(), Diags)); if (!Unit) return true; // Don't filter diagnostics anymore. Diags->setClient(DiagClient, /*ShouldOwnClient=*/false); ASTContext &Ctx = Unit->getASTContext(); if (Diags->hasFatalErrorOccurred()) { Diags->Reset(); DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); capturedDiags.reportDiagnostics(*Diags); DiagClient->EndSourceFile(); return true; } // After parsing of source files ended, we want to reuse the // diagnostics objects to emit further diagnostics. // We call BeginSourceFile because DiagnosticClient requires that // diagnostics with source range information are emitted only in between // BeginSourceFile() and EndSourceFile(). DiagClient->BeginSourceFile(Ctx.getLangOptions(), &Unit->getPreprocessor()); // No macros will be added since we are just checking and we won't modify // source code. std::vector<SourceLocation> ARCMTMacroLocs; TransformActions testAct(*Diags, capturedDiags, Ctx, Unit->getPreprocessor()); MigrationPass pass(Ctx, Unit->getSema(), testAct, ARCMTMacroLocs); for (unsigned i=0, e = transforms.size(); i != e; ++i) transforms[i](pass); capturedDiags.reportDiagnostics(*Diags); DiagClient->EndSourceFile(); // If we are migrating code that gets the '-fobjc-arc' flag, make sure // to remove it so that we don't get errors from normal compilation. origCI.getLangOpts().ObjCAutoRefCount = false; return capturedDiags.hasErrors(); }