diff options
author | dim <dim@FreeBSD.org> | 2010-09-17 15:54:40 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2010-09-17 15:54:40 +0000 |
commit | 36c49e3f258dced101949edabd72e9bc3f1dedc4 (patch) | |
tree | 0bbe07708f7571f8b5291f6d7b96c102b7c99dee /tools | |
parent | fc84956ac8b7cd244ef30e7a4d4d38a58dec5904 (diff) | |
download | FreeBSD-src-36c49e3f258dced101949edabd72e9bc3f1dedc4.zip FreeBSD-src-36c49e3f258dced101949edabd72e9bc3f1dedc4.tar.gz |
Vendor import of clang r114020 (from the release_28 branch):
http://llvm.org/svn/llvm-project/cfe/branches/release_28@114020
Approved by: rpaulo (mentor)
Diffstat (limited to 'tools')
-rw-r--r-- | tools/c-index-test/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tools/c-index-test/Makefile | 5 | ||||
-rw-r--r-- | tools/c-index-test/c-index-test.c | 268 | ||||
-rw-r--r-- | tools/driver/CMakeLists.txt | 5 | ||||
-rw-r--r-- | tools/driver/Info.plist.in | 18 | ||||
-rw-r--r-- | tools/driver/Makefile | 33 | ||||
-rw-r--r-- | tools/driver/cc1_main.cpp | 149 | ||||
-rw-r--r-- | tools/driver/cc1as_main.cpp | 41 | ||||
-rw-r--r-- | tools/driver/driver.cpp | 160 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 1131 | ||||
-rw-r--r-- | tools/libclang/CIndexCXX.cpp | 124 | ||||
-rw-r--r-- | tools/libclang/CIndexCodeCompletion.cpp | 306 | ||||
-rw-r--r-- | tools/libclang/CIndexDiagnostic.cpp | 27 | ||||
-rw-r--r-- | tools/libclang/CIndexUSRs.cpp | 237 | ||||
-rw-r--r-- | tools/libclang/CMakeLists.txt | 27 | ||||
-rw-r--r-- | tools/libclang/CXCursor.cpp | 98 | ||||
-rw-r--r-- | tools/libclang/CXCursor.h | 28 | ||||
-rw-r--r-- | tools/libclang/CXType.cpp (renamed from tools/libclang/CXTypes.cpp) | 13 | ||||
-rw-r--r-- | tools/libclang/CXType.h | 29 | ||||
-rw-r--r-- | tools/libclang/Makefile | 26 | ||||
-rw-r--r-- | tools/libclang/libclang.darwin.exports | 19 | ||||
-rw-r--r-- | tools/libclang/libclang.exports | 19 |
22 files changed, 2307 insertions, 459 deletions
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt index d965fd2..5cf2cd6 100644 --- a/tools/c-index-test/CMakeLists.txt +++ b/tools/c-index-test/CMakeLists.txt @@ -5,10 +5,11 @@ set( LLVM_USED_LIBS clangIndex clangFrontend clangDriver + clangSerialization + clangParse clangSema clangAnalysis clangAST - clangParse clangLex clangBasic ) diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile index d168df5..f41aa80 100644 --- a/tools/c-index-test/Makefile +++ b/tools/c-index-test/Makefile @@ -14,7 +14,8 @@ TOOLNAME = c-index-test TOOL_NO_EXPORTS = 1 LINK_COMPONENTS := bitreader mc core -USEDLIBS = clang.a clangIndex.a clangFrontend.a clangDriver.a clangSema.a \ - clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a +USEDLIBS = clang.a clangIndex.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-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 4ed24b1..58eff97 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -1,6 +1,7 @@ /* c-index-test.c */ #include "clang-c/Index.h" +#include <ctype.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -28,6 +29,18 @@ char *basename(const char* path) extern char *basename(const char *); #endif +/** \brief Return the default parsing options. */ +static unsigned getDefaultParsingOptions() { + unsigned options = CXTranslationUnit_DetailedPreprocessingRecord; + + if (getenv("CINDEXTEST_EDITING")) + options |= clang_defaultEditingTranslationUnitOptions(); + if (getenv("CINDEXTEST_COMPLETION_CACHING")) + options |= CXTranslationUnit_CacheCompletionResults; + + return options; +} + static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column, unsigned end_line, unsigned end_column) { fprintf(out, "[%d:%d - %d:%d]", begin_line, begin_column, @@ -38,7 +51,7 @@ static unsigned CreateTranslationUnit(CXIndex Idx, const char *file, CXTranslationUnit *TU) { *TU = clang_createTranslationUnit(Idx, file); - if (!TU) { + if (!*TU) { fprintf(stderr, "Unable to load translation unit from '%s'!\n", file); return 0; } @@ -52,6 +65,7 @@ void free_remapped_files(struct CXUnsavedFile *unsaved_files, free((char *)unsaved_files[i].Filename); free((char *)unsaved_files[i].Contents); } + free(unsaved_files); } int parse_remapped_files(int argc, const char **argv, int start_arg, @@ -75,8 +89,8 @@ int parse_remapped_files(int argc, const char **argv, int start_arg, return 0; *unsaved_files - = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) * - *num_unsaved_files); + = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) * + *num_unsaved_files); for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) { struct CXUnsavedFile *unsaved = *unsaved_files + i; const char *arg_string = argv[arg] + prefix_len; @@ -152,7 +166,8 @@ static void PrintCursor(CXCursor Cursor) { CXString string, ks; CXCursor Referenced; unsigned line, column; - + CXCursor SpecializationOf; + ks = clang_getCursorKindSpelling(Cursor.kind); string = clang_getCursorSpelling(Cursor); printf("%s=%s", clang_getCString(ks), @@ -169,6 +184,57 @@ static void PrintCursor(CXCursor Cursor) { if (clang_isCursorDefinition(Cursor)) printf(" (Definition)"); + + switch (clang_getCursorAvailability(Cursor)) { + case CXAvailability_Available: + break; + + case CXAvailability_Deprecated: + printf(" (deprecated)"); + break; + + case CXAvailability_NotAvailable: + printf(" (unavailable)"); + break; + } + + if (Cursor.kind == CXCursor_IBOutletCollectionAttr) { + CXType T = + clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor)); + CXString S = clang_getTypeKindSpelling(T.kind); + printf(" [IBOutletCollection=%s]", clang_getCString(S)); + clang_disposeString(S); + } + + if (Cursor.kind == CXCursor_CXXBaseSpecifier) { + enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor); + unsigned isVirtual = clang_isVirtualBase(Cursor); + const char *accessStr = 0; + + switch (access) { + case CX_CXXInvalidAccessSpecifier: + accessStr = "invalid"; break; + case CX_CXXPublic: + accessStr = "public"; break; + case CX_CXXProtected: + accessStr = "protected"; break; + case CX_CXXPrivate: + accessStr = "private"; break; + } + + printf(" [access=%s isVirtual=%s]", accessStr, + isVirtual ? "true" : "false"); + } + + SpecializationOf = clang_getSpecializedCursorTemplate(Cursor); + if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) { + CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf); + CXString Name = clang_getCursorSpelling(SpecializationOf); + clang_getInstantiationLocation(Loc, 0, &line, &column, 0); + printf(" [Specialization of %s:%d:%d]", + clang_getCString(Name), line, column); + clang_disposeString(Name); + } } } @@ -477,6 +543,8 @@ static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p, clang_disposeString(RS); } } + /* Print if this is a non-POD type. */ + printf(" [isPOD=%d]", clang_isPODType(T)); printf("\n"); } @@ -558,7 +626,7 @@ int perform_test_load_source(int argc, const char **argv, struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; int result; - + Idx = clang_createIndex(/* excludeDeclsFromPCH */ !strcmp(filter, "local") ? 1 : 0, /* displayDiagnosics=*/1); @@ -578,6 +646,7 @@ int perform_test_load_source(int argc, const char **argv, unsaved_files); if (!TU) { fprintf(stderr, "Unable to load translation unit!\n"); + free_remapped_files(unsaved_files, num_unsaved_files); clang_disposeIndex(Idx); return 1; } @@ -588,6 +657,60 @@ int perform_test_load_source(int argc, const char **argv, return result; } +int perform_test_reparse_source(int argc, const char **argv, int trials, + const char *filter, CXCursorVisitor Visitor, + PostVisitTU PV) { + const char *UseExternalASTs = + getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION"); + CXIndex Idx; + CXTranslationUnit TU; + struct CXUnsavedFile *unsaved_files = 0; + int num_unsaved_files = 0; + int result; + int trial; + + Idx = clang_createIndex(/* excludeDeclsFromPCH */ + !strcmp(filter, "local") ? 1 : 0, + /* displayDiagnosics=*/1); + + if (UseExternalASTs && strlen(UseExternalASTs)) + clang_setUseExternalASTGeneration(Idx, 1); + + if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) { + clang_disposeIndex(Idx); + return -1; + } + + /* Load the initial translation unit -- we do this without honoring remapped + * files, so that we have a way to test results after changing the source. */ + TU = clang_parseTranslationUnit(Idx, 0, + argv + num_unsaved_files, + argc - num_unsaved_files, + 0, 0, getDefaultParsingOptions()); + if (!TU) { + fprintf(stderr, "Unable to load translation unit!\n"); + free_remapped_files(unsaved_files, num_unsaved_files); + clang_disposeIndex(Idx); + return 1; + } + + for (trial = 0; trial < trials; ++trial) { + if (clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files, + clang_defaultReparseOptions(TU))) { + fprintf(stderr, "Unable to reparse translation unit!\n"); + clang_disposeTranslationUnit(TU); + free_remapped_files(unsaved_files, num_unsaved_files); + clang_disposeIndex(Idx); + return -1; + } + } + + result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV); + free_remapped_files(unsaved_files, num_unsaved_files); + clang_disposeIndex(Idx); + return result; +} + /******************************************************************************/ /* Logic for testing clang_getCursor(). */ /******************************************************************************/ @@ -795,8 +918,40 @@ void print_completion_result(CXCompletionResult *completion_result, clang_disposeString(ks); print_completion_string(completion_result->CompletionString, file); - fprintf(file, " (%u)\n", + fprintf(file, " (%u)", clang_getCompletionPriority(completion_result->CompletionString)); + switch (clang_getCompletionAvailability(completion_result->CompletionString)){ + case CXAvailability_Available: + break; + + case CXAvailability_Deprecated: + fprintf(file, " (deprecated)"); + break; + + case CXAvailability_NotAvailable: + fprintf(file, " (unavailable)"); + break; + } + fprintf(file, "\n"); +} + +int my_stricmp(const char *s1, const char *s2) { + while (*s1 && *s2) { + int c1 = tolower(*s1), c2 = tolower(*s2); + if (c1 < c2) + return -1; + else if (c1 > c2) + return 1; + + ++s1; + ++s2; + } + + if (*s1) + return 1; + else if (*s2) + return -1; + return 0; } int perform_code_completion(int argc, const char **argv, int timing_only) { @@ -809,7 +964,8 @@ int perform_code_completion(int argc, const char **argv, int timing_only) { struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; CXCodeCompleteResults *results = 0; - + CXTranslationUnit *TU = 0; + if (timing_only) input += strlen("-code-completion-timing="); else @@ -823,17 +979,43 @@ int perform_code_completion(int argc, const char **argv, int timing_only) { return -1; CIdx = clang_createIndex(0, 1); - results = clang_codeComplete(CIdx, - argv[argc - 1], argc - num_unsaved_files - 3, - argv + num_unsaved_files + 2, - num_unsaved_files, unsaved_files, - filename, line, column); + if (getenv("CINDEXTEST_EDITING")) { + unsigned I, Repeats = 5; + TU = clang_parseTranslationUnit(CIdx, 0, + argv + num_unsaved_files + 2, + argc - num_unsaved_files - 2, + 0, 0, getDefaultParsingOptions()); + if (!TU) { + fprintf(stderr, "Unable to load translation unit!\n"); + return 1; + } + for (I = 0; I != Repeats; ++I) { + results = clang_codeCompleteAt(TU, filename, line, column, + unsaved_files, num_unsaved_files, + clang_defaultCodeCompleteOptions()); + if (!results) { + fprintf(stderr, "Unable to perform code completion!\n"); + return 1; + } + if (I != Repeats-1) + clang_disposeCodeCompleteResults(results); + } + } else + results = clang_codeComplete(CIdx, + argv[argc - 1], argc - num_unsaved_files - 3, + argv + num_unsaved_files + 2, + num_unsaved_files, unsaved_files, + filename, line, column); if (results) { unsigned i, n = results->NumResults; - if (!timing_only) + if (!timing_only) { + /* Sort the code-completion results based on the typed text. */ + clang_sortCodeCompletionResults(results->Results, results->NumResults); + for (i = 0; i != n; ++i) print_completion_result(results->Results + i, stdout); + } n = clang_codeCompleteGetNumDiagnostics(results); for (i = 0; i != n; ++i) { CXDiagnostic diag = clang_codeCompleteGetDiagnostic(results, i); @@ -842,7 +1024,7 @@ int perform_code_completion(int argc, const char **argv, int timing_only) { } clang_disposeCodeCompleteResults(results); } - + clang_disposeTranslationUnit(TU); clang_disposeIndex(CIdx); free(filename); @@ -1197,6 +1379,43 @@ int print_usrs_file(const char *file_name) { /******************************************************************************/ /* Command line processing. */ /******************************************************************************/ +int write_pch_file(const char *filename, int argc, const char *argv[]) { + CXIndex Idx; + CXTranslationUnit TU; + struct CXUnsavedFile *unsaved_files = 0; + int num_unsaved_files = 0; + + Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnosics=*/1); + + if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) { + clang_disposeIndex(Idx); + return -1; + } + + TU = clang_parseTranslationUnit(Idx, 0, + argv + num_unsaved_files, + argc - num_unsaved_files, + unsaved_files, + num_unsaved_files, + CXTranslationUnit_Incomplete); + if (!TU) { + fprintf(stderr, "Unable to load translation unit!\n"); + free_remapped_files(unsaved_files, num_unsaved_files); + clang_disposeIndex(Idx); + return 1; + } + + if (clang_saveTranslationUnit(TU, filename, clang_defaultSaveOptions(TU))) + fprintf(stderr, "Unable to write PCH file %s\n", filename); + clang_disposeTranslationUnit(TU); + free_remapped_files(unsaved_files, num_unsaved_files); + clang_disposeIndex(Idx); + return 0; +} + +/******************************************************************************/ +/* Command line processing. */ +/******************************************************************************/ static CXCursorVisitor GetVisitor(const char *s) { if (s[0] == '\0') @@ -1219,14 +1438,19 @@ static void print_usage(void) { "[FileCheck prefix]\n" " c-index-test -test-load-source <symbol filter> {<args>}*\n"); fprintf(stderr, + " c-index-test -test-load-source-reparse <trials> <symbol filter> " + " {<args>}*\n" " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n" " c-index-test -test-annotate-tokens=<range> {<args>}*\n" " c-index-test -test-inclusion-stack-source {<args>}*\n" " c-index-test -test-inclusion-stack-tu <AST file>\n" " c-index-test -test-print-linkage-source {<args>}*\n" " c-index-test -test-print-typekind {<args>}*\n" - " c-index-test -print-usr [<CursorKind> {<args>}]*\n" - " c-index-test -print-usr-file <file>\n\n" + " c-index-test -print-usr [<CursorKind> {<args>}]*\n"); + fprintf(stderr, + " c-index-test -print-usr-file <file>\n" + " c-index-test -write-pch <file> <compiler arguments>\n\n"); + fprintf(stderr, " <symbol filter> values:\n%s", " all - load all symbols, including those from PCH\n" " local - load all symbols except those in PCH\n" @@ -1252,6 +1476,14 @@ int main(int argc, const char **argv) { return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I, NULL); } + else if (argc >= 5 && strncmp(argv[1], "-test-load-source-reparse", 25) == 0){ + CXCursorVisitor I = GetVisitor(argv[1] + 25); + if (I) { + int trials = atoi(argv[2]); + return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I, + NULL); + } + } else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) { CXCursorVisitor I = GetVisitor(argv[1] + 17); if (I) @@ -1284,7 +1516,9 @@ int main(int argc, const char **argv) { } else if (argc > 2 && strcmp(argv[1], "-print-usr-file") == 0) return print_usrs_file(argv[2]); - + else if (argc > 2 && strcmp(argv[1], "-write-pch") == 0) + return write_pch_file(argv[2], argc - 3, argv + 3); + print_usage(); return 1; } diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index 0eaddba..ec6e9c6 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -1,15 +1,18 @@ set(LLVM_NO_RTTI 1) set( LLVM_USED_LIBS + clangFrontendTool clangFrontend clangDriver + clangSerialization clangCodeGen + clangParse clangSema clangChecker clangAnalysis + clangIndex clangRewrite clangAST - clangParse clangLex clangBasic ) diff --git a/tools/driver/Info.plist.in b/tools/driver/Info.plist.in new file mode 100644 index 0000000..c938fb0 --- /dev/null +++ b/tools/driver/Info.plist.in @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleIdentifier</key> + <string>@TOOL_INFO_UTI@</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>@TOOL_INFO_NAME</string> + <key>CFBundleShortVersionString</key> + <string>@TOOL_INFO_VERSION@</string> + <key>CFBundleVersion</key> + <string>@TOOL_INFO_BUILD_VERSION@</string> + <key>CFBundleSignature</key> + <string>????</string> +</dict> +</plist> diff --git a/tools/driver/Makefile b/tools/driver/Makefile index b049af6..447f0e4 100644 --- a/tools/driver/Makefile +++ b/tools/driver/Makefile @@ -17,6 +17,9 @@ else endif endif +# Include tool version information on OS X. +TOOL_INFO_PLIST := Info.plist + # Include this here so we can get the configuration of the targets that have # been configured for construction. We have to do this early so we can set up # LINK_COMPONENTS before including Makefile.rules @@ -24,12 +27,36 @@ include $(CLANG_LEVEL)/../../Makefile.config LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \ ipo selectiondag -USEDLIBS = clangFrontend.a clangDriver.a clangCodeGen.a clangSema.a \ - clangChecker.a clangAnalysis.a clangRewrite.a clangAST.a \ - clangParse.a clangLex.a clangBasic.a +USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \ + clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \ + clangChecker.a clangAnalysis.a clangIndex.a clangRewrite.a \ + clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile +# Set the tool version information values. +ifeq ($(HOST_OS),Darwin) +ifdef CLANG_VENDOR +TOOL_INFO_NAME := $(CLANG_VENDOR) clang +else +TOOL_INFO_NAME := clang +endif + +ifdef CLANG_VENDOR_UTI +TOOL_INFO_UTI := $(CLANG_VENDOR_UTI) +else +TOOL_INFO_UTI := org.llvm.clang +endif + +TOOL_INFO_VERSION := $(word 3,$(shell grep "CLANG_VERSION " \ + $(PROJ_OBJ_DIR)/$(CLANG_LEVEL)/include/clang/Basic/Version.inc)) +ifdef LLVM_SUBMIT_VERSION +TOOL_INFO_BUILD_VERSION := $(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION) +else +TOOL_INFO_BUILD_VERSION := +endif +endif + # Translate make variable to define when building a "production" clang. ifdef CLANG_IS_PRODUCTION CPP.Defines += -DCLANG_IS_PRODUCTION diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index 841e40a..de5e8bf 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -13,9 +13,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/Diagnostic.h" -#include "clang/Checker/FrontendActions.h" -#include "clang/CodeGen/CodeGenAction.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/CC1Options.h" @@ -23,20 +20,16 @@ #include "clang/Driver/OptTable.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" -#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" -#include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Rewrite/FrontendActions.h" +#include "clang/FrontendTool/Utils.h" #include "llvm/LLVMContext.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/DynamicLibrary.h" #include "llvm/Target/TargetSelect.h" #include <cstdio> using namespace clang; @@ -54,78 +47,6 @@ static void LLVMErrorHandler(void *UserData, const std::string &Message) { exit(1); } -static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { - using namespace clang::frontend; - - switch (CI.getFrontendOpts().ProgramAction) { - default: - llvm_unreachable("Invalid program action!"); - - case ASTDump: return new ASTDumpAction(); - case ASTPrint: return new ASTPrintAction(); - case ASTPrintXML: return new ASTPrintXMLAction(); - case ASTView: return new ASTViewAction(); - case BoostCon: return new BoostConAction(); - case DumpRawTokens: return new DumpRawTokensAction(); - case DumpTokens: return new DumpTokensAction(); - case EmitAssembly: return new EmitAssemblyAction(); - case EmitBC: return new EmitBCAction(); - case EmitHTML: return new HTMLPrintAction(); - case EmitLLVM: return new EmitLLVMAction(); - case EmitLLVMOnly: return new EmitLLVMOnlyAction(); - case EmitCodeGenOnly: return new EmitCodeGenOnlyAction(); - case EmitObj: return new EmitObjAction(); - case FixIt: return new FixItAction(); - case GeneratePCH: return new GeneratePCHAction(); - case GeneratePTH: return new GeneratePTHAction(); - case InheritanceView: return new InheritanceViewAction(); - case InitOnly: return new InitOnlyAction(); - case ParseNoop: return new ParseOnlyAction(); - case ParsePrintCallbacks: return new PrintParseAction(); - case ParseSyntaxOnly: return new SyntaxOnlyAction(); - - case PluginAction: { - - for (FrontendPluginRegistry::iterator it = - FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); - it != ie; ++it) { - if (it->getName() == CI.getFrontendOpts().ActionName) { - PluginASTAction* plugin = it->instantiate(); - plugin->ParseArgs(CI.getFrontendOpts().PluginArgs); - return plugin; - } - } - - CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) - << CI.getFrontendOpts().ActionName; - return 0; - } - - case PrintDeclContext: return new DeclContextPrintAction(); - case PrintPreprocessedInput: return new PrintPreprocessedAction(); - case RewriteMacros: return new RewriteMacrosAction(); - case RewriteObjC: return new RewriteObjCAction(); - case RewriteTest: return new RewriteTestAction(); - case RunAnalysis: return new AnalysisAction(); - case RunPreprocessorOnly: return new PreprocessOnlyAction(); - } -} - -static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { - // Create the underlying action. - FrontendAction *Act = CreateFrontendBaseAction(CI); - if (!Act) - return 0; - - // If there are any AST files to merge, create a frontend action - // adaptor to perform the merge. - if (!CI.getFrontendOpts().ASTMergeFiles.empty()) - Act = new ASTMergeAction(Act, &CI.getFrontendOpts().ASTMergeFiles[0], - CI.getFrontendOpts().ASTMergeFiles.size()); - - return Act; -} - // FIXME: Define the need for this testing away. static int cc1_test(Diagnostic &Diags, const char **ArgBegin, const char **ArgEnd) { @@ -200,8 +121,8 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, // Run clang -cc1 test. if (ArgBegin != ArgEnd && llvm::StringRef(ArgBegin[0]) == "-cc1test") { - TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions()); - Diagnostic Diags(&DiagClient); + Diagnostic Diags(new TextDiagnosticPrinter(llvm::errs(), + DiagnosticOptions())); return cc1_test(Diags, ArgBegin + 1, ArgEnd); } @@ -212,8 +133,8 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, // Buffer diagnostics from argument parsing so that we can output them using a // well formed diagnostic object. - TextDiagnosticBuffer DiagsBuffer; - Diagnostic Diags(&DiagsBuffer); + TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; + Diagnostic Diags(DiagsBuffer); CompilerInvocation::CreateFromArgs(Clang->getInvocation(), ArgBegin, ArgEnd, Diags); @@ -223,35 +144,6 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, Clang->getHeaderSearchOpts().ResourceDir = CompilerInvocation::GetResourcesPath(Argv0, MainAddr); - // Honor -help. - if (Clang->getFrontendOpts().ShowHelp) { - llvm::OwningPtr<driver::OptTable> Opts(driver::createCC1OptTable()); - Opts->PrintHelp(llvm::outs(), "clang -cc1", - "LLVM 'Clang' Compiler: http://clang.llvm.org"); - return 0; - } - - // Honor -version. - // - // FIXME: Use a better -version message? - if (Clang->getFrontendOpts().ShowVersion) { - llvm::cl::PrintVersionMessage(); - return 0; - } - - // Honor -mllvm. - // - // FIXME: Remove this, one day. - if (!Clang->getFrontendOpts().LLVMArgs.empty()) { - unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size(); - const char **Args = new const char*[NumArgs + 2]; - Args[0] = "clang (LLVM option parsing)"; - for (unsigned i = 0; i != NumArgs; ++i) - Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str(); - Args[NumArgs + 1] = 0; - llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args)); - } - // Create the actual diagnostics engine. Clang->createDiagnostics(ArgEnd - ArgBegin, const_cast<char**>(ArgBegin)); if (!Clang->hasDiagnostics()) @@ -262,33 +154,20 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd, llvm::install_fatal_error_handler(LLVMErrorHandler, static_cast<void*>(&Clang->getDiagnostics())); - DiagsBuffer.FlushDiagnostics(Clang->getDiagnostics()); + DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics()); - // Load any requested plugins. - for (unsigned i = 0, - e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) { - const std::string &Path = Clang->getFrontendOpts().Plugins[i]; - std::string Error; - if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) - Diags.Report(diag::err_fe_unable_to_load_plugin) << Path << Error; - } - - // If there were errors in processing arguments, don't do anything else. - bool Success = false; - if (!Clang->getDiagnostics().getNumErrors()) { - // Create and execute the frontend action. - llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(*Clang)); - if (Act) { - Success = Clang->ExecuteAction(*Act); - if (Clang->getFrontendOpts().DisableFree) - Act.take(); - } - } + // Execute the frontend actions. + bool Success = ExecuteCompilerInvocation(Clang.get()); // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. llvm::TimerGroup::printAll(llvm::errs()); - + + // Our error handler depends on the Diagnostics object, which we're + // potentially about to delete. Uninstall the handler now so that any + // later errors use the default handling behavior instead. + llvm::remove_fatal_error_handler(); + // When running with -disable-free, don't do any destruction or shutdown. if (Clang->getFrontendOpts().DisableFree) { if (Clang->getFrontendOpts().ShowStats) diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp index 3c5ca92..5bce70c 100644 --- a/tools/driver/cc1as_main.cpp +++ b/tools/driver/cc1as_main.cpp @@ -24,7 +24,9 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/MC/MCParser/AsmParser.h" +#include "llvm/ADT/Triple.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" @@ -141,7 +143,7 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, // Construct the invocation. // Target Options - Opts.Triple = Args->getLastArgValue(OPT_triple); + Opts.Triple = Triple::normalize(Args->getLastArgValue(OPT_triple)); if (Opts.Triple.empty()) // Use the host triple if unspecified. Opts.Triple = sys::getHostTriple(); @@ -253,38 +255,38 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, Diagnostic &Diags) { return false; } - OwningPtr<MCCodeEmitter> CE; OwningPtr<MCStreamer> Str; - OwningPtr<TargetAsmBackend> TAB; if (Opts.OutputType == AssemblerInvocation::FT_Asm) { MCInstPrinter *IP = TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI); + MCCodeEmitter *CE = 0; if (Opts.ShowEncoding) - CE.reset(TheTarget->createCodeEmitter(*TM, Ctx)); + CE = TheTarget->createCodeEmitter(*TM, Ctx); Str.reset(createAsmStreamer(Ctx, *Out,TM->getTargetData()->isLittleEndian(), - /*asmverbose*/true, IP, CE.get(), - Opts.ShowInst)); + /*asmverbose*/true, IP, CE, Opts.ShowInst)); } else if (Opts.OutputType == AssemblerInvocation::FT_Null) { Str.reset(createNullStreamer(Ctx)); } else { assert(Opts.OutputType == AssemblerInvocation::FT_Obj && "Invalid file type!"); - CE.reset(TheTarget->createCodeEmitter(*TM, Ctx)); - TAB.reset(TheTarget->createAsmBackend(Opts.Triple)); - Str.reset(createMachOStreamer(Ctx, *TAB, *Out, CE.get(), Opts.RelaxAll)); + MCCodeEmitter *CE = TheTarget->createCodeEmitter(*TM, Ctx); + TargetAsmBackend *TAB = TheTarget->createAsmBackend(Opts.Triple); + Str.reset(TheTarget->createObjectStreamer(Opts.Triple, Ctx, *TAB, *Out, + CE, Opts.RelaxAll)); } - AsmParser Parser(*TheTarget, SrcMgr, Ctx, *Str.get(), *MAI); - OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(Parser)); + OwningPtr<MCAsmParser> Parser(createMCAsmParser(*TheTarget, SrcMgr, Ctx, + *Str.get(), *MAI)); + OwningPtr<TargetAsmParser> TAP(TheTarget->createAsmParser(*Parser, *TM)); if (!TAP) { Diags.Report(diag::err_target_unknown_triple) << Opts.Triple; return false; } - Parser.setTargetParser(*TAP.get()); + Parser->setTargetParser(*TAP.get()); - bool Success = !Parser.Run(Opts.NoInitialTextSection); + bool Success = !Parser->Run(Opts.NoInitialTextSection); // Close the output. delete Out; @@ -320,14 +322,15 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd, InitializeAllAsmParsers(); // Construct our diagnostic client. - TextDiagnosticPrinter DiagClient(errs(), DiagnosticOptions()); - DiagClient.setPrefix("clang -cc1as"); - Diagnostic Diags(&DiagClient); + TextDiagnosticPrinter *DiagClient + = new TextDiagnosticPrinter(errs(), DiagnosticOptions()); + DiagClient->setPrefix("clang -cc1as"); + Diagnostic Diags(DiagClient); // Set an error handler, so that any LLVM backend diagnostics go through our // error handler. - install_fatal_error_handler(LLVMErrorHandler, - static_cast<void*>(&Diags)); + ScopedFatalErrorHandler FatalErrorHandler + (LLVMErrorHandler, static_cast<void*>(&Diags)); // Parse the arguments. AssemblerInvocation Asm; diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index c4b12cb..c058ece 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -19,15 +19,19 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Config/config.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Regex.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Host.h" #include "llvm/System/Path.h" +#include "llvm/System/Program.h" #include "llvm/System/Signals.h" using namespace clang; using namespace clang::driver; @@ -75,7 +79,7 @@ static const char *SaveStringInSet(std::set<std::string> &SavedStrings, /// \param Edit - The override command to perform. /// \param SavedStrings - Set to use for storing string representations. static void ApplyOneQAOverride(llvm::raw_ostream &OS, - std::vector<const char*> &Args, + llvm::SmallVectorImpl<const char*> &Args, llvm::StringRef Edit, std::set<std::string> &SavedStrings) { // This does not need to be efficient. @@ -141,7 +145,7 @@ static void ApplyOneQAOverride(llvm::raw_ostream &OS, /// ApplyQAOverride - Apply a comma separate list of edits to the /// input argument lists. See ApplyOneQAOverride. -static void ApplyQAOverride(std::vector<const char*> &Args, +static void ApplyQAOverride(llvm::SmallVectorImpl<const char*> &Args, const char *OverrideStr, std::set<std::string> &SavedStrings) { llvm::raw_ostream *OS = &llvm::errs(); @@ -173,19 +177,97 @@ extern int cc1_main(const char **ArgBegin, const char **ArgEnd, extern int cc1as_main(const char **ArgBegin, const char **ArgEnd, const char *Argv0, void *MainAddr); -int main(int argc, const char **argv) { +static void ExpandArgsFromBuf(const char *Arg, + llvm::SmallVectorImpl<const char*> &ArgVector, + std::set<std::string> &SavedStrings) { + const char *FName = Arg + 1; + llvm::MemoryBuffer *MemBuf = llvm::MemoryBuffer::getFile(FName); + if (!MemBuf) { + ArgVector.push_back(SaveStringInSet(SavedStrings, Arg)); + return; + } + + const char *Buf = MemBuf->getBufferStart(); + char InQuote = ' '; + std::string CurArg; + + for (const char *P = Buf; ; ++P) { + if (*P == '\0' || (isspace(*P) && InQuote == ' ')) { + if (!CurArg.empty()) { + + if (CurArg[0] != '@') { + ArgVector.push_back(SaveStringInSet(SavedStrings, CurArg)); + } else { + ExpandArgsFromBuf(CurArg.c_str(), ArgVector, SavedStrings); + } + + CurArg = ""; + } + if (*P == '\0') + break; + else + continue; + } + + if (isspace(*P)) { + if (InQuote != ' ') + CurArg.push_back(*P); + continue; + } + + if (*P == '"' || *P == '\'') { + if (InQuote == *P) + InQuote = ' '; + else if (InQuote == ' ') + InQuote = *P; + else + CurArg.push_back(*P); + continue; + } + + if (*P == '\\') { + ++P; + if (*P != '\0') + CurArg.push_back(*P); + continue; + } + CurArg.push_back(*P); + } + delete MemBuf; +} + +static void ExpandArgv(int argc, const char **argv, + llvm::SmallVectorImpl<const char*> &ArgVector, + std::set<std::string> &SavedStrings) { + for (int i = 0; i < argc; ++i) { + const char *Arg = argv[i]; + if (Arg[0] != '@') { + ArgVector.push_back(SaveStringInSet(SavedStrings, std::string(Arg))); + continue; + } + + ExpandArgsFromBuf(Arg, ArgVector, SavedStrings); + } +} + +int main(int argc_, const char **argv_) { llvm::sys::PrintStackTraceOnErrorSignal(); - llvm::PrettyStackTraceProgram X(argc, argv); + llvm::PrettyStackTraceProgram X(argc_, argv_); + + std::set<std::string> SavedStrings; + llvm::SmallVector<const char*, 256> argv; + + ExpandArgv(argc_, argv_, argv, SavedStrings); // Handle -cc1 integrated tools. - if (argc > 1 && llvm::StringRef(argv[1]).startswith("-cc1")) { + if (argv.size() > 1 && llvm::StringRef(argv[1]).startswith("-cc1")) { llvm::StringRef Tool = argv[1] + 4; if (Tool == "") - return cc1_main(argv+2, argv+argc, argv[0], + return cc1_main(argv.data()+2, argv.data()+argv.size(), argv[0], (void*) (intptr_t) GetExecutablePath); if (Tool == "as") - return cc1as_main(argv+2, argv+argc, argv[0], + return cc1as_main(argv.data()+2, argv.data()+argv.size(), argv[0], (void*) (intptr_t) GetExecutablePath); // Reject unknown tools. @@ -194,7 +276,7 @@ int main(int argc, const char **argv) { } bool CanonicalPrefixes = true; - for (int i = 1; i < argc; ++i) { + for (int i = 1, size = argv.size(); i < size; ++i) { if (llvm::StringRef(argv[i]) == "-no-canonical-prefixes") { CanonicalPrefixes = false; break; @@ -203,10 +285,10 @@ int main(int argc, const char **argv) { llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes); - TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions()); - DiagClient.setPrefix(Path.getBasename()); - - Diagnostic Diags(&DiagClient); + TextDiagnosticPrinter *DiagClient + = new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); + DiagClient->setPrefix(Path.getBasename()); + Diagnostic Diags(DiagClient); #ifdef CLANG_IS_PRODUCTION const bool IsProduction = true; @@ -219,11 +301,27 @@ int main(int argc, const char **argv) { const bool IsProduction = false; const bool CXXIsProduction = false; #endif - Driver TheDriver(Path.getBasename(), Path.getDirname(), - llvm::sys::getHostTriple(), + Driver TheDriver(Path.str(), llvm::sys::getHostTriple(), "a.out", IsProduction, CXXIsProduction, Diags); + // Attempt to find the original path used to invoke the driver, to determine + // the installed path. We do this manually, because we want to support that + // path being a symlink. + llvm::sys::Path InstalledPath(argv[0]); + + // Do a PATH lookup, if there are no directory components. + if (InstalledPath.getLast() == InstalledPath.str()) { + llvm::sys::Path Tmp = + llvm::sys::Program::FindProgramByName(InstalledPath.getLast()); + if (!Tmp.empty()) + InstalledPath = Tmp; + } + InstalledPath.makeAbsolute(); + InstalledPath.eraseComponent(); + if (InstalledPath.exists()) + TheDriver.setInstalledDir(InstalledPath.str()); + // Check for ".*++" or ".*++-[^-]*" to determine if we are a C++ // compiler. This matches things like "c++", "clang++", and "clang++-1.1". // @@ -231,15 +329,14 @@ int main(int argc, const char **argv) { // being a symlink. // // We use *argv instead of argv[0] to work around a bogus g++ warning. - std::string ProgName(llvm::sys::Path(*argv).getBasename()); + const char *progname = argv_[0]; + std::string ProgName(llvm::sys::Path(progname).getBasename()); if (llvm::StringRef(ProgName).endswith("++") || llvm::StringRef(ProgName).rsplit('-').first.endswith("++")) { TheDriver.CCCIsCXX = true; TheDriver.CCCGenericGCCName = "g++"; } - llvm::OwningPtr<Compilation> C; - // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE. TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS"); if (TheDriver.CCPrintOptions) @@ -247,46 +344,35 @@ int main(int argc, const char **argv) { // Handle QA_OVERRIDE_GCC3_OPTIONS and CCC_ADD_ARGS, used for editing a // command line behind the scenes. - std::set<std::string> SavedStrings; if (const char *OverrideStr = ::getenv("QA_OVERRIDE_GCC3_OPTIONS")) { // FIXME: Driver shouldn't take extra initial argument. - std::vector<const char*> StringPointers(argv, argv + argc); - - ApplyQAOverride(StringPointers, OverrideStr, SavedStrings); - - C.reset(TheDriver.BuildCompilation(StringPointers.size(), - &StringPointers[0])); + ApplyQAOverride(argv, OverrideStr, SavedStrings); } else if (const char *Cur = ::getenv("CCC_ADD_ARGS")) { - std::vector<const char*> StringPointers; - // FIXME: Driver shouldn't take extra initial argument. - StringPointers.push_back(argv[0]); + std::vector<const char*> ExtraArgs; for (;;) { const char *Next = strchr(Cur, ','); if (Next) { - StringPointers.push_back(SaveStringInSet(SavedStrings, - std::string(Cur, Next))); + ExtraArgs.push_back(SaveStringInSet(SavedStrings, + std::string(Cur, Next))); Cur = Next + 1; } else { if (*Cur != '\0') - StringPointers.push_back(SaveStringInSet(SavedStrings, Cur)); + ExtraArgs.push_back(SaveStringInSet(SavedStrings, Cur)); break; } } - StringPointers.insert(StringPointers.end(), argv + 1, argv + argc); - - C.reset(TheDriver.BuildCompilation(StringPointers.size(), - &StringPointers[0])); - } else - C.reset(TheDriver.BuildCompilation(argc, argv)); + argv.insert(&argv[1], ExtraArgs.begin(), ExtraArgs.end()); + } + llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv.size(), + &argv[0])); int Res = 0; if (C.get()) Res = TheDriver.ExecuteCompilation(*C); - // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 7f32a1c..5117f2c 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -14,6 +14,7 @@ #include "CIndexer.h" #include "CXCursor.h" +#include "CXType.h" #include "CXSourceLocation.h" #include "CIndexDiagnostic.h" @@ -29,7 +30,9 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Timer.h" #include "llvm/System/Program.h" #include "llvm/System/Signals.h" @@ -143,10 +146,10 @@ static RangeComparisonResult RangeCompare(SourceManager &SM, SourceRange R2) { assert(R1.isValid() && "First range is invalid?"); assert(R2.isValid() && "Second range is invalid?"); - if (R1.getEnd() == R2.getBegin() || + if (R1.getEnd() != R2.getBegin() && SM.isBeforeInTranslationUnit(R1.getEnd(), R2.getBegin())) return RangeBefore; - if (R2.getEnd() == R1.getBegin() || + if (R2.getEnd() != R1.getBegin() && SM.isBeforeInTranslationUnit(R2.getEnd(), R1.getBegin())) return RangeAfter; return RangeOverlap; @@ -158,10 +161,8 @@ static RangeComparisonResult LocationCompare(SourceManager &SM, SourceLocation L, SourceRange R) { assert(R.isValid() && "First range is invalid?"); assert(L.isValid() && "Second range is invalid?"); - if (L == R.getBegin()) + if (L == R.getBegin() || L == R.getEnd()) return RangeOverlap; - if (L == R.getEnd()) - return RangeAfter; if (SM.isBeforeInTranslationUnit(L, R.getBegin())) return RangeBefore; if (SM.isBeforeInTranslationUnit(R.getEnd(), L)) @@ -284,15 +285,24 @@ public: // Declaration visitors bool VisitAttributes(Decl *D); bool VisitBlockDecl(BlockDecl *B); + bool VisitCXXRecordDecl(CXXRecordDecl *D); bool VisitDeclContext(DeclContext *DC); bool VisitTranslationUnitDecl(TranslationUnitDecl *D); bool VisitTypedefDecl(TypedefDecl *D); bool VisitTagDecl(TagDecl *D); + bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D); + bool VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D); + bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); bool VisitEnumConstantDecl(EnumConstantDecl *D); bool VisitDeclaratorDecl(DeclaratorDecl *DD); bool VisitFunctionDecl(FunctionDecl *ND); bool VisitFieldDecl(FieldDecl *D); bool VisitVarDecl(VarDecl *); + bool VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + bool VisitClassTemplateDecl(ClassTemplateDecl *D); + bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); bool VisitObjCMethodDecl(ObjCMethodDecl *ND); bool VisitObjCContainerDecl(ObjCContainerDecl *D); bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); @@ -309,14 +319,28 @@ public: bool VisitObjCClassDecl(ObjCClassDecl *D); bool VisitLinkageSpecDecl(LinkageSpecDecl *D); bool VisitNamespaceDecl(NamespaceDecl *D); - + bool VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + bool VisitUsingDecl(UsingDecl *D); + bool VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); + bool VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + + // Name visitor + bool VisitDeclarationNameInfo(DeclarationNameInfo Name); + bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range); + + // Template visitors + bool VisitTemplateParameters(const TemplateParameterList *Params); + bool VisitTemplateName(TemplateName Name, SourceLocation Loc); + bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL); + // Type visitors - // FIXME: QualifiedTypeLoc doesn't provide any location information + bool VisitQualifiedTypeLoc(QualifiedTypeLoc TL); bool VisitBuiltinTypeLoc(BuiltinTypeLoc TL); bool VisitTypedefTypeLoc(TypedefTypeLoc TL); bool VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL); bool VisitTagTypeLoc(TagTypeLoc TL); - // FIXME: TemplateTypeParmTypeLoc doesn't provide any location information + bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL); bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL); bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL); @@ -325,9 +349,9 @@ public: bool VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL); bool VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL); bool VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL); - bool VisitFunctionTypeLoc(FunctionTypeLoc TL); + bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false); bool VisitArrayTypeLoc(ArrayTypeLoc TL); - // FIXME: Implement for TemplateSpecializationTypeLoc + bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL); // FIXME: Implement visitors here when the unimplemented TypeLocs get // implemented bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL); @@ -345,6 +369,8 @@ public: // bool VisitSwitchCase(SwitchCase *S); // Expression visitors + bool VisitDeclRefExpr(DeclRefExpr *E); + bool VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); bool VisitBlockExpr(BlockExpr *B); bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E); bool VisitExplicitCastExpr(ExplicitCastExpr *E); @@ -352,10 +378,30 @@ public: bool VisitObjCEncodeExpr(ObjCEncodeExpr *E); bool VisitOffsetOfExpr(OffsetOfExpr *E); bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + bool VisitMemberExpr(MemberExpr *E); + // FIXME: AddrLabelExpr (once we have cursors for labels) + bool VisitTypesCompatibleExpr(TypesCompatibleExpr *E); + bool VisitVAArgExpr(VAArgExpr *E); + // FIXME: InitListExpr (for the designators) + // FIXME: DesignatedInitExpr + bool VisitCXXTypeidExpr(CXXTypeidExpr *E); + bool VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { return false; } + // FIXME: CXXTemporaryObjectExpr has poor source-location information. + // FIXME: CXXScalarValueInitExpr has poor source-location information. + // FIXME: CXXNewExpr has poor source-location information + bool VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E); + // FIXME: UnaryTypeTraitExpr has poor source-location information. + bool VisitOverloadExpr(OverloadExpr *E); + bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E); + // FIXME: CXXUnresolvedConstructExpr has poor source-location information. + bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); + bool VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E); }; } // end anonymous namespace +static SourceRange getRawCursorExtent(CXCursor C); + RangeComparisonResult CursorVisitor::CompareRegionOfInterest(SourceRange R) { return RangeCompare(TU->getSourceManager(), R, RegionOfInterest); } @@ -387,8 +433,7 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) { // If we have a range of interest, and this cursor doesn't intersect with it, // we're done. if (RegionOfInterest.isValid() && !CheckedRegionOfInterest) { - SourceRange Range = - cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor)); + SourceRange Range = getRawCursorExtent(Cursor); if (Range.isInvalid() || CompareRegionOfInterest(Range)) return false; } @@ -478,10 +523,10 @@ bool CursorVisitor::VisitChildren(CXCursor Cursor) { ASTUnit *CXXUnit = getCursorASTUnit(Cursor); if (!CXXUnit->isMainFileAST() && CXXUnit->getOnlyLocalDecls() && RegionOfInterest.isInvalid()) { - const std::vector<Decl*> &TLDs = CXXUnit->getTopLevelDecls(); - for (std::vector<Decl*>::const_iterator it = TLDs.begin(), - ie = TLDs.end(); it != ie; ++it) { - if (Visit(MakeCXCursor(*it, CXXUnit), true)) + for (ASTUnit::top_level_iterator TL = CXXUnit->top_level_begin(), + TLEnd = CXXUnit->top_level_end(); + TL != TLEnd; ++TL) { + if (Visit(MakeCXCursor(*TL, CXXUnit), true)) return true; } } else if (VisitDeclContext( @@ -520,7 +565,10 @@ bool CursorVisitor::VisitBlockDecl(BlockDecl *B) { if (Visit(B->getSignatureAsWritten()->getTypeLoc())) return true; - return Visit(MakeCXCursor(B->getBody(), StmtParent, TU)); + if (Stmt *Body = B->getBody()) + return Visit(MakeCXCursor(Body, StmtParent, TU)); + + return false; } bool CursorVisitor::VisitDeclContext(DeclContext *DC) { @@ -534,8 +582,7 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) { CXCursor Cursor = MakeCXCursor(D, TU); if (RegionOfInterest.isValid()) { - SourceRange Range = - cxloc::translateCXSourceRange(clang_getCursorExtent(Cursor)); + SourceRange Range = getRawCursorExtent(Cursor); if (Range.isInvalid()) continue; @@ -577,6 +624,67 @@ bool CursorVisitor::VisitTagDecl(TagDecl *D) { return VisitDeclContext(D); } +bool CursorVisitor::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D) { + bool ShouldVisitBody = false; + switch (D->getSpecializationKind()) { + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + // Nothing to visit + return false; + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + break; + + case TSK_ExplicitSpecialization: + ShouldVisitBody = true; + break; + } + + // Visit the template arguments used in the specialization. + if (TypeSourceInfo *SpecType = D->getTypeAsWritten()) { + TypeLoc TL = SpecType->getTypeLoc(); + if (TemplateSpecializationTypeLoc *TSTLoc + = dyn_cast<TemplateSpecializationTypeLoc>(&TL)) { + for (unsigned I = 0, N = TSTLoc->getNumArgs(); I != N; ++I) + if (VisitTemplateArgumentLoc(TSTLoc->getArgLoc(I))) + return true; + } + } + + if (ShouldVisitBody && VisitCXXRecordDecl(D)) + return true; + + return false; +} + +bool CursorVisitor::VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D) { + // FIXME: Visit the "outer" template parameter lists on the TagDecl + // before visiting these template parameters. + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + // Visit the partial specialization arguments. + const TemplateArgumentLoc *TemplateArgs = D->getTemplateArgsAsWritten(); + for (unsigned I = 0, N = D->getNumTemplateArgsAsWritten(); I != N; ++I) + if (VisitTemplateArgumentLoc(TemplateArgs[I])) + return true; + + return VisitCXXRecordDecl(D); +} + +bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + // Visit the default argument. + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + if (TypeSourceInfo *DefArg = D->getDefaultArgumentInfo()) + if (Visit(DefArg->getTypeLoc())) + return true; + + return false; +} + bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) { if (Expr *Init = D->getInitExpr()) return Visit(MakeCXCursor(Init, StmtParent, TU)); @@ -592,9 +700,37 @@ bool CursorVisitor::VisitDeclaratorDecl(DeclaratorDecl *DD) { } bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) { - if (VisitDeclaratorDecl(ND)) - return true; - + if (TypeSourceInfo *TSInfo = ND->getTypeSourceInfo()) { + // Visit the function declaration's syntactic components in the order + // written. This requires a bit of work. + TypeLoc TL = TSInfo->getTypeLoc(); + FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL); + + // If we have a function declared directly (without the use of a typedef), + // visit just the return type. Otherwise, just visit the function's type + // now. + if ((FTL && !isa<CXXConversionDecl>(ND) && Visit(FTL->getResultLoc())) || + (!FTL && Visit(TL))) + return true; + + // Visit the nested-name-specifier, if present. + if (NestedNameSpecifier *Qualifier = ND->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, ND->getQualifierRange())) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(ND->getNameInfo())) + return true; + + // FIXME: Visit explicitly-specified template arguments! + + // Visit the function parameters, if we have a function type. + if (FTL && VisitFunctionTypeLoc(*FTL, true)) + return true; + + // FIXME: Attributes? + } + if (ND->isThisDeclarationADefinition() && Visit(MakeCXCursor(ND->getBody(), StmtParent, TU))) return true; @@ -622,6 +758,46 @@ bool CursorVisitor::VisitVarDecl(VarDecl *D) { return false; } +bool CursorVisitor::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + if (VisitDeclaratorDecl(D)) + return true; + + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + if (Expr *DefArg = D->getDefaultArgument()) + return Visit(MakeCXCursor(DefArg, StmtParent, TU)); + + return false; +} + +bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + // FIXME: Visit the "outer" template parameter lists on the FunctionDecl + // before visiting these template parameters. + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + return VisitFunctionDecl(D->getTemplatedDecl()); +} + +bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) { + // FIXME: Visit the "outer" template parameter lists on the TagDecl + // before visiting these template parameters. + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + return VisitCXXRecordDecl(D->getTemplatedDecl()); +} + +bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited() && + VisitTemplateArgumentLoc(D->getDefaultArgument())) + return true; + + return false; +} + bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { if (TypeSourceInfo *TSInfo = ND->getResultTypeSourceInfo()) if (Visit(TSInfo->getTypeLoc())) @@ -773,10 +949,207 @@ bool CursorVisitor::VisitNamespaceDecl(NamespaceDecl *D) { return VisitDeclContext(D); } +bool CursorVisitor::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifier *Qualifier = D->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, D->getQualifierRange())) + return true; + + return Visit(MakeCursorNamespaceRef(D->getAliasedNamespace(), + D->getTargetNameLoc(), TU)); +} + +bool CursorVisitor::VisitUsingDecl(UsingDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifier *Qualifier = D->getTargetNestedNameDecl()) + if (VisitNestedNameSpecifier(Qualifier, D->getNestedNameRange())) + return true; + + // FIXME: Provide a multi-reference of some kind for all of the declarations + // that the using declaration refers to. We don't have this kind of cursor + // yet. + + return VisitDeclarationNameInfo(D->getNameInfo()); +} + +bool CursorVisitor::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifier *Qualifier = D->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, D->getQualifierRange())) + return true; + + return Visit(MakeCursorNamespaceRef(D->getNominatedNamespaceAsWritten(), + D->getIdentLocation(), TU)); +} + +bool CursorVisitor::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifier *Qualifier = D->getTargetNestedNameSpecifier()) + if (VisitNestedNameSpecifier(Qualifier, D->getTargetNestedNameRange())) + return true; + + return VisitDeclarationNameInfo(D->getNameInfo()); +} + +bool CursorVisitor::VisitUnresolvedUsingTypenameDecl( + UnresolvedUsingTypenameDecl *D) { + // Visit nested-name-specifier. + if (NestedNameSpecifier *Qualifier = D->getTargetNestedNameSpecifier()) + if (VisitNestedNameSpecifier(Qualifier, D->getTargetNestedNameRange())) + return true; + + return false; +} + +bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) { + switch (Name.getName().getNameKind()) { + case clang::DeclarationName::Identifier: + case clang::DeclarationName::CXXLiteralOperatorName: + case clang::DeclarationName::CXXOperatorName: + case clang::DeclarationName::CXXUsingDirective: + return false; + + case clang::DeclarationName::CXXConstructorName: + case clang::DeclarationName::CXXDestructorName: + case clang::DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TSInfo = Name.getNamedTypeInfo()) + return Visit(TSInfo->getTypeLoc()); + return false; + + case clang::DeclarationName::ObjCZeroArgSelector: + case clang::DeclarationName::ObjCOneArgSelector: + case clang::DeclarationName::ObjCMultiArgSelector: + // FIXME: Per-identifier location info? + return false; + } + + return false; +} + +bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS, + SourceRange Range) { + // FIXME: This whole routine is a hack to work around the lack of proper + // source information in nested-name-specifiers (PR5791). Since we do have + // a beginning source location, we can visit the first component of the + // nested-name-specifier, if it's a single-token component. + if (!NNS) + return false; + + // Get the first component in the nested-name-specifier. + while (NestedNameSpecifier *Prefix = NNS->getPrefix()) + NNS = Prefix; + + switch (NNS->getKind()) { + case NestedNameSpecifier::Namespace: + // FIXME: The token at this source location might actually have been a + // namespace alias, but we don't model that. Lame! + return Visit(MakeCursorNamespaceRef(NNS->getAsNamespace(), Range.getBegin(), + TU)); + + case NestedNameSpecifier::TypeSpec: { + // If the type has a form where we know that the beginning of the source + // range matches up with a reference cursor. Visit the appropriate reference + // cursor. + Type *T = NNS->getAsType(); + if (const TypedefType *Typedef = dyn_cast<TypedefType>(T)) + return Visit(MakeCursorTypeRef(Typedef->getDecl(), Range.getBegin(), TU)); + if (const TagType *Tag = dyn_cast<TagType>(T)) + return Visit(MakeCursorTypeRef(Tag->getDecl(), Range.getBegin(), TU)); + if (const TemplateSpecializationType *TST + = dyn_cast<TemplateSpecializationType>(T)) + return VisitTemplateName(TST->getTemplateName(), Range.getBegin()); + break; + } + + case NestedNameSpecifier::TypeSpecWithTemplate: + case NestedNameSpecifier::Global: + case NestedNameSpecifier::Identifier: + break; + } + + return false; +} + +bool CursorVisitor::VisitTemplateParameters( + const TemplateParameterList *Params) { + if (!Params) + return false; + + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (Visit(MakeCXCursor(*P, TU))) + return true; + } + + return false; +} + +bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) { + switch (Name.getKind()) { + case TemplateName::Template: + return Visit(MakeCursorTemplateRef(Name.getAsTemplateDecl(), Loc, TU)); + + case TemplateName::OverloadedTemplate: + // FIXME: We need a way to return multiple lookup results in a single + // cursor. + return false; + + case TemplateName::DependentTemplate: + // FIXME: Visit nested-name-specifier. + return false; + + case TemplateName::QualifiedTemplate: + // FIXME: Visit nested-name-specifier. + return Visit(MakeCursorTemplateRef( + Name.getAsQualifiedTemplateName()->getDecl(), + Loc, TU)); + } + + return false; +} + +bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) { + switch (TAL.getArgument().getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Integral: + return false; + + case TemplateArgument::Pack: + // FIXME: Implement when variadic templates come along. + return false; + + case TemplateArgument::Type: + if (TypeSourceInfo *TSInfo = TAL.getTypeSourceInfo()) + return Visit(TSInfo->getTypeLoc()); + return false; + + case TemplateArgument::Declaration: + if (Expr *E = TAL.getSourceDeclExpression()) + return Visit(MakeCXCursor(E, StmtParent, TU)); + return false; + + case TemplateArgument::Expression: + if (Expr *E = TAL.getSourceExpression()) + return Visit(MakeCXCursor(E, StmtParent, TU)); + return false; + + case TemplateArgument::Template: + return VisitTemplateName(TAL.getArgument().getAsTemplate(), + TAL.getTemplateNameLoc()); + } + + return false; +} + bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) { return VisitDeclContext(D); } +bool CursorVisitor::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { + return Visit(TL.getUnqualifiedLoc()); +} + bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { ASTContext &Context = TU->getASTContext(); @@ -848,6 +1221,13 @@ bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) { return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); } +bool CursorVisitor::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + // FIXME: We can't visit the template template parameter, but there's + // no context information with which we can match up the depth/index in the + // type to the appropriate + return false; +} + bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU))) return true; @@ -892,8 +1272,9 @@ bool CursorVisitor::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { return Visit(TL.getPointeeLoc()); } -bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL) { - if (Visit(TL.getResultLoc())) +bool CursorVisitor::VisitFunctionTypeLoc(FunctionTypeLoc TL, + bool SkipResultType) { + if (!SkipResultType && Visit(TL.getResultLoc())) return true; for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) @@ -914,6 +1295,21 @@ bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) { return false; } +bool CursorVisitor::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + // Visit the template name. + if (VisitTemplateName(TL.getTypePtr()->getTemplateName(), + TL.getTemplateNameLoc())) + return true; + + // Visit the template arguments. + for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) + if (VisitTemplateArgumentLoc(TL.getArgLoc(I))) + return true; + + return false; +} + bool CursorVisitor::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { return Visit(MakeCXCursor(TL.getUnderlyingExpr(), StmtParent, TU)); } @@ -1054,6 +1450,56 @@ bool CursorVisitor::VisitForStmt(ForStmt *S) { return false; } +bool CursorVisitor::VisitDeclRefExpr(DeclRefExpr *E) { + // Visit nested-name-specifier, if present. + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit declaration name. + if (VisitDeclarationNameInfo(E->getNameInfo())) + return true; + + // Visit explicitly-specified template arguments. + if (E->hasExplicitTemplateArgs()) { + ExplicitTemplateArgumentList &Args = E->getExplicitTemplateArgs(); + for (TemplateArgumentLoc *Arg = Args.getTemplateArgs(), + *ArgEnd = Arg + Args.NumTemplateArgs; + Arg != ArgEnd; ++Arg) + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + + return false; +} + +bool CursorVisitor::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + if (Visit(MakeCXCursor(E->getArg(0), StmtParent, TU))) + return true; + + if (Visit(MakeCXCursor(E->getCallee(), StmtParent, TU))) + return true; + + for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I) + if (Visit(MakeCXCursor(E->getArg(I), StmtParent, TU))) + return true; + + return false; +} + +bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) { + if (D->isDefinition()) { + for (CXXRecordDecl::base_class_iterator I = D->bases_begin(), + E = D->bases_end(); I != E; ++I) { + if (Visit(cxcursor::MakeCursorCXXBaseSpecifier(I, TU))) + return true; + } + } + + return VisitTagDecl(D); +} + + bool CursorVisitor::VisitBlockExpr(BlockExpr *B) { return Visit(B->getBlockDecl()); } @@ -1077,6 +1523,34 @@ bool CursorVisitor::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return VisitExpr(E); } +bool CursorVisitor::VisitMemberExpr(MemberExpr *E) { + // Visit the base expression. + if (Visit(MakeCXCursor(E->getBase(), StmtParent, TU))) + return true; + + // Visit the nested-name-specifier + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(E->getMemberNameInfo())) + return true; + + // Visit the explicitly-specified template arguments, if any. + if (E->hasExplicitTemplateArgs()) { + for (const TemplateArgumentLoc *Arg = E->getTemplateArgs(), + *ArgEnd = Arg + E->getNumTemplateArgs(); + Arg != ArgEnd; + ++Arg) { + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + } + + return false; +} + bool CursorVisitor::VisitExplicitCastExpr(ExplicitCastExpr *E) { if (TypeSourceInfo *TSInfo = E->getTypeInfoAsWritten()) if (Visit(TSInfo->getTypeLoc())) @@ -1093,6 +1567,143 @@ bool CursorVisitor::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return VisitExpr(E); } +bool CursorVisitor::VisitTypesCompatibleExpr(TypesCompatibleExpr *E) { + return Visit(E->getArgTInfo1()->getTypeLoc()) || + Visit(E->getArgTInfo2()->getTypeLoc()); +} + +bool CursorVisitor::VisitVAArgExpr(VAArgExpr *E) { + if (Visit(E->getWrittenTypeInfo()->getTypeLoc())) + return true; + + return Visit(MakeCXCursor(E->getSubExpr(), StmtParent, TU)); +} + +bool CursorVisitor::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + if (E->isTypeOperand()) { + if (TypeSourceInfo *TSInfo = E->getTypeOperandSourceInfo()) + return Visit(TSInfo->getTypeLoc()); + + return false; + } + + return VisitExpr(E); +} + +bool CursorVisitor::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { + // Visit base expression. + if (Visit(MakeCXCursor(E->getBase(), StmtParent, TU))) + return true; + + // Visit the nested-name-specifier. + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit the scope type that looks disturbingly like the nested-name-specifier + // but isn't. + if (TypeSourceInfo *TSInfo = E->getScopeTypeInfo()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + // Visit the name of the type being destroyed. + if (TypeSourceInfo *TSInfo = E->getDestroyedTypeInfo()) + if (Visit(TSInfo->getTypeLoc())) + return true; + + return false; +} + +bool CursorVisitor::VisitOverloadExpr(OverloadExpr *E) { + // Visit the nested-name-specifier. + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(E->getNameInfo())) + return true; + + // Visit the explicitly-specified template arguments. + if (const ExplicitTemplateArgumentList *ArgList + = E->getOptionalExplicitTemplateArgs()) { + for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(), + *ArgEnd = Arg + ArgList->NumTemplateArgs; + Arg != ArgEnd; ++Arg) { + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + } + + // FIXME: We don't have a way to visit all of the declarations referenced + // here. + return false; +} + +bool CursorVisitor::VisitDependentScopeDeclRefExpr( + DependentScopeDeclRefExpr *E) { + // Visit the nested-name-specifier. + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(E->getNameInfo())) + return true; + + // Visit the explicitly-specified template arguments. + if (const ExplicitTemplateArgumentList *ArgList + = E->getOptionalExplicitTemplateArgs()) { + for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(), + *ArgEnd = Arg + ArgList->NumTemplateArgs; + Arg != ArgEnd; ++Arg) { + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + } + + return false; +} + +bool CursorVisitor::VisitCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *E) { + // Visit the base expression, if there is one. + if (!E->isImplicitAccess() && + Visit(MakeCXCursor(E->getBase(), StmtParent, TU))) + return true; + + // Visit the nested-name-specifier. + if (NestedNameSpecifier *Qualifier = E->getQualifier()) + if (VisitNestedNameSpecifier(Qualifier, E->getQualifierRange())) + return true; + + // Visit the declaration name. + if (VisitDeclarationNameInfo(E->getMemberNameInfo())) + return true; + + // Visit the explicitly-specified template arguments. + if (const ExplicitTemplateArgumentList *ArgList + = E->getOptionalExplicitTemplateArgs()) { + for (const TemplateArgumentLoc *Arg = ArgList->getTemplateArgs(), + *ArgEnd = Arg + ArgList->NumTemplateArgs; + Arg != ArgEnd; ++Arg) { + if (VisitTemplateArgumentLoc(*Arg)) + return true; + } + } + + return false; +} + +bool CursorVisitor::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { + // Visit the base expression, if there is one. + if (!E->isImplicitAccess() && + Visit(MakeCXCursor(E->getBase(), StmtParent, TU))) + return true; + + return VisitOverloadExpr(E); +} + bool CursorVisitor::VisitObjCMessageExpr(ObjCMessageExpr *E) { if (TypeSourceInfo *TSInfo = E->getClassReceiverTypeInfo()) if (Visit(TSInfo->getTypeLoc())) @@ -1107,8 +1718,9 @@ bool CursorVisitor::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { bool CursorVisitor::VisitAttributes(Decl *D) { - for (const Attr *A = D->getAttrs(); A; A = A->getNext()) - if (Visit(MakeCXCursor(A, D, TU))) + for (AttrVec::const_iterator i = D->attr_begin(), e = D->attr_end(); + i != e; ++i) + if (Visit(MakeCXCursor(*i, D, TU))) return true; return false; @@ -1117,6 +1729,10 @@ bool CursorVisitor::VisitAttributes(Decl *D) { extern "C" { CXIndex clang_createIndex(int excludeDeclarationsFromPCH, int displayDiagnostics) { + // We use crash recovery to make some of our APIs more reliable, implicitly + // enable it. + llvm::CrashRecoveryContext::Enable(); + CIndexer *CIdxr = new CIndexer(); if (excludeDeclarationsFromPCH) CIdxr->setOnlyLocalDecls(); @@ -1128,6 +1744,8 @@ CXIndex clang_createIndex(int excludeDeclarationsFromPCH, void clang_disposeIndex(CXIndex CIdx) { if (CIdx) delete static_cast<CIndexer *>(CIdx); + if (getenv("LIBCLANG_TIMING")) + llvm::TimerGroup::printAll(llvm::errs()); } void clang_setUseExternalASTGeneration(CXIndex CIdx, int value) { @@ -1145,23 +1763,61 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx, CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); llvm::IntrusiveRefCntPtr<Diagnostic> Diags; - return ASTUnit::LoadFromPCHFile(ast_filename, Diags, + return ASTUnit::LoadFromASTFile(ast_filename, Diags, CXXIdx->getOnlyLocalDecls(), 0, 0, true); } +unsigned clang_defaultEditingTranslationUnitOptions() { + return CXTranslationUnit_PrecompiledPreamble; +} + CXTranslationUnit clang_createTranslationUnitFromSourceFile(CXIndex CIdx, const char *source_filename, int num_command_line_args, - const char **command_line_args, + const char * const *command_line_args, unsigned num_unsaved_files, struct CXUnsavedFile *unsaved_files) { + return clang_parseTranslationUnit(CIdx, source_filename, + command_line_args, num_command_line_args, + unsaved_files, num_unsaved_files, + CXTranslationUnit_DetailedPreprocessingRecord); +} + +struct ParseTranslationUnitInfo { + CXIndex CIdx; + const char *source_filename; + const char *const *command_line_args; + int num_command_line_args; + struct CXUnsavedFile *unsaved_files; + unsigned num_unsaved_files; + unsigned options; + CXTranslationUnit result; +}; +static void clang_parseTranslationUnit_Impl(void *UserData) { + ParseTranslationUnitInfo *PTUI = + static_cast<ParseTranslationUnitInfo*>(UserData); + CXIndex CIdx = PTUI->CIdx; + const char *source_filename = PTUI->source_filename; + const char * const *command_line_args = PTUI->command_line_args; + int num_command_line_args = PTUI->num_command_line_args; + struct CXUnsavedFile *unsaved_files = PTUI->unsaved_files; + unsigned num_unsaved_files = PTUI->num_unsaved_files; + unsigned options = PTUI->options; + PTUI->result = 0; + if (!CIdx) - return 0; + return; CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); + bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble; + bool CompleteTranslationUnit + = ((options & CXTranslationUnit_Incomplete) == 0); + bool CacheCodeCompetionResults + = options & CXTranslationUnit_CacheCompletionResults; + // Configure the diagnostics. DiagnosticOptions DiagOpts; llvm::IntrusiveRefCntPtr<Diagnostic> Diags; @@ -1195,8 +1851,13 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, Args.insert(Args.end(), command_line_args, command_line_args + num_command_line_args); - Args.push_back("-Xclang"); - Args.push_back("-detailed-preprocessing-record"); + + // Do we need the detailed preprocessing record? + if (options & CXTranslationUnit_DetailedPreprocessingRecord) { + Args.push_back("-Xclang"); + Args.push_back("-detailed-preprocessing-record"); + } + unsigned NumErrors = Diags->getNumErrors(); #ifdef USE_CRASHTRACER @@ -1210,7 +1871,10 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, CXXIdx->getOnlyLocalDecls(), RemappedFiles.data(), RemappedFiles.size(), - /*CaptureDiagnostics=*/true)); + /*CaptureDiagnostics=*/true, + PrecompilePreamble, + CompleteTranslationUnit, + CacheCodeCompetionResults)); if (NumErrors != Diags->getNumErrors()) { // Make sure to check that 'Unit' is non-NULL. @@ -1233,7 +1897,8 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, } } - return Unit.take(); + PTUI->result = Unit.take(); + return; } // Build up the arguments for invoking 'clang'. @@ -1269,7 +1934,7 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, std::vector<llvm::sys::Path> TemporaryFiles; std::vector<std::string> RemapArgs; if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) - return 0; + return; // The pointers into the elements of RemapArgs are stable because we // won't be adding anything to RemapArgs after this point. @@ -1300,9 +1965,12 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, TemporaryFiles.push_back(DiagnosticsFile); argv.push_back("-fdiagnostics-binary"); - argv.push_back("-Xclang"); - argv.push_back("-detailed-preprocessing-record"); - + // Do we need the detailed preprocessing record? + if (options & CXTranslationUnit_DetailedPreprocessingRecord) { + argv.push_back("-Xclang"); + argv.push_back("-detailed-preprocessing-record"); + } + // Add the null terminator. argv.push_back(NULL); @@ -1328,7 +1996,7 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg; } - ASTUnit *ATU = ASTUnit::LoadFromPCHFile(astTmpFile, Diags, + ASTUnit *ATU = ASTUnit::LoadFromASTFile(astTmpFile, Diags, CXXIdx->getOnlyLocalDecls(), RemappedFiles.data(), RemappedFiles.size(), @@ -1373,7 +2041,7 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, // Make the translation unit responsible for destroying all temporary files. for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i) ATU->addTemporaryFile(TemporaryFiles[i]); - ATU->addTemporaryFile(llvm::sys::Path(ATU->getPCHFileName())); + ATU->addTemporaryFile(llvm::sys::Path(ATU->getASTFileName())); } else { // Destroy all of the temporary files now; they can't be referenced any // longer. @@ -1382,13 +2050,124 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx, TemporaryFiles[i].eraseFromDisk(); } - return ATU; + PTUI->result = ATU; +} +CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx, + const char *source_filename, + const char * const *command_line_args, + int num_command_line_args, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options) { + ParseTranslationUnitInfo PTUI = { CIdx, source_filename, command_line_args, + num_command_line_args, unsaved_files, num_unsaved_files, + options, 0 }; + llvm::CrashRecoveryContext CRC; + + if (!CRC.RunSafely(clang_parseTranslationUnit_Impl, &PTUI)) { + fprintf(stderr, "libclang: crash detected during parsing: {\n"); + fprintf(stderr, " 'source_filename' : '%s'\n", source_filename); + fprintf(stderr, " 'command_line_args' : ["); + for (int i = 0; i != num_command_line_args; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "'%s'", command_line_args[i]); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'unsaved_files' : ["); + for (unsigned i = 0; i != num_unsaved_files; ++i) { + if (i) + fprintf(stderr, ", "); + fprintf(stderr, "('%s', '...', %ld)", unsaved_files[i].Filename, + unsaved_files[i].Length); + } + fprintf(stderr, "],\n"); + fprintf(stderr, " 'options' : %d,\n", options); + fprintf(stderr, "}\n"); + + return 0; + } + + return PTUI.result; +} + +unsigned clang_defaultSaveOptions(CXTranslationUnit TU) { + return CXSaveTranslationUnit_None; +} + +int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName, + unsigned options) { + if (!TU) + return 1; + + return static_cast<ASTUnit *>(TU)->Save(FileName); } void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) { - if (CTUnit) + if (CTUnit) { + // If the translation unit has been marked as unsafe to free, just discard + // it. + if (static_cast<ASTUnit *>(CTUnit)->isUnsafeToFree()) + return; + delete static_cast<ASTUnit *>(CTUnit); + } +} + +unsigned clang_defaultReparseOptions(CXTranslationUnit TU) { + return CXReparse_None; +} + +struct ReparseTranslationUnitInfo { + CXTranslationUnit TU; + unsigned num_unsaved_files; + struct CXUnsavedFile *unsaved_files; + unsigned options; + int result; +}; +static void clang_reparseTranslationUnit_Impl(void *UserData) { + ReparseTranslationUnitInfo *RTUI = + static_cast<ReparseTranslationUnitInfo*>(UserData); + CXTranslationUnit TU = RTUI->TU; + unsigned num_unsaved_files = RTUI->num_unsaved_files; + struct CXUnsavedFile *unsaved_files = RTUI->unsaved_files; + unsigned options = RTUI->options; + (void) options; + RTUI->result = 1; + + if (!TU) + return; + + llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; + for (unsigned I = 0; I != num_unsaved_files; ++I) { + llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); + RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, + Buffer)); + } + + if (!static_cast<ASTUnit *>(TU)->Reparse(RemappedFiles.data(), + RemappedFiles.size())) + RTUI->result = 0; } +int clang_reparseTranslationUnit(CXTranslationUnit TU, + unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + unsigned options) { + ReparseTranslationUnitInfo RTUI = { TU, num_unsaved_files, unsaved_files, + options, 0 }; + llvm::CrashRecoveryContext CRC; + + if (!CRC.RunSafely(clang_reparseTranslationUnit_Impl, &RTUI)) { + fprintf(stderr, "libclang: crash detected during reparsing\n"); + static_cast<ASTUnit *>(TU)->setUnsafeToFree(true); + return 1; + } + + return RTUI.result; +} + CXString clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit) { if (!CTUnit) @@ -1574,18 +2353,8 @@ unsigned clang_visitChildren(CXCursor parent, CXClientData client_data) { ASTUnit *CXXUnit = getCursorASTUnit(parent); - unsigned PCHLevel = Decl::MaxPCHLevel; - - // Set the PCHLevel to filter out unwanted decls if requested. - if (CXXUnit->getOnlyLocalDecls()) { - PCHLevel = 0; - - // If the main input was an AST, bump the level. - if (CXXUnit->isMainFileAST()) - ++PCHLevel; - } - - CursorVisitor CursorVis(CXXUnit, visitor, client_data, PCHLevel); + CursorVisitor CursorVis(CXXUnit, visitor, client_data, + CXXUnit->getMaxPCHLevel()); return CursorVis.VisitChildren(parent); } @@ -1603,6 +2372,9 @@ static CXString getDeclSpelling(Decl *D) { // ObjCCategoryImplDecl returns the category name. return createCXString(CIMP->getIdentifier()->getNameStart()); + if (isa<UsingDirectiveDecl>(D)) + return createCXString(""); + llvm::SmallString<1024> S; llvm::raw_svector_ostream os(S); ND->printName(os); @@ -1629,6 +2401,10 @@ CXString clang_getCursorSpelling(CXCursor C) { assert(OID && "getCursorSpelling(): Missing protocol decl"); return createCXString(OID->getIdentifier()->getNameStart()); } + case CXCursor_CXXBaseSpecifier: { + CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); + return createCXString(B->getType().getAsString()); + } case CXCursor_TypeRef: { TypeDecl *Type = getCursorTypeRef(C).first; assert(Type && "Missing type decl"); @@ -1636,6 +2412,19 @@ CXString clang_getCursorSpelling(CXCursor C) { return createCXString(getCursorContext(C).getTypeDeclType(Type). getAsString()); } + case CXCursor_TemplateRef: { + TemplateDecl *Template = getCursorTemplateRef(C).first; + assert(Template && "Missing template decl"); + + return createCXString(Template->getNameAsString()); + } + + case CXCursor_NamespaceRef: { + NamedDecl *NS = getCursorNamespaceRef(C).first; + assert(NS && "Missing namespace decl"); + + return createCXString(NS->getNameAsString()); + } default: return createCXString("<not implemented>"); @@ -1715,6 +2504,10 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("ObjCClassRef"); case CXCursor_TypeRef: return createCXString("TypeRef"); + case CXCursor_TemplateRef: + return createCXString("TemplateRef"); + case CXCursor_NamespaceRef: + return createCXString("NamespaceRef"); case CXCursor_UnexposedExpr: return createCXString("UnexposedExpr"); case CXCursor_BlockExpr: @@ -1757,6 +2550,32 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("Namespace"); case CXCursor_LinkageSpec: return createCXString("LinkageSpec"); + case CXCursor_CXXBaseSpecifier: + return createCXString("C++ base class specifier"); + case CXCursor_Constructor: + return createCXString("CXXConstructor"); + case CXCursor_Destructor: + return createCXString("CXXDestructor"); + case CXCursor_ConversionFunction: + return createCXString("CXXConversion"); + case CXCursor_TemplateTypeParameter: + return createCXString("TemplateTypeParameter"); + case CXCursor_NonTypeTemplateParameter: + return createCXString("NonTypeTemplateParameter"); + case CXCursor_TemplateTemplateParameter: + return createCXString("TemplateTemplateParameter"); + case CXCursor_FunctionTemplate: + return createCXString("FunctionTemplate"); + case CXCursor_ClassTemplate: + return createCXString("ClassTemplate"); + case CXCursor_ClassTemplatePartialSpecialization: + return createCXString("ClassTemplatePartialSpecialization"); + case CXCursor_NamespaceAlias: + return createCXString("NamespaceAlias"); + case CXCursor_UsingDirective: + return createCXString("UsingDirective"); + case CXCursor_UsingDeclaration: + return createCXString("UsingDeclaration"); } llvm_unreachable("Unhandled CXCursorKind"); @@ -1776,20 +2595,28 @@ CXCursor clang_getCursor(CXTranslationUnit TU, CXSourceLocation Loc) { return clang_getNullCursor(); ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU); - ASTUnit::ConcurrencyCheck Check(*CXXUnit); + // Translate the given source location to make it point at the beginning of + // the token under the cursor. SourceLocation SLoc = cxloc::translateSourceLocation(Loc); + + // Guard against an invalid SourceLocation, or we may assert in one + // of the following calls. + if (SLoc.isInvalid()) + return clang_getNullCursor(); + + SLoc = Lexer::GetBeginningOfToken(SLoc, CXXUnit->getSourceManager(), + CXXUnit->getASTContext().getLangOptions()); + CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound); if (SLoc.isValid()) { - SourceRange RegionOfInterest(SLoc, SLoc.getFileLocWithOffset(1)); - // 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. CXCursor Parent = clang_getTranslationUnitCursor(CXXUnit); CursorVisitor CursorVis(CXXUnit, GetCursorVisitor, &Result, - Decl::MaxPCHLevel, RegionOfInterest); + Decl::MaxPCHLevel, SourceLocation(SLoc)); CursorVis.VisitChildren(Parent); } return Result; @@ -1873,6 +2700,21 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); } + case CXCursor_TemplateRef: { + std::pair<TemplateDecl *, SourceLocation> P = getCursorTemplateRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_NamespaceRef: { + std::pair<NamedDecl *, SourceLocation> P = getCursorNamespaceRef(C); + return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); + } + + case CXCursor_CXXBaseSpecifier: { + // FIXME: Figure out what location to return for a CXXBaseSpecifier. + return clang_getNullLocation(); + } + default: // FIXME: Need a way to enumerate all non-reference cases. llvm_unreachable("Missed a reference kind"); @@ -1909,67 +2751,68 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { return cxloc::translateSourceLocation(getCursorContext(C), Loc); } -CXSourceRange clang_getCursorExtent(CXCursor C) { +} // end extern "C" + +static SourceRange getRawCursorExtent(CXCursor C) { if (clang_isReference(C.kind)) { switch (C.kind) { - case CXCursor_ObjCSuperClassRef: { - std::pair<ObjCInterfaceDecl *, SourceLocation> P - = getCursorObjCSuperClassRef(C); - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } + case CXCursor_ObjCSuperClassRef: + return getCursorObjCSuperClassRef(C).second; - case CXCursor_ObjCProtocolRef: { - std::pair<ObjCProtocolDecl *, SourceLocation> P - = getCursorObjCProtocolRef(C); - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } + case CXCursor_ObjCProtocolRef: + return getCursorObjCProtocolRef(C).second; - case CXCursor_ObjCClassRef: { - std::pair<ObjCInterfaceDecl *, SourceLocation> P - = getCursorObjCClassRef(C); + case CXCursor_ObjCClassRef: + return getCursorObjCClassRef(C).second; - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } + case CXCursor_TypeRef: + return getCursorTypeRef(C).second; - case CXCursor_TypeRef: { - std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C); - return cxloc::translateSourceRange(P.first->getASTContext(), P.second); - } + case CXCursor_TemplateRef: + return getCursorTemplateRef(C).second; + + case CXCursor_NamespaceRef: + return getCursorNamespaceRef(C).second; + + case CXCursor_CXXBaseSpecifier: + // FIXME: Figure out what source range to use for a CXBaseSpecifier. + return SourceRange(); - default: - // FIXME: Need a way to enumerate all non-reference cases. - llvm_unreachable("Missed a reference kind"); + default: + // FIXME: Need a way to enumerate all non-reference cases. + llvm_unreachable("Missed a reference kind"); } } if (clang_isExpression(C.kind)) - return cxloc::translateSourceRange(getCursorContext(C), - getCursorExpr(C)->getSourceRange()); + return getCursorExpr(C)->getSourceRange(); if (clang_isStatement(C.kind)) - return cxloc::translateSourceRange(getCursorContext(C), - getCursorStmt(C)->getSourceRange()); + return getCursorStmt(C)->getSourceRange(); - if (C.kind == CXCursor_PreprocessingDirective) { - SourceRange R = cxcursor::getCursorPreprocessingDirective(C); - return cxloc::translateSourceRange(getCursorContext(C), R); - } + if (C.kind == CXCursor_PreprocessingDirective) + return cxcursor::getCursorPreprocessingDirective(C); - if (C.kind == CXCursor_MacroInstantiation) { - SourceRange R = cxcursor::getCursorMacroInstantiation(C)->getSourceRange(); - return cxloc::translateSourceRange(getCursorContext(C), R); - } + if (C.kind == CXCursor_MacroInstantiation) + return cxcursor::getCursorMacroInstantiation(C)->getSourceRange(); - if (C.kind == CXCursor_MacroDefinition) { - SourceRange R = cxcursor::getCursorMacroDefinition(C)->getSourceRange(); - return cxloc::translateSourceRange(getCursorContext(C), R); - } + if (C.kind == CXCursor_MacroDefinition) + return cxcursor::getCursorMacroDefinition(C)->getSourceRange(); - if (C.kind < CXCursor_FirstDecl || C.kind > CXCursor_LastDecl) + if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) + return getCursorDecl(C)->getSourceRange(); + + return SourceRange(); +} + +extern "C" { + +CXSourceRange clang_getCursorExtent(CXCursor C) { + SourceRange R = getRawCursorExtent(C); + if (R.isInvalid()) return clang_getNullRange(); - Decl *D = getCursorDecl(C); - return cxloc::translateSourceRange(getCursorContext(C), D->getSourceRange()); + return cxloc::translateSourceRange(getCursorContext(C), R); } CXCursor clang_getCursorReferenced(CXCursor C) { @@ -2008,6 +2851,18 @@ CXCursor clang_getCursorReferenced(CXCursor C) { case CXCursor_TypeRef: return MakeCXCursor(getCursorTypeRef(C).first, CXXUnit); + case CXCursor_TemplateRef: + return MakeCXCursor(getCursorTemplateRef(C).first, CXXUnit); + + case CXCursor_NamespaceRef: + return MakeCXCursor(getCursorNamespaceRef(C).first, CXXUnit); + + case CXCursor_CXXBaseSpecifier: { + CXXBaseSpecifier *B = cxcursor::getCursorCXXBaseSpecifier(C); + return clang_getTypeDeclaration(cxtype::MakeCXType(B->getType(), + CXXUnit)); + } + default: // We would prefer to enumerate all non-reference cursor kinds here. llvm_unreachable("Unhandled reference cursor kind"); @@ -2118,8 +2973,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::ClassTemplate: { if (RecordDecl *Def = cast<ClassTemplateDecl>(D)->getTemplatedDecl() ->getDefinition()) - return MakeCXCursor( - cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(), + return MakeCXCursor(cast<CXXRecordDecl>(Def)->getDescribedClassTemplate(), CXXUnit); return clang_getNullCursor(); } @@ -2530,8 +3384,7 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { return CXChildVisit_Recurse; } - CXSourceRange cursorExtent = clang_getCursorExtent(cursor); - SourceRange cursorRange = cxloc::translateCXSourceRange(cursorExtent); + SourceRange cursorRange = getRawCursorExtent(cursor); if (cursorRange.isInvalid()) return CXChildVisit_Continue; @@ -2559,11 +3412,27 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { } } + // If the location of the cursor occurs within a macro instantiation, record + // the spelling location of the cursor in our annotation map. We can then + // paper over the token labelings during a post-processing step to try and + // get cursor mappings for tokens that are the *arguments* of a macro + // instantiation. + if (L.isMacroID()) { + unsigned rawEncoding = SrcMgr.getSpellingLoc(L).getRawEncoding(); + // Only invalidate the old annotation if it isn't part of a preprocessing + // directive. Here we assume that the default construction of CXCursor + // results in CXCursor.kind being an initialized value (i.e., 0). If + // this isn't the case, we can fix by doing lookup + insertion. + + CXCursor &oldC = Annotated[rawEncoding]; + if (!clang_isPreprocessing(oldC.kind)) + oldC = cursor; + } + const enum CXCursorKind K = clang_getCursorKind(parent); const CXCursor updateC = - (clang_isInvalid(K) || K == CXCursor_TranslationUnit || - L.isMacroID()) - ? clang_getNullCursor() : parent; + (clang_isInvalid(K) || K == CXCursor_TranslationUnit) + ? clang_getNullCursor() : parent; while (MoreTokens()) { const unsigned I = NextToken(); @@ -2574,7 +3443,6 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) { AdvanceToken(); continue; case RangeAfter: - return CXChildVisit_Continue; case RangeOverlap: break; } @@ -2658,11 +3526,9 @@ void clang_annotateTokens(CXTranslationUnit TU, SourceRange RegionOfInterest; RegionOfInterest.setBegin(cxloc::translateSourceLocation( clang_getTokenLocation(TU, Tokens[0]))); - - SourceLocation End - = cxloc::translateSourceLocation(clang_getTokenLocation(TU, - Tokens[NumTokens - 1])); - RegionOfInterest.setEnd(CXXUnit->getPreprocessor().getLocForEndOfToken(End)); + RegionOfInterest.setEnd(cxloc::translateSourceLocation( + clang_getTokenLocation(TU, + Tokens[NumTokens - 1]))); // A mapping from the source locations found when re-lexing or traversing the // region of interest to the corresponding cursors. @@ -2811,6 +3677,21 @@ static CXLanguageKind getDeclLanguage(const Decl *D) { } extern "C" { + +enum CXAvailabilityKind clang_getCursorAvailability(CXCursor cursor) { + if (clang_isDeclaration(cursor.kind)) + if (Decl *D = cxcursor::getCursorDecl(cursor)) { + if (D->hasAttr<UnavailableAttr>() || + (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isDeleted())) + return CXAvailability_Available; + + if (D->hasAttr<DeprecatedAttr>()) + return CXAvailability_Deprecated; + } + + return CXAvailability_Available; +} + CXLanguageKind clang_getCursorLanguage(CXCursor cursor) { if (clang_isDeclaration(cursor.kind)) return getDeclLanguage(cxcursor::getCursorDecl(cursor)); @@ -2828,13 +3709,35 @@ extern "C" { unsigned clang_CXXMethod_isStatic(CXCursor C) { if (!clang_isDeclaration(C.kind)) return 0; - CXXMethodDecl *D = dyn_cast<CXXMethodDecl>(cxcursor::getCursorDecl(C)); - return (D && D->isStatic()) ? 1 : 0; + + CXXMethodDecl *Method = 0; + Decl *D = cxcursor::getCursorDecl(C); + if (FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(D)) + Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl()); + else + Method = dyn_cast_or_null<CXXMethodDecl>(D); + return (Method && Method->isStatic()) ? 1 : 0; } } // end: extern "C" //===----------------------------------------------------------------------===// +// Attribute introspection. +//===----------------------------------------------------------------------===// + +extern "C" { +CXType clang_getIBOutletCollectionType(CXCursor C) { + if (C.kind != CXCursor_IBOutletCollectionAttr) + return cxtype::MakeCXType(QualType(), cxcursor::getCursorASTUnit(C)); + + IBOutletCollectionAttr *A = + cast<IBOutletCollectionAttr>(cxcursor::getCursorAttr(C)); + + return cxtype::MakeCXType(A->getInterface(), cxcursor::getCursorASTUnit(C)); +} +} // end: extern "C" + +//===----------------------------------------------------------------------===// // CXString Operations. //===----------------------------------------------------------------------===// diff --git a/tools/libclang/CIndexCXX.cpp b/tools/libclang/CIndexCXX.cpp new file mode 100644 index 0000000..3ade519 --- /dev/null +++ b/tools/libclang/CIndexCXX.cpp @@ -0,0 +1,124 @@ +//===- CIndexCXX.cpp - Clang-C Source Indexing 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 libclang support for C++ cursors. +// +//===----------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "CXType.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" + +using namespace clang; +using namespace clang::cxstring; +using namespace clang::cxcursor; + +extern "C" { + +unsigned clang_isVirtualBase(CXCursor C) { + if (C.kind != CXCursor_CXXBaseSpecifier) + return 0; + + CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); + return B->isVirtual(); +} + +enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) { + if (C.kind != CXCursor_CXXBaseSpecifier) + return CX_CXXInvalidAccessSpecifier; + + CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); + switch (B->getAccessSpecifier()) { + case AS_public: return CX_CXXPublic; + case AS_protected: return CX_CXXProtected; + case AS_private: return CX_CXXPrivate; + case AS_none: return CX_CXXInvalidAccessSpecifier; + } + + // FIXME: Clang currently thinks this is reachable. + return CX_CXXInvalidAccessSpecifier; +} + +enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) { + using namespace clang::cxcursor; + + switch (C.kind) { + case CXCursor_ClassTemplate: + case CXCursor_FunctionTemplate: + if (TemplateDecl *Template + = dyn_cast_or_null<TemplateDecl>(getCursorDecl(C))) + return MakeCXCursor(Template->getTemplatedDecl(), + getCursorASTUnit(C)).kind; + break; + + case CXCursor_ClassTemplatePartialSpecialization: + if (ClassTemplateSpecializationDecl *PartialSpec + = dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>( + getCursorDecl(C))) { + switch (PartialSpec->getTagKind()) { + case TTK_Class: return CXCursor_ClassDecl; + case TTK_Struct: return CXCursor_StructDecl; + case TTK_Union: return CXCursor_UnionDecl; + case TTK_Enum: return CXCursor_NoDeclFound; + } + } + break; + + default: + break; + } + + return CXCursor_NoDeclFound; +} + +CXCursor clang_getSpecializedCursorTemplate(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return clang_getNullCursor(); + + Decl *D = getCursorDecl(C); + if (!D) + return clang_getNullCursor(); + + Decl *Template = 0; + if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) { + if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) + Template = PartialSpec->getSpecializedTemplate(); + else if (ClassTemplateSpecializationDecl *ClassSpec + = dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) { + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> Result + = ClassSpec->getSpecializedTemplateOrPartial(); + if (Result.is<ClassTemplateDecl *>()) + Template = Result.get<ClassTemplateDecl *>(); + else + Template = Result.get<ClassTemplatePartialSpecializationDecl *>(); + + } else + Template = CXXRecord->getInstantiatedFromMemberClass(); + } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + Template = Function->getPrimaryTemplate(); + if (!Template) + Template = Function->getInstantiatedFromMemberFunction(); + } else if (VarDecl *Var = dyn_cast<VarDecl>(D)) { + if (Var->isStaticDataMember()) + Template = Var->getInstantiatedFromStaticDataMember(); + } else if (RedeclarableTemplateDecl *Tmpl + = dyn_cast<RedeclarableTemplateDecl>(D)) + Template = Tmpl->getInstantiatedFromMemberTemplate(); + + if (!Template) + return clang_getNullCursor(); + + return MakeCXCursor(Template, getCursorASTUnit(C)); +} + +} // end extern "C" diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index 277fadf..d591c5d 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -16,18 +16,23 @@ #include "CIndexDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" +#include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Sema/CodeCompleteConsumer.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Timer.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/System/Program.h" +#include <cstdlib> +#include <cstdio> + #ifdef UDP_CODE_COMPLETION_LOGGER #include "clang/Basic/Version.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/Support/Timer.h" -#include "llvm/Support/raw_ostream.h" #include <arpa/inet.h> #include <sys/socket.h> #include <sys/types.h> @@ -43,11 +48,15 @@ namespace { /// This is the representation behind a CXCompletionString. class CXStoredCodeCompletionString : public CodeCompletionString { unsigned Priority; + CXAvailabilityKind Availability; public: - CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { } + CXStoredCodeCompletionString(unsigned Priority, + CXAvailabilityKind Availability) + : Priority(Priority), Availability(Availability) { } unsigned getPriority() const { return Priority; } + CXAvailabilityKind getAvailability() const { return Availability; } }; } @@ -205,6 +214,13 @@ unsigned clang_getCompletionPriority(CXCompletionString completion_string) { return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely); } +enum CXAvailabilityKind +clang_getCompletionAvailability(CXCompletionString completion_string) { + CXStoredCodeCompletionString *CCStr + = (CXStoredCodeCompletionString *)completion_string; + return CCStr? CCStr->getAvailability() : CXAvailability_Available; +} + static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, unsigned &Value) { if (Memory + sizeof(unsigned) > MemoryEnd) @@ -221,15 +237,11 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { AllocatedCXCodeCompleteResults(); ~AllocatedCXCodeCompleteResults(); - /// \brief The memory buffer from which we parsed the results. We - /// retain this buffer because the completion strings point into it. - llvm::MemoryBuffer *Buffer; - /// \brief Diagnostics produced while performing code completion. llvm::SmallVector<StoredDiagnostic, 8> Diagnostics; /// \brief Diag object - Diagnostic Diag; + llvm::IntrusiveRefCntPtr<Diagnostic> Diag; /// \brief Language options used to adjust source locations. LangOptions LangOpts; @@ -243,25 +255,29 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { /// \brief Temporary files that should be removed once we have finished /// with the code-completion results. std::vector<llvm::sys::Path> TemporaryFiles; + + /// \brief Temporary buffers that will be deleted once we have finished with the code-completion results. + llvm::SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers; }; AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() - : CXCodeCompleteResults(), Buffer(0), SourceMgr(Diag) { } + : CXCodeCompleteResults(), Diag(new Diagnostic), SourceMgr(*Diag) { } AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { for (unsigned I = 0, N = NumResults; I != N; ++I) delete (CXStoredCodeCompletionString *)Results[I].CompletionString; delete [] Results; - delete Buffer; for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) TemporaryFiles[I].eraseFromDisk(); + for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I) + delete TemporaryBuffers[I]; } CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, const char *source_filename, int num_command_line_args, - const char **command_line_args, + const char * const *command_line_args, unsigned num_unsaved_files, struct CXUnsavedFile *unsaved_files, const char *complete_filename, @@ -273,6 +289,17 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, #endif #endif + bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; + + llvm::OwningPtr<llvm::NamedRegionTimer> CCTimer; + if (getenv("LIBCLANG_TIMING")) { + llvm::SmallString<128> TimerName; + llvm::raw_svector_ostream TimerNameOut(TimerName); + TimerNameOut << "Code completion (out-of-process) @ " << complete_filename + << ":" << complete_line << ":" << complete_column; + CCTimer.reset(new llvm::NamedRegionTimer(TimerNameOut.str())); + } + // The indexer, which is mainly used to determine where diagnostics go. CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); @@ -348,6 +375,15 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, argv.push_back(arg); } + if (EnableLogging) { + std::string Log = ClangPath.str(); + for (unsigned I = 0, N = argv.size(); I != N; ++I) { + Log += ' '; + Log += argv[I]; + } + fprintf(stderr, "libclang (Code Completion): %s\n", Log.c_str()); + } + // Add the null terminator. argv.push_back(NULL); @@ -363,6 +399,8 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, llvm::sys::Path DiagnosticsFile(tmpResultsFileName); TemporaryFiles.push_back(DiagnosticsFile); + + // Invoke 'clang'. llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null // on Unix or NUL (Windows). @@ -392,7 +430,6 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; Results->Results = 0; Results->NumResults = 0; - Results->Buffer = 0; // FIXME: Set Results->LangOpts! if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) { llvm::SmallVector<CXCompletionResult, 4> CompletionResults; @@ -407,8 +444,13 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, if (ReadUnsigned(Str, StrEnd, Priority)) break; + unsigned Availability; + if (ReadUnsigned(Str, StrEnd, Availability)) + break; + CXStoredCodeCompletionString *CCStr - = new CXStoredCodeCompletionString(Priority); + = new CXStoredCodeCompletionString(Priority, + (CXAvailabilityKind)Availability); if (!CCStr->Deserialize(Str, StrEnd)) { delete CCStr; continue; @@ -428,7 +470,7 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, Results->NumResults = CompletionResults.size(); memcpy(Results->Results, CompletionResults.data(), CompletionResults.size() * sizeof(CXCompletionResult)); - Results->Buffer = F; + Results->TemporaryBuffers.push_back(F); } LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files, @@ -511,9 +553,208 @@ CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, } #endif #endif + clang_sortCodeCompletionResults(Results->Results, Results->NumResults); return Results; } +} // end extern "C" + +namespace { + class CaptureCompletionResults : public CodeCompleteConsumer { + AllocatedCXCodeCompleteResults &AllocatedResults; + + public: + explicit CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results) + : CodeCompleteConsumer(true, false, true, false), + AllocatedResults(Results) { } + + virtual void ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) { + AllocatedResults.Results = new CXCompletionResult [NumResults]; + AllocatedResults.NumResults = NumResults; + for (unsigned I = 0; I != NumResults; ++I) { + CXStoredCodeCompletionString *StoredCompletion + = new CXStoredCodeCompletionString(Results[I].Priority, + Results[I].Availability); + (void)Results[I].CreateCodeCompletionString(S, StoredCompletion); + AllocatedResults.Results[I].CursorKind = Results[I].CursorKind; + AllocatedResults.Results[I].CompletionString = StoredCompletion; + } + } + + // FIXME: Add ProcessOverloadCandidates? + }; +} + +extern "C" { +struct CodeCompleteAtInfo { + CXTranslationUnit TU; + const char *complete_filename; + unsigned complete_line; + unsigned complete_column; + struct CXUnsavedFile *unsaved_files; + unsigned num_unsaved_files; + unsigned options; + CXCodeCompleteResults *result; +}; +void clang_codeCompleteAt_Impl(void *UserData) { + CodeCompleteAtInfo *CCAI = static_cast<CodeCompleteAtInfo*>(UserData); + CXTranslationUnit TU = CCAI->TU; + const char *complete_filename = CCAI->complete_filename; + unsigned complete_line = CCAI->complete_line; + unsigned complete_column = CCAI->complete_column; + struct CXUnsavedFile *unsaved_files = CCAI->unsaved_files; + unsigned num_unsaved_files = CCAI->num_unsaved_files; + unsigned options = CCAI->options; + CCAI->result = 0; + +#ifdef UDP_CODE_COMPLETION_LOGGER +#ifdef UDP_CODE_COMPLETION_LOGGER_PORT + const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); +#endif +#endif + + bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; + + ASTUnit *AST = static_cast<ASTUnit *>(TU); + if (!AST) + return; + + // Perform the remapping of source files. + llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; + for (unsigned I = 0; I != num_unsaved_files; ++I) { + llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); + const llvm::MemoryBuffer *Buffer + = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); + RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, + Buffer)); + } + + if (EnableLogging) { + // FIXME: Add logging. + } + + // Parse the resulting source file to find code-completion results. + AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; + Results->Results = 0; + Results->NumResults = 0; + + // Create a code-completion consumer to capture the results. + CaptureCompletionResults Capture(*Results); + + // Perform completion. + AST->CodeComplete(complete_filename, complete_line, complete_column, + RemappedFiles.data(), RemappedFiles.size(), + (options & CXCodeComplete_IncludeMacros), + (options & CXCodeComplete_IncludeCodePatterns), + Capture, + *Results->Diag, Results->LangOpts, Results->SourceMgr, + Results->FileMgr, Results->Diagnostics, + Results->TemporaryBuffers); + + + +#ifdef UDP_CODE_COMPLETION_LOGGER +#ifdef UDP_CODE_COMPLETION_LOGGER_PORT + const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); + llvm::SmallString<256> LogResult; + llvm::raw_svector_ostream os(LogResult); + + // Figure out the language and whether or not it uses PCH. + const char *lang = 0; + bool usesPCH = false; + + for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); + I != E; ++I) { + if (*I == 0) + continue; + if (strcmp(*I, "-x") == 0) { + if (I + 1 != E) { + lang = *(++I); + continue; + } + } + else if (strcmp(*I, "-include") == 0) { + if (I+1 != E) { + const char *arg = *(++I); + llvm::SmallString<512> pchName; + { + llvm::raw_svector_ostream os(pchName); + os << arg << ".pth"; + } + pchName.push_back('\0'); + struct stat stat_results; + if (stat(pchName.data(), &stat_results) == 0) + usesPCH = true; + continue; + } + } + } + + os << "{ "; + os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); + os << ", \"numRes\": " << Results->NumResults; + os << ", \"diags\": " << Results->Diagnostics.size(); + os << ", \"pch\": " << (usesPCH ? "true" : "false"); + os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; + const char *name = getlogin(); + os << ", \"user\": \"" << (name ? name : "unknown") << '"'; + os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; + os << " }"; + + llvm::StringRef res = os.str(); + if (res.size() > 0) { + do { + // Setup the UDP socket. + struct sockaddr_in servaddr; + bzero(&servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); + if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, + &servaddr.sin_addr) <= 0) + break; + + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + break; + + sendto(sockfd, res.data(), res.size(), 0, + (struct sockaddr *)&servaddr, sizeof(servaddr)); + close(sockfd); + } + while (false); + } +#endif +#endif + CCAI->result = Results; +} +CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU, + const char *complete_filename, + unsigned complete_line, + unsigned complete_column, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, + unsigned options) { + CodeCompleteAtInfo CCAI = { TU, complete_filename, complete_line, + complete_column, unsaved_files, num_unsaved_files, + options, 0 }; + llvm::CrashRecoveryContext CRC; + + if (!CRC.RunSafely(clang_codeCompleteAt_Impl, &CCAI)) { + fprintf(stderr, "libclang: crash detected in code completion\n"); + static_cast<ASTUnit *>(TU)->setUnsafeToFree(true); + return 0; + } + + return CCAI.result; +} + +unsigned clang_defaultCodeCompleteOptions(void) { + return CXCodeComplete_IncludeMacros; +} + void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { if (!ResultsIn) return; @@ -522,7 +763,7 @@ void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); delete Results; } - + unsigned clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) { AllocatedCXCodeCompleteResults *Results @@ -546,3 +787,36 @@ clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn, } // end extern "C" + +namespace { + struct OrderCompletionResults { + bool operator()(const CXCompletionResult &XR, + const CXCompletionResult &YR) const { + CXStoredCodeCompletionString *X + = (CXStoredCodeCompletionString *)XR.CompletionString; + CXStoredCodeCompletionString *Y + = (CXStoredCodeCompletionString *)YR.CompletionString; + + const char *XText = X->getTypedText(); + const char *YText = Y->getTypedText(); + if (!XText || !YText) + return XText != 0; + + int result = llvm::StringRef(XText).compare_lower(YText); + if (result < 0) + return true; + if (result > 0) + return false; + + result = llvm::StringRef(XText).compare(YText); + return result; + } + }; +} + +extern "C" { + void clang_sortCodeCompletionResults(CXCompletionResult *Results, + unsigned NumResults) { + std::stable_sort(Results, Results + NumResults, OrderCompletionResults()); + } +} diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp index 3db37b9..531992e 100644 --- a/tools/libclang/CIndexDiagnostic.cpp +++ b/tools/libclang/CIndexDiagnostic.cpp @@ -204,26 +204,13 @@ CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt, const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt]; if (ReplacementRange) { - if (Hint.RemoveRange.isInvalid()) { - // Create an empty range that refers to a single source - // location (which is the insertion point). - CXSourceRange Range = { - { (void *)&StoredDiag->Diag.getLocation().getManager(), - (void *)&StoredDiag->LangOpts }, - Hint.InsertionLoc.getRawEncoding(), - Hint.InsertionLoc.getRawEncoding() - }; - - *ReplacementRange = Range; - } else { - // Create a range that covers the entire replacement (or - // removal) range, adjusting the end of the range to point to - // the end of the token. - *ReplacementRange - = translateSourceRange(StoredDiag->Diag.getLocation().getManager(), - StoredDiag->LangOpts, - Hint.RemoveRange); - } + // Create a range that covers the entire replacement (or + // removal) range, adjusting the end of the range to point to + // the end of the token. + *ReplacementRange + = translateSourceRange(StoredDiag->Diag.getLocation().getManager(), + StoredDiag->LangOpts, + Hint.RemoveRange); } return createCXString(Hint.CodeToInsert); diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index e98fd26..8f3dacf 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -13,6 +13,7 @@ #include "CIndexer.h" #include "CXCursor.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Lex/PreprocessingRecord.h" @@ -64,6 +65,9 @@ public: void VisitFunctionDecl(FunctionDecl *D); void VisitNamedDecl(NamedDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); + void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + void VisitClassTemplateDecl(ClassTemplateDecl *D); void VisitObjCClassDecl(ObjCClassDecl *CD); void VisitObjCContainerDecl(ObjCContainerDecl *CD); void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *P); @@ -72,12 +76,26 @@ public: void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitTagDecl(TagDecl *D); void VisitTypedefDecl(TypedefDecl *D); + void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitVarDecl(VarDecl *D); + void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D) { IgnoreResults = true; - return; } - + void VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + IgnoreResults = true; + } + void VisitUsingDecl(UsingDecl *D) { + IgnoreResults = true; + } + void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + IgnoreResults = true; + } + void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { + IgnoreResults = true; + } + /// Generate the string component containing the location of the /// declaration. bool GenLoc(const Decl *D); @@ -104,7 +122,10 @@ public: void GenObjCProtocol(llvm::StringRef prot); void VisitType(QualType T); - + void VisitTemplateParameterList(const TemplateParameterList *Params); + void VisitTemplateName(TemplateName Name); + void VisitTemplateArgument(const TemplateArgument &Arg); + /// Emit a Decl's name using NamedDecl::printName() and return true if /// the decl had no name. bool EmitDeclName(const NamedDecl *D); @@ -155,7 +176,11 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { return; VisitDeclContext(D->getDeclContext()); - Out << "@F@"; + if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) { + Out << "@FT@"; + VisitTemplateParameterList(FunTmpl->getTemplateParameters()); + } else + Out << "@F@"; D->printName(Out); ASTContext &Ctx = AU->getASTContext(); @@ -207,7 +232,7 @@ void USRGenerator::VisitVarDecl(VarDecl *D) { // The string can be empty if the declaration has no name; e.g., it is // the ParmDecl with no name for declaration of a function pointer type, e.g.: - // void (*f)(void *); + // void (*f)(void *); // In this case, don't generate a USR. if (s.empty()) IgnoreResults = true; @@ -215,6 +240,16 @@ void USRGenerator::VisitVarDecl(VarDecl *D) { Out << '@' << s; } +void USRGenerator::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + GenLoc(D); + return; +} + +void USRGenerator::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + GenLoc(D); + return; +} + void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { if (D->isAnonymousNamespace()) { Out << "@aN"; @@ -226,8 +261,35 @@ void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { Out << "@N@" << D->getName(); } +void USRGenerator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + VisitFunctionDecl(D->getTemplatedDecl()); +} + +void USRGenerator::VisitClassTemplateDecl(ClassTemplateDecl *D) { + VisitTagDecl(D->getTemplatedDecl()); +} + +void USRGenerator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + VisitDeclContext(D->getDeclContext()); + if (!IgnoreResults) + Out << "@NA@" << D->getName(); +} + void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { - Visit(cast<Decl>(D->getDeclContext())); + Decl *container = cast<Decl>(D->getDeclContext()); + + // The USR for a method declared in a class extension is based on + // the ObjCInterfaceDecl, not the ObjCCategoryDecl. + do { + if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(container)) + if (CD->IsClassExtension()) { + Visit(CD->getClassInterface()); + break; + } + Visit(cast<Decl>(D->getDeclContext())); + } + while (false); + // Ideally we would use 'GenObjCMethod', but this is such a hot path // for Objective-C code that we don't want to use // DeclarationName::getAsString(). @@ -267,7 +329,15 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) { IgnoreResults = true; return; } - GenObjCCategory(ID->getName(), CD->getName()); + // Specially handle class extensions, which are anonymous categories. + // We want to mangle in the location to uniquely distinguish them. + if (CD->IsClassExtension()) { + Out << "objc(ext)" << ID->getName() << '@'; + GenLoc(CD); + } + else + GenObjCCategory(ID->getName(), CD->getName()); + break; } case Decl::ObjCCategoryImpl: { @@ -313,13 +383,41 @@ void USRGenerator::VisitTagDecl(TagDecl *D) { D = D->getCanonicalDecl(); VisitDeclContext(D->getDeclContext()); - switch (D->getTagKind()) { - case TTK_Struct: Out << "@S"; break; - case TTK_Class: Out << "@C"; break; - case TTK_Union: Out << "@U"; break; - case TTK_Enum: Out << "@E"; break; + bool AlreadyStarted = false; + if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) { + if (ClassTemplateDecl *ClassTmpl = CXXRecord->getDescribedClassTemplate()) { + AlreadyStarted = true; + + switch (D->getTagKind()) { + case TTK_Struct: Out << "@ST"; break; + case TTK_Class: Out << "@CT"; break; + case TTK_Union: Out << "@UT"; break; + case TTK_Enum: llvm_unreachable("enum template"); break; + } + VisitTemplateParameterList(ClassTmpl->getTemplateParameters()); + } else if (ClassTemplatePartialSpecializationDecl *PartialSpec + = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) { + AlreadyStarted = true; + + switch (D->getTagKind()) { + case TTK_Struct: Out << "@SP"; break; + case TTK_Class: Out << "@CP"; break; + case TTK_Union: Out << "@UP"; break; + case TTK_Enum: llvm_unreachable("enum partial specialization"); break; + } + VisitTemplateParameterList(PartialSpec->getTemplateParameters()); + } } - + + if (!AlreadyStarted) { + switch (D->getTagKind()) { + case TTK_Struct: Out << "@S"; break; + case TTK_Class: Out << "@C"; break; + case TTK_Union: Out << "@U"; break; + case TTK_Enum: Out << "@E"; break; + } + } + Out << '@'; Out.flush(); assert(Buf.size() > 0); @@ -333,6 +431,17 @@ void USRGenerator::VisitTagDecl(TagDecl *D) { else Buf[off] = 'a'; } + + // For a class template specialization, mangle the template arguments. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs(); + Out << '>'; + for (unsigned I = 0, N = Args.size(); I != N; ++I) { + Out << '#'; + VisitTemplateArgument(Args.get(I)); + } + } } void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { @@ -345,6 +454,11 @@ void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { Out << D->getName(); } +void USRGenerator::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + GenLoc(D); + return; +} + bool USRGenerator::GenLoc(const Decl *D) { if (generatedLoc) return IgnoreResults; @@ -368,10 +482,10 @@ bool USRGenerator::GenLoc(const Decl *D) { IgnoreResults = true; return true; } - Out << '@' - << SM.getLineNumber(Decomposed.first, Decomposed.second) << ':' - << SM.getColumnNumber(Decomposed.first, Decomposed.second); - + // Use the offest into the FileID to represent the location. Using + // a line/column can cause us to look back at the original source file, + // which is expensive. + Out << '@' << Decomposed.second; return IgnoreResults; } @@ -494,13 +608,100 @@ void USRGenerator::VisitType(QualType T) { VisitTagDecl(TT->getDecl()); return; } - + if (const TemplateTypeParmType *TTP = T->getAs<TemplateTypeParmType>()) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + if (const TemplateSpecializationType *Spec + = T->getAs<TemplateSpecializationType>()) { + Out << '>'; + VisitTemplateName(Spec->getTemplateName()); + Out << Spec->getNumArgs(); + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) + VisitTemplateArgument(Spec->getArg(I)); + return; + } + // Unhandled type. Out << ' '; break; } while (true); } +void USRGenerator::VisitTemplateParameterList( + const TemplateParameterList *Params) { + if (!Params) + return; + Out << '>' << Params->size(); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + Out << '#'; + if (isa<TemplateTypeParmDecl>(*P)) { + Out << 'T'; + continue; + } + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + Out << 'N'; + VisitType(NTTP->getType()); + continue; + } + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P); + Out << 't'; + VisitTemplateParameterList(TTP->getTemplateParameters()); + } +} + +void USRGenerator::VisitTemplateName(TemplateName Name) { + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Template)) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + + Visit(Template); + return; + } + + // FIXME: Visit dependent template names. +} + +void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Declaration: + Visit(Arg.getAsDecl()); + break; + + case TemplateArgument::Template: + VisitTemplateName(Arg.getAsTemplate()); + break; + + case TemplateArgument::Expression: + // FIXME: Visit expressions. + break; + + case TemplateArgument::Pack: + // FIXME: Variadic templates + break; + + case TemplateArgument::Type: + VisitType(Arg.getAsType()); + break; + + case TemplateArgument::Integral: + Out << 'V'; + VisitType(Arg.getIntegralType()); + Out << *Arg.getAsIntegral(); + break; + } +} + //===----------------------------------------------------------------------===// // General purpose USR generation methods. //===----------------------------------------------------------------------===// diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index ab4acca..29ef574 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -5,10 +5,11 @@ set(LLVM_NO_RTTI 1) set(LLVM_USED_LIBS clangFrontend clangDriver + clangSerialization + clangParse clangSema clangAnalysis clangAST - clangParse clangLex clangBasic) @@ -20,28 +21,34 @@ set( LLVM_LINK_COMPONENTS add_clang_library(libclang CIndex.cpp + CIndexCXX.cpp CIndexCodeCompletion.cpp CIndexDiagnostic.cpp CIndexInclusionStack.cpp CIndexUSRs.cpp CIndexer.cpp CXCursor.cpp - CXTypes.cpp + CXType.cpp ../../include/clang-c/Index.h ) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - # FIXME: Deal with LLVM_SUBMIT_VERSION? + # dylib versioning information + # FIXME: Is there a more CMake-ish way to handle this? + set(LIBCLANG_VERSION 1 + CACHE STRING "Version number of the libclang library") + set(LIBCLANG_SUBVERSION 0 + CACHE STRING "Minor version number of the libclang library") + set(LIBCLANG_LINK_FLAGS + "-Wl,-current_version -Wl,${LIBCLANG_VERSION}.${LIBCLANG_SUBVERSION} -Wl,-compatibility_version -Wl,1") + + set(LIBCLANG_LINK_FLAGS + "${LIBCLANG_LINK_FLAGS} -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000") - # FIXME: This uses a special darwin-specific exports file in order to - # get underscore-prefixed names. It would be better to have build rules - # which know how to produce a darwin-suitable exports file from the - # regular exports file. set_target_properties(libclang PROPERTIES - LINK_FLAGS "-avoid-version -Wl,-exported_symbols_list -Wl,${CMAKE_CURRENT_SOURCE_DIR}/libclang.darwin.exports -Wl,-dead_strip -Wl,-seg1addr -Wl,0xE0000000" - INSTALL_NAME_DIR "@executable_path/../lib" - ) + LINK_FLAGS "${LIBCLANG_LINK_FLAGS}" + INSTALL_NAME_DIR "@executable_path/../lib") endif() if(MSVC) diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index be3623f..a8fd049 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -16,6 +16,7 @@ #include "CXCursor.h" #include "clang/Frontend/ASTUnit.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "llvm/Support/ErrorHandling.h" @@ -28,52 +29,6 @@ CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) { return C; } -static CXCursorKind GetCursorKind(Decl *D) { - assert(D && "Invalid arguments!"); - switch (D->getKind()) { - case Decl::Enum: return CXCursor_EnumDecl; - case Decl::EnumConstant: return CXCursor_EnumConstantDecl; - case Decl::Field: return CXCursor_FieldDecl; - case Decl::Function: - return CXCursor_FunctionDecl; - case Decl::ObjCCategory: return CXCursor_ObjCCategoryDecl; - case Decl::ObjCCategoryImpl: return CXCursor_ObjCCategoryImplDecl; - case Decl::ObjCClass: - // FIXME - return CXCursor_UnexposedDecl; - case Decl::ObjCForwardProtocol: - // FIXME - return CXCursor_UnexposedDecl; - case Decl::ObjCImplementation: return CXCursor_ObjCImplementationDecl; - case Decl::ObjCInterface: return CXCursor_ObjCInterfaceDecl; - case Decl::ObjCIvar: return CXCursor_ObjCIvarDecl; - case Decl::ObjCMethod: - return cast<ObjCMethodDecl>(D)->isInstanceMethod() - ? CXCursor_ObjCInstanceMethodDecl : CXCursor_ObjCClassMethodDecl; - case Decl::CXXMethod: return CXCursor_CXXMethod; - case Decl::ObjCProperty: return CXCursor_ObjCPropertyDecl; - case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl; - case Decl::ParmVar: return CXCursor_ParmDecl; - case Decl::Typedef: return CXCursor_TypedefDecl; - case Decl::Var: return CXCursor_VarDecl; - case Decl::Namespace: return CXCursor_Namespace; - default: - if (TagDecl *TD = dyn_cast<TagDecl>(D)) { - switch (TD->getTagKind()) { - case TTK_Struct: return CXCursor_StructDecl; - case TTK_Class: return CXCursor_ClassDecl; - case TTK_Union: return CXCursor_UnionDecl; - case TTK_Enum: return CXCursor_EnumDecl; - } - } - - return CXCursor_UnexposedDecl; - } - - llvm_unreachable("Invalid Decl"); - return CXCursor_NotImplemented; -} - static CXCursorKind GetCursorKind(const Attr *A) { assert(A && "Invalid arguments!"); switch (A->getKind()) { @@ -94,7 +49,7 @@ CXCursor cxcursor::MakeCXCursor(const Attr *A, Decl *Parent, ASTUnit *TU) { CXCursor cxcursor::MakeCXCursor(Decl *D, ASTUnit *TU) { assert(D && TU && "Invalid arguments!"); - CXCursor C = { GetCursorKind(D), { D, 0, TU } }; + CXCursor C = { getCursorKindForDecl(D), { D, 0, TU } }; return C; } @@ -182,7 +137,6 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, ASTUnit *TU) { case Stmt::UnaryTypeTraitExprClass: case Stmt::DependentScopeDeclRefExprClass: case Stmt::CXXBindTemporaryExprClass: - case Stmt::CXXBindReferenceExprClass: case Stmt::CXXExprWithTemporariesClass: case Stmt::CXXUnresolvedConstructExprClass: case Stmt::CXXDependentScopeMemberExprClass: @@ -302,6 +256,50 @@ cxcursor::getCursorTypeRef(CXCursor C) { reinterpret_cast<uintptr_t>(C.data[1]))); } +CXCursor cxcursor::MakeCursorTemplateRef(TemplateDecl *Template, + SourceLocation Loc, ASTUnit *TU) { + assert(Template && TU && "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_TemplateRef, { Template, RawLoc, TU } }; + return C; +} + +std::pair<TemplateDecl *, SourceLocation> +cxcursor::getCursorTemplateRef(CXCursor C) { + assert(C.kind == CXCursor_TemplateRef); + return std::make_pair(static_cast<TemplateDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorNamespaceRef(NamedDecl *NS, SourceLocation Loc, + ASTUnit *TU) { + + assert(NS && (isa<NamespaceDecl>(NS) || isa<NamespaceAliasDecl>(NS)) && TU && + "Invalid arguments!"); + void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding()); + CXCursor C = { CXCursor_NamespaceRef, { NS, RawLoc, TU } }; + return C; +} + +std::pair<NamedDecl *, SourceLocation> +cxcursor::getCursorNamespaceRef(CXCursor C) { + assert(C.kind == CXCursor_NamespaceRef); + return std::make_pair(static_cast<NamedDecl *>(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast<uintptr_t>(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B, ASTUnit *TU){ + CXCursor C = { CXCursor_CXXBaseSpecifier, { B, 0, TU } }; + return C; +} + +CXXBaseSpecifier *cxcursor::getCursorCXXBaseSpecifier(CXCursor C) { + assert(C.kind == CXCursor_CXXBaseSpecifier); + return static_cast<CXXBaseSpecifier*>(C.data[0]); +} + CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range, ASTUnit *TU) { CXCursor C = { CXCursor_PreprocessingDirective, @@ -358,6 +356,10 @@ Stmt *cxcursor::getCursorStmt(CXCursor Cursor) { return (Stmt *)Cursor.data[1]; } +Attr *cxcursor::getCursorAttr(CXCursor Cursor) { + return (Attr *)Cursor.data[1]; +} + ASTContext &cxcursor::getCursorContext(CXCursor Cursor) { return getCursorASTUnit(Cursor)->getASTContext(); } diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h index 1664f5a..a5f111e 100644 --- a/tools/libclang/CXCursor.h +++ b/tools/libclang/CXCursor.h @@ -23,6 +23,7 @@ namespace clang { class ASTContext; class ASTUnit; class Attr; +class CXXBaseSpecifier; class Decl; class Expr; class MacroDefinition; @@ -31,6 +32,7 @@ class NamedDecl; class ObjCInterfaceDecl; class ObjCProtocolDecl; class Stmt; +class TemplateDecl; class TypeDecl; namespace cxcursor { @@ -70,11 +72,33 @@ std::pair<ObjCInterfaceDecl *, SourceLocation> /// \brief Create a type reference at the given location. CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, ASTUnit *TU); - + /// \brief Unpack a TypeRef cursor into the class it references /// and optionally the location where the reference occurred. std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C); +/// \brief Create a reference to a template at the given location. +CXCursor MakeCursorTemplateRef(TemplateDecl *Template, SourceLocation Loc, + ASTUnit *TU); + +/// \brief Unpack a TemplateRef cursor into the template it references and +/// the location where the reference occurred. +std::pair<TemplateDecl *, SourceLocation> getCursorTemplateRef(CXCursor C); + +/// \brief Create a reference to a namespace or namespace alias at the given +/// location. +CXCursor MakeCursorNamespaceRef(NamedDecl *NS, SourceLocation Loc, ASTUnit *TU); + +/// \brief Unpack a NamespaceRef cursor into the namespace or namespace alias +/// it references and the location where the reference occurred. +std::pair<NamedDecl *, SourceLocation> getCursorNamespaceRef(CXCursor C); + +/// \brief Create a CXX base specifier cursor. +CXCursor MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B, ASTUnit *TU); + +/// \brief Unpack a CXXBaseSpecifier cursor into a CXXBaseSpecifier. +CXXBaseSpecifier *getCursorCXXBaseSpecifier(CXCursor C); + /// \brief Create a preprocessing directive cursor. CXCursor MakePreprocessingDirectiveCursor(SourceRange Range, ASTUnit *TU); @@ -98,6 +122,8 @@ MacroInstantiation *getCursorMacroInstantiation(CXCursor C); Decl *getCursorDecl(CXCursor Cursor); Expr *getCursorExpr(CXCursor Cursor); Stmt *getCursorStmt(CXCursor Cursor); +Attr *getCursorAttr(CXCursor Cursor); + ASTContext &getCursorContext(CXCursor Cursor); ASTUnit *getCursorASTUnit(CXCursor Cursor); diff --git a/tools/libclang/CXTypes.cpp b/tools/libclang/CXType.cpp index d5c9f45..aa173ca 100644 --- a/tools/libclang/CXTypes.cpp +++ b/tools/libclang/CXType.cpp @@ -13,6 +13,7 @@ #include "CIndexer.h" #include "CXCursor.h" +#include "CXType.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "clang/AST/Decl.h" @@ -85,12 +86,15 @@ static CXTypeKind GetTypeKind(QualType T) { #undef TKCASE } -static CXType MakeCXType(QualType T, ASTUnit *TU) { + +CXType cxtype::MakeCXType(QualType T, ASTUnit *TU) { CXTypeKind TK = GetTypeKind(T); CXType CT = { TK, { TK == CXType_Invalid ? 0 : T.getAsOpaquePtr(), TU }}; return CT; } +using cxtype::MakeCXType; + static inline QualType GetQualType(CXType CT) { return QualType::getFromOpaquePtr(CT.data[0]); } @@ -283,4 +287,11 @@ CXType clang_getCursorResultType(CXCursor C) { return MakeCXType(QualType(), cxcursor::getCursorASTUnit(C)); } +unsigned clang_isPODType(CXType X) { + QualType T = GetQualType(X); + if (!T.getTypePtr()) + return 0; + return T->isPODType() ? 1 : 0; +} + } // end: extern "C" diff --git a/tools/libclang/CXType.h b/tools/libclang/CXType.h new file mode 100644 index 0000000..94151ed --- /dev/null +++ b/tools/libclang/CXType.h @@ -0,0 +1,29 @@ +//===- CXTypes.h - Routines for manipulating CXTypes ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines routines for manipulating CXCursors. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CXTYPES_H +#define LLVM_CLANG_CXTYPES_H + +#include "clang-c/Index.h" +#include "clang/AST/Type.h" + +namespace clang { + +class ASTUnit; + +namespace cxtype { + +CXType MakeCXType(QualType T, ASTUnit *TU); + +}} // end namespace clang::cxtype +#endif diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile index 253ea38..6d2a13c 100644 --- a/tools/libclang/Makefile +++ b/tools/libclang/Makefile @@ -16,8 +16,8 @@ LINK_LIBS_IN_SHARED = 1 SHARED_LIBRARY = 1 LINK_COMPONENTS := bitreader mc core -USEDLIBS = clangFrontend.a clangDriver.a clangSema.a \ - clangAnalysis.a clangAST.a clangParse.a clangLex.a clangBasic.a +USEDLIBS = clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \ + clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a include $(CLANG_LEVEL)/Makefile @@ -26,23 +26,21 @@ include $(CLANG_LEVEL)/Makefile ##===----------------------------------------------------------------------===## ifeq ($(HOST_OS),Darwin) - # set dylib internal version number to llvmCore submission number + LLVMLibsOptions += -Wl,-compatibility_version,1 + + # Set dylib internal version number to submission number. ifdef LLVM_SUBMIT_VERSION - LLVMLibsOptions := $(LLVMLibsOptions) -Wl,-current_version \ - -Wl,$(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION) \ - -Wl,-compatibility_version -Wl,1 + LLVMLibsOptions += -Wl,-current_version \ + -Wl,$(LLVM_SUBMIT_VERSION).$(LLVM_SUBMIT_SUBVERSION) endif - # extra options to override libtool defaults - LLVMLibsOptions := $(LLVMLibsOptions) \ - -avoid-version \ - -Wl,-dead_strip \ - -Wl,-seg1addr -Wl,0xE0000000 + + # Extra options to override libtool defaults. + LLVMLibsOptions += -Wl,-dead_strip -Wl,-seg1addr,0xE0000000 # Mac OS X 10.4 and earlier tools do not allow a second -install_name on command line DARWIN_VERS := $(shell echo $(TARGET_TRIPLE) | sed 's/.*darwin\([0-9]*\).*/\1/') ifneq ($(DARWIN_VERS),8) - LLVMLibsOptions := $(LLVMLibsOptions) \ - -no-undefined -Wl,-install_name \ - -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" + LLVMLibsOptions += -Wl,-install_name \ + -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" endif endif diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports index f21fec6..d1b45a2 100644 --- a/tools/libclang/libclang.darwin.exports +++ b/tools/libclang/libclang.darwin.exports @@ -1,6 +1,7 @@ _clang_CXXMethod_isStatic _clang_annotateTokens _clang_codeComplete +_clang_codeCompleteAt _clang_codeCompleteGetDiagnostic _clang_codeCompleteGetNumDiagnostics _clang_constructUSR_ObjCCategory @@ -12,7 +13,11 @@ _clang_constructUSR_ObjCProtocol _clang_createIndex _clang_createTranslationUnit _clang_createTranslationUnitFromSourceFile +_clang_defaultCodeCompleteOptions _clang_defaultDiagnosticDisplayOptions +_clang_defaultEditingTranslationUnitOptions +_clang_defaultReparseOptions +_clang_defaultSaveOptions _clang_disposeCodeCompleteResults _clang_disposeDiagnostic _clang_disposeIndex @@ -25,13 +30,16 @@ _clang_equalLocations _clang_equalTypes _clang_formatDiagnostic _clang_getCString +_clang_getCXXAccessSpecifier _clang_getCanonicalType _clang_getClangVersion +_clang_getCompletionAvailability _clang_getCompletionChunkCompletionString _clang_getCompletionChunkKind _clang_getCompletionChunkText _clang_getCompletionPriority _clang_getCursor +_clang_getCursorAvailability _clang_getCursorDefinition _clang_getCursorExtent _clang_getCursorKind @@ -40,8 +48,8 @@ _clang_getCursorLanguage _clang_getCursorLinkage _clang_getCursorLocation _clang_getCursorReferenced -_clang_getCursorSpelling _clang_getCursorResultType +_clang_getCursorSpelling _clang_getCursorType _clang_getCursorUSR _clang_getDefinitionSpellingAndExtent @@ -56,6 +64,7 @@ _clang_getDiagnosticSpelling _clang_getFile _clang_getFileName _clang_getFileTime +_clang_getIBOutletCollectionType _clang_getInclusions _clang_getInstantiationLocation _clang_getLocation @@ -69,6 +78,8 @@ _clang_getRange _clang_getRangeEnd _clang_getRangeStart _clang_getResultType +_clang_getSpecializedCursorTemplate +_clang_getTemplateCursorKind _clang_getTokenExtent _clang_getTokenKind _clang_getTokenLocation @@ -81,11 +92,17 @@ _clang_isCursorDefinition _clang_isDeclaration _clang_isExpression _clang_isInvalid +_clang_isPODType _clang_isPreprocessing _clang_isReference _clang_isStatement _clang_isTranslationUnit _clang_isUnexposed +_clang_isVirtualBase +_clang_parseTranslationUnit +_clang_reparseTranslationUnit +_clang_saveTranslationUnit _clang_setUseExternalASTGeneration +_clang_sortCodeCompletionResults _clang_tokenize _clang_visitChildren diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index dcb40d4..0ea6993 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -1,6 +1,7 @@ clang_CXXMethod_isStatic clang_annotateTokens clang_codeComplete +clang_codeCompleteAt clang_codeCompleteGetDiagnostic clang_codeCompleteGetNumDiagnostics clang_constructUSR_ObjCCategory @@ -12,7 +13,11 @@ clang_constructUSR_ObjCProtocol clang_createIndex clang_createTranslationUnit clang_createTranslationUnitFromSourceFile +clang_defaultCodeCompleteOptions clang_defaultDiagnosticDisplayOptions +clang_defaultEditingTranslationUnitOptions +clang_defaultReparseOptions +clang_defaultSaveOptions clang_disposeCodeCompleteResults clang_disposeDiagnostic clang_disposeIndex @@ -25,13 +30,16 @@ clang_equalLocations clang_equalTypes clang_formatDiagnostic clang_getCString +clang_getCXXAccessSpecifier clang_getCanonicalType clang_getClangVersion +clang_getCompletionAvailability clang_getCompletionChunkCompletionString clang_getCompletionChunkKind clang_getCompletionChunkText clang_getCompletionPriority clang_getCursor +clang_getCursorAvailability clang_getCursorDefinition clang_getCursorExtent clang_getCursorKind @@ -40,8 +48,8 @@ clang_getCursorLanguage clang_getCursorLinkage clang_getCursorLocation clang_getCursorReferenced -clang_getCursorSpelling clang_getCursorResultType +clang_getCursorSpelling clang_getCursorType clang_getCursorUSR clang_getDefinitionSpellingAndExtent @@ -56,6 +64,7 @@ clang_getDiagnosticSpelling clang_getFile clang_getFileName clang_getFileTime +clang_getIBOutletCollectionType clang_getInclusions clang_getInstantiationLocation clang_getLocation @@ -69,6 +78,8 @@ clang_getRange clang_getRangeEnd clang_getRangeStart clang_getResultType +clang_getSpecializedCursorTemplate +clang_getTemplateCursorKind clang_getTokenExtent clang_getTokenKind clang_getTokenLocation @@ -81,11 +92,17 @@ clang_isCursorDefinition clang_isDeclaration clang_isExpression clang_isInvalid +clang_isPODType clang_isPreprocessing clang_isReference clang_isStatement clang_isTranslationUnit clang_isUnexposed +clang_isVirtualBase +clang_parseTranslationUnit +clang_reparseTranslationUnit +clang_saveTranslationUnit clang_setUseExternalASTGeneration +clang_sortCodeCompletionResults clang_tokenize clang_visitChildren |