diff options
author | John McCall <rjmccall@apple.com> | 2011-06-15 23:25:17 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-06-15 23:25:17 +0000 |
commit | 8f0e8d22960d56f8390f4971e2c0f2f0a0884602 (patch) | |
tree | 288fc5496bfa36bab70b98f3be6bb5cd13645214 /tools | |
parent | f85e193739c953358c865005855253af4f68a497 (diff) | |
download | clang-8f0e8d22960d56f8390f4971e2c0f2f0a0884602.tar.gz |
The ARC Migration Tool. All the credit goes to Argyrios and Fariborz
for this.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133104 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools')
-rw-r--r-- | tools/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tools/Makefile | 4 | ||||
-rw-r--r-- | tools/arcmt-test/CMakeLists.txt | 14 | ||||
-rw-r--r-- | tools/arcmt-test/Makefile | 24 | ||||
-rw-r--r-- | tools/arcmt-test/arcmt-test.cpp | 253 | ||||
-rw-r--r-- | tools/driver/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tools/driver/Makefile | 2 | ||||
-rwxr-xr-x | tools/scan-build/ccc-analyzer | 19 |
8 files changed, 306 insertions, 12 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index ae33b782d4..8f8aa097ce 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(libclang) add_subdirectory(c-index-test) +add_subdirectory(arcmt-test) add_subdirectory(driver) diff --git a/tools/Makefile b/tools/Makefile index 000293f09c..e0afc6a04a 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -8,12 +8,12 @@ ##===----------------------------------------------------------------------===## CLANG_LEVEL := .. -DIRS := driver libclang c-index-test +DIRS := driver libclang c-index-test arcmt-test include $(CLANG_LEVEL)/../../Makefile.config ifeq ($(OS), $(filter $(OS), Minix)) -DIRS := $(filter-out libclang c-index-test, $(DIRS)) +DIRS := $(filter-out libclang c-index-test, arcmt-test, $(DIRS)) endif include $(CLANG_LEVEL)/Makefile diff --git a/tools/arcmt-test/CMakeLists.txt b/tools/arcmt-test/CMakeLists.txt new file mode 100644 index 0000000000..11ea6e4390 --- /dev/null +++ b/tools/arcmt-test/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_USED_LIBS + libclang + clangARCMigrate + clangRewrite + ) + +set( LLVM_LINK_COMPONENTS + support + mc + ) + +add_clang_executable(arcmt-test + arcmt-test.cpp + ) diff --git a/tools/arcmt-test/Makefile b/tools/arcmt-test/Makefile new file mode 100644 index 0000000000..cf435bd417 --- /dev/null +++ b/tools/arcmt-test/Makefile @@ -0,0 +1,24 @@ +##===- tools/arcmt-test/Makefile ---------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +CLANG_LEVEL := ../.. + +TOOLNAME = arcmt-test + +# No plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 + +# Don't install this. It is used for tests. +NO_INSTALL = 1 + +LINK_COMPONENTS := support mc +USEDLIBS = clang.a clangIndex.a clangARCMigrate.a clangRewrite.a \ + clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \ + clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a + +include $(CLANG_LEVEL)/Makefile diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp new file mode 100644 index 0000000000..a5a7125f1e --- /dev/null +++ b/tools/arcmt-test/arcmt-test.cpp @@ -0,0 +1,253 @@ +//===-- arcmt-test.cpp - ARC Migration Tool testbed -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/ARCMigrate/ARCMT.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Frontend/VerifyDiagnosticsClient.h" +#include "clang/Frontend/Utils.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Signals.h" + +using namespace clang; +using namespace arcmt; + +static llvm::cl::opt<bool> +CheckOnly("check-only", + llvm::cl::desc("Just check for issues that need to be handled manually")); + +//static llvm::cl::opt<bool> +//TestResultForARC("test-result", +//llvm::cl::desc("Test the result of transformations by parsing it in ARC mode")); + +static llvm::cl::opt<bool> +OutputTransformations("output-transformations", + llvm::cl::desc("Print the source transformations")); + +static llvm::cl::opt<bool> +VerifyDiags("verify",llvm::cl::desc("Verify emitted diagnostics and warnings")); + +static llvm::cl::opt<bool> +VerboseOpt("v", llvm::cl::desc("Enable verbose output")); + +static llvm::cl::extrahelp extraHelp( + "\nusage with compiler args: arcmt-test [options] --args [compiler flags]\n"); + +// This function isn't referenced outside its translation unit, but it +// can't use the "static" keyword because its address is used for +// GetMainExecutable (since some platforms don't support taking the +// address of main, and some platforms can't implement GetMainExecutable +// without being given the address of a function in the main executable). +llvm::sys::Path GetExecutablePath(const char *Argv0) { + // This just needs to be some symbol in the binary; C++ doesn't + // allow taking the address of ::main however. + void *MainAddr = (void*) (intptr_t) GetExecutablePath; + return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr); +} + +static void printSourceLocation(SourceLocation loc, ASTContext &Ctx, + llvm::raw_ostream &OS); +static void printSourceRange(CharSourceRange range, ASTContext &Ctx, + llvm::raw_ostream &OS); + +namespace { + +class PrintTransforms : public MigrationProcess::RewriteListener { + ASTContext *Ctx; + llvm::raw_ostream &OS; + +public: + PrintTransforms(llvm::raw_ostream &OS) + : Ctx(0), OS(OS) { } + + virtual void start(ASTContext &ctx) { Ctx = &ctx; } + virtual void finish() { Ctx = 0; } + + virtual void insert(SourceLocation loc, llvm::StringRef text) { + assert(Ctx); + OS << "Insert: "; + printSourceLocation(loc, *Ctx, OS); + OS << " \"" << text << "\"\n"; + } + + virtual void remove(CharSourceRange range) { + assert(Ctx); + OS << "Remove: "; + printSourceRange(range, *Ctx, OS); + OS << '\n'; + } +}; + +} // anonymous namespace + +static bool checkForMigration(llvm::StringRef resourcesPath, + llvm::ArrayRef<const char *> Args) { + DiagnosticClient *DiagClient = + new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); + llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID, DiagClient)); + // Chain in -verify checker, if requested. + VerifyDiagnosticsClient *verifyDiag = 0; + if (VerifyDiags) { + verifyDiag = new VerifyDiagnosticsClient(*Diags, Diags->takeClient()); + Diags->setClient(verifyDiag); + } + + llvm::OwningPtr<CompilerInvocation> CI; + CI.reset(clang::createInvocationFromCommandLine(Args, Diags)); + if (!CI) + return true; + + if (CI->getFrontendOpts().Inputs.empty()) { + llvm::errs() << "error: no input files\n"; + return true; + } + + if (!CI->getLangOpts().ObjC1) + return false; + + return arcmt::checkForManualIssues(*CI, + CI->getFrontendOpts().Inputs[0].second, + CI->getFrontendOpts().Inputs[0].first, + Diags->getClient()); +} + +static void printResult(FileRemapper &remapper, llvm::raw_ostream &OS) { + CompilerInvocation CI; + remapper.applyMappings(CI); + PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); + // The changed files will be in memory buffers, print them. + for (unsigned i = 0, e = PPOpts.RemappedFileBuffers.size(); i != e; ++i) { + const llvm::MemoryBuffer *mem = PPOpts.RemappedFileBuffers[i].second; + OS << mem->getBuffer(); + } +} + +static bool performTransformations(llvm::StringRef resourcesPath, + llvm::ArrayRef<const char *> Args) { + // Check first. + if (checkForMigration(resourcesPath, Args)) + return true; + + DiagnosticClient *DiagClient = + new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); + llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr<Diagnostic> TopDiags(new Diagnostic(DiagID, DiagClient)); + + llvm::OwningPtr<CompilerInvocation> origCI; + origCI.reset(clang::createInvocationFromCommandLine(Args, TopDiags)); + if (!origCI) + 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, DiagClient); + + std::vector<TransformFn> transforms = arcmt::getAllTransformations(); + assert(!transforms.empty()); + + llvm::OwningPtr<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; +} + +//===----------------------------------------------------------------------===// +// Misc. functions. +//===----------------------------------------------------------------------===// + +static void printSourceLocation(SourceLocation loc, ASTContext &Ctx, + llvm::raw_ostream &OS) { + SourceManager &SM = Ctx.getSourceManager(); + PresumedLoc PL = SM.getPresumedLoc(loc); + + OS << llvm::sys::path::filename(PL.getFilename()); + OS << ":" << PL.getLine() << ":" + << PL.getColumn(); +} + +static void printSourceRange(CharSourceRange range, ASTContext &Ctx, + llvm::raw_ostream &OS) { + SourceManager &SM = Ctx.getSourceManager(); + const LangOptions &langOpts = Ctx.getLangOptions(); + + PresumedLoc PL = SM.getPresumedLoc(range.getBegin()); + + OS << llvm::sys::path::filename(PL.getFilename()); + OS << " [" << PL.getLine() << ":" + << PL.getColumn(); + OS << " - "; + + SourceLocation end = range.getEnd(); + PL = SM.getPresumedLoc(end); + + unsigned endCol = PL.getColumn() - 1; + if (!range.isTokenRange()) + endCol += Lexer::MeasureTokenLength(end, SM, langOpts); + OS << PL.getLine() << ":" << endCol << "]"; +} + +//===----------------------------------------------------------------------===// +// Command line processing. +//===----------------------------------------------------------------------===// + +int main(int argc, const char **argv) { + using llvm::StringRef; + void *MainAddr = (void*) (intptr_t) GetExecutablePath; + llvm::sys::PrintStackTraceOnErrorSignal(); + + std::string + resourcesPath = CompilerInvocation::GetResourcesPath(argv[0], MainAddr); + + int optargc = 0; + for (; optargc != argc; ++optargc) { + if (StringRef(argv[optargc]) == "--args") + break; + } + llvm::cl::ParseCommandLineOptions(optargc, const_cast<char **>(argv), "arcmt-test"); + + if (optargc == argc) { + llvm::cl::PrintHelpMessage(); + return 1; + } + + llvm::ArrayRef<const char*> Args(argv+optargc+1, argc-optargc-1); + + if (CheckOnly) + return checkForMigration(resourcesPath, Args); + + return performTransformations(resourcesPath, Args); +} diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 0c41490175..e6d0f1ac37 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -9,6 +9,7 @@ set( LLVM_USED_LIBS clangIndex clangLex clangParse + clangARCMigrate clangRewrite clangSema clangSerialization diff --git a/tools/driver/Makefile b/tools/driver/Makefile index abe70983df..1ba8bc24d1 100644 --- a/tools/driver/Makefile +++ b/tools/driver/Makefile @@ -41,7 +41,7 @@ USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \ clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \ clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \ clangStaticAnalyzerCore.a \ - clangAnalysis.a clangIndex.a clangRewrite.a \ + clangAnalysis.a clangIndex.a clangARCMigrate.a clangRewrite.a \ clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer index 7793a8db49..5697b214a2 100755 --- a/tools/scan-build/ccc-analyzer +++ b/tools/scan-build/ccc-analyzer @@ -365,11 +365,9 @@ my %LangMap = ( 'cp' => 'c++', 'cpp' => 'c++', 'cc' => 'c++', - 'ii' => 'c++', 'i' => 'c-cpp-output', 'm' => 'objective-c', - 'mi' => 'objective-c-cpp-output', - 'mm' => 'objective-c++' + 'mi' => 'objective-c-cpp-output' ); my %UniqueOptions = ( @@ -382,11 +380,14 @@ my %UniqueOptions = ( my %LangsAccepted = ( "objective-c" => 1, - "c" => 1, - "c++" => 1, - "objective-c++" => 1 + "c" => 1 ); +if (defined $ENV{'CCC_ANALYZER_CPLUSPLUS'}) { + $LangsAccepted{"c++"} = 1; + $LangsAccepted{"objective-c++"} = 1; +} + ##----------------------------------------------------------------------------## # Main Logic. ##----------------------------------------------------------------------------## @@ -620,9 +621,9 @@ if ($Action eq 'compile' or $Action eq 'link') { push @AnalyzeArgs, "-analyzer-constraints=$ConstraintsModel"; } - if (defined $Analyses) { - push @AnalyzeArgs, split '\s+', $Analyses; - } +# if (defined $Analyses) { +# push @AnalyzeArgs, split '\s+', $Analyses; +# } if (defined $OutputFormat) { push @AnalyzeArgs, "-analyzer-output=" . $OutputFormat; |