forked from OSchip/llvm-project
[arcmt] Add some additional driver flags to optionally emit or save the pre-migration ARC errors.
-arcmt-migrate-emit-errors : Emits the pre-migration ARC errors but it doesn't affect anything else -arcmt-migrate-report-output : Writes out the pre-migration ARC errors to the provided plist file rdar://9791454 llvm-svn: 135491
This commit is contained in:
parent
08636b4633
commit
d571363e45
|
@ -28,10 +28,19 @@ namespace arcmt {
|
|||
/// It then checks the AST and produces errors/warning for ARC migration issues
|
||||
/// that the user needs to handle manually.
|
||||
///
|
||||
/// \param emitPremigrationARCErrors if true all ARC errors will get emitted
|
||||
/// even if the migrator can fix them, but the function will still return false
|
||||
/// if all ARC errors can be fixed.
|
||||
///
|
||||
/// \param plistOut if non-empty, it is the file path to store the plist with
|
||||
/// the pre-migration ARC diagnostics.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool checkForManualIssues(CompilerInvocation &CI,
|
||||
llvm::StringRef Filename, InputKind Kind,
|
||||
DiagnosticClient *DiagClient);
|
||||
DiagnosticClient *DiagClient,
|
||||
bool emitPremigrationARCErrors = false,
|
||||
llvm::StringRef plistOut = llvm::StringRef());
|
||||
|
||||
/// \brief Works similar to checkForManualIssues but instead of checking, it
|
||||
/// applies automatic modifications to source files to conform to ARC.
|
||||
|
@ -44,11 +53,20 @@ bool applyTransformations(CompilerInvocation &origCI,
|
|||
/// \brief Applies automatic modifications and produces temporary files
|
||||
/// and metadata into the \arg outputDir path.
|
||||
///
|
||||
/// \param emitPremigrationARCErrors if true all ARC errors will get emitted
|
||||
/// even if the migrator can fix them, but the function will still return false
|
||||
/// if all ARC errors can be fixed.
|
||||
///
|
||||
/// \param plistOut if non-empty, it is the file path to store the plist with
|
||||
/// the pre-migration ARC diagnostics.
|
||||
///
|
||||
/// \returns false if no error is produced, true otherwise.
|
||||
bool migrateWithTemporaryFiles(CompilerInvocation &origCI,
|
||||
llvm::StringRef Filename, InputKind Kind,
|
||||
DiagnosticClient *DiagClient,
|
||||
llvm::StringRef outputDir);
|
||||
llvm::StringRef outputDir,
|
||||
bool emitPremigrationARCErrors,
|
||||
llvm::StringRef plistOut);
|
||||
|
||||
/// \brief Get the set of file remappings from the \arg outputDir path that
|
||||
/// migrateWithTemporaryFiles produced.
|
||||
|
|
|
@ -34,11 +34,15 @@ public:
|
|||
|
||||
class MigrateAction : public WrapperFrontendAction {
|
||||
std::string MigrateDir;
|
||||
std::string PlistOut;
|
||||
bool EmitPremigrationARCErros;
|
||||
protected:
|
||||
virtual bool BeginInvocation(CompilerInstance &CI);
|
||||
|
||||
public:
|
||||
MigrateAction(FrontendAction *WrappedAction, llvm::StringRef migrateDir);
|
||||
MigrateAction(FrontendAction *WrappedAction, llvm::StringRef migrateDir,
|
||||
llvm::StringRef plistOut,
|
||||
bool emitPremigrationARCErrors);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -394,6 +394,10 @@ def arcmt_migrate : Flag<"-arcmt-migrate">,
|
|||
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
|
||||
def arcmt_migrate_directory : Separate<"-arcmt-migrate-directory">,
|
||||
HelpText<"Directory for temporary files produced during ARC migration">;
|
||||
def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">,
|
||||
HelpText<"Output path for the plist report">;
|
||||
def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">,
|
||||
HelpText<"Emit ARC errors even if the migrator can fix them">;
|
||||
|
||||
def import_module : Separate<"-import-module">,
|
||||
HelpText<"Import a module definition file">;
|
||||
|
|
|
@ -122,6 +122,10 @@ def ccc_arcmt_migrate : Separate<"-ccc-arcmt-migrate">, CCCDriverOpt,
|
|||
HelpText<"Apply modifications and produces temporary files that conform to ARC">;
|
||||
def ccc_arcmt_migrate_EQ : Joined<"-ccc-arcmt-migrate=">, CCCDriverOpt,
|
||||
Alias<ccc_arcmt_migrate>;
|
||||
def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">,
|
||||
HelpText<"Output path for the plist report">;
|
||||
def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">,
|
||||
HelpText<"Emit ARC errors even if the migrator can fix them">;
|
||||
|
||||
// Make sure all other -ccc- options are rejected.
|
||||
def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>;
|
||||
|
|
|
@ -75,6 +75,8 @@ public:
|
|||
unsigned ShowVersion : 1; ///< Show the -version text.
|
||||
unsigned FixWhatYouCan : 1; ///< Apply fixes even if there are
|
||||
/// unfixable errors.
|
||||
unsigned ARCMTMigrateEmitARCErrors : 1; /// Emit ARC errors even if the
|
||||
/// migrator can fix them
|
||||
|
||||
enum {
|
||||
ARCMT_None,
|
||||
|
@ -84,6 +86,7 @@ public:
|
|||
} ARCMTAction;
|
||||
|
||||
std::string ARCMTMigrateDir;
|
||||
std::string ARCMTMigrateReportOut;
|
||||
|
||||
/// The input files and their types.
|
||||
std::vector<std::pair<InputKind, std::string> > Inputs;
|
||||
|
@ -140,6 +143,7 @@ public:
|
|||
ShowTimers = 0;
|
||||
ShowVersion = 0;
|
||||
ARCMTAction = ARCMT_None;
|
||||
ARCMTMigrateEmitARCErrors = 0;
|
||||
}
|
||||
|
||||
/// getInputKindForExtension - Return the appropriate input kind for a file
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Internals.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/Rewrite/Rewriter.h"
|
||||
|
@ -194,13 +195,29 @@ CompilerInvocation *createInvocationForMigration(CompilerInvocation &origCI) {
|
|||
return CInvok.take();
|
||||
}
|
||||
|
||||
void emitPremigrationErrors(const CapturedDiagList &arcDiags,
|
||||
const DiagnosticOptions &diagOpts,
|
||||
Preprocessor &PP) {
|
||||
TextDiagnosticPrinter printer(llvm::errs(), diagOpts);
|
||||
llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
|
||||
llvm::IntrusiveRefCntPtr<Diagnostic> Diags(
|
||||
new Diagnostic(DiagID, &printer, /*ShouldOwnClient=*/false));
|
||||
Diags->setSourceManager(&PP.getSourceManager());
|
||||
|
||||
printer.BeginSourceFile(PP.getLangOptions(), &PP);
|
||||
arcDiags.reportDiagnostics(*Diags);
|
||||
printer.EndSourceFile();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// checkForManualIssues.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
|
||||
llvm::StringRef Filename, InputKind Kind,
|
||||
DiagnosticClient *DiagClient) {
|
||||
DiagnosticClient *DiagClient,
|
||||
bool emitPremigrationARCErrors,
|
||||
llvm::StringRef plistOut) {
|
||||
if (!origCI.getLangOpts().ObjC1)
|
||||
return false;
|
||||
|
||||
|
@ -241,6 +258,18 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (emitPremigrationARCErrors)
|
||||
emitPremigrationErrors(capturedDiags, origCI.getDiagnosticOpts(),
|
||||
Unit->getPreprocessor());
|
||||
if (!plistOut.empty()) {
|
||||
llvm::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.getLangOptions());
|
||||
}
|
||||
|
||||
// After parsing of source files ended, we want to reuse the
|
||||
// diagnostics objects to emit further diagnostics.
|
||||
// We call BeginSourceFile because DiagnosticClient requires that
|
||||
|
@ -276,13 +305,16 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI,
|
|||
static bool applyTransforms(CompilerInvocation &origCI,
|
||||
llvm::StringRef Filename, InputKind Kind,
|
||||
DiagnosticClient *DiagClient,
|
||||
llvm::StringRef outputDir) {
|
||||
llvm::StringRef outputDir,
|
||||
bool emitPremigrationARCErrors,
|
||||
llvm::StringRef plistOut) {
|
||||
if (!origCI.getLangOpts().ObjC1)
|
||||
return false;
|
||||
|
||||
// Make sure checking is successful first.
|
||||
CompilerInvocation CInvokForCheck(origCI);
|
||||
if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient))
|
||||
if (arcmt::checkForManualIssues(CInvokForCheck, Filename, Kind, DiagClient,
|
||||
emitPremigrationARCErrors, plistOut))
|
||||
return true;
|
||||
|
||||
CompilerInvocation CInvok(origCI);
|
||||
|
@ -317,15 +349,19 @@ static bool applyTransforms(CompilerInvocation &origCI,
|
|||
bool arcmt::applyTransformations(CompilerInvocation &origCI,
|
||||
llvm::StringRef Filename, InputKind Kind,
|
||||
DiagnosticClient *DiagClient) {
|
||||
return applyTransforms(origCI, Filename, Kind, DiagClient, llvm::StringRef());
|
||||
return applyTransforms(origCI, Filename, Kind, DiagClient,
|
||||
llvm::StringRef(), false, llvm::StringRef());
|
||||
}
|
||||
|
||||
bool arcmt::migrateWithTemporaryFiles(CompilerInvocation &origCI,
|
||||
llvm::StringRef Filename, InputKind Kind,
|
||||
DiagnosticClient *DiagClient,
|
||||
llvm::StringRef outputDir) {
|
||||
llvm::StringRef outputDir,
|
||||
bool emitPremigrationARCErrors,
|
||||
llvm::StringRef plistOut) {
|
||||
assert(!outputDir.empty() && "Expected output directory path");
|
||||
return applyTransforms(origCI, Filename, Kind, DiagClient, outputDir);
|
||||
return applyTransforms(origCI, Filename, Kind, DiagClient,
|
||||
outputDir, emitPremigrationARCErrors, plistOut);
|
||||
}
|
||||
|
||||
bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > &
|
||||
|
|
|
@ -38,16 +38,26 @@ ModifyAction::ModifyAction(FrontendAction *WrappedAction)
|
|||
: WrapperFrontendAction(WrappedAction) {}
|
||||
|
||||
bool MigrateAction::BeginInvocation(CompilerInstance &CI) {
|
||||
return !arcmt::migrateWithTemporaryFiles(CI.getInvocation(),
|
||||
if (arcmt::migrateWithTemporaryFiles(CI.getInvocation(),
|
||||
getCurrentFile(),
|
||||
getCurrentFileKind(),
|
||||
CI.getDiagnostics().getClient(),
|
||||
MigrateDir);
|
||||
MigrateDir,
|
||||
EmitPremigrationARCErros,
|
||||
PlistOut))
|
||||
return false; // errors, stop the action.
|
||||
|
||||
// We only want to see diagnostics emitted by migrateWithTemporaryFiles.
|
||||
CI.getDiagnostics().setIgnoreAllWarnings(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
MigrateAction::MigrateAction(FrontendAction *WrappedAction,
|
||||
llvm::StringRef migrateDir)
|
||||
: WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir) {
|
||||
llvm::StringRef migrateDir,
|
||||
llvm::StringRef plistOut,
|
||||
bool emitPremigrationARCErrors)
|
||||
: WrapperFrontendAction(WrappedAction), MigrateDir(migrateDir),
|
||||
PlistOut(plistOut), EmitPremigrationARCErros(emitPremigrationARCErrors) {
|
||||
if (MigrateDir.empty())
|
||||
MigrateDir = "."; // user current directory if none is given.
|
||||
}
|
||||
|
|
|
@ -32,8 +32,16 @@ public:
|
|||
void reportDiagnostics(Diagnostic &diags) const;
|
||||
|
||||
bool hasErrors() const;
|
||||
|
||||
typedef ListTy::const_iterator iterator;
|
||||
iterator begin() const { return List.begin(); }
|
||||
iterator end() const { return List.end(); }
|
||||
};
|
||||
|
||||
void writeARCDiagsToPlist(const std::string &outPath,
|
||||
llvm::ArrayRef<StoredDiagnostic> diags,
|
||||
SourceManager &SM, const LangOptions &LangOpts);
|
||||
|
||||
class TransformActions {
|
||||
Diagnostic &Diags;
|
||||
CapturedDiagList &CapturedDiags;
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
//===--- PlistReporter.cpp - ARC Migrate Tool Plist Reporter ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Internals.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace arcmt;
|
||||
using llvm::StringRef;
|
||||
|
||||
// FIXME: This duplicates significant functionality from PlistDiagnostics.cpp,
|
||||
// it would be jolly good if there was a reusable PlistWriter or something.
|
||||
|
||||
typedef llvm::DenseMap<FileID, unsigned> FIDMap;
|
||||
|
||||
static void AddFID(FIDMap &FIDs, llvm::SmallVectorImpl<FileID> &V,
|
||||
const SourceManager &SM, SourceLocation L) {
|
||||
|
||||
FileID FID = SM.getFileID(SM.getInstantiationLoc(L));
|
||||
FIDMap::iterator I = FIDs.find(FID);
|
||||
if (I != FIDs.end()) return;
|
||||
FIDs[FID] = V.size();
|
||||
V.push_back(FID);
|
||||
}
|
||||
|
||||
static unsigned GetFID(const FIDMap& FIDs, const SourceManager &SM,
|
||||
SourceLocation L) {
|
||||
FileID FID = SM.getFileID(SM.getInstantiationLoc(L));
|
||||
FIDMap::const_iterator I = FIDs.find(FID);
|
||||
assert(I != FIDs.end());
|
||||
return I->second;
|
||||
}
|
||||
|
||||
static llvm::raw_ostream& Indent(llvm::raw_ostream& o, const unsigned indent) {
|
||||
for (unsigned i = 0; i < indent; ++i) o << ' ';
|
||||
return o;
|
||||
}
|
||||
|
||||
static void EmitLocation(llvm::raw_ostream& o, const SourceManager &SM,
|
||||
const LangOptions &LangOpts,
|
||||
SourceLocation L, const FIDMap &FM,
|
||||
unsigned indent, bool extend = false) {
|
||||
|
||||
FullSourceLoc Loc(SM.getInstantiationLoc(L), const_cast<SourceManager&>(SM));
|
||||
|
||||
// Add in the length of the token, so that we cover multi-char tokens.
|
||||
unsigned offset =
|
||||
extend ? Lexer::MeasureTokenLength(Loc, SM, LangOpts) - 1 : 0;
|
||||
|
||||
Indent(o, indent) << "<dict>\n";
|
||||
Indent(o, indent) << " <key>line</key><integer>"
|
||||
<< Loc.getInstantiationLineNumber() << "</integer>\n";
|
||||
Indent(o, indent) << " <key>col</key><integer>"
|
||||
<< Loc.getInstantiationColumnNumber() + offset << "</integer>\n";
|
||||
Indent(o, indent) << " <key>file</key><integer>"
|
||||
<< GetFID(FM, SM, Loc) << "</integer>\n";
|
||||
Indent(o, indent) << "</dict>\n";
|
||||
}
|
||||
|
||||
static void EmitRange(llvm::raw_ostream& o, const SourceManager &SM,
|
||||
const LangOptions &LangOpts,
|
||||
CharSourceRange R, const FIDMap &FM,
|
||||
unsigned indent) {
|
||||
Indent(o, indent) << "<array>\n";
|
||||
EmitLocation(o, SM, LangOpts, R.getBegin(), FM, indent+1);
|
||||
EmitLocation(o, SM, LangOpts, R.getEnd(), FM, indent+1, R.isTokenRange());
|
||||
Indent(o, indent) << "</array>\n";
|
||||
}
|
||||
|
||||
static llvm::raw_ostream& EmitString(llvm::raw_ostream& o,
|
||||
StringRef s) {
|
||||
o << "<string>";
|
||||
for (StringRef::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) {
|
||||
char c = *I;
|
||||
switch (c) {
|
||||
default: o << c; break;
|
||||
case '&': o << "&"; break;
|
||||
case '<': o << "<"; break;
|
||||
case '>': o << ">"; break;
|
||||
case '\'': o << "'"; break;
|
||||
case '\"': o << """; break;
|
||||
}
|
||||
}
|
||||
o << "</string>";
|
||||
return o;
|
||||
}
|
||||
|
||||
void arcmt::writeARCDiagsToPlist(const std::string &outPath,
|
||||
llvm::ArrayRef<StoredDiagnostic> diags,
|
||||
SourceManager &SM,
|
||||
const LangOptions &LangOpts) {
|
||||
DiagnosticIDs DiagIDs;
|
||||
|
||||
// Build up a set of FIDs that we use by scanning the locations and
|
||||
// ranges of the diagnostics.
|
||||
FIDMap FM;
|
||||
llvm::SmallVector<FileID, 10> Fids;
|
||||
|
||||
for (llvm::ArrayRef<StoredDiagnostic>::iterator
|
||||
I = diags.begin(), E = diags.end(); I != E; ++I) {
|
||||
const StoredDiagnostic &D = *I;
|
||||
|
||||
AddFID(FM, Fids, SM, D.getLocation());
|
||||
|
||||
for (StoredDiagnostic::range_iterator
|
||||
RI = D.range_begin(), RE = D.range_end(); RI != RE; ++RI) {
|
||||
AddFID(FM, Fids, SM, RI->getBegin());
|
||||
AddFID(FM, Fids, SM, RI->getEnd());
|
||||
}
|
||||
}
|
||||
|
||||
std::string errMsg;
|
||||
llvm::raw_fd_ostream o(outPath.c_str(), errMsg);
|
||||
if (!errMsg.empty()) {
|
||||
llvm::errs() << "error: could not create file: " << outPath << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
// Write the plist header.
|
||||
o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
|
||||
"\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
|
||||
"<plist version=\"1.0\">\n";
|
||||
|
||||
// Write the root object: a <dict> containing...
|
||||
// - "files", an <array> mapping from FIDs to file names
|
||||
// - "diagnostics", an <array> containing the diagnostics
|
||||
o << "<dict>\n"
|
||||
" <key>files</key>\n"
|
||||
" <array>\n";
|
||||
|
||||
for (llvm::SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end();
|
||||
I!=E; ++I) {
|
||||
o << " ";
|
||||
EmitString(o, SM.getFileEntryForID(*I)->getName()) << '\n';
|
||||
}
|
||||
|
||||
o << " </array>\n"
|
||||
" <key>diagnostics</key>\n"
|
||||
" <array>\n";
|
||||
|
||||
for (llvm::ArrayRef<StoredDiagnostic>::iterator
|
||||
DI = diags.begin(), DE = diags.end(); DI != DE; ++DI) {
|
||||
|
||||
const StoredDiagnostic &D = *DI;
|
||||
|
||||
if (D.getLevel() == Diagnostic::Ignored)
|
||||
continue;
|
||||
|
||||
o << " <dict>\n";
|
||||
|
||||
// Output the diagnostic.
|
||||
o << " <key>description</key>";
|
||||
EmitString(o, D.getMessage()) << '\n';
|
||||
o << " <key>category</key>";
|
||||
EmitString(o, DiagIDs.getCategoryNameFromID(
|
||||
DiagIDs.getCategoryNumberForDiag(D.getID()))) << '\n';
|
||||
o << " <key>type</key>";
|
||||
if (D.getLevel() >= Diagnostic::Error)
|
||||
EmitString(o, "error") << '\n';
|
||||
else if (D.getLevel() == Diagnostic::Warning)
|
||||
EmitString(o, "warning") << '\n';
|
||||
else
|
||||
EmitString(o, "note") << '\n';
|
||||
|
||||
// Output the location of the bug.
|
||||
o << " <key>location</key>\n";
|
||||
EmitLocation(o, SM, LangOpts, D.getLocation(), FM, 2);
|
||||
|
||||
// Output the ranges (if any).
|
||||
StoredDiagnostic::range_iterator RI = D.range_begin(), RE = D.range_end();
|
||||
|
||||
if (RI != RE) {
|
||||
o << " <key>ranges</key>\n";
|
||||
o << " <array>\n";
|
||||
for (; RI != RE; ++RI)
|
||||
EmitRange(o, SM, LangOpts, *RI, FM, 4);
|
||||
o << " </array>\n";
|
||||
}
|
||||
|
||||
// Close up the entry.
|
||||
o << " </dict>\n";
|
||||
}
|
||||
|
||||
o << " </array>\n";
|
||||
|
||||
// Finish.
|
||||
o << "</dict>\n</plist>";
|
||||
}
|
|
@ -1444,6 +1444,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
CmdArgs.push_back("-arcmt-migrate");
|
||||
CmdArgs.push_back("-arcmt-migrate-directory");
|
||||
CmdArgs.push_back(A->getValue(Args));
|
||||
|
||||
Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output);
|
||||
Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -439,6 +439,12 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
|
|||
Res.push_back("-arcmt-migrate-directory");
|
||||
Res.push_back(Opts.ARCMTMigrateDir);
|
||||
}
|
||||
if (!Opts.ARCMTMigrateReportOut.empty()) {
|
||||
Res.push_back("-arcmt-migrate-report-output");
|
||||
Res.push_back(Opts.ARCMTMigrateReportOut);
|
||||
}
|
||||
if (Opts.ARCMTMigrateEmitARCErrors)
|
||||
Res.push_back("-arcmt-migrate-emit-errors");
|
||||
|
||||
bool NeedLang = false;
|
||||
for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
|
||||
|
@ -1278,6 +1284,10 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
|
|||
}
|
||||
}
|
||||
Opts.ARCMTMigrateDir = Args.getLastArgValue(OPT_arcmt_migrate_directory);
|
||||
Opts.ARCMTMigrateReportOut
|
||||
= Args.getLastArgValue(OPT_arcmt_migrate_report_output);
|
||||
Opts.ARCMTMigrateEmitARCErrors
|
||||
= Args.hasArg(OPT_arcmt_migrate_emit_arc_errors);
|
||||
|
||||
InputKind DashX = IK_None;
|
||||
if (const Arg *A = Args.getLastArg(OPT_x)) {
|
||||
|
|
|
@ -100,7 +100,10 @@ static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
|
|||
Act = new arcmt::ModifyAction(Act);
|
||||
break;
|
||||
case FrontendOptions::ARCMT_Migrate:
|
||||
Act = new arcmt::MigrateAction(Act, CI.getFrontendOpts().ARCMTMigrateDir);
|
||||
Act = new arcmt::MigrateAction(Act,
|
||||
CI.getFrontendOpts().ARCMTMigrateDir,
|
||||
CI.getFrontendOpts().ARCMTMigrateReportOut,
|
||||
CI.getFrontendOpts().ARCMTMigrateEmitARCErrors);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t -arcmt-migrate-emit-errors %s -fobjc-nonfragile-abi 2>&1 | FileCheck %s
|
||||
// RUN: rm -rf %t
|
||||
|
||||
@protocol NSObject
|
||||
- (oneway void)release;
|
||||
@end
|
||||
|
||||
void test(id p) {
|
||||
[p release];
|
||||
}
|
||||
|
||||
// CHECK: error: ARC forbids explicit message send of 'release'
|
|
@ -0,0 +1,50 @@
|
|||
// RUN: %clang_cc1 -arcmt-migrate -arcmt-migrate-directory %t.dir -arcmt-migrate-report-output %t.plist %s -fobjc-nonfragile-abi
|
||||
// RUN: FileCheck %s -input-file=%t.plist
|
||||
// RUN: rm -rf %t.dir
|
||||
|
||||
@protocol NSObject
|
||||
- (oneway void)release;
|
||||
@end
|
||||
|
||||
void test(id p) {
|
||||
[p release];
|
||||
}
|
||||
|
||||
// CHECK: <?xml version="1.0" encoding="UTF-8"?>
|
||||
// CHECK: <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
// CHECK: <plist version="1.0">
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>files</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: </array>
|
||||
// CHECK: <key>diagnostics</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>description</key><string>ARC forbids explicit message send of 'release'</string>
|
||||
// CHECK: <key>category</key><string>Automatic Reference Counting Issue</string>
|
||||
// CHECK: <key>type</key><string>error</string>
|
||||
// CHECK: <key>location</key>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>10</integer>
|
||||
// CHECK: <key>col</key><integer>4</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <key>ranges</key>
|
||||
// CHECK: <array>
|
||||
// CHECK: <array>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>10</integer>
|
||||
// CHECK: <key>col</key><integer>6</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: <dict>
|
||||
// CHECK: <key>line</key><integer>10</integer>
|
||||
// CHECK: <key>col</key><integer>12</integer>
|
||||
// CHECK: <key>file</key><integer>0</integer>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </array>
|
||||
// CHECK: </dict>
|
||||
// CHECK: </plist>
|
Loading…
Reference in New Issue