summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2010-09-17 15:54:40 +0000
committerdim <dim@FreeBSD.org>2010-09-17 15:54:40 +0000
commit36c49e3f258dced101949edabd72e9bc3f1dedc4 (patch)
tree0bbe07708f7571f8b5291f6d7b96c102b7c99dee /tools
parentfc84956ac8b7cd244ef30e7a4d4d38a58dec5904 (diff)
downloadFreeBSD-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.txt3
-rw-r--r--tools/c-index-test/Makefile5
-rw-r--r--tools/c-index-test/c-index-test.c268
-rw-r--r--tools/driver/CMakeLists.txt5
-rw-r--r--tools/driver/Info.plist.in18
-rw-r--r--tools/driver/Makefile33
-rw-r--r--tools/driver/cc1_main.cpp149
-rw-r--r--tools/driver/cc1as_main.cpp41
-rw-r--r--tools/driver/driver.cpp160
-rw-r--r--tools/libclang/CIndex.cpp1131
-rw-r--r--tools/libclang/CIndexCXX.cpp124
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp306
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp27
-rw-r--r--tools/libclang/CIndexUSRs.cpp237
-rw-r--r--tools/libclang/CMakeLists.txt27
-rw-r--r--tools/libclang/CXCursor.cpp98
-rw-r--r--tools/libclang/CXCursor.h28
-rw-r--r--tools/libclang/CXType.cpp (renamed from tools/libclang/CXTypes.cpp)13
-rw-r--r--tools/libclang/CXType.h29
-rw-r--r--tools/libclang/Makefile26
-rw-r--r--tools/libclang/libclang.darwin.exports19
-rw-r--r--tools/libclang/libclang.exports19
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
OpenPOWER on IntegriCloud