diff options
author | dim <dim@FreeBSD.org> | 2011-07-17 15:40:56 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2011-07-17 15:40:56 +0000 |
commit | 611ba3ea3300b71eb95dc4e45f20eee5dddd32e1 (patch) | |
tree | 2097d084eb235c0b12c0bff3445f4ec7bbaa8a12 /tools | |
parent | c49018d9cce52d8c9f34b44865ec3ba8e89a1488 (diff) | |
download | FreeBSD-src-611ba3ea3300b71eb95dc4e45f20eee5dddd32e1.zip FreeBSD-src-611ba3ea3300b71eb95dc4e45f20eee5dddd32e1.tar.gz |
Vendor import of clang trunk r135360:
http://llvm.org/svn/llvm-project/cfe/trunk@135360
Diffstat (limited to 'tools')
26 files changed, 1119 insertions, 74 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index ae33b78..aff437f 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,3 +1,5 @@ add_subdirectory(libclang) add_subdirectory(c-index-test) +add_subdirectory(arcmt-test) +add_subdirectory(c-arcmt-test) add_subdirectory(driver) diff --git a/tools/Makefile b/tools/Makefile index 000293f..bfd2a64 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 c-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 0000000..9227f8e --- /dev/null +++ b/tools/arcmt-test/CMakeLists.txt @@ -0,0 +1,13 @@ +set(LLVM_USED_LIBS + 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 0000000..c143e27 --- /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 = 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 0000000..eb0f569 --- /dev/null +++ b/tools/arcmt-test/arcmt-test.cpp @@ -0,0 +1,374 @@ +//===-- 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/FileSystem.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.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::opt<bool> +VerifyTransformedFiles("verify-transformed-files", +llvm::cl::desc("Read pairs of file mappings (typically the output of " + "c-arcmt-test) and compare their contents with the filenames " + "provided in command-line")); + +static llvm::cl::opt<std::string> +RemappingsFile("remappings-file", + llvm::cl::desc("Pairs of file mappings (typically the output of " + "c-arcmt-test)")); + +static llvm::cl::list<std::string> +ResultFiles(llvm::cl::Positional, llvm::cl::desc("<filename>...")); + +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); + } + + CompilerInvocation CI; + CompilerInvocation::CreateFromArgs(CI, Args.begin(), Args.end(), *Diags); + + 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].second, + CI.getFrontendOpts().Inputs[0].first, + Diags->getClient()); + return Diags->getClient()->getNumErrors() > 0; +} + +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)); + + CompilerInvocation origCI; + CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(), + *TopDiags); + + 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; +} + +static bool filesCompareEqual(llvm::StringRef fname1, llvm::StringRef fname2) { + using namespace llvm; + + OwningPtr<MemoryBuffer> file1; + MemoryBuffer::getFile(fname1, file1); + if (!file1) + return false; + + OwningPtr<MemoryBuffer> file2; + MemoryBuffer::getFile(fname2, file2); + if (!file2) + return false; + + return file1->getBuffer() == file2->getBuffer(); +} + +static bool verifyTransformedFiles(llvm::ArrayRef<std::string> resultFiles) { + using namespace llvm; + + assert(!resultFiles.empty()); + + std::map<StringRef, StringRef> resultMap; + + for (ArrayRef<std::string>::iterator + I = resultFiles.begin(), E = resultFiles.end(); I != E; ++I) { + StringRef fname(*I); + if (!fname.endswith(".result")) { + errs() << "error: filename '" << fname + << "' does not have '.result' extension\n"; + return true; + } + resultMap[sys::path::stem(fname)] = fname; + } + + OwningPtr<MemoryBuffer> inputBuf; + if (RemappingsFile.empty()) + MemoryBuffer::getSTDIN(inputBuf); + else + MemoryBuffer::getFile(RemappingsFile, inputBuf); + if (!inputBuf) { + errs() << "error: could not read remappings input\n"; + return true; + } + + SmallVector<StringRef, 8> strs; + inputBuf->getBuffer().split(strs, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); + + if (strs.empty()) { + errs() << "error: no files to verify from stdin\n"; + return true; + } + if (strs.size() % 2 != 0) { + errs() << "error: files to verify are not original/result pairs\n"; + return true; + } + + for (unsigned i = 0, e = strs.size(); i != e; i += 2) { + StringRef inputOrigFname = strs[i]; + StringRef inputResultFname = strs[i+1]; + + std::map<StringRef, StringRef>::iterator It; + It = resultMap.find(sys::path::filename(inputOrigFname)); + if (It == resultMap.end()) { + errs() << "error: '" << inputOrigFname << "' is not in the list of " + << "transformed files to verify\n"; + return true; + } + + bool exists = false; + sys::fs::exists(It->second, exists); + if (!exists) { + errs() << "error: '" << It->second << "' does not exist\n"; + return true; + } + sys::fs::exists(inputResultFname, exists); + if (!exists) { + errs() << "error: '" << inputResultFname << "' does not exist\n"; + return true; + } + + if (!filesCompareEqual(It->second, inputResultFname)) { + errs() << "error: '" << It->second << "' is different than " + << "'" << inputResultFname << "'\n"; + return true; + } + + resultMap.erase(It); + } + + if (!resultMap.empty()) { + for (std::map<StringRef, StringRef>::iterator + I = resultMap.begin(), E = resultMap.end(); I != E; ++I) + errs() << "error: '" << I->second << "' was not verified!\n"; + return true; + } + + 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 (VerifyTransformedFiles) { + if (ResultFiles.empty()) { + llvm::cl::PrintHelpMessage(); + return 1; + } + return verifyTransformedFiles(ResultFiles); + } + + 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/c-arcmt-test/CMakeLists.txt b/tools/c-arcmt-test/CMakeLists.txt new file mode 100644 index 0000000..351f4ad --- /dev/null +++ b/tools/c-arcmt-test/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_USED_LIBS libclang) + +set( LLVM_LINK_COMPONENTS + support + mc + ) + +add_clang_executable(c-arcmt-test + c-arcmt-test.c + ) + +set_target_properties(c-arcmt-test + PROPERTIES + LINKER_LANGUAGE CXX) diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile new file mode 100644 index 0000000..b72a08a --- /dev/null +++ b/tools/c-arcmt-test/Makefile @@ -0,0 +1,25 @@ +##===- tools/c-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 = c-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/c-arcmt-test/c-arcmt-test.c b/tools/c-arcmt-test/c-arcmt-test.c new file mode 100644 index 0000000..5522b33 --- /dev/null +++ b/tools/c-arcmt-test/c-arcmt-test.c @@ -0,0 +1,91 @@ +/* c-arcmt-test.c */ + +#include "clang-c/Index.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#if defined(_WIN32) +#include <io.h> +#include <fcntl.h> +#endif + +static int print_remappings(const char *path) { + CXRemapping remap; + unsigned i, N; + CXString origFname; + CXString transFname; + + remap = clang_getRemappings(path); + if (!remap) + return 1; + + N = clang_remap_getNumFiles(remap); + for (i = 0; i != N; ++i) { + clang_remap_getFilenames(remap, i, &origFname, &transFname); + + fprintf(stdout, "%s\n", clang_getCString(origFname)); + fprintf(stdout, "%s\n", clang_getCString(transFname)); + + clang_disposeString(origFname); + clang_disposeString(transFname); + } + + clang_remap_dispose(remap); + return 0; +} + +/******************************************************************************/ +/* Command line processing. */ +/******************************************************************************/ + +static void print_usage(void) { + fprintf(stderr, + "usage: c-arcmt-test -arcmt-migrate-directory <path>\n\n\n"); +} + +/***/ + +int carcmttest_main(int argc, const char **argv) { + clang_enableStackTraces(); + if (argc == 3 && strncmp(argv[1], "-arcmt-migrate-directory", 24) == 0) + return print_remappings(argv[2]); + + print_usage(); + return 1; +} + +/***/ + +/* We intentionally run in a separate thread to ensure we at least minimal + * testing of a multithreaded environment (for example, having a reduced stack + * size). */ + +typedef struct thread_info { + int argc; + const char **argv; + int result; +} thread_info; +void thread_runner(void *client_data_v) { + thread_info *client_data = client_data_v; + client_data->result = carcmttest_main(client_data->argc, client_data->argv); +} + +int main(int argc, const char **argv) { + thread_info client_data; + +#if defined(_WIN32) + if (getenv("LIBCLANG_LOGGING") == NULL) + putenv("LIBCLANG_LOGGING=1"); + _setmode( _fileno(stdout), _O_BINARY ); +#else + setenv("LIBCLANG_LOGGING", "1", /*overwrite=*/0); +#endif + + if (getenv("CINDEXTEST_NOTHREADS")) + return carcmttest_main(argc, argv); + + client_data.argc = argc; + client_data.argv = argv; + clang_executeOnThread(thread_runner, &client_data, 0); + return client_data.result; +} diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile index 6806404..5e5b857 100644 --- a/tools/c-index-test/Makefile +++ b/tools/c-index-test/Makefile @@ -18,7 +18,7 @@ NO_INSTALL = 1 LINK_COMPONENTS := support mc USEDLIBS = clang.a clangIndex.a clangFrontend.a clangDriver.a \ - clangSerialization.a clangParse.a clangSema.a clangAnalysis.a \ - clangAST.a clangLex.a clangBasic.a + clangSerialization.a clangParse.a clangSema.a \ + clangAnalysis.a clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 837fc89..6e0aaac 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -38,7 +38,7 @@ static unsigned getDefaultParsingOptions() { if (getenv("CINDEXTEST_COMPLETION_CACHING")) options |= CXTranslationUnit_CacheCompletionResults; if (getenv("CINDEXTEST_NESTED_MACROS")) - options |= CXTranslationUnit_NestedMacroInstantiations; + options |= CXTranslationUnit_NestedMacroExpansions; return options; } @@ -1018,6 +1018,79 @@ void print_completion_result(CXCompletionResult *completion_result, fprintf(file, "\n"); } +void print_completion_contexts(unsigned long long contexts, FILE *file) { + fprintf(file, "Completion contexts:\n"); + if (contexts == CXCompletionContext_Unknown) { + fprintf(file, "Unknown\n"); + } + if (contexts & CXCompletionContext_AnyType) { + fprintf(file, "Any type\n"); + } + if (contexts & CXCompletionContext_AnyValue) { + fprintf(file, "Any value\n"); + } + if (contexts & CXCompletionContext_ObjCObjectValue) { + fprintf(file, "Objective-C object value\n"); + } + if (contexts & CXCompletionContext_ObjCSelectorValue) { + fprintf(file, "Objective-C selector value\n"); + } + if (contexts & CXCompletionContext_CXXClassTypeValue) { + fprintf(file, "C++ class type value\n"); + } + if (contexts & CXCompletionContext_DotMemberAccess) { + fprintf(file, "Dot member access\n"); + } + if (contexts & CXCompletionContext_ArrowMemberAccess) { + fprintf(file, "Arrow member access\n"); + } + if (contexts & CXCompletionContext_ObjCPropertyAccess) { + fprintf(file, "Objective-C property access\n"); + } + if (contexts & CXCompletionContext_EnumTag) { + fprintf(file, "Enum tag\n"); + } + if (contexts & CXCompletionContext_UnionTag) { + fprintf(file, "Union tag\n"); + } + if (contexts & CXCompletionContext_StructTag) { + fprintf(file, "Struct tag\n"); + } + if (contexts & CXCompletionContext_ClassTag) { + fprintf(file, "Class name\n"); + } + if (contexts & CXCompletionContext_Namespace) { + fprintf(file, "Namespace or namespace alias\n"); + } + if (contexts & CXCompletionContext_NestedNameSpecifier) { + fprintf(file, "Nested name specifier\n"); + } + if (contexts & CXCompletionContext_ObjCInterface) { + fprintf(file, "Objective-C interface\n"); + } + if (contexts & CXCompletionContext_ObjCProtocol) { + fprintf(file, "Objective-C protocol\n"); + } + if (contexts & CXCompletionContext_ObjCCategory) { + fprintf(file, "Objective-C category\n"); + } + if (contexts & CXCompletionContext_ObjCInstanceMessage) { + fprintf(file, "Objective-C instance method\n"); + } + if (contexts & CXCompletionContext_ObjCClassMessage) { + fprintf(file, "Objective-C class method\n"); + } + if (contexts & CXCompletionContext_ObjCSelectorName) { + fprintf(file, "Objective-C selector name\n"); + } + if (contexts & CXCompletionContext_MacroName) { + fprintf(file, "Macro name\n"); + } + if (contexts & CXCompletionContext_NaturalLanguage) { + fprintf(file, "Natural language\n"); + } +} + int my_stricmp(const char *s1, const char *s2) { while (*s1 && *s2) { int c1 = tolower((unsigned char)*s1), c2 = tolower((unsigned char)*s2); @@ -1099,6 +1172,7 @@ int perform_code_completion(int argc, const char **argv, int timing_only) { if (results) { unsigned i, n = results->NumResults; + unsigned long long contexts; if (!timing_only) { /* Sort the code-completion results based on the typed text. */ clang_sortCodeCompletionResults(results->Results, results->NumResults); @@ -1112,6 +1186,10 @@ int perform_code_completion(int argc, const char **argv, int timing_only) { PrintDiagnostic(diag); clang_disposeDiagnostic(diag); } + + contexts = clang_codeCompleteGetContexts(results); + print_completion_contexts(contexts, stdout); + clang_disposeCodeCompleteResults(results); } clang_disposeTranslationUnit(TU); @@ -1496,6 +1574,7 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) { CXTranslationUnit TU; struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; + int result = 0; Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnosics=*/1); @@ -1517,12 +1596,34 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) { return 1; } - if (clang_saveTranslationUnit(TU, filename, clang_defaultSaveOptions(TU))) - fprintf(stderr, "Unable to write PCH file %s\n", filename); + switch (clang_saveTranslationUnit(TU, filename, + clang_defaultSaveOptions(TU))) { + case CXSaveError_None: + break; + + case CXSaveError_TranslationErrors: + fprintf(stderr, "Unable to write PCH file %s: translation errors\n", + filename); + result = 2; + break; + + case CXSaveError_InvalidTU: + fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n", + filename); + result = 3; + break; + + case CXSaveError_Unknown: + default: + fprintf(stderr, "Unable to write PCH file %s: unknown error \n", filename); + result = 1; + break; + } + clang_disposeTranslationUnit(TU); free_remapped_files(unsaved_files, num_unsaved_files); clang_disposeIndex(Idx); - return 0; + return result; } /******************************************************************************/ diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 0c41490..e6d0f1a 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 abe7098..1ba8bc2 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/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index 535eaa9..9ad4af1 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -126,6 +126,8 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, // Initialize targets first, so that --version shows registered targets. llvm::InitializeAllTargets(); + llvm::InitializeAllMCAsmInfos(); + llvm::InitializeAllMCSubtargetInfos(); llvm::InitializeAllAsmPrinters(); llvm::InitializeAllAsmParsers(); diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp index f449235..358d746 100644 --- a/tools/driver/cc1as_main.cpp +++ b/tools/driver/cc1as_main.cpp @@ -29,7 +29,9 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/ErrorHandling.h" @@ -47,11 +49,13 @@ #include "llvm/Target/TargetAsmInfo.h" #include "llvm/Target/TargetAsmParser.h" #include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetSelect.h" +#include "llvm/Target/TargetSubtargetInfo.h" using namespace clang; using namespace clang::driver; using namespace llvm; @@ -252,7 +256,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) { // it later. SrcMgr.setIncludeDirs(Opts.IncludePaths); - OwningPtr<MCAsmInfo> MAI(TheTarget->createAsmInfo(Opts.Triple)); + OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(Opts.Triple)); assert(MAI && "Unable to create target asm info!"); bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj; @@ -261,7 +265,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) { return false; // FIXME: We shouldn't need to do this (and link in codegen). - OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(Opts.Triple, "")); + OwningPtr<TargetMachine> TM(TheTarget->createTargetMachine(Opts.Triple, + "", "")); if (!TM) { Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; return false; @@ -278,14 +283,16 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) { TM->getTargetLowering()->getObjFileLowering(); const_cast<TargetLoweringObjectFile&>(TLOF).Initialize(Ctx, *TM); + const MCSubtargetInfo &STI = TM->getSubtarget<MCSubtargetInfo>(); + // FIXME: There is a bit of code duplication with addPassesToEmitFile. if (Opts.OutputType == AssemblerInvocation::FT_Asm) { MCInstPrinter *IP = - TheTarget->createMCInstPrinter(*TM, Opts.OutputAsmVariant, *MAI); + TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI); MCCodeEmitter *CE = 0; TargetAsmBackend *TAB = 0; if (Opts.ShowEncoding) { - CE = TheTarget->createCodeEmitter(*TM, Ctx); + CE = TheTarget->createCodeEmitter(*TM->getInstrInfo(), STI, Ctx); TAB = TheTarget->createAsmBackend(Opts.Triple); } Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true, @@ -297,7 +304,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) { } else { assert(Opts.OutputType == AssemblerInvocation::FT_Obj && "Invalid file type!"); - MCCodeEmitter *CE = TheTarget->createCodeEmitter(*TM, Ctx); + MCCodeEmitter *CE = TheTarget->createCodeEmitter(*TM->getInstrInfo(), + STI, Ctx); TargetAsmBackend *TAB = TheTarget->createAsmBackend(Opts.Triple); Str.reset(TheTarget->createObjectStreamer(Opts.Triple, Ctx, *TAB, *Out, CE, Opts.RelaxAll, @@ -307,7 +315,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) { OwningPtr<MCAsmParser> Parser(createMCAsmParser(*TheTarget, SrcMgr, Ctx, *Str.get(), *MAI)); - OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(*Parser, *TM)); + OwningPtr<TargetAsmParser> + TAP(TheTarget->createAsmParser(const_cast<MCSubtargetInfo&>(STI), *Parser)); if (!TAP) { Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; return false; @@ -347,6 +356,9 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd, InitializeAllTargetInfos(); // FIXME: We shouldn't need to initialize the Target(Machine)s. InitializeAllTargets(); + InitializeAllMCAsmInfos(); + InitializeAllMCInstrInfos(); + InitializeAllMCSubtargetInfos(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index db72da4..ca89826 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -327,9 +327,11 @@ static void ParseProgName(llvm::SmallVectorImpl<const char *> &ArgVector, std::string IgnoredError; if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) { - ArgVector.insert(&ArgVector[1], - SaveStringInSet(SavedStrings, Prefix)); - ArgVector.insert(&ArgVector[1], + llvm::SmallVectorImpl<const char *>::iterator it = ArgVector.begin(); + if (it != ArgVector.end()) + ++it; + ArgVector.insert(it, SaveStringInSet(SavedStrings, Prefix)); + ArgVector.insert(it, SaveStringInSet(SavedStrings, std::string("-ccc-host-triple"))); } } diff --git a/tools/libclang/ARCMigrate.cpp b/tools/libclang/ARCMigrate.cpp new file mode 100644 index 0000000..39c7d84 --- /dev/null +++ b/tools/libclang/ARCMigrate.cpp @@ -0,0 +1,98 @@ +//===- ARCMigrate.cpp - Clang-C ARC Migration Library ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the main API hooks in the Clang-C ARC Migration library. +// +//===----------------------------------------------------------------------===// + +#include "clang-c/Index.h" + +#include "CXString.h" +#include "clang/ARCMigrate/ARCMT.h" +#include "clang/Frontend/TextDiagnosticBuffer.h" +#include "llvm/Support/FileSystem.h" + +using namespace clang; +using namespace arcmt; + +namespace { + +struct Remap { + std::vector<std::pair<std::string, std::string> > Vec; +}; + +} // anonymous namespace. + +//===----------------------------------------------------------------------===// +// libClang public APIs. +//===----------------------------------------------------------------------===// + +extern "C" { + +CXRemapping clang_getRemappings(const char *migrate_dir_path) { + bool Logging = ::getenv("LIBCLANG_LOGGING"); + + if (!migrate_dir_path) { + if (Logging) + llvm::errs() << "clang_getRemappings was called with NULL parameter\n"; + return 0; + } + + bool exists = false; + llvm::sys::fs::exists(migrate_dir_path, exists); + if (!exists) { + if (Logging) { + llvm::errs() << "Error by clang_getRemappings(\"" << migrate_dir_path + << "\")\n"; + llvm::errs() << "\"" << migrate_dir_path << "\" does not exist\n"; + } + return 0; + } + + TextDiagnosticBuffer diagBuffer; + llvm::OwningPtr<Remap> remap(new Remap()); + + bool err = arcmt::getFileRemappings(remap->Vec, migrate_dir_path,&diagBuffer); + + if (err) { + if (Logging) { + llvm::errs() << "Error by clang_getRemappings(\"" << migrate_dir_path + << "\")\n"; + for (TextDiagnosticBuffer::const_iterator + I = diagBuffer.err_begin(), E = diagBuffer.err_end(); I != E; ++I) + llvm::errs() << I->second << '\n'; + } + return 0; + } + + return remap.take(); +} + +unsigned clang_remap_getNumFiles(CXRemapping map) { + return static_cast<Remap *>(map)->Vec.size(); + +} + +void clang_remap_getFilenames(CXRemapping map, unsigned index, + CXString *original, CXString *transformed) { + if (original) + *original = cxstring::createCXString( + static_cast<Remap *>(map)->Vec[index].first, + /*DupString =*/ true); + if (transformed) + *transformed = cxstring::createCXString( + static_cast<Remap *>(map)->Vec[index].second, + /*DupString =*/ true); +} + +void clang_remap_dispose(CXRemapping map) { + delete static_cast<Remap *>(map); +} + +} // end: extern "C" diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 2a9d96d..50d56fc 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -544,8 +544,8 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { // do so. PreprocessingRecord::iterator E, EEnd; for (llvm::tie(E, EEnd) = getPreprocessedEntities(); E != EEnd; ++E) { - if (MacroInstantiation *MI = dyn_cast<MacroInstantiation>(*E)) { - if (Visit(MakeMacroInstantiationCursor(MI, tu))) + if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*E)) { + if (Visit(MakeMacroExpansionCursor(ME, tu))) return true; continue; @@ -1330,6 +1330,11 @@ bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) { return Visit(MakeCursorTemplateRef( Name.getAsQualifiedTemplateName()->getDecl(), Loc, TU)); + + case TemplateName::SubstTemplateTemplateParm: + return Visit(MakeCursorTemplateRef( + Name.getAsSubstTemplateTemplateParm()->getParameter(), + Loc, TU)); case TemplateName::SubstTemplateTemplateParmPack: return Visit(MakeCursorTemplateRef( @@ -2374,7 +2379,8 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, unsigned clang_defaultEditingTranslationUnitOptions() { return CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_CacheCompletionResults | - CXTranslationUnit_CXXPrecompiledPreamble; + CXTranslationUnit_CXXPrecompiledPreamble | + CXTranslationUnit_CXXChainedPCH; } CXTranslationUnit @@ -2385,7 +2391,7 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, unsigned num_unsaved_files, struct CXUnsavedFile *unsaved_files) { unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord | - CXTranslationUnit_NestedMacroInstantiations; + CXTranslationUnit_NestedMacroExpansions; return clang_parseTranslationUnit(CIdx, source_filename, command_line_args, num_command_line_args, unsaved_files, num_unsaved_files, @@ -2490,12 +2496,12 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { Args->push_back(source_filename); // Do we need the detailed preprocessing record? - bool NestedMacroInstantiations = false; + bool NestedMacroExpansions = false; if (options & CXTranslationUnit_DetailedPreprocessingRecord) { Args->push_back("-Xclang"); Args->push_back("-detailed-preprocessing-record"); - NestedMacroInstantiations - = (options & CXTranslationUnit_NestedMacroInstantiations); + NestedMacroExpansions + = (options & CXTranslationUnit_NestedMacroExpansions); } unsigned NumErrors = Diags->getClient()->getNumErrors(); @@ -2515,7 +2521,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { CacheCodeCompetionResults, CXXPrecompilePreamble, CXXChainedPCH, - NestedMacroInstantiations)); + NestedMacroExpansions)); if (NumErrors != Diags->getClient()->getNumErrors()) { // Make sure to check that 'Unit' is non-NULL. @@ -2588,9 +2594,9 @@ unsigned clang_defaultSaveOptions(CXTranslationUnit TU) { int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName, unsigned options) { if (!TU) - return 1; + return CXSaveError_InvalidTU; - int result = static_cast<ASTUnit *>(TU->TUData)->Save(FileName); + CXSaveError result = static_cast<ASTUnit *>(TU->TUData)->Save(FileName); if (getenv("LIBCLANG_RESOURCE_USAGE")) PrintLibclangResourceUsage(TU); return result; @@ -2800,7 +2806,7 @@ void clang_getInstantiationLocation(CXSourceLocation location, *static_cast<const SourceManager*>(location.ptr_data[0]); SourceLocation InstLoc = SM.getInstantiationLoc(Loc); - // Check that the FileID is invalid on the instantiation location. + // Check that the FileID is invalid on the expansion location. // This can manifest in invalid code. FileID fileID = SM.getFileID(InstLoc); bool Invalid = false; @@ -3145,8 +3151,8 @@ CXString clang_getCursorSpelling(CXCursor C) { return createCXString(""); } - if (C.kind == CXCursor_MacroInstantiation) - return createCXString(getCursorMacroInstantiation(C)->getName() + if (C.kind == CXCursor_MacroExpansion) + return createCXString(getCursorMacroExpansion(C)->getName() ->getNameStart()); if (C.kind == CXCursor_MacroDefinition) @@ -3346,8 +3352,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("preprocessing directive"); case CXCursor_MacroDefinition: return createCXString("macro definition"); - case CXCursor_MacroInstantiation: - return createCXString("macro instantiation"); + case CXCursor_MacroExpansion: + return createCXString("macro expansion"); case CXCursor_InclusionDirective: return createCXString("inclusion directive"); case CXCursor_Namespace: @@ -3392,11 +3398,34 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString((const char*) 0); } +struct GetCursorData { + SourceLocation TokenBeginLoc; + CXCursor &BestCursor; + + GetCursorData(SourceLocation tokenBegin, CXCursor &outputCursor) + : TokenBeginLoc(tokenBegin), BestCursor(outputCursor) { } +}; + enum CXChildVisitResult GetCursorVisitor(CXCursor cursor, CXCursor parent, CXClientData client_data) { - CXCursor *BestCursor = static_cast<CXCursor *>(client_data); - + GetCursorData *Data = static_cast<GetCursorData *>(client_data); + CXCursor *BestCursor = &Data->BestCursor; + + if (clang_isExpression(cursor.kind) && + clang_isDeclaration(BestCursor->kind)) { + Decl *D = getCursorDecl(*BestCursor); + + // Avoid having the cursor of an expression replace the declaration cursor + // when the expression source range overlaps the declaration range. + // This can happen for C++ constructor expressions whose range generally + // include the variable declaration, e.g.: + // MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl cursor. + if (D->getLocation().isValid() && Data->TokenBeginLoc.isValid() && + D->getLocation() == Data->TokenBeginLoc) + return CXChildVisit_Break; + } + // If our current best cursor is the construction of a temporary object, // don't replace that cursor with a type reference, because we want // clang_getCursor() to point at the constructor. @@ -3440,8 +3469,9 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { // FIXME: Would be great to have a "hint" cursor, then walk from that // hint cursor upward until we find a cursor whose source range encloses // the region of interest, rather than starting from the translation unit. + GetCursorData ResultData(SLoc, Result); CXCursor Parent = clang_getTranslationUnitCursor(TU); - CursorVisitor CursorVis(TU, GetCursorVisitor, &Result, + CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData, Decl::MaxPCHLevel, true, SourceLocation(SLoc)); CursorVis.VisitChildren(Parent); } @@ -3532,6 +3562,10 @@ unsigned clang_isStatement(enum CXCursorKind K) { return K >= CXCursor_FirstStmt && K <= CXCursor_LastStmt; } +unsigned clang_isAttribute(enum CXCursorKind K) { + return K >= CXCursor_FirstAttr && K <= CXCursor_LastAttr; +} + unsigned clang_isTranslationUnit(enum CXCursorKind K) { return K == CXCursor_TranslationUnit; } @@ -3638,9 +3672,9 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { return cxloc::translateSourceLocation(getCursorContext(C), L); } - if (C.kind == CXCursor_MacroInstantiation) { + if (C.kind == CXCursor_MacroExpansion) { SourceLocation L - = cxcursor::getCursorMacroInstantiation(C)->getSourceRange().getBegin(); + = cxcursor::getCursorMacroExpansion(C)->getSourceRange().getBegin(); return cxloc::translateSourceLocation(getCursorContext(C), L); } @@ -3725,8 +3759,8 @@ static SourceRange getRawCursorExtent(CXCursor C) { if (C.kind == CXCursor_PreprocessingDirective) return cxcursor::getCursorPreprocessingDirective(C); - if (C.kind == CXCursor_MacroInstantiation) - return cxcursor::getCursorMacroInstantiation(C)->getSourceRange(); + if (C.kind == CXCursor_MacroExpansion) + return cxcursor::getCursorMacroExpansion(C)->getSourceRange(); if (C.kind == CXCursor_MacroDefinition) return cxcursor::getCursorMacroDefinition(C)->getSourceRange(); @@ -3842,8 +3876,8 @@ CXCursor clang_getCursorReferenced(CXCursor C) { return clang_getNullCursor(); } - if (C.kind == CXCursor_MacroInstantiation) { - if (MacroDefinition *Def = getCursorMacroInstantiation(C)->getDefinition()) + if (C.kind == CXCursor_MacroExpansion) { + if (MacroDefinition *Def = getCursorMacroExpansion(C)->getDefinition()) return MakeMacroDefinitionCursor(Def, tu); } @@ -3911,7 +3945,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { WasReference = true; } - if (C.kind == CXCursor_MacroInstantiation) + if (C.kind == CXCursor_MacroExpansion) return clang_getCursorReferenced(C); if (!clang_isDeclaration(C.kind)) @@ -4107,8 +4141,17 @@ CXCursor clang_getCanonicalCursor(CXCursor C) { if (!clang_isDeclaration(C.kind)) return C; - if (Decl *D = getCursorDecl(C)) + if (Decl *D = getCursorDecl(C)) { + if (ObjCCategoryImplDecl *CatImplD = dyn_cast<ObjCCategoryImplDecl>(D)) + if (ObjCCategoryDecl *CatD = CatImplD->getCategoryDecl()) + return MakeCXCursor(CatD, getCursorTU(C)); + + if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + return MakeCXCursor(IFD, getCursorTU(C)); + return MakeCXCursor(D->getCanonicalDecl(), getCursorTU(C)); + } return C; } @@ -4507,9 +4550,9 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { } if (clang_isPreprocessing(cursor.kind)) { - // For macro instantiations, just note where the beginning of the macro - // instantiation occurs. - if (cursor.kind == CXCursor_MacroInstantiation) { + // For macro expansions, just note where the beginning of the macro + // expansion occurs. + if (cursor.kind == CXCursor_MacroExpansion) { Annotated[Loc.int_data] = cursor; return CXChildVisit_Recurse; } @@ -4626,6 +4669,24 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { break; } + // Avoid having the cursor of an expression "overwrite" the annotation of the + // variable declaration that it belongs to. + // This can happen for C++ constructor expressions whose range generally + // include the variable declaration, e.g.: + // MyCXXClass foo; // Make sure we don't annotate 'foo' as a CallExpr cursor. + if (clang_isExpression(cursorK)) { + Expr *E = getCursorExpr(cursor); + if (Decl *D = getCursorParentDecl(cursor)) { + const unsigned I = NextToken(); + if (E->getLocStart().isValid() && D->getLocation().isValid() && + E->getLocStart() == D->getLocation() && + E->getLocStart() == GetTokenLoc(I)) { + Cursors[I] = updateC; + AdvanceToken(); + } + } + } + // Visit children to get their cursor information. const unsigned BeforeChildren = NextToken(); VisitChildren(cursor); @@ -4797,6 +4858,7 @@ static void clang_annotateTokensImpl(void *UserData) { llvm::StringSwitch<bool>(II->getName()) .Case("readonly", true) .Case("assign", true) + .Case("unsafe_unretained", true) .Case("readwrite", true) .Case("retain", true) .Case("copy", true) @@ -4804,6 +4866,8 @@ static void clang_annotateTokensImpl(void *UserData) { .Case("atomic", true) .Case("getter", true) .Case("setter", true) + .Case("strong", true) + .Case("weak", true) .Default(false)) Tokens[I].int_data[0] = CXToken_Keyword; } @@ -5354,10 +5418,9 @@ CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) { // How much memory is being used by the Preprocessor? Preprocessor &pp = astUnit->getPreprocessor(); - const llvm::BumpPtrAllocator &ppAlloc = pp.getPreprocessorAllocator(); createCXTUResourceUsageEntry(*entries, CXTUResourceUsage_Preprocessor, - ppAlloc.getTotalMemory()); + pp.getTotalMemory()); if (PreprocessingRecord *pRec = pp.getPreprocessingRecord()) { createCXTUResourceUsageEntry(*entries, diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index 0c8317e..832e2f2 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -235,6 +235,13 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { /// \brief Allocator used to store code completion results. clang::CodeCompletionAllocator CodeCompletionAllocator; + + /// \brief Context under which completion occurred. + enum clang::CodeCompletionContext::Kind ContextKind; + + /// \brief A bitfield representing the acceptable completions for the + /// current context. + unsigned long long Contexts; }; /// \brief Tracks the number of code-completion result objects that are @@ -273,6 +280,177 @@ AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { } // end extern "C" +static unsigned long long getContextsForContextKind( + enum CodeCompletionContext::Kind kind, + Sema &S) { + unsigned long long contexts = 0; + switch (kind) { + case CodeCompletionContext::CCC_OtherWithMacros: { + //We can allow macros here, but we don't know what else is permissible + //So we'll say the only thing permissible are macros + contexts = CXCompletionContext_MacroName; + break; + } + case CodeCompletionContext::CCC_TopLevel: + case CodeCompletionContext::CCC_ObjCIvarList: + case CodeCompletionContext::CCC_ClassStructUnion: + case CodeCompletionContext::CCC_Type: { + contexts = CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface; + if (S.getLangOptions().CPlusPlus) { + contexts |= CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_Statement: { + contexts = CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface | + CXCompletionContext_AnyValue; + if (S.getLangOptions().CPlusPlus) { + contexts |= CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_Expression: { + contexts = CXCompletionContext_AnyValue; + if (S.getLangOptions().CPlusPlus) { + contexts |= CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface | + CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_ObjCMessageReceiver: { + contexts = CXCompletionContext_ObjCObjectValue | + CXCompletionContext_ObjCSelectorValue | + CXCompletionContext_ObjCInterface; + if (S.getLangOptions().CPlusPlus) { + contexts |= CXCompletionContext_CXXClassTypeValue | + CXCompletionContext_AnyType | + CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_DotMemberAccess: { + contexts = CXCompletionContext_DotMemberAccess; + break; + } + case CodeCompletionContext::CCC_ArrowMemberAccess: { + contexts = CXCompletionContext_ArrowMemberAccess; + break; + } + case CodeCompletionContext::CCC_ObjCPropertyAccess: { + contexts = CXCompletionContext_ObjCPropertyAccess; + break; + } + case CodeCompletionContext::CCC_EnumTag: { + contexts = CXCompletionContext_EnumTag | + CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_UnionTag: { + contexts = CXCompletionContext_UnionTag | + CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_ClassOrStructTag: { + contexts = CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_ObjCProtocolName: { + contexts = CXCompletionContext_ObjCProtocol; + break; + } + case CodeCompletionContext::CCC_Namespace: { + contexts = CXCompletionContext_Namespace; + break; + } + case CodeCompletionContext::CCC_PotentiallyQualifiedName: { + contexts = CXCompletionContext_NestedNameSpecifier; + break; + } + case CodeCompletionContext::CCC_MacroNameUse: { + contexts = CXCompletionContext_MacroName; + break; + } + case CodeCompletionContext::CCC_NaturalLanguage: { + contexts = CXCompletionContext_NaturalLanguage; + break; + } + case CodeCompletionContext::CCC_SelectorName: { + contexts = CXCompletionContext_ObjCSelectorName; + break; + } + case CodeCompletionContext::CCC_ParenthesizedExpression: { + contexts = CXCompletionContext_AnyType | + CXCompletionContext_ObjCInterface | + CXCompletionContext_AnyValue; + if (S.getLangOptions().CPlusPlus) { + contexts |= CXCompletionContext_EnumTag | + CXCompletionContext_UnionTag | + CXCompletionContext_StructTag | + CXCompletionContext_ClassTag | + CXCompletionContext_NestedNameSpecifier; + } + break; + } + case CodeCompletionContext::CCC_ObjCInstanceMessage: { + contexts = CXCompletionContext_ObjCInstanceMessage; + break; + } + case CodeCompletionContext::CCC_ObjCClassMessage: { + contexts = CXCompletionContext_ObjCClassMessage; + break; + } + case CodeCompletionContext::CCC_ObjCSuperclass: { + contexts = CXCompletionContext_ObjCInterface; + break; + } + case CodeCompletionContext::CCC_ObjCCategoryName: { + contexts = CXCompletionContext_ObjCCategory; + break; + } + case CodeCompletionContext::CCC_Other: + case CodeCompletionContext::CCC_ObjCInterface: + case CodeCompletionContext::CCC_ObjCImplementation: + case CodeCompletionContext::CCC_Name: + case CodeCompletionContext::CCC_MacroName: + case CodeCompletionContext::CCC_PreprocessorExpression: + case CodeCompletionContext::CCC_PreprocessorDirective: + case CodeCompletionContext::CCC_TypeQualifiers: { + //Only Clang results should be accepted, so we'll set all of the other + //context bits to 0 (i.e. the empty set) + contexts = CXCompletionContext_Unexposed; + break; + } + case CodeCompletionContext::CCC_Recovery: { + //We don't know what the current context is, so we'll return unknown + //This is the equivalent of setting all of the other context bits + contexts = CXCompletionContext_Unknown; + break; + } + } + return contexts; +} + namespace { class CaptureCompletionResults : public CodeCompleteConsumer { AllocatedCXCodeCompleteResults &AllocatedResults; @@ -298,6 +476,11 @@ namespace { R.CompletionString = StoredCompletion; StoredResults.push_back(R); } + + enum CodeCompletionContext::Kind kind = Context.getKind(); + + AllocatedResults.ContextKind = kind; + AllocatedResults.Contexts = getContextsForContextKind(kind, S); } virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, @@ -538,6 +721,15 @@ clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn, return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts); } +unsigned long long +clang_codeCompleteGetContexts(CXCodeCompleteResults *ResultsIn) { + AllocatedCXCodeCompleteResults *Results + = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); + if (!Results) + return 0; + + return Results->Contexts; +} } // end extern "C" diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index 7a6270d..f45389f 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -1,4 +1,6 @@ set(LLVM_USED_LIBS + clangARCMigrate + clangRewrite clangFrontend clangDriver clangSerialization @@ -14,6 +16,7 @@ set( LLVM_LINK_COMPONENTS ) set(SOURCES + ARCMigrate.cpp CIndex.cpp CIndexCXX.cpp CIndexCodeCompletion.cpp diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index b34370d..b3c57dc 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -92,6 +92,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::ObjCAtFinallyStmtClass: case Stmt::ObjCAtThrowStmtClass: case Stmt::ObjCAtSynchronizedStmtClass: + case Stmt::ObjCAutoreleasePoolStmtClass: case Stmt::ObjCForCollectionStmtClass: case Stmt::CXXCatchStmtClass: case Stmt::CXXTryStmtClass: @@ -99,6 +100,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::SEHTryStmtClass: case Stmt::SEHExceptStmtClass: case Stmt::SEHFinallyStmtClass: + case Stmt::MaterializeTemporaryExprClass: K = CXCursor_UnexposedStmt; break; @@ -167,7 +169,9 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::ObjCEncodeExprClass: case Stmt::ObjCSelectorExprClass: case Stmt::ObjCProtocolExprClass: - case Stmt::ObjCIsaExprClass: + case Stmt::ObjCIsaExprClass: + case Stmt::ObjCIndirectCopyRestoreExprClass: + case Stmt::ObjCBridgedCastExprClass: case Stmt::ShuffleVectorExprClass: case Stmt::BlockExprClass: case Stmt::OpaqueValueExprClass: @@ -179,6 +183,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::DeclRefExprClass: case Stmt::BlockDeclRefExprClass: + case Stmt::SubstNonTypeTemplateParmExprClass: case Stmt::SubstNonTypeTemplateParmPackExprClass: // FIXME: UnresolvedLookupExpr? // FIXME: DependentScopeDeclRefExpr? @@ -374,15 +379,15 @@ MacroDefinition *cxcursor::getCursorMacroDefinition(CXCursor C) { return static_cast<MacroDefinition *>(C.data[0]); } -CXCursor cxcursor::MakeMacroInstantiationCursor(MacroInstantiation *MI, - CXTranslationUnit TU) { - CXCursor C = { CXCursor_MacroInstantiation, { MI, 0, TU } }; +CXCursor cxcursor::MakeMacroExpansionCursor(MacroExpansion *MI, + CXTranslationUnit TU) { + CXCursor C = { CXCursor_MacroExpansion, { MI, 0, TU } }; return C; } -MacroInstantiation *cxcursor::getCursorMacroInstantiation(CXCursor C) { - assert(C.kind == CXCursor_MacroInstantiation); - return static_cast<MacroInstantiation *>(C.data[0]); +MacroExpansion *cxcursor::getCursorMacroExpansion(CXCursor C) { + assert(C.kind == CXCursor_MacroExpansion); + return static_cast<MacroExpansion *>(C.data[0]); } CXCursor cxcursor::MakeInclusionDirectiveCursor(InclusionDirective *ID, @@ -480,6 +485,10 @@ Attr *cxcursor::getCursorAttr(CXCursor Cursor) { return (Attr *)Cursor.data[1]; } +Decl *cxcursor::getCursorParentDecl(CXCursor Cursor) { + return (Decl *)Cursor.data[0]; +} + ASTContext &cxcursor::getCursorContext(CXCursor Cursor) { return getCursorASTUnit(Cursor)->getASTContext(); } diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h index 11f2500..68d09e7 100644 --- a/tools/libclang/CXCursor.h +++ b/tools/libclang/CXCursor.h @@ -31,7 +31,7 @@ class FieldDecl; class InclusionDirective; class LabelStmt; class MacroDefinition; -class MacroInstantiation; +class MacroExpansion; class NamedDecl; class ObjCInterfaceDecl; class ObjCProtocolDecl; @@ -134,13 +134,13 @@ CXCursor MakeMacroDefinitionCursor(MacroDefinition *, CXTranslationUnit TU); /// source range. MacroDefinition *getCursorMacroDefinition(CXCursor C); -/// \brief Create a macro instantiation cursor. -CXCursor MakeMacroInstantiationCursor(MacroInstantiation *, - CXTranslationUnit TU); +/// \brief Create a macro expansion cursor. +CXCursor MakeMacroExpansionCursor(MacroExpansion *, + CXTranslationUnit TU); -/// \brief Unpack a given macro instantiation cursor to retrieve its +/// \brief Unpack a given macro expansion cursor to retrieve its /// source range. -MacroInstantiation *getCursorMacroInstantiation(CXCursor C); +MacroExpansion *getCursorMacroExpansion(CXCursor C); /// \brief Create an inclusion directive cursor. CXCursor MakeInclusionDirectiveCursor(InclusionDirective *, @@ -184,6 +184,7 @@ Decl *getCursorDecl(CXCursor Cursor); Expr *getCursorExpr(CXCursor Cursor); Stmt *getCursorStmt(CXCursor Cursor); Attr *getCursorAttr(CXCursor Cursor); +Decl *getCursorParentDecl(CXCursor Cursor); ASTContext &getCursorContext(CXCursor Cursor); ASTUnit *getCursorASTUnit(CXCursor Cursor); diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp index 5af9553..45c7346 100644 --- a/tools/libclang/CXType.cpp +++ b/tools/libclang/CXType.cpp @@ -366,7 +366,11 @@ unsigned clang_isPODType(CXType X) { QualType T = GetQualType(X); if (!T.getTypePtrOrNull()) return 0; - return T->isPODType() ? 1 : 0; + + CXTranslationUnit TU = GetTU(X); + ASTUnit *AU = static_cast<ASTUnit*>(TU->TUData); + + return T.isPODType(AU->getASTContext()) ? 1 : 0; } CXString clang_getDeclObjCTypeEncoding(CXCursor C) { diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile index e684652..375f7f2 100644 --- a/tools/libclang/Makefile +++ b/tools/libclang/Makefile @@ -16,8 +16,9 @@ LINK_LIBS_IN_SHARED = 1 SHARED_LIBRARY = 1 LINK_COMPONENTS := support mc -USEDLIBS = clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \ - clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a +USEDLIBS = 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/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports index 85dfcb6..bfc5be9 100644 --- a/tools/libclang/libclang.darwin.exports +++ b/tools/libclang/libclang.darwin.exports @@ -6,6 +6,7 @@ _clang_annotateTokens _clang_codeCompleteAt _clang_codeCompleteGetDiagnostic _clang_codeCompleteGetNumDiagnostics +_clang_codeCompleteGetContexts _clang_constructUSR_ObjCCategory _clang_constructUSR_ObjCClass _clang_constructUSR_ObjCIvar @@ -112,6 +113,7 @@ _clang_getTranslationUnitSpelling _clang_getTypeDeclaration _clang_getTypeKindSpelling _clang_hashCursor +_clang_isAttribute _clang_isConstQualifiedType _clang_isCursorDefinition _clang_isDeclaration @@ -135,3 +137,7 @@ _clang_toggleCrashRecovery _clang_tokenize _clang_visitChildren _clang_visitChildrenWithBlock +_clang_getRemappings +_clang_remap_getNumFiles +_clang_remap_getFilenames +_clang_remap_dispose diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 403cd67..47b7030 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -6,6 +6,7 @@ clang_annotateTokens clang_codeCompleteAt clang_codeCompleteGetDiagnostic clang_codeCompleteGetNumDiagnostics +clang_codeCompleteGetContexts clang_constructUSR_ObjCCategory clang_constructUSR_ObjCClass clang_constructUSR_ObjCIvar @@ -112,6 +113,7 @@ clang_getTranslationUnitSpelling clang_getTypeDeclaration clang_getTypeKindSpelling clang_hashCursor +clang_isAttribute clang_isConstQualifiedType clang_isCursorDefinition clang_isDeclaration @@ -135,3 +137,7 @@ clang_toggleCrashRecovery clang_tokenize clang_visitChildren clang_visitChildrenWithBlock +clang_getRemappings +clang_remap_getNumFiles +clang_remap_getFilenames +clang_remap_dispose diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer index 7793a8d..5697b21 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; |