aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2012-04-14 14:01:31 +0000
committerDimitry Andric <dim@FreeBSD.org>2012-04-14 14:01:31 +0000
commitdbe13110f59f48b4dbb7552b3ac2935acdeece7f (patch)
treebe1815eb79b42ff482a8562b13c2dcbf0c5dcbee /tools
parent9da628931ebf2609493570f87824ca22402cc65f (diff)
downloadsrc-dbe13110f59f48b4dbb7552b3ac2935acdeece7f.tar.gz
src-dbe13110f59f48b4dbb7552b3ac2935acdeece7f.zip
Vendor import of clang trunk r154661:vendor/clang/clang-trunk-r154661
Notes
Notes: svn path=/vendor/clang/dist/; revision=234287 svn path=/vendor/clang/clang-trunk-r154661/; revision=234288; tag=vendor/clang/clang-trunk-r154661
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt1
-rw-r--r--tools/Makefile7
-rw-r--r--tools/arcmt-test/CMakeLists.txt1
-rw-r--r--tools/arcmt-test/Makefile2
-rw-r--r--tools/arcmt-test/arcmt-test.cpp39
-rw-r--r--tools/c-arcmt-test/Makefile2
-rw-r--r--tools/c-arcmt-test/c-arcmt-test.c36
-rw-r--r--tools/c-index-test/Makefile6
-rw-r--r--tools/c-index-test/c-index-test.c863
-rw-r--r--tools/clang-check/CMakeLists.txt5
-rw-r--r--tools/clang-check/ClangCheck.cpp62
-rw-r--r--tools/clang-check/Makefile24
-rw-r--r--tools/diagtool/ListWarnings.cpp34
-rw-r--r--tools/diagtool/Makefile5
-rw-r--r--tools/driver/CMakeLists.txt16
-rw-r--r--tools/driver/Makefile4
-rw-r--r--tools/driver/cc1_main.cpp22
-rw-r--r--tools/driver/cc1as_main.cpp80
-rw-r--r--tools/driver/driver.cpp38
-rw-r--r--tools/libclang/ARCMigrate.cpp43
-rw-r--r--tools/libclang/CIndex.cpp1407
-rw-r--r--tools/libclang/CIndexCXX.cpp5
-rw-r--r--tools/libclang/CIndexCodeCompletion.cpp81
-rw-r--r--tools/libclang/CIndexDiagnostic.cpp343
-rw-r--r--tools/libclang/CIndexDiagnostic.h137
-rw-r--r--tools/libclang/CIndexHigh.cpp184
-rw-r--r--tools/libclang/CIndexUSRs.cpp61
-rw-r--r--tools/libclang/CIndexer.cpp2
-rw-r--r--tools/libclang/CIndexer.h23
-rw-r--r--tools/libclang/CMakeLists.txt19
-rw-r--r--tools/libclang/CXCursor.cpp261
-rw-r--r--tools/libclang/CXCursor.h27
-rw-r--r--tools/libclang/CXLoadedDiagnostic.cpp672
-rw-r--r--tools/libclang/CXLoadedDiagnostic.h94
-rw-r--r--tools/libclang/CXSourceLocation.cpp326
-rw-r--r--tools/libclang/CXSourceLocation.h4
-rw-r--r--tools/libclang/CXStoredDiagnostic.cpp119
-rw-r--r--tools/libclang/CXString.h2
-rw-r--r--tools/libclang/CXTranslationUnit.h22
-rw-r--r--tools/libclang/CXType.cpp203
-rw-r--r--tools/libclang/CursorVisitor.h259
-rw-r--r--tools/libclang/IndexBody.cpp154
-rw-r--r--tools/libclang/IndexDecl.cpp336
-rw-r--r--tools/libclang/IndexTypeSourceInfo.cpp156
-rw-r--r--tools/libclang/Index_Internal.h12
-rw-r--r--tools/libclang/Indexing.cpp818
-rw-r--r--tools/libclang/IndexingContext.cpp1080
-rw-r--r--tools/libclang/IndexingContext.h556
-rw-r--r--tools/libclang/Makefile3
-rw-r--r--tools/libclang/libclang.exports52
-rwxr-xr-xtools/scan-build/ccc-analyzer30
-rwxr-xr-xtools/scan-build/scan-build10
-rwxr-xr-xtools/scan-build/set-xcode-analyzer16
53 files changed, 7699 insertions, 1065 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 117d10a603f3..ab4748d1b922 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -4,3 +4,4 @@ add_subdirectory(arcmt-test)
add_subdirectory(c-arcmt-test)
add_subdirectory(diagtool)
add_subdirectory(driver)
+add_subdirectory(clang-check)
diff --git a/tools/Makefile b/tools/Makefile
index 4ea2cdd32d21..5059ade93092 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -8,12 +8,9 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ..
-DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool
+DIRS := driver libclang c-index-test arcmt-test c-arcmt-test diagtool \
+ clang-check
include $(CLANG_LEVEL)/../../Makefile.config
-ifeq ($(OS), $(filter $(OS), Minix))
-DIRS := $(filter-out libclang c-index-test, arcmt-test, $(DIRS))
-endif
-
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/arcmt-test/CMakeLists.txt b/tools/arcmt-test/CMakeLists.txt
index 9227f8ee63c7..a0029b416f29 100644
--- a/tools/arcmt-test/CMakeLists.txt
+++ b/tools/arcmt-test/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_USED_LIBS
clangARCMigrate
+ clangEdit
clangRewrite
)
diff --git a/tools/arcmt-test/Makefile b/tools/arcmt-test/Makefile
index c143e27f33e2..f5ca81a6d117 100644
--- a/tools/arcmt-test/Makefile
+++ b/tools/arcmt-test/Makefile
@@ -19,6 +19,6 @@ NO_INSTALL = 1
LINK_COMPONENTS := support mc
USEDLIBS = clangIndex.a clangARCMigrate.a clangRewrite.a \
clangFrontend.a clangDriver.a clangSerialization.a clangParse.a \
- clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+ clangSema.a clangEdit.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/arcmt-test/arcmt-test.cpp b/tools/arcmt-test/arcmt-test.cpp
index d27483f29142..3983c249022e 100644
--- a/tools/arcmt-test/arcmt-test.cpp
+++ b/tools/arcmt-test/arcmt-test.cpp
@@ -107,8 +107,8 @@ static bool checkForMigration(StringRef resourcesPath,
ArrayRef<const char *> Args) {
DiagnosticConsumer *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
new DiagnosticsEngine(DiagID, DiagClient));
// Chain in -verify checker, if requested.
VerifyDiagnosticConsumer *verifyDiag = 0;
@@ -118,27 +118,25 @@ static bool checkForMigration(StringRef resourcesPath,
}
CompilerInvocation CI;
- CompilerInvocation::CreateFromArgs(CI, Args.begin(), Args.end(), *Diags);
+ if (!CompilerInvocation::CreateFromArgs(CI, Args.begin(), Args.end(), *Diags))
+ return true;
if (CI.getFrontendOpts().Inputs.empty()) {
llvm::errs() << "error: no input files\n";
return true;
}
- if (!CI.getLangOpts().ObjC1)
+ if (!CI.getLangOpts()->ObjC1)
return false;
- arcmt::checkForManualIssues(CI,
- CI.getFrontendOpts().Inputs[0].second,
- CI.getFrontendOpts().Inputs[0].first,
+ arcmt::checkForManualIssues(CI, CI.getFrontendOpts().Inputs[0],
Diags->getClient());
return Diags->getClient()->getNumErrors() > 0;
}
static void printResult(FileRemapper &remapper, raw_ostream &OS) {
- CompilerInvocation CI;
- remapper.applyMappings(CI);
- PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
+ PreprocessorOptions PPOpts;
+ remapper.applyMappings(PPOpts);
// The changed files will be in memory buffers, print them.
for (unsigned i = 0, e = PPOpts.RemappedFileBuffers.size(); i != e; ++i) {
const llvm::MemoryBuffer *mem = PPOpts.RemappedFileBuffers[i].second;
@@ -154,28 +152,31 @@ static bool performTransformations(StringRef resourcesPath,
DiagnosticConsumer *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> TopDiags(
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticsEngine> TopDiags(
new DiagnosticsEngine(DiagID, DiagClient));
CompilerInvocation origCI;
- CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(),
- *TopDiags);
+ if (!CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(),
+ *TopDiags))
+ return true;
if (origCI.getFrontendOpts().Inputs.empty()) {
llvm::errs() << "error: no input files\n";
return true;
}
- if (!origCI.getLangOpts().ObjC1)
+ if (!origCI.getLangOpts()->ObjC1)
return false;
MigrationProcess migration(origCI, DiagClient);
- std::vector<TransformFn> transforms = arcmt::getAllTransformations();
+ std::vector<TransformFn>
+ transforms = arcmt::getAllTransformations(origCI.getLangOpts()->getGC(),
+ origCI.getMigratorOpts().NoFinalizeRemoval);
assert(!transforms.empty());
- llvm::OwningPtr<PrintTransforms> transformPrinter;
+ OwningPtr<PrintTransforms> transformPrinter;
if (OutputTransformations)
transformPrinter.reset(new PrintTransforms(llvm::outs()));
@@ -317,7 +318,7 @@ static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
raw_ostream &OS) {
SourceManager &SM = Ctx.getSourceManager();
- const LangOptions &langOpts = Ctx.getLangOptions();
+ const LangOptions &langOpts = Ctx.getLangOpts();
PresumedLoc PL = SM.getPresumedLoc(range.getBegin());
@@ -351,7 +352,7 @@ int main(int argc, const char **argv) {
if (StringRef(argv[optargc]) == "--args")
break;
}
- llvm::cl::ParseCommandLineOptions(optargc, const_cast<char **>(argv), "arcmt-test");
+ llvm::cl::ParseCommandLineOptions(optargc, argv, "arcmt-test");
if (VerifyTransformedFiles) {
if (ResultFiles.empty()) {
diff --git a/tools/c-arcmt-test/Makefile b/tools/c-arcmt-test/Makefile
index b72a08ab53bb..878eb6f4ce2d 100644
--- a/tools/c-arcmt-test/Makefile
+++ b/tools/c-arcmt-test/Makefile
@@ -20,6 +20,6 @@ LINK_COMPONENTS := support mc
USEDLIBS = clang.a clangIndex.a clangARCMigrate.a clangRewrite.a \
clangFrontend.a clangDriver.a \
clangSerialization.a clangParse.a clangSema.a \
- clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+ clangAnalysis.a clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/c-arcmt-test/c-arcmt-test.c b/tools/c-arcmt-test/c-arcmt-test.c
index 5522b33e23a5..56a4132dba3c 100644
--- a/tools/c-arcmt-test/c-arcmt-test.c
+++ b/tools/c-arcmt-test/c-arcmt-test.c
@@ -34,22 +34,51 @@ static int print_remappings(const char *path) {
return 0;
}
+static int print_remappings_filelist(const char **files, unsigned numFiles) {
+ CXRemapping remap;
+ unsigned i, N;
+ CXString origFname;
+ CXString transFname;
+
+ remap = clang_getRemappingsFromFileList(files, numFiles);
+ if (!remap)
+ return 1;
+
+ N = clang_remap_getNumFiles(remap);
+ for (i = 0; i != N; ++i) {
+ clang_remap_getFilenames(remap, i, &origFname, &transFname);
+
+ fprintf(stdout, "%s\n", clang_getCString(origFname));
+ fprintf(stdout, "%s\n", clang_getCString(transFname));
+
+ clang_disposeString(origFname);
+ clang_disposeString(transFname);
+ }
+
+ clang_remap_dispose(remap);
+ return 0;
+}
+
/******************************************************************************/
/* Command line processing. */
/******************************************************************************/
static void print_usage(void) {
fprintf(stderr,
- "usage: c-arcmt-test -arcmt-migrate-directory <path>\n\n\n");
+ "usage: c-arcmt-test -mt-migrate-directory <path>\n"
+ " c-arcmt-test <remap-file-path1> <remap-file-path2> ...\n\n\n");
}
/***/
int carcmttest_main(int argc, const char **argv) {
clang_enableStackTraces();
- if (argc == 3 && strncmp(argv[1], "-arcmt-migrate-directory", 24) == 0)
+ if (argc == 3 && strncmp(argv[1], "-mt-migrate-directory", 21) == 0)
return print_remappings(argv[2]);
+ if (argc > 1)
+ return print_remappings_filelist(argv+1, argc-1);
+
print_usage();
return 1;
}
@@ -68,6 +97,9 @@ typedef struct thread_info {
void thread_runner(void *client_data_v) {
thread_info *client_data = client_data_v;
client_data->result = carcmttest_main(client_data->argc, client_data->argv);
+#ifdef __CYGWIN__
+ fflush(stdout); /* stdout is not flushed on Cygwin. */
+#endif
}
int main(int argc, const char **argv) {
diff --git a/tools/c-index-test/Makefile b/tools/c-index-test/Makefile
index c21b3279a287..95a961f6611e 100644
--- a/tools/c-index-test/Makefile
+++ b/tools/c-index-test/Makefile
@@ -10,12 +10,16 @@ CLANG_LEVEL := ../..
TOOLNAME = c-index-test
+# If a separate install prefix was specified for internal tools, use it
+# when installing c-index-test.
+INTERNAL_TOOL = 1
+
# No plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
LINK_COMPONENTS := support mc
USEDLIBS = clang.a clangIndex.a clangFrontend.a clangDriver.a \
clangSerialization.a clangParse.a clangSema.a \
- clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+ clangAnalysis.a clangEdit.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 2a3584b892b8..573e6dc3141f 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -37,12 +37,16 @@ static unsigned getDefaultParsingOptions() {
options |= clang_defaultEditingTranslationUnitOptions();
if (getenv("CINDEXTEST_COMPLETION_CACHING"))
options |= CXTranslationUnit_CacheCompletionResults;
- if (getenv("CINDEXTEST_NESTED_MACROS"))
- options |= CXTranslationUnit_NestedMacroExpansions;
+ if (getenv("CINDEXTEST_COMPLETION_NO_CACHING"))
+ options &= ~CXTranslationUnit_CacheCompletionResults;
+ if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
+ options |= CXTranslationUnit_SkipFunctionBodies;
return options;
}
+static int checkForErrors(CXTranslationUnit TU);
+
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,
@@ -169,7 +173,8 @@ static void PrintRange(CXSourceRange R, const char *str) {
if (!begin_file || !end_file)
return;
- printf(" %s=", str);
+ if (str)
+ printf(" %s=", str);
PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
}
@@ -338,7 +343,7 @@ static const char* GetCursorSource(CXCursor Cursor) {
CXSourceLocation Loc = clang_getCursorLocation(Cursor);
CXString source;
CXFile file;
- clang_getSpellingLocation(Loc, &file, 0, 0, 0);
+ clang_getExpansionLocation(Loc, &file, 0, 0, 0);
source = clang_getFileName(file);
if (!clang_getCString(source)) {
clang_disposeString(source);
@@ -379,6 +384,7 @@ void PrintDiagnostic(CXDiagnostic Diagnostic) {
return;
num_fixits = clang_getDiagnosticNumFixIts(Diagnostic);
+ fprintf(stderr, "Number FIX-ITs = %d\n", num_fixits);
for (i = 0; i != num_fixits; ++i) {
CXSourceRange range;
CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range);
@@ -414,13 +420,21 @@ void PrintDiagnostic(CXDiagnostic Diagnostic) {
}
}
-void PrintDiagnostics(CXTranslationUnit TU) {
- int i, n = clang_getNumDiagnostics(TU);
- for (i = 0; i != n; ++i) {
- CXDiagnostic Diag = clang_getDiagnostic(TU, i);
+void PrintDiagnosticSet(CXDiagnosticSet Set) {
+ int i = 0, n = clang_getNumDiagnosticsInSet(Set);
+ for ( ; i != n ; ++i) {
+ CXDiagnostic Diag = clang_getDiagnosticInSet(Set, i);
+ CXDiagnosticSet ChildDiags = clang_getChildDiagnostics(Diag);
PrintDiagnostic(Diag);
- clang_disposeDiagnostic(Diag);
- }
+ if (ChildDiags)
+ PrintDiagnosticSet(ChildDiags);
+ }
+}
+
+void PrintDiagnostics(CXTranslationUnit TU) {
+ CXDiagnosticSet TUSet = clang_getDiagnosticSetFromTU(TU);
+ PrintDiagnosticSet(TUSet);
+ clang_disposeDiagnosticSet(TUSet);
}
void PrintMemoryUsage(CXTranslationUnit TU) {
@@ -651,6 +665,23 @@ static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
clang_disposeString(RS);
}
}
+ /* Print the argument types if they exist. */
+ {
+ int numArgs = clang_Cursor_getNumArguments(cursor);
+ if (numArgs != -1 && numArgs != 0) {
+ int i;
+ printf(" [args=");
+ for (i = 0; i < numArgs; ++i) {
+ CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i));
+ if (T.kind != CXType_Invalid) {
+ CXString S = clang_getTypeKindSpelling(T.kind);
+ printf(" %s", clang_getCString(S));
+ clang_disposeString(S);
+ }
+ }
+ printf("]");
+ }
+ }
/* Print if this is a non-POD type. */
printf(" [isPOD=%d]", clang_isPODType(T));
@@ -705,6 +736,11 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
PV(TU);
PrintDiagnostics(TU);
+ if (checkForErrors(TU) != 0) {
+ clang_disposeTranslationUnit(TU);
+ return -1;
+ }
+
clang_disposeTranslationUnit(TU);
return 0;
}
@@ -800,6 +836,9 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
return 1;
}
+ if (checkForErrors(TU) != 0)
+ return -1;
+
if (getenv("CINDEXTEST_REMAP_AFTER_TRIAL")) {
remap_after_trial =
strtol(getenv("CINDEXTEST_REMAP_AFTER_TRIAL"), &endptr, 10);
@@ -816,9 +855,13 @@ int perform_test_reparse_source(int argc, const char **argv, int trials,
clang_disposeIndex(Idx);
return -1;
}
+
+ if (checkForErrors(TU) != 0)
+ 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;
@@ -995,6 +1038,31 @@ clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
return "Unknown";
}
+static int checkForErrors(CXTranslationUnit TU) {
+ unsigned Num, i;
+ CXDiagnostic Diag;
+ CXString DiagStr;
+
+ if (!getenv("CINDEXTEST_FAILONERROR"))
+ return 0;
+
+ Num = clang_getNumDiagnostics(TU);
+ for (i = 0; i != Num; ++i) {
+ Diag = clang_getDiagnostic(TU, i);
+ if (clang_getDiagnosticSeverity(Diag) >= CXDiagnostic_Error) {
+ DiagStr = clang_formatDiagnostic(Diag,
+ clang_defaultDiagnosticDisplayOptions());
+ fprintf(stderr, "%s\n", clang_getCString(DiagStr));
+ clang_disposeString(DiagStr);
+ clang_disposeDiagnostic(Diag);
+ return -1;
+ }
+ clang_disposeDiagnostic(Diag);
+ }
+
+ return 0;
+}
+
void print_completion_string(CXCompletionString completion_string, FILE *file) {
int I, N;
@@ -1034,7 +1102,9 @@ void print_completion_result(CXCompletionResult *completion_result,
FILE *file = (FILE *)client_data;
CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
unsigned annotationCount;
-
+ enum CXCursorKind ParentKind;
+ CXString ParentName;
+
fprintf(file, "%s:", clang_getCString(ks));
clang_disposeString(ks);
@@ -1073,6 +1143,19 @@ void print_completion_result(CXCompletionResult *completion_result,
fprintf(file, ")");
}
+ if (!getenv("CINDEXTEST_NO_COMPLETION_PARENTS")) {
+ ParentName = clang_getCompletionParent(completion_result->CompletionString,
+ &ParentKind);
+ if (ParentKind != CXCursor_NotImplemented) {
+ CXString KindSpelling = clang_getCursorKindSpelling(ParentKind);
+ fprintf(file, " (parent: %s '%s')",
+ clang_getCString(KindSpelling),
+ clang_getCString(ParentName));
+ clang_disposeString(KindSpelling);
+ }
+ clang_disposeString(ParentName);
+ }
+
fprintf(file, "\n");
}
@@ -1347,6 +1430,9 @@ static int inspect_cursor_at(int argc, const char **argv) {
return -1;
}
+ if (checkForErrors(TU) != 0)
+ return -1;
+
for (I = 0; I != Repeats; ++I) {
if (Repeats > 1 &&
clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
@@ -1354,6 +1440,9 @@ static int inspect_cursor_at(int argc, const char **argv) {
clang_disposeTranslationUnit(TU);
return 1;
}
+
+ if (checkForErrors(TU) != 0)
+ return -1;
for (Loc = 0; Loc < NumLocations; ++Loc) {
CXFile file = clang_getFile(TU, Locations[Loc].filename);
@@ -1363,10 +1452,38 @@ static int inspect_cursor_at(int argc, const char **argv) {
Cursor = clang_getCursor(TU,
clang_getLocation(TU, file, Locations[Loc].line,
Locations[Loc].column));
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+
if (I + 1 == Repeats) {
CXCompletionString completionString = clang_getCursorCompletionString(
Cursor);
+ CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
+ CXString Spelling;
+ const char *cspell;
+ unsigned line, column;
+ clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
+ printf("%d:%d ", line, column);
PrintCursor(Cursor);
+ PrintCursorExtent(Cursor);
+ Spelling = clang_getCursorSpelling(Cursor);
+ cspell = clang_getCString(Spelling);
+ if (cspell && strlen(cspell) != 0) {
+ unsigned pieceIndex;
+ printf(" Spelling=%s (", cspell);
+ for (pieceIndex = 0; ; ++pieceIndex) {
+ CXSourceRange range =
+ clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
+ if (clang_Range_isNull(range))
+ break;
+ PrintRange(range, 0);
+ }
+ printf(")");
+ }
+ clang_disposeString(Spelling);
+ if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
+ printf(" Selector index=%d",clang_Cursor_getObjCSelectorIndex(Cursor));
if (completionString != NULL) {
printf("\nCompletion string: ");
print_completion_string(completionString, stdout);
@@ -1446,6 +1563,9 @@ static int find_file_refs_at(int argc, const char **argv) {
return -1;
}
+ if (checkForErrors(TU) != 0)
+ return -1;
+
for (I = 0; I != Repeats; ++I) {
if (Repeats > 1 &&
clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
@@ -1453,6 +1573,9 @@ static int find_file_refs_at(int argc, const char **argv) {
clang_disposeTranslationUnit(TU);
return 1;
}
+
+ if (checkForErrors(TU) != 0)
+ return -1;
for (Loc = 0; Loc < NumLocations; ++Loc) {
CXFile file = clang_getFile(TU, Locations[Loc].filename);
@@ -1462,12 +1585,19 @@ static int find_file_refs_at(int argc, const char **argv) {
Cursor = clang_getCursor(TU,
clang_getLocation(TU, file, Locations[Loc].line,
Locations[Loc].column));
+
+ if (checkForErrors(TU) != 0)
+ return -1;
+
if (I + 1 == Repeats) {
CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
PrintCursor(Cursor);
printf("\n");
clang_findReferencesInFile(Cursor, file, visitor);
free(Locations[Loc].filename);
+
+ if (checkForErrors(TU) != 0)
+ return -1;
}
}
}
@@ -1480,6 +1610,521 @@ static int find_file_refs_at(int argc, const char **argv) {
return 0;
}
+typedef struct {
+ const char *check_prefix;
+ int first_check_printed;
+ int fail_for_error;
+ int abort;
+ const char *main_filename;
+} IndexData;
+
+static void printCheck(IndexData *data) {
+ if (data->check_prefix) {
+ if (data->first_check_printed) {
+ printf("// %s-NEXT: ", data->check_prefix);
+ } else {
+ printf("// %s : ", data->check_prefix);
+ data->first_check_printed = 1;
+ }
+ }
+}
+
+static void printCXIndexFile(CXIdxClientFile file) {
+ CXString filename = clang_getFileName((CXFile)file);
+ printf("%s", clang_getCString(filename));
+ clang_disposeString(filename);
+}
+
+static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
+ IndexData *index_data;
+ CXString filename;
+ const char *cname;
+ CXIdxClientFile file;
+ unsigned line, column;
+ int isMainFile;
+
+ index_data = (IndexData *)client_data;
+ clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
+ if (line == 0) {
+ printf("<null loc>");
+ return;
+ }
+ if (!file) {
+ printf("<no idxfile>");
+ return;
+ }
+ filename = clang_getFileName((CXFile)file);
+ cname = clang_getCString(filename);
+ if (strcmp(cname, index_data->main_filename) == 0)
+ isMainFile = 1;
+ else
+ isMainFile = 0;
+ clang_disposeString(filename);
+
+ if (!isMainFile) {
+ printCXIndexFile(file);
+ printf(":");
+ }
+ printf("%d:%d", line, column);
+}
+
+static unsigned digitCount(unsigned val) {
+ unsigned c = 1;
+ while (1) {
+ if (val < 10)
+ return c;
+ ++c;
+ val /= 10;
+ }
+}
+
+static CXIdxClientContainer makeClientContainer(const CXIdxEntityInfo *info,
+ CXIdxLoc loc) {
+ const char *name;
+ char *newStr;
+ CXIdxClientFile file;
+ unsigned line, column;
+
+ name = info->name;
+ if (!name)
+ name = "<anon-tag>";
+
+ clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
+ /* FIXME: free these.*/
+ newStr = (char *)malloc(strlen(name) +
+ digitCount(line) + digitCount(column) + 3);
+ sprintf(newStr, "%s:%d:%d", name, line, column);
+ return (CXIdxClientContainer)newStr;
+}
+
+static void printCXIndexContainer(const CXIdxContainerInfo *info) {
+ CXIdxClientContainer container;
+ container = clang_index_getClientContainer(info);
+ if (!container)
+ printf("[<<NULL>>]");
+ else
+ printf("[%s]", (const char *)container);
+}
+
+static const char *getEntityKindString(CXIdxEntityKind kind) {
+ switch (kind) {
+ case CXIdxEntity_Unexposed: return "<<UNEXPOSED>>";
+ case CXIdxEntity_Typedef: return "typedef";
+ case CXIdxEntity_Function: return "function";
+ case CXIdxEntity_Variable: return "variable";
+ case CXIdxEntity_Field: return "field";
+ case CXIdxEntity_EnumConstant: return "enumerator";
+ case CXIdxEntity_ObjCClass: return "objc-class";
+ case CXIdxEntity_ObjCProtocol: return "objc-protocol";
+ case CXIdxEntity_ObjCCategory: return "objc-category";
+ case CXIdxEntity_ObjCInstanceMethod: return "objc-instance-method";
+ case CXIdxEntity_ObjCClassMethod: return "objc-class-method";
+ case CXIdxEntity_ObjCProperty: return "objc-property";
+ case CXIdxEntity_ObjCIvar: return "objc-ivar";
+ case CXIdxEntity_Enum: return "enum";
+ case CXIdxEntity_Struct: return "struct";
+ case CXIdxEntity_Union: return "union";
+ case CXIdxEntity_CXXClass: return "c++-class";
+ case CXIdxEntity_CXXNamespace: return "namespace";
+ case CXIdxEntity_CXXNamespaceAlias: return "namespace-alias";
+ case CXIdxEntity_CXXStaticVariable: return "c++-static-var";
+ case CXIdxEntity_CXXStaticMethod: return "c++-static-method";
+ case CXIdxEntity_CXXInstanceMethod: return "c++-instance-method";
+ case CXIdxEntity_CXXConstructor: return "constructor";
+ case CXIdxEntity_CXXDestructor: return "destructor";
+ case CXIdxEntity_CXXConversionFunction: return "conversion-func";
+ case CXIdxEntity_CXXTypeAlias: return "type-alias";
+ }
+ assert(0 && "Garbage entity kind");
+ return 0;
+}
+
+static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind) {
+ switch (kind) {
+ case CXIdxEntity_NonTemplate: return "";
+ case CXIdxEntity_Template: return "-template";
+ case CXIdxEntity_TemplatePartialSpecialization:
+ return "-template-partial-spec";
+ case CXIdxEntity_TemplateSpecialization: return "-template-spec";
+ }
+ assert(0 && "Garbage entity kind");
+ return 0;
+}
+
+static const char *getEntityLanguageString(CXIdxEntityLanguage kind) {
+ switch (kind) {
+ case CXIdxEntityLang_None: return "<none>";
+ case CXIdxEntityLang_C: return "C";
+ case CXIdxEntityLang_ObjC: return "ObjC";
+ case CXIdxEntityLang_CXX: return "C++";
+ }
+ assert(0 && "Garbage language kind");
+ return 0;
+}
+
+static void printEntityInfo(const char *cb,
+ CXClientData client_data,
+ const CXIdxEntityInfo *info) {
+ const char *name;
+ IndexData *index_data;
+ unsigned i;
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ if (!info) {
+ printf("%s: <<NULL>>", cb);
+ return;
+ }
+
+ name = info->name;
+ if (!name)
+ name = "<anon-tag>";
+
+ printf("%s: kind: %s%s", cb, getEntityKindString(info->kind),
+ getEntityTemplateKindString(info->templateKind));
+ printf(" | name: %s", name);
+ printf(" | USR: %s", info->USR);
+ printf(" | lang: %s", getEntityLanguageString(info->lang));
+
+ for (i = 0; i != info->numAttributes; ++i) {
+ const CXIdxAttrInfo *Attr = info->attributes[i];
+ printf(" <attribute>: ");
+ PrintCursor(Attr->cursor);
+ }
+}
+
+static void printBaseClassInfo(CXClientData client_data,
+ const CXIdxBaseClassInfo *info) {
+ printEntityInfo(" <base>", client_data, info->base);
+ printf(" | cursor: ");
+ PrintCursor(info->cursor);
+ printf(" | loc: ");
+ printCXIndexLoc(info->loc, client_data);
+}
+
+static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo,
+ CXClientData client_data) {
+ unsigned i;
+ for (i = 0; i < ProtoInfo->numProtocols; ++i) {
+ printEntityInfo(" <protocol>", client_data,
+ ProtoInfo->protocols[i]->protocol);
+ printf(" | cursor: ");
+ PrintCursor(ProtoInfo->protocols[i]->cursor);
+ printf(" | loc: ");
+ printCXIndexLoc(ProtoInfo->protocols[i]->loc, client_data);
+ printf("\n");
+ }
+}
+
+static void index_diagnostic(CXClientData client_data,
+ CXDiagnosticSet diagSet, void *reserved) {
+ CXString str;
+ const char *cstr;
+ unsigned numDiags, i;
+ CXDiagnostic diag;
+ IndexData *index_data;
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ numDiags = clang_getNumDiagnosticsInSet(diagSet);
+ for (i = 0; i != numDiags; ++i) {
+ diag = clang_getDiagnosticInSet(diagSet, i);
+ str = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions());
+ cstr = clang_getCString(str);
+ printf("[diagnostic]: %s\n", cstr);
+ clang_disposeString(str);
+
+ if (getenv("CINDEXTEST_FAILONERROR") &&
+ clang_getDiagnosticSeverity(diag) >= CXDiagnostic_Error) {
+ index_data->fail_for_error = 1;
+ }
+ }
+}
+
+static CXIdxClientFile index_enteredMainFile(CXClientData client_data,
+ CXFile file, void *reserved) {
+ IndexData *index_data;
+ CXString filename;
+
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ filename = clang_getFileName(file);
+ index_data->main_filename = clang_getCString(filename);
+ clang_disposeString(filename);
+
+ printf("[enteredMainFile]: ");
+ printCXIndexFile((CXIdxClientFile)file);
+ printf("\n");
+
+ return (CXIdxClientFile)file;
+}
+
+static CXIdxClientFile index_ppIncludedFile(CXClientData client_data,
+ const CXIdxIncludedFileInfo *info) {
+ IndexData *index_data;
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ printf("[ppIncludedFile]: ");
+ printCXIndexFile((CXIdxClientFile)info->file);
+ printf(" | name: \"%s\"", info->filename);
+ printf(" | hash loc: ");
+ printCXIndexLoc(info->hashLoc, client_data);
+ printf(" | isImport: %d | isAngled: %d\n", info->isImport, info->isAngled);
+
+ return (CXIdxClientFile)info->file;
+}
+
+static CXIdxClientContainer index_startedTranslationUnit(CXClientData client_data,
+ void *reserved) {
+ IndexData *index_data;
+ index_data = (IndexData *)client_data;
+ printCheck(index_data);
+
+ printf("[startedTranslationUnit]\n");
+ return (CXIdxClientContainer)"TU";
+}
+
+static void index_indexDeclaration(CXClientData client_data,
+ const CXIdxDeclInfo *info) {
+ IndexData *index_data;
+ const CXIdxObjCCategoryDeclInfo *CatInfo;
+ const CXIdxObjCInterfaceDeclInfo *InterInfo;
+ const CXIdxObjCProtocolRefListInfo *ProtoInfo;
+ const CXIdxObjCPropertyDeclInfo *PropInfo;
+ const CXIdxCXXClassDeclInfo *CXXClassInfo;
+ unsigned i;
+ index_data = (IndexData *)client_data;
+
+ printEntityInfo("[indexDeclaration]", client_data, info->entityInfo);
+ printf(" | cursor: ");
+ PrintCursor(info->cursor);
+ printf(" | loc: ");
+ printCXIndexLoc(info->loc, client_data);
+ printf(" | semantic-container: ");
+ printCXIndexContainer(info->semanticContainer);
+ printf(" | lexical-container: ");
+ printCXIndexContainer(info->lexicalContainer);
+ printf(" | isRedecl: %d", info->isRedeclaration);
+ printf(" | isDef: %d", info->isDefinition);
+ printf(" | isContainer: %d", info->isContainer);
+ printf(" | isImplicit: %d\n", info->isImplicit);
+
+ for (i = 0; i != info->numAttributes; ++i) {
+ const CXIdxAttrInfo *Attr = info->attributes[i];
+ printf(" <attribute>: ");
+ PrintCursor(Attr->cursor);
+ printf("\n");
+ }
+
+ if (clang_index_isEntityObjCContainerKind(info->entityInfo->kind)) {
+ const char *kindName = 0;
+ CXIdxObjCContainerKind K = clang_index_getObjCContainerDeclInfo(info)->kind;
+ switch (K) {
+ case CXIdxObjCContainer_ForwardRef:
+ kindName = "forward-ref"; break;
+ case CXIdxObjCContainer_Interface:
+ kindName = "interface"; break;
+ case CXIdxObjCContainer_Implementation:
+ kindName = "implementation"; break;
+ }
+ printCheck(index_data);
+ printf(" <ObjCContainerInfo>: kind: %s\n", kindName);
+ }
+
+ if ((CatInfo = clang_index_getObjCCategoryDeclInfo(info))) {
+ printEntityInfo(" <ObjCCategoryInfo>: class", client_data,
+ CatInfo->objcClass);
+ printf(" | cursor: ");
+ PrintCursor(CatInfo->classCursor);
+ printf(" | loc: ");
+ printCXIndexLoc(CatInfo->classLoc, client_data);
+ printf("\n");
+ }
+
+ if ((InterInfo = clang_index_getObjCInterfaceDeclInfo(info))) {
+ if (InterInfo->superInfo) {
+ printBaseClassInfo(client_data, InterInfo->superInfo);
+ printf("\n");
+ }
+ }
+
+ if ((ProtoInfo = clang_index_getObjCProtocolRefListInfo(info))) {
+ printProtocolList(ProtoInfo, client_data);
+ }
+
+ if ((PropInfo = clang_index_getObjCPropertyDeclInfo(info))) {
+ if (PropInfo->getter) {
+ printEntityInfo(" <getter>", client_data, PropInfo->getter);
+ printf("\n");
+ }
+ if (PropInfo->setter) {
+ printEntityInfo(" <setter>", client_data, PropInfo->setter);
+ printf("\n");
+ }
+ }
+
+ if ((CXXClassInfo = clang_index_getCXXClassDeclInfo(info))) {
+ for (i = 0; i != CXXClassInfo->numBases; ++i) {
+ printBaseClassInfo(client_data, CXXClassInfo->bases[i]);
+ printf("\n");
+ }
+ }
+
+ if (info->declAsContainer)
+ clang_index_setClientContainer(info->declAsContainer,
+ makeClientContainer(info->entityInfo, info->loc));
+}
+
+static void index_indexEntityReference(CXClientData client_data,
+ const CXIdxEntityRefInfo *info) {
+ printEntityInfo("[indexEntityReference]", client_data, info->referencedEntity);
+ printf(" | cursor: ");
+ PrintCursor(info->cursor);
+ printf(" | loc: ");
+ printCXIndexLoc(info->loc, client_data);
+ printEntityInfo(" | <parent>:", client_data, info->parentEntity);
+ printf(" | container: ");
+ printCXIndexContainer(info->container);
+ printf(" | refkind: ");
+ switch (info->kind) {
+ case CXIdxEntityRef_Direct: printf("direct"); break;
+ case CXIdxEntityRef_Implicit: printf("implicit"); break;
+ }
+ printf("\n");
+}
+
+static int index_abortQuery(CXClientData client_data, void *reserved) {
+ IndexData *index_data;
+ index_data = (IndexData *)client_data;
+ return index_data->abort;
+}
+
+static IndexerCallbacks IndexCB = {
+ index_abortQuery,
+ index_diagnostic,
+ index_enteredMainFile,
+ index_ppIncludedFile,
+ 0, /*importedASTFile*/
+ index_startedTranslationUnit,
+ index_indexDeclaration,
+ index_indexEntityReference
+};
+
+static unsigned getIndexOptions(void) {
+ unsigned index_opts;
+ index_opts = 0;
+ if (getenv("CINDEXTEST_SUPPRESSREFS"))
+ index_opts |= CXIndexOpt_SuppressRedundantRefs;
+ if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
+ index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
+
+ return index_opts;
+}
+
+static int index_file(int argc, const char **argv) {
+ const char *check_prefix;
+ CXIndex Idx;
+ CXIndexAction idxAction;
+ IndexData index_data;
+ unsigned index_opts;
+ int result;
+
+ check_prefix = 0;
+ if (argc > 0) {
+ if (strstr(argv[0], "-check-prefix=") == argv[0]) {
+ check_prefix = argv[0] + strlen("-check-prefix=");
+ ++argv;
+ --argc;
+ }
+ }
+
+ if (argc == 0) {
+ fprintf(stderr, "no compiler arguments\n");
+ return -1;
+ }
+
+ if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
+ /* displayDiagnosics=*/1))) {
+ fprintf(stderr, "Could not create Index\n");
+ return 1;
+ }
+ idxAction = 0;
+ result = 1;
+
+ index_data.check_prefix = check_prefix;
+ index_data.first_check_printed = 0;
+ index_data.fail_for_error = 0;
+ index_data.abort = 0;
+
+ index_opts = getIndexOptions();
+ idxAction = clang_IndexAction_create(Idx);
+ result = clang_indexSourceFile(idxAction, &index_data,
+ &IndexCB,sizeof(IndexCB), index_opts,
+ 0, argv, argc, 0, 0, 0, 0);
+ if (index_data.fail_for_error)
+ result = -1;
+
+ clang_IndexAction_dispose(idxAction);
+ clang_disposeIndex(Idx);
+ return result;
+}
+
+static int index_tu(int argc, const char **argv) {
+ CXIndex Idx;
+ CXIndexAction idxAction;
+ CXTranslationUnit TU;
+ const char *check_prefix;
+ IndexData index_data;
+ unsigned index_opts;
+ int result;
+
+ check_prefix = 0;
+ if (argc > 0) {
+ if (strstr(argv[0], "-check-prefix=") == argv[0]) {
+ check_prefix = argv[0] + strlen("-check-prefix=");
+ ++argv;
+ --argc;
+ }
+ }
+
+ if (argc == 0) {
+ fprintf(stderr, "no ast file\n");
+ return -1;
+ }
+
+ if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
+ /* displayDiagnosics=*/1))) {
+ fprintf(stderr, "Could not create Index\n");
+ return 1;
+ }
+ idxAction = 0;
+ result = 1;
+
+ if (!CreateTranslationUnit(Idx, argv[0], &TU))
+ goto finished;
+
+ index_data.check_prefix = check_prefix;
+ index_data.first_check_printed = 0;
+ index_data.fail_for_error = 0;
+ index_data.abort = 0;
+
+ index_opts = getIndexOptions();
+ idxAction = clang_IndexAction_create(Idx);
+ result = clang_indexTranslationUnit(idxAction, &index_data,
+ &IndexCB,sizeof(IndexCB),
+ index_opts, TU);
+ if (index_data.fail_for_error)
+ goto finished;
+
+ finished:
+ clang_IndexAction_dispose(idxAction);
+ clang_disposeIndex(Idx);
+
+ return result;
+}
+
int perform_token_annotation(int argc, const char **argv) {
const char *input = argv[1];
char *filename = 0;
@@ -1522,6 +2167,9 @@ int perform_token_annotation(int argc, const char **argv) {
}
errorCode = 0;
+ if (checkForErrors(TU) != 0)
+ return -1;
+
if (getenv("CINDEXTEST_EDITING")) {
for (i = 0; i < 5; ++i) {
if (clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
@@ -1533,6 +2181,11 @@ int perform_token_annotation(int argc, const char **argv) {
}
}
+ if (checkForErrors(TU) != 0) {
+ errorCode = -1;
+ goto teardown;
+ }
+
file = clang_getFile(TU, filename);
if (!file) {
fprintf(stderr, "file %s is not in this translation unit\n", filename);
@@ -1558,8 +2211,20 @@ int perform_token_annotation(int argc, const char **argv) {
range = clang_getRange(startLoc, endLoc);
clang_tokenize(TU, range, &tokens, &num_tokens);
+
+ if (checkForErrors(TU) != 0) {
+ errorCode = -1;
+ goto teardown;
+ }
+
cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
clang_annotateTokens(TU, tokens, num_tokens, cursors);
+
+ if (checkForErrors(TU) != 0) {
+ errorCode = -1;
+ goto teardown;
+ }
+
for (i = 0; i != num_tokens; ++i) {
const char *kind = "<unknown>";
CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
@@ -1829,6 +2494,167 @@ int write_pch_file(const char *filename, int argc, const char *argv[]) {
}
/******************************************************************************/
+/* Serialized diagnostics. */
+/******************************************************************************/
+
+static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) {
+ switch (error) {
+ case CXLoadDiag_CannotLoad: return "Cannot Load File";
+ case CXLoadDiag_None: break;
+ case CXLoadDiag_Unknown: return "Unknown";
+ case CXLoadDiag_InvalidFile: return "Invalid File";
+ }
+ return "None";
+}
+
+static const char *getSeverityString(enum CXDiagnosticSeverity severity) {
+ switch (severity) {
+ case CXDiagnostic_Note: return "note";
+ case CXDiagnostic_Error: return "error";
+ case CXDiagnostic_Fatal: return "fatal";
+ case CXDiagnostic_Ignored: return "ignored";
+ case CXDiagnostic_Warning: return "warning";
+ }
+ return "unknown";
+}
+
+static void printIndent(unsigned indent) {
+ if (indent == 0)
+ return;
+ fprintf(stderr, "+");
+ --indent;
+ while (indent > 0) {
+ fprintf(stderr, "-");
+ --indent;
+ }
+}
+
+static void printLocation(CXSourceLocation L) {
+ CXFile File;
+ CXString FileName;
+ unsigned line, column, offset;
+
+ clang_getExpansionLocation(L, &File, &line, &column, &offset);
+ FileName = clang_getFileName(File);
+
+ fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column);
+ clang_disposeString(FileName);
+}
+
+static void printRanges(CXDiagnostic D, unsigned indent) {
+ unsigned i, n = clang_getDiagnosticNumRanges(D);
+
+ for (i = 0; i < n; ++i) {
+ CXSourceLocation Start, End;
+ CXSourceRange SR = clang_getDiagnosticRange(D, i);
+ Start = clang_getRangeStart(SR);
+ End = clang_getRangeEnd(SR);
+
+ printIndent(indent);
+ fprintf(stderr, "Range: ");
+ printLocation(Start);
+ fprintf(stderr, " ");
+ printLocation(End);
+ fprintf(stderr, "\n");
+ }
+}
+
+static void printFixIts(CXDiagnostic D, unsigned indent) {
+ unsigned i, n = clang_getDiagnosticNumFixIts(D);
+ fprintf(stderr, "Number FIXITs = %d\n", n);
+ for (i = 0 ; i < n; ++i) {
+ CXSourceRange ReplacementRange;
+ CXString text;
+ text = clang_getDiagnosticFixIt(D, i, &ReplacementRange);
+
+ printIndent(indent);
+ fprintf(stderr, "FIXIT: (");
+ printLocation(clang_getRangeStart(ReplacementRange));
+ fprintf(stderr, " - ");
+ printLocation(clang_getRangeEnd(ReplacementRange));
+ fprintf(stderr, "): \"%s\"\n", clang_getCString(text));
+ clang_disposeString(text);
+ }
+}
+
+static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
+ unsigned i, n;
+
+ if (!Diags)
+ return;
+
+ n = clang_getNumDiagnosticsInSet(Diags);
+ for (i = 0; i < n; ++i) {
+ CXSourceLocation DiagLoc;
+ CXDiagnostic D;
+ CXFile File;
+ CXString FileName, DiagSpelling, DiagOption, DiagCat;
+ unsigned line, column, offset;
+ const char *DiagOptionStr = 0, *DiagCatStr = 0;
+
+ D = clang_getDiagnosticInSet(Diags, i);
+ DiagLoc = clang_getDiagnosticLocation(D);
+ clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
+ FileName = clang_getFileName(File);
+ DiagSpelling = clang_getDiagnosticSpelling(D);
+
+ printIndent(indent);
+
+ fprintf(stderr, "%s:%d:%d: %s: %s",
+ clang_getCString(FileName),
+ line,
+ column,
+ getSeverityString(clang_getDiagnosticSeverity(D)),
+ clang_getCString(DiagSpelling));
+
+ DiagOption = clang_getDiagnosticOption(D, 0);
+ DiagOptionStr = clang_getCString(DiagOption);
+ if (DiagOptionStr) {
+ fprintf(stderr, " [%s]", DiagOptionStr);
+ }
+
+ DiagCat = clang_getDiagnosticCategoryText(D);
+ DiagCatStr = clang_getCString(DiagCat);
+ if (DiagCatStr) {
+ fprintf(stderr, " [%s]", DiagCatStr);
+ }
+
+ fprintf(stderr, "\n");
+
+ printRanges(D, indent);
+ printFixIts(D, indent);
+
+ /* Print subdiagnostics. */
+ printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
+
+ clang_disposeString(FileName);
+ clang_disposeString(DiagSpelling);
+ clang_disposeString(DiagOption);
+ }
+}
+
+static int read_diagnostics(const char *filename) {
+ enum CXLoadDiag_Error error;
+ CXString errorString;
+ CXDiagnosticSet Diags = 0;
+
+ Diags = clang_loadDiagnostics(filename, &error, &errorString);
+ if (!Diags) {
+ fprintf(stderr, "Trouble deserializing file (%s): %s\n",
+ getDiagnosticCodeStr(error),
+ clang_getCString(errorString));
+ clang_disposeString(errorString);
+ return 1;
+ }
+
+ printDiagnosticSet(Diags, 0);
+ fprintf(stderr, "Number of diagnostics: %d\n",
+ clang_getNumDiagnosticsInSet(Diags));
+ clang_disposeDiagnosticSet(Diags);
+ return 0;
+}
+
+/******************************************************************************/
/* Command line processing. */
/******************************************************************************/
@@ -1848,6 +2674,8 @@ static void print_usage(void) {
" c-index-test -code-completion-timing=<site> <compiler arguments>\n"
" c-index-test -cursor-at=<site> <compiler arguments>\n"
" c-index-test -file-refs-at=<site> <compiler arguments>\n"
+ " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
+ " c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
" c-index-test -test-file-scan <AST file> <source file> "
"[FileCheck prefix]\n");
fprintf(stderr,
@@ -1872,7 +2700,9 @@ static void print_usage(void) {
" c-index-test -test-print-typekind {<args>}*\n"
" c-index-test -print-usr [<CursorKind> {<args>}]*\n"
" c-index-test -print-usr-file <file>\n"
- " c-index-test -write-pch <file> <compiler arguments>\n\n");
+ " c-index-test -write-pch <file> <compiler arguments>\n");
+ fprintf(stderr,
+ " c-index-test -read-diagnostics <file>\n\n");
fprintf(stderr,
" <symbol filter> values:\n%s",
" all - load all symbols, including those from PCH\n"
@@ -1889,6 +2719,8 @@ static void print_usage(void) {
int cindextest_main(int argc, const char **argv) {
clang_enableStackTraces();
+ if (argc > 2 && strcmp(argv[1], "-read-diagnostics") == 0)
+ return read_diagnostics(argv[2]);
if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
return perform_code_completion(argc, argv, 0);
if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1])
@@ -1897,6 +2729,10 @@ int cindextest_main(int argc, const char **argv) {
return inspect_cursor_at(argc, argv);
if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
return find_file_refs_at(argc, argv);
+ if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
+ return index_file(argc - 2, argv + 2);
+ if (argc > 2 && strcmp(argv[1], "-index-tu") == 0)
+ return index_tu(argc - 2, argv + 2);
else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
CXCursorVisitor I = GetVisitor(argv[1] + 13);
if (I)
@@ -1970,6 +2806,9 @@ typedef struct thread_info {
void thread_runner(void *client_data_v) {
thread_info *client_data = client_data_v;
client_data->result = cindextest_main(client_data->argc, client_data->argv);
+#ifdef __CYGWIN__
+ fflush(stdout); /* stdout is not flushed on Cygwin. */
+#endif
}
int main(int argc, const char **argv) {
diff --git a/tools/clang-check/CMakeLists.txt b/tools/clang-check/CMakeLists.txt
new file mode 100644
index 000000000000..851d6cdd1615
--- /dev/null
+++ b/tools/clang-check/CMakeLists.txt
@@ -0,0 +1,5 @@
+set(LLVM_USED_LIBS clangTooling clangBasic)
+
+add_clang_executable(clang-check
+ ClangCheck.cpp
+ )
diff --git a/tools/clang-check/ClangCheck.cpp b/tools/clang-check/ClangCheck.cpp
new file mode 100644
index 000000000000..b5b6bd5a14ae
--- /dev/null
+++ b/tools/clang-check/ClangCheck.cpp
@@ -0,0 +1,62 @@
+//===- examples/Tooling/ClangCheck.cpp - Clang check tool -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a clang-check tool that runs the
+// clang::SyntaxOnlyAction over a number of translation units.
+//
+// Usage:
+// clang-check <cmake-output-dir> <file1> <file2> ...
+//
+// Where <cmake-output-dir> is a CMake build directory in which a file named
+// compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
+// CMake to get this output).
+//
+// <file1> ... specify the paths of files in the CMake source tree. This path
+// is looked up in the compile command database. If the path of a file is
+// absolute, it needs to point into CMake's source tree. If the path is
+// relative, the current working directory needs to be in the CMake source
+// tree and the file must be in a subdirectory of the current working
+// directory. "./" prefixes in the relative files will be automatically
+// removed, but the rest of a relative path must be a suffix of a path in
+// the compile command line database.
+//
+// For example, to use clang-check on all files in a subtree of the source
+// tree, use:
+//
+// /path/in/subtree $ find . -name '*.cpp'| xargs clang-check /path/to/source
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CommandLine.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/CompilationDatabase.h"
+#include "clang/Tooling/Tooling.h"
+
+using namespace clang::tooling;
+using namespace llvm;
+
+cl::opt<std::string> BuildPath(
+ cl::Positional,
+ cl::desc("<build-path>"));
+
+cl::list<std::string> SourcePaths(
+ cl::Positional,
+ cl::desc("<source0> [... <sourceN>]"),
+ cl::OneOrMore);
+
+int main(int argc, char **argv) {
+ cl::ParseCommandLineOptions(argc, argv);
+ std::string ErrorMessage;
+ llvm::OwningPtr<CompilationDatabase> Compilations(
+ CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage));
+ if (!Compilations)
+ llvm::report_fatal_error(ErrorMessage);
+ ClangTool Tool(*Compilations, SourcePaths);
+ return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
+}
diff --git a/tools/clang-check/Makefile b/tools/clang-check/Makefile
new file mode 100644
index 000000000000..49b1ada95b93
--- /dev/null
+++ b/tools/clang-check/Makefile
@@ -0,0 +1,24 @@
+##===- tools/clang-check/Makefile --------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+
+TOOLNAME = clang-check
+NO_INSTALL = 1
+
+# No plugins, optimize startup time.
+TOOL_NO_EXPORTS = 1
+
+LINK_COMPONENTS := support mc
+USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a \
+ clangTooling.a clangParse.a clangSema.a clangAnalysis.a \
+ clangEdit.a clangAST.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/Makefile
+
diff --git a/tools/diagtool/ListWarnings.cpp b/tools/diagtool/ListWarnings.cpp
index 7f7db8ef10b6..2bbeca802497 100644
--- a/tools/diagtool/ListWarnings.cpp
+++ b/tools/diagtool/ListWarnings.cpp
@@ -16,6 +16,8 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/StringMap.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/AllDiagnostics.h"
DEF_DIAGTOOL("list-warnings",
"List warnings and their corresponding flags",
@@ -23,6 +25,27 @@ DEF_DIAGTOOL("list-warnings",
using namespace clang;
+namespace {
+struct StaticDiagNameIndexRec {
+ const char *NameStr;
+ unsigned short DiagID;
+ uint8_t NameLen;
+
+ StringRef getName() const {
+ return StringRef(NameStr, NameLen);
+ }
+};
+}
+
+static const StaticDiagNameIndexRec StaticDiagNameIndex[] = {
+#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM, STR_SIZE(#ENUM, uint8_t) },
+#include "clang/Basic/DiagnosticIndexName.inc"
+#undef DIAG_NAME_INDEX
+ { 0, 0, 0 }
+};
+
+static const unsigned StaticDiagNameIndexSize =
+ sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1;
namespace {
struct Entry {
@@ -47,16 +70,13 @@ static void printEntries(std::vector<Entry> &entries, llvm::raw_ostream &out) {
}
int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> Diags(new DiagnosticIDs);
- DiagnosticsEngine D(Diags);
-
std::vector<Entry> Flagged, Unflagged;
llvm::StringMap<std::vector<unsigned> > flagHistogram;
- for (DiagnosticIDs::diag_iterator di = DiagnosticIDs::diags_begin(),
- de = DiagnosticIDs::diags_end(); di != de; ++di) {
+ for (const StaticDiagNameIndexRec *di = StaticDiagNameIndex, *de = StaticDiagNameIndex + StaticDiagNameIndexSize;
+ di != de; ++di) {
- unsigned diagID = di.getDiagID();
+ unsigned diagID = di->DiagID;
if (DiagnosticIDs::isBuiltinNote(diagID))
continue;
@@ -64,7 +84,7 @@ int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) {
if (!DiagnosticIDs::isBuiltinWarningOrExtension(diagID))
continue;
- Entry entry(di.getDiagName(),
+ Entry entry(di->getName(),
DiagnosticIDs::getWarningOptionForDiag(diagID));
if (entry.Flag.empty())
diff --git a/tools/diagtool/Makefile b/tools/diagtool/Makefile
index 22d74110e444..6e3bcfc292b1 100644
--- a/tools/diagtool/Makefile
+++ b/tools/diagtool/Makefile
@@ -17,9 +17,8 @@ TOOL_NO_EXPORTS := 1
NO_INSTALL = 1
LINK_COMPONENTS := support
-
-USEDLIBS = clangCodeGen.a clangParse.a clangSema.a \
- clangAST.a clangLex.a clangBasic.a
+
+USEDLIBS = clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt
index e6d0f1ac3763..c4c864bdbf5b 100644
--- a/tools/driver/CMakeLists.txt
+++ b/tools/driver/CMakeLists.txt
@@ -1,14 +1,16 @@
set( LLVM_USED_LIBS
+ clangFrontendTool
clangAST
clangAnalysis
clangBasic
clangCodeGen
clangDriver
+ clangEdit
clangFrontend
- clangFrontendTool
clangIndex
clangLex
clangParse
+ clangEdit
clangARCMigrate
clangRewrite
clangSema
@@ -26,6 +28,7 @@ set( LLVM_LINK_COMPONENTS
codegen
instrumentation
ipo
+ linker
selectiondag
)
@@ -39,18 +42,17 @@ set_target_properties(clang PROPERTIES VERSION ${CLANG_EXECUTABLE_VERSION})
if(UNIX)
set(CLANGXX_LINK_OR_COPY create_symlink)
+# Create a relative symlink
+ set(clang_binary "clang${CMAKE_EXECUTABLE_SUFFIX}")
else()
set(CLANGXX_LINK_OR_COPY copy)
+ set(clang_binary "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang${CMAKE_EXECUTABLE_SUFFIX}")
endif()
# Create the clang++ symlink in the build directory.
set(clang_pp "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang++${CMAKE_EXECUTABLE_SUFFIX}")
-add_custom_target(clang++ ALL
- ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY}
- "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/clang${CMAKE_EXECUTABLE_SUFFIX}"
- "${clang_pp}"
- DEPENDS clang)
-set_target_properties(clang++ PROPERTIES FOLDER "Clang executables")
+add_custom_command(TARGET clang POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E ${CLANGXX_LINK_OR_COPY} "${clang_binary}" "${clang_pp}")
set_property(DIRECTORY APPEND
PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${clang_pp})
diff --git a/tools/driver/Makefile b/tools/driver/Makefile
index 6b34a991bf18..d828f6786830 100644
--- a/tools/driver/Makefile
+++ b/tools/driver/Makefile
@@ -30,13 +30,13 @@ TOOL_INFO_PLIST := Info.plist
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader bitwriter codegen \
- instrumentation ipo selectiondag
+ instrumentation ipo linker selectiondag
USEDLIBS = clangFrontendTool.a clangFrontend.a clangDriver.a \
clangSerialization.a clangCodeGen.a clangParse.a clangSema.a \
clangStaticAnalyzerFrontend.a clangStaticAnalyzerCheckers.a \
clangStaticAnalyzerCore.a \
clangAnalysis.a clangIndex.a clangARCMigrate.a clangRewrite.a \
- clangAST.a clangLex.a clangBasic.a
+ clangEdit.a clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp
index 27f79b7e6677..a211090085d3 100644
--- a/tools/driver/cc1_main.cpp
+++ b/tools/driver/cc1_main.cpp
@@ -30,6 +30,7 @@
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/LinkAllPasses.h"
#include <cstdio>
using namespace clang;
@@ -76,7 +77,8 @@ static int cc1_test(DiagnosticsEngine &Diags,
// Create a compiler invocation.
llvm::errs() << "cc1 creating invocation.\n";
CompilerInvocation Invocation;
- CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags);
+ if (!CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags))
+ return 1;
// Convert the invocation back to argument strings.
std::vector<std::string> InvocationArgs;
@@ -94,8 +96,9 @@ static int cc1_test(DiagnosticsEngine &Diags,
// Convert those arguments to another invocation, and check that we got the
// same thing.
CompilerInvocation Invocation2;
- CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(),
- Invocation2Args.end(), Diags);
+ if (!CompilerInvocation::CreateFromArgs(Invocation2, Invocation2Args.begin(),
+ Invocation2Args.end(), Diags))
+ return 1;
// FIXME: Implement CompilerInvocation comparison.
if (true) {
@@ -114,8 +117,8 @@ static int cc1_test(DiagnosticsEngine &Diags,
int cc1_main(const char **ArgBegin, const char **ArgEnd,
const char *Argv0, void *MainAddr) {
- llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance());
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ OwningPtr<CompilerInstance> Clang(new CompilerInstance());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
// Run clang -cc1 test.
if (ArgBegin != ArgEnd && StringRef(ArgBegin[0]) == "-cc1test") {
@@ -134,8 +137,9 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
// well formed diagnostic object.
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
DiagnosticsEngine Diags(DiagID, DiagsBuffer);
- CompilerInvocation::CreateFromArgs(Clang->getInvocation(), ArgBegin, ArgEnd,
- Diags);
+ bool Success;
+ Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
+ ArgBegin, ArgEnd, Diags);
// Infer the builtin include path if unspecified.
if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
@@ -154,9 +158,11 @@ int cc1_main(const char **ArgBegin, const char **ArgEnd,
static_cast<void*>(&Clang->getDiagnostics()));
DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
+ if (!Success)
+ return 1;
// Execute the frontend actions.
- bool Success = ExecuteCompilerInvocation(Clang.get());
+ 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.
diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp
index 7cc42aa62768..508d6da54c92 100644
--- a/tools/driver/cc1as_main.cpp
+++ b/tools/driver/cc1as_main.cpp
@@ -63,8 +63,17 @@ struct AssemblerInvocation {
/// @name Target Options
/// @{
+ /// The name of the target triple to assemble for.
std::string Triple;
+ /// If given, the name of the target CPU to determine which instructions
+ /// are legal.
+ std::string CPU;
+
+ /// The list of target specific features to enable or disable -- this should
+ /// be a list of strings starting with '+' or '-'.
+ std::vector<std::string> Features;
+
/// @}
/// @name Language Options
/// @{
@@ -72,6 +81,8 @@ struct AssemblerInvocation {
std::vector<std::string> IncludePaths;
unsigned NoInitialTextSection : 1;
unsigned SaveTemporaryLabels : 1;
+ unsigned GenDwarfForAssembly : 1;
+ std::string DwarfDebugFlags;
/// @}
/// @name Frontend Options
@@ -120,17 +131,19 @@ public:
NoExecStack = 0;
}
- static void CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin,
+ static bool CreateFromArgs(AssemblerInvocation &Res, const char **ArgBegin,
const char **ArgEnd, DiagnosticsEngine &Diags);
};
}
-void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
+bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
const char **ArgBegin,
const char **ArgEnd,
DiagnosticsEngine &Diags) {
using namespace clang::driver::cc1asoptions;
+ bool Success = true;
+
// Parse the arguments.
OwningPtr<OptTable> OptTbl(createCC1AsOptTable());
unsigned MissingArgIndex, MissingArgCount;
@@ -138,26 +151,36 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
OptTbl->ParseArgs(ArgBegin, ArgEnd,MissingArgIndex, MissingArgCount));
// Check for missing argument error.
- if (MissingArgCount)
+ if (MissingArgCount) {
Diags.Report(diag::err_drv_missing_argument)
<< Args->getArgString(MissingArgIndex) << MissingArgCount;
+ Success = false;
+ }
// Issue errors on unknown arguments.
for (arg_iterator it = Args->filtered_begin(cc1asoptions::OPT_UNKNOWN),
- ie = Args->filtered_end(); it != ie; ++it)
+ ie = Args->filtered_end(); it != ie; ++it) {
Diags.Report(diag::err_drv_unknown_argument) << (*it) ->getAsString(*Args);
+ Success = false;
+ }
// Construct the invocation.
// Target Options
- Opts.Triple = Triple::normalize(Args->getLastArgValue(OPT_triple));
- if (Opts.Triple.empty()) // Use the host triple if unspecified.
- Opts.Triple = sys::getHostTriple();
+ Opts.Triple = llvm::Triple::normalize(Args->getLastArgValue(OPT_triple));
+ Opts.CPU = Args->getLastArgValue(OPT_target_cpu);
+ Opts.Features = Args->getAllArgValues(OPT_target_feature);
+
+ // Use the default target triple if unspecified.
+ if (Opts.Triple.empty())
+ Opts.Triple = llvm::sys::getDefaultTargetTriple();
// Language Options
Opts.IncludePaths = Args->getAllArgValues(OPT_I);
Opts.NoInitialTextSection = Args->hasArg(OPT_n);
Opts.SaveTemporaryLabels = Args->hasArg(OPT_L);
+ Opts.GenDwarfForAssembly = Args->hasArg(OPT_g);
+ Opts.DwarfDebugFlags = Args->getLastArgValue(OPT_dwarf_debug_flags);
// Frontend Options
if (Args->hasArg(OPT_INPUT)) {
@@ -167,8 +190,10 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
const Arg *A = it;
if (First)
Opts.InputFile = A->getValue(*Args);
- else
+ else {
Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(*Args);
+ Success = false;
+ }
}
}
Opts.LLVMArgs = Args->getAllArgValues(OPT_mllvm);
@@ -182,10 +207,11 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
.Case("null", FT_Null)
.Case("obj", FT_Obj)
.Default(~0U);
- if (OutputType == ~0U)
+ if (OutputType == ~0U) {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(*Args) << Name;
- else
+ Success = false;
+ } else
Opts.OutputType = FileType(OutputType);
}
Opts.ShowHelp = Args->hasArg(OPT_help);
@@ -200,6 +226,8 @@ void AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
// Assemble Options
Opts.RelaxAll = Args->hasArg(OPT_relax_all);
Opts.NoExecStack = Args->hasArg(OPT_no_exec_stack);
+
+ return Success;
}
static formatted_raw_ostream *GetOutputStream(AssemblerInvocation &Opts,
@@ -267,23 +295,36 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
- MCContext Ctx(*MAI, *MRI, MOFI.get());
+ MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr);
// FIXME: Assembler behavior can change with -static.
MOFI->InitMCObjectFileInfo(Opts.Triple,
Reloc::Default, CodeModel::Default, Ctx);
if (Opts.SaveTemporaryLabels)
Ctx.setAllowTemporaryLabels(false);
+ if (Opts.GenDwarfForAssembly)
+ Ctx.setGenDwarfForAssembly(true);
+ if (!Opts.DwarfDebugFlags.empty())
+ Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
+
+ // Build up the feature string from the target feature list.
+ std::string FS;
+ if (!Opts.Features.empty()) {
+ FS = Opts.Features[0];
+ for (unsigned i = 1, e = Opts.Features.size(); i != e; ++i)
+ FS += "," + Opts.Features[i];
+ }
OwningPtr<MCStreamer> Str;
OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
OwningPtr<MCSubtargetInfo>
- STI(TheTarget->createMCSubtargetInfo(Opts.Triple, "", ""));
+ STI(TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
MCInstPrinter *IP =
- TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI, *STI);
+ TheTarget->createMCInstPrinter(Opts.OutputAsmVariant, *MAI, *MCII, *MRI,
+ *STI);
MCCodeEmitter *CE = 0;
MCAsmBackend *MAB = 0;
if (Opts.ShowEncoding) {
@@ -292,7 +333,9 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts,
}
Str.reset(TheTarget->createAsmStreamer(Ctx, *Out, /*asmverbose*/true,
/*useLoc*/ true,
- /*useCFI*/ true, IP, CE, MAB,
+ /*useCFI*/ true,
+ /*useDwarfDirectory*/ true,
+ IP, CE, MAB,
Opts.ShowInst));
} else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
Str.reset(createNullStreamer(Ctx));
@@ -354,7 +397,7 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
TextDiagnosticPrinter *DiagClient
= new TextDiagnosticPrinter(errs(), DiagnosticOptions());
DiagClient->setPrefix("clang -cc1as");
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
DiagnosticsEngine Diags(DiagID, DiagClient);
// Set an error handler, so that any LLVM backend diagnostics go through our
@@ -364,11 +407,12 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
// Parse the arguments.
AssemblerInvocation Asm;
- AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags);
+ if (!AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags))
+ return 1;
// Honor -help.
if (Asm.ShowHelp) {
- llvm::OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable());
+ OwningPtr<driver::OptTable> Opts(driver::createCC1AsOptTable());
Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler");
return 0;
}
@@ -391,7 +435,7 @@ int cc1as_main(const char **ArgBegin, const char **ArgEnd,
for (unsigned i = 0; i != NumArgs; ++i)
Args[i + 1] = Asm.LLVMArgs[i].c_str();
Args[NumArgs + 1] = 0;
- llvm::cl::ParseCommandLineOptions(NumArgs + 1, const_cast<char **>(Args));
+ llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args);
}
// Execute the invocation, unless there were parsing errors.
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index bd1d2a2f5f35..8c05fff4dee9 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -12,17 +12,21 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/CC1Options.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Option.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
#include "llvm/ADT/ArrayRef.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/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
@@ -187,7 +191,7 @@ static void ExpandArgsFromBuf(const char *Arg,
SmallVectorImpl<const char*> &ArgVector,
std::set<std::string> &SavedStrings) {
const char *FName = Arg + 1;
- llvm::OwningPtr<llvm::MemoryBuffer> MemBuf;
+ OwningPtr<llvm::MemoryBuffer> MemBuf;
if (llvm::MemoryBuffer::getFile(FName, MemBuf)) {
ArgVector.push_back(SaveStringInSet(SavedStrings, Arg));
return;
@@ -272,7 +276,7 @@ static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
// the function tries to identify a target as prefix. E.g.
// "x86_64-linux-clang" as interpreted as suffix "clang" with
// target prefix "x86_64-linux". If such a target prefix is found,
- // is gets added via -ccc-host-triple as implicit first argument.
+ // is gets added via -target as implicit first argument.
static const struct {
const char *Suffix;
bool IsCXX;
@@ -332,7 +336,7 @@ static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
++it;
ArgVector.insert(it, SaveStringInSet(SavedStrings, Prefix));
ArgVector.insert(it,
- SaveStringInSet(SavedStrings, std::string("-ccc-host-triple")));
+ SaveStringInSet(SavedStrings, std::string("-target")));
}
}
@@ -371,25 +375,41 @@ int main(int argc_, const char **argv_) {
llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes);
+ DiagnosticOptions DiagOpts;
+ {
+ // Note that ParseDiagnosticArgs() uses the cc1 option table.
+ OwningPtr<OptTable> CC1Opts(createCC1OptTable());
+ unsigned MissingArgIndex, MissingArgCount;
+ OwningPtr<InputArgList> Args(CC1Opts->ParseArgs(argv.begin()+1, argv.end(),
+ MissingArgIndex, MissingArgCount));
+ // We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
+ // Any errors that would be diagnosed here will also be diagnosed later,
+ // when the DiagnosticsEngine actually exists.
+ (void) ParseDiagnosticArgs(DiagOpts, *Args);
+ }
+ // Now we can create the DiagnosticsEngine with a properly-filled-out
+ // DiagnosticOptions instance.
TextDiagnosticPrinter *DiagClient
- = new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions());
+ = new TextDiagnosticPrinter(llvm::errs(), DiagOpts);
DiagClient->setPrefix(llvm::sys::path::stem(Path.str()));
- llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+
DiagnosticsEngine Diags(DiagID, DiagClient);
+ ProcessWarningOptions(Diags, DiagOpts);
#ifdef CLANG_IS_PRODUCTION
const bool IsProduction = true;
#else
const bool IsProduction = false;
#endif
- Driver TheDriver(Path.str(), llvm::sys::getHostTriple(),
+ Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(),
"a.out", IsProduction, 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::SmallString<128> InstalledPath(argv[0]);
+ SmallString<128> InstalledPath(argv[0]);
// Do a PATH lookup, if there are no directory components.
if (llvm::sys::path::filename(InstalledPath) == InstalledPath) {
@@ -449,7 +469,7 @@ int main(int argc_, const char **argv_) {
argv.insert(&argv[1], ExtraArgs.begin(), ExtraArgs.end());
}
- llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv));
+ OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv));
int Res = 0;
const Command *FailingCommand = 0;
if (C.get())
diff --git a/tools/libclang/ARCMigrate.cpp b/tools/libclang/ARCMigrate.cpp
index 39c7d84d5190..5ee5cf6e4ef8 100644
--- a/tools/libclang/ARCMigrate.cpp
+++ b/tools/libclang/ARCMigrate.cpp
@@ -56,7 +56,7 @@ CXRemapping clang_getRemappings(const char *migrate_dir_path) {
}
TextDiagnosticBuffer diagBuffer;
- llvm::OwningPtr<Remap> remap(new Remap());
+ OwningPtr<Remap> remap(new Remap());
bool err = arcmt::getFileRemappings(remap->Vec, migrate_dir_path,&diagBuffer);
@@ -74,6 +74,47 @@ CXRemapping clang_getRemappings(const char *migrate_dir_path) {
return remap.take();
}
+CXRemapping clang_getRemappingsFromFileList(const char **filePaths,
+ unsigned numFiles) {
+ bool Logging = ::getenv("LIBCLANG_LOGGING");
+
+ OwningPtr<Remap> remap(new Remap());
+
+ if (numFiles == 0) {
+ if (Logging)
+ llvm::errs() << "clang_getRemappingsFromFileList was called with "
+ "numFiles=0\n";
+ return remap.take();
+ }
+
+ if (!filePaths) {
+ if (Logging)
+ llvm::errs() << "clang_getRemappingsFromFileList was called with "
+ "NULL filePaths\n";
+ return 0;
+ }
+
+ TextDiagnosticBuffer diagBuffer;
+ SmallVector<StringRef, 32> Files;
+ for (unsigned i = 0; i != numFiles; ++i)
+ Files.push_back(filePaths[i]);
+
+ bool err = arcmt::getFileRemappingsFromFileList(remap->Vec, Files,
+ &diagBuffer);
+
+ if (err) {
+ if (Logging) {
+ llvm::errs() << "Error by clang_getRemappingsFromFileList\n";
+ for (TextDiagnosticBuffer::const_iterator
+ I = diagBuffer.err_begin(), E = diagBuffer.err_end(); I != E; ++I)
+ llvm::errs() << I->second << '\n';
+ }
+ return remap.take();
+ }
+
+ return remap.take();
+}
+
unsigned clang_remap_getNumFiles(CXRemapping map) {
return static_cast<Remap *>(map)->Vec.size();
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 46ba3d55340d..ece91ce20e83 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -19,12 +19,11 @@
#include "CXType.h"
#include "CXSourceLocation.h"
#include "CIndexDiagnostic.h"
+#include "CursorVisitor.h"
#include "clang/Basic/Version.h"
-#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/TypeLocVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -36,7 +35,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
-#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -52,27 +51,23 @@ using namespace clang;
using namespace clang::cxcursor;
using namespace clang::cxstring;
using namespace clang::cxtu;
+using namespace clang::cxindex;
-CXTranslationUnit cxtu::MakeCXTranslationUnit(ASTUnit *TU) {
+CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU) {
if (!TU)
return 0;
CXTranslationUnit D = new CXTranslationUnitImpl();
+ D->CIdx = CIdx;
D->TUData = TU;
D->StringPool = createCXStringPool();
+ D->Diagnostics = 0;
return D;
}
-/// \brief The result of comparing two source ranges.
-enum RangeComparisonResult {
- /// \brief Either the ranges overlap or one of the ranges is invalid.
- RangeOverlap,
-
- /// \brief The first range ends before the second range starts.
- RangeBefore,
-
- /// \brief The first range starts after the second range ends.
- RangeAfter
-};
+cxtu::CXTUOwner::~CXTUOwner() {
+ if (TU)
+ clang_disposeTranslationUnit(TU);
+}
/// \brief Compare two source ranges to determine their relative position in
/// the translation unit.
@@ -117,10 +112,11 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
// We want the last character in this location, so we will adjust the
// location accordingly.
SourceLocation EndLoc = R.getEnd();
- if (EndLoc.isValid() && EndLoc.isMacroID())
+ if (EndLoc.isValid() && EndLoc.isMacroID() && !SM.isMacroArgExpansion(EndLoc))
EndLoc = SM.getExpansionRange(EndLoc).second;
- if (R.isTokenRange() && !EndLoc.isInvalid() && EndLoc.isFileID()) {
- unsigned Length = Lexer::MeasureTokenLength(EndLoc, SM, LangOpts);
+ if (R.isTokenRange() && !EndLoc.isInvalid()) {
+ unsigned Length = Lexer::MeasureTokenLength(SM.getSpellingLoc(EndLoc),
+ SM, LangOpts);
EndLoc = EndLoc.getLocWithOffset(Length);
}
@@ -134,213 +130,6 @@ CXSourceRange cxloc::translateSourceRange(const SourceManager &SM,
// Cursor visitor.
//===----------------------------------------------------------------------===//
-namespace {
-
-class VisitorJob {
-public:
- enum Kind { DeclVisitKind, StmtVisitKind, MemberExprPartsKind,
- TypeLocVisitKind, OverloadExprPartsKind,
- DeclRefExprPartsKind, LabelRefVisitKind,
- ExplicitTemplateArgsVisitKind,
- NestedNameSpecifierLocVisitKind,
- DeclarationNameInfoVisitKind,
- MemberRefVisitKind, SizeOfPackExprPartsKind };
-protected:
- void *data[3];
- CXCursor parent;
- Kind K;
- VisitorJob(CXCursor C, Kind k, void *d1, void *d2 = 0, void *d3 = 0)
- : parent(C), K(k) {
- data[0] = d1;
- data[1] = d2;
- data[2] = d3;
- }
-public:
- Kind getKind() const { return K; }
- const CXCursor &getParent() const { return parent; }
- static bool classof(VisitorJob *VJ) { return true; }
-};
-
-typedef SmallVector<VisitorJob, 10> VisitorWorkList;
-
-// Cursor visitor.
-class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
- public TypeLocVisitor<CursorVisitor, bool>
-{
- /// \brief The translation unit we are traversing.
- CXTranslationUnit TU;
- ASTUnit *AU;
-
- /// \brief The parent cursor whose children we are traversing.
- CXCursor Parent;
-
- /// \brief The declaration that serves at the parent of any statement or
- /// expression nodes.
- Decl *StmtParent;
-
- /// \brief The visitor function.
- CXCursorVisitor Visitor;
-
- /// \brief The opaque client data, to be passed along to the visitor.
- CXClientData ClientData;
-
- /// \brief Whether we should visit the preprocessing record entries last,
- /// after visiting other declarations.
- bool VisitPreprocessorLast;
-
- /// \brief When valid, a source range to which the cursor should restrict
- /// its search.
- SourceRange RegionOfInterest;
-
- // FIXME: Eventually remove. This part of a hack to support proper
- // iteration over all Decls contained lexically within an ObjC container.
- DeclContext::decl_iterator *DI_current;
- DeclContext::decl_iterator DE_current;
-
- // Cache of pre-allocated worklists for data-recursion walk of Stmts.
- SmallVector<VisitorWorkList*, 5> WorkListFreeList;
- SmallVector<VisitorWorkList*, 5> WorkListCache;
-
- using DeclVisitor<CursorVisitor, bool>::Visit;
- using TypeLocVisitor<CursorVisitor, bool>::Visit;
-
- /// \brief Determine whether this particular source range comes before, comes
- /// after, or overlaps the region of interest.
- ///
- /// \param R a half-open source range retrieved from the abstract syntax tree.
- RangeComparisonResult CompareRegionOfInterest(SourceRange R);
-
- class SetParentRAII {
- CXCursor &Parent;
- Decl *&StmtParent;
- CXCursor OldParent;
-
- public:
- SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent)
- : Parent(Parent), StmtParent(StmtParent), OldParent(Parent)
- {
- Parent = NewParent;
- if (clang_isDeclaration(Parent.kind))
- StmtParent = getCursorDecl(Parent);
- }
-
- ~SetParentRAII() {
- Parent = OldParent;
- if (clang_isDeclaration(Parent.kind))
- StmtParent = getCursorDecl(Parent);
- }
- };
-
-public:
- CursorVisitor(CXTranslationUnit TU, CXCursorVisitor Visitor,
- CXClientData ClientData,
- bool VisitPreprocessorLast,
- SourceRange RegionOfInterest = SourceRange())
- : TU(TU), AU(static_cast<ASTUnit*>(TU->TUData)),
- Visitor(Visitor), ClientData(ClientData),
- VisitPreprocessorLast(VisitPreprocessorLast),
- RegionOfInterest(RegionOfInterest), DI_current(0)
- {
- Parent.kind = CXCursor_NoDeclFound;
- Parent.data[0] = 0;
- Parent.data[1] = 0;
- Parent.data[2] = 0;
- StmtParent = 0;
- }
-
- ~CursorVisitor() {
- // Free the pre-allocated worklists for data-recursion.
- for (SmallVectorImpl<VisitorWorkList*>::iterator
- I = WorkListCache.begin(), E = WorkListCache.end(); I != E; ++I) {
- delete *I;
- }
- }
-
- ASTUnit *getASTUnit() const { return static_cast<ASTUnit*>(TU->TUData); }
- CXTranslationUnit getTU() const { return TU; }
-
- bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false);
-
- bool visitPreprocessedEntitiesInRegion();
-
- template<typename InputIterator>
- bool visitPreprocessedEntities(InputIterator First, InputIterator Last);
-
- bool VisitChildren(CXCursor Parent);
-
- // Declaration visitors
- bool VisitTypeAliasDecl(TypeAliasDecl *D);
- bool VisitAttributes(Decl *D);
- bool VisitBlockDecl(BlockDecl *B);
- bool VisitCXXRecordDecl(CXXRecordDecl *D);
- llvm::Optional<bool> shouldVisitCursor(CXCursor C);
- 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);
- bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID);
- bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD);
- bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
- bool VisitObjCImplDecl(ObjCImplDecl *D);
- bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
- bool VisitObjCImplementationDecl(ObjCImplementationDecl *D);
- // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations.
- bool VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
- bool VisitObjCClassDecl(ObjCClassDecl *D);
- bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD);
- 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);
- bool VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
-
- // Template visitors
- bool VisitTemplateParameters(const TemplateParameterList *Params);
- bool VisitTemplateName(TemplateName Name, SourceLocation Loc);
- bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL);
-
- // Type visitors
-#define ABSTRACT_TYPELOC(CLASS, PARENT)
-#define TYPELOC(CLASS, PARENT) \
- bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
-#include "clang/AST/TypeLocNodes.def"
-
- bool VisitTagTypeLoc(TagTypeLoc TL);
- bool VisitArrayTypeLoc(ArrayTypeLoc TL);
- bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false);
-
- // Data-recursive visitor functions.
- bool IsInRegionOfInterest(CXCursor C);
- bool RunVisitorWorkList(VisitorWorkList &WL);
- void EnqueueWorkList(VisitorWorkList &WL, Stmt *S);
- LLVM_ATTRIBUTE_NOINLINE bool Visit(Stmt *S);
-};
-
-} // end anonymous namespace
-
static SourceRange getRawCursorExtent(CXCursor C);
static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr);
@@ -365,7 +154,11 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
if (clang_isDeclaration(Cursor.kind)) {
Decl *D = getCursorDecl(Cursor);
- assert(D && "Invalid declaration cursor");
+ if (!D) {
+ assert(0 && "Invalid declaration cursor");
+ return true; // abort.
+ }
+
// Ignore implicit declarations, unless it's an objc method because
// currently we should report implicit methods for properties when indexing.
if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
@@ -391,48 +184,242 @@ bool CursorVisitor::Visit(CXCursor Cursor, bool CheckedRegionOfInterest) {
return VisitChildren(Cursor);
}
+ llvm_unreachable("Invalid CXChildVisitResult!");
+}
+
+static bool visitPreprocessedEntitiesInRange(SourceRange R,
+ PreprocessingRecord &PPRec,
+ CursorVisitor &Visitor) {
+ SourceManager &SM = Visitor.getASTUnit()->getSourceManager();
+ FileID FID;
+
+ if (!Visitor.shouldVisitIncludedEntities()) {
+ // If the begin/end of the range lie in the same FileID, do the optimization
+ // where we skip preprocessed entities that do not come from the same FileID.
+ FID = SM.getFileID(SM.getFileLoc(R.getBegin()));
+ if (FID != SM.getFileID(SM.getFileLoc(R.getEnd())))
+ FID = FileID();
+ }
+
+ std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
+ Entities = PPRec.getPreprocessedEntitiesInRange(R);
+ return Visitor.visitPreprocessedEntities(Entities.first, Entities.second,
+ PPRec, FID);
+}
+
+void CursorVisitor::visitFileRegion() {
+ if (RegionOfInterest.isInvalid())
+ return;
+
+ ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+ SourceManager &SM = Unit->getSourceManager();
+
+ std::pair<FileID, unsigned>
+ Begin = SM.getDecomposedLoc(SM.getFileLoc(RegionOfInterest.getBegin())),
+ End = SM.getDecomposedLoc(SM.getFileLoc(RegionOfInterest.getEnd()));
+
+ if (End.first != Begin.first) {
+ // If the end does not reside in the same file, try to recover by
+ // picking the end of the file of begin location.
+ End.first = Begin.first;
+ End.second = SM.getFileIDSize(Begin.first);
+ }
+
+ assert(Begin.first == End.first);
+ if (Begin.second > End.second)
+ return;
+
+ FileID File = Begin.first;
+ unsigned Offset = Begin.second;
+ unsigned Length = End.second - Begin.second;
+
+ if (!VisitDeclsOnly && !VisitPreprocessorLast)
+ if (visitPreprocessedEntitiesInRegion())
+ return; // visitation break.
+
+ visitDeclsFromFileRegion(File, Offset, Length);
+
+ if (!VisitDeclsOnly && VisitPreprocessorLast)
+ visitPreprocessedEntitiesInRegion();
+}
+
+static bool isInLexicalContext(Decl *D, DeclContext *DC) {
+ if (!DC)
+ return false;
+
+ for (DeclContext *DeclDC = D->getLexicalDeclContext();
+ DeclDC; DeclDC = DeclDC->getLexicalParent()) {
+ if (DeclDC == DC)
+ return true;
+ }
return false;
}
+void CursorVisitor::visitDeclsFromFileRegion(FileID File,
+ unsigned Offset, unsigned Length) {
+ ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+ SourceManager &SM = Unit->getSourceManager();
+ SourceRange Range = RegionOfInterest;
+
+ SmallVector<Decl *, 16> Decls;
+ Unit->findFileRegionDecls(File, Offset, Length, Decls);
+
+ // If we didn't find any file level decls for the file, try looking at the
+ // file that it was included from.
+ while (Decls.empty() || Decls.front()->isTopLevelDeclInObjCContainer()) {
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &SLEntry = SM.getSLocEntry(File, &Invalid);
+ if (Invalid)
+ return;
+
+ SourceLocation Outer;
+ if (SLEntry.isFile())
+ Outer = SLEntry.getFile().getIncludeLoc();
+ else
+ Outer = SLEntry.getExpansion().getExpansionLocStart();
+ if (Outer.isInvalid())
+ return;
+
+ llvm::tie(File, Offset) = SM.getDecomposedExpansionLoc(Outer);
+ Length = 0;
+ Unit->findFileRegionDecls(File, Offset, Length, Decls);
+ }
+
+ assert(!Decls.empty());
+
+ bool VisitedAtLeastOnce = false;
+ DeclContext *CurDC = 0;
+ SmallVector<Decl *, 16>::iterator DIt = Decls.begin();
+ for (SmallVector<Decl *, 16>::iterator DE = Decls.end(); DIt != DE; ++DIt) {
+ Decl *D = *DIt;
+ if (D->getSourceRange().isInvalid())
+ continue;
+
+ if (isInLexicalContext(D, CurDC))
+ continue;
+
+ CurDC = dyn_cast<DeclContext>(D);
+
+ if (TagDecl *TD = dyn_cast<TagDecl>(D))
+ if (!TD->isFreeStanding())
+ continue;
+
+ RangeComparisonResult CompRes = RangeCompare(SM, D->getSourceRange(),Range);
+ if (CompRes == RangeBefore)
+ continue;
+ if (CompRes == RangeAfter)
+ break;
+
+ assert(CompRes == RangeOverlap);
+ VisitedAtLeastOnce = true;
+
+ if (isa<ObjCContainerDecl>(D)) {
+ FileDI_current = &DIt;
+ FileDE_current = DE;
+ } else {
+ FileDI_current = 0;
+ }
+
+ if (Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true))
+ break;
+ }
+
+ if (VisitedAtLeastOnce)
+ return;
+
+ // No Decls overlapped with the range. Move up the lexical context until there
+ // is a context that contains the range or we reach the translation unit
+ // level.
+ DeclContext *DC = DIt == Decls.begin() ? (*DIt)->getLexicalDeclContext()
+ : (*(DIt-1))->getLexicalDeclContext();
+
+ while (DC && !DC->isTranslationUnit()) {
+ Decl *D = cast<Decl>(DC);
+ SourceRange CurDeclRange = D->getSourceRange();
+ if (CurDeclRange.isInvalid())
+ break;
+
+ if (RangeCompare(SM, CurDeclRange, Range) == RangeOverlap) {
+ Visit(MakeCXCursor(D, TU, Range), /*CheckedRegionOfInterest=*/true);
+ break;
+ }
+
+ DC = D->getLexicalDeclContext();
+ }
+}
+
bool CursorVisitor::visitPreprocessedEntitiesInRegion() {
+ if (!AU->getPreprocessor().getPreprocessingRecord())
+ return false;
+
PreprocessingRecord &PPRec
= *AU->getPreprocessor().getPreprocessingRecord();
+ SourceManager &SM = AU->getSourceManager();
if (RegionOfInterest.isValid()) {
SourceRange MappedRange = AU->mapRangeToPreamble(RegionOfInterest);
- std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator>
- Entities = PPRec.getPreprocessedEntitiesInRange(MappedRange);
- return visitPreprocessedEntities(Entities.first, Entities.second);
+ SourceLocation B = MappedRange.getBegin();
+ SourceLocation E = MappedRange.getEnd();
+
+ if (AU->isInPreambleFileID(B)) {
+ if (SM.isLoadedSourceLocation(E))
+ return visitPreprocessedEntitiesInRange(SourceRange(B, E),
+ PPRec, *this);
+
+ // Beginning of range lies in the preamble but it also extends beyond
+ // it into the main file. Split the range into 2 parts, one covering
+ // the preamble and another covering the main file. This allows subsequent
+ // calls to visitPreprocessedEntitiesInRange to accept a source range that
+ // lies in the same FileID, allowing it to skip preprocessed entities that
+ // do not come from the same FileID.
+ bool breaked =
+ visitPreprocessedEntitiesInRange(
+ SourceRange(B, AU->getEndOfPreambleFileID()),
+ PPRec, *this);
+ if (breaked) return true;
+ return visitPreprocessedEntitiesInRange(
+ SourceRange(AU->getStartOfMainFileID(), E),
+ PPRec, *this);
+ }
+
+ return visitPreprocessedEntitiesInRange(SourceRange(B, E), PPRec, *this);
}
bool OnlyLocalDecls
= !AU->isMainFileAST() && AU->getOnlyLocalDecls();
if (OnlyLocalDecls)
- return visitPreprocessedEntities(PPRec.local_begin(), PPRec.local_end());
+ return visitPreprocessedEntities(PPRec.local_begin(), PPRec.local_end(),
+ PPRec);
- return visitPreprocessedEntities(PPRec.begin(), PPRec.end());
+ return visitPreprocessedEntities(PPRec.begin(), PPRec.end(), PPRec);
}
template<typename InputIterator>
bool CursorVisitor::visitPreprocessedEntities(InputIterator First,
- InputIterator Last) {
+ InputIterator Last,
+ PreprocessingRecord &PPRec,
+ FileID FID) {
for (; First != Last; ++First) {
- if (MacroExpansion *ME = dyn_cast<MacroExpansion>(*First)) {
+ if (!FID.isInvalid() && !PPRec.isEntityInFileID(First, FID))
+ continue;
+
+ PreprocessedEntity *PPE = *First;
+ if (MacroExpansion *ME = dyn_cast<MacroExpansion>(PPE)) {
if (Visit(MakeMacroExpansionCursor(ME, TU)))
return true;
continue;
}
- if (MacroDefinition *MD = dyn_cast<MacroDefinition>(*First)) {
+ if (MacroDefinition *MD = dyn_cast<MacroDefinition>(PPE)) {
if (Visit(MakeMacroDefinitionCursor(MD, TU)))
return true;
continue;
}
- if (InclusionDirective *ID = dyn_cast<InclusionDirective>(*First)) {
+ if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) {
if (Visit(MakeInclusionDirectiveCursor(ID, TU)))
return true;
@@ -576,6 +563,20 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
if (D->getLexicalDeclContext() != DC)
continue;
CXCursor Cursor = MakeCXCursor(D, TU, RegionOfInterest);
+
+ // FIXME: ObjCClassRef/ObjCProtocolRef for forward class/protocol
+ // declarations is a mismatch with the compiler semantics.
+ if (Cursor.kind == CXCursor_ObjCInterfaceDecl) {
+ ObjCInterfaceDecl *ID = cast<ObjCInterfaceDecl>(D);
+ if (!ID->isThisDeclarationADefinition())
+ Cursor = MakeCursorObjCClassRef(ID, ID->getLocation(), TU);
+
+ } else if (Cursor.kind == CXCursor_ObjCProtocolDecl) {
+ ObjCProtocolDecl *PD = cast<ObjCProtocolDecl>(D);
+ if (!PD->isThisDeclarationADefinition())
+ Cursor = MakeCursorObjCProtocolRef(PD, PD->getLocation(), TU);
+ }
+
const llvm::Optional<bool> &V = shouldVisitCursor(Cursor);
if (!V.hasValue())
continue;
@@ -589,7 +590,6 @@ bool CursorVisitor::VisitDeclContext(DeclContext *DC) {
bool CursorVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
llvm_unreachable("Translation units are visited directly by Visit()");
- return false;
}
bool CursorVisitor::VisitTypeAliasDecl(TypeAliasDecl *D) {
@@ -761,8 +761,8 @@ bool CursorVisitor::VisitFunctionDecl(FunctionDecl *ND) {
if (Visit(MakeCursorMemberRef(Init->getAnyMember(),
Init->getMemberLocation(), TU)))
return true;
- } else if (TypeSourceInfo *BaseInfo = Init->getBaseClassInfo()) {
- if (Visit(BaseInfo->getTypeLoc()))
+ } else if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo()) {
+ if (Visit(TInfo->getTypeLoc()))
return true;
}
@@ -859,6 +859,27 @@ bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
return false;
}
+template <typename DeclIt>
+static void addRangedDeclsInContainer(DeclIt *DI_current, DeclIt DE_current,
+ SourceManager &SM, SourceLocation EndLoc,
+ SmallVectorImpl<Decl *> &Decls) {
+ DeclIt next = *DI_current;
+ while (++next != DE_current) {
+ Decl *D_next = *next;
+ if (!D_next)
+ break;
+ SourceLocation L = D_next->getLocStart();
+ if (!L.isValid())
+ break;
+ if (SM.isBeforeInTranslationUnit(L, EndLoc)) {
+ *DI_current = next;
+ Decls.push_back(D_next);
+ continue;
+ }
+ break;
+ }
+}
+
namespace {
struct ContainerDeclsSort {
SourceManager &SM;
@@ -877,7 +898,7 @@ bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
// an @implementation can lexically contain Decls that are not properly
// nested in the AST. When we identify such cases, we need to retrofit
// this nesting here.
- if (!DI_current)
+ if (!DI_current && !FileDI_current)
return VisitDeclContext(D);
// Scan the Decls that immediately come after the container
@@ -888,20 +909,12 @@ bool CursorVisitor::VisitObjCContainerDecl(ObjCContainerDecl *D) {
SourceLocation EndLoc = D->getSourceRange().getEnd();
SourceManager &SM = AU->getSourceManager();
if (EndLoc.isValid()) {
- DeclContext::decl_iterator next = *DI_current;
- while (++next != DE_current) {
- Decl *D_next = *next;
- if (!D_next)
- break;
- SourceLocation L = D_next->getLocStart();
- if (!L.isValid())
- break;
- if (SM.isBeforeInTranslationUnit(L, EndLoc)) {
- *DI_current = next;
- DeclsInContainer.push_back(D_next);
- continue;
- }
- break;
+ if (DI_current) {
+ addRangedDeclsInContainer(DI_current, DE_current, SM, EndLoc,
+ DeclsInContainer);
+ } else {
+ addRangedDeclsInContainer(FileDI_current, FileDE_current, SM, EndLoc,
+ DeclsInContainer);
}
}
@@ -954,6 +967,9 @@ bool CursorVisitor::VisitObjCCategoryDecl(ObjCCategoryDecl *ND) {
}
bool CursorVisitor::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
+ if (!PID->isThisDeclarationADefinition())
+ return Visit(MakeCursorObjCProtocolRef(PID, PID->getLocation(), TU));
+
ObjCProtocolDecl::protocol_loc_iterator PL = PID->protocol_loc_begin();
for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(),
E = PID->protocol_end(); I != E; ++I, ++PL)
@@ -1001,6 +1017,11 @@ bool CursorVisitor::VisitObjCPropertyDecl(ObjCPropertyDecl *PD) {
}
bool CursorVisitor::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ if (!D->isThisDeclarationADefinition()) {
+ // Forward declaration is treated like a reference.
+ return Visit(MakeCursorObjCClassRef(D, D->getLocation(), TU));
+ }
+
// Issue callbacks for super class.
if (D->getSuperClass() &&
Visit(MakeCursorObjCSuperClassRef(D->getSuperClass(),
@@ -1044,24 +1065,6 @@ bool CursorVisitor::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
return VisitObjCImplDecl(D);
}
-bool CursorVisitor::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
- ObjCForwardProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin();
- for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(),
- E = D->protocol_end();
- I != E; ++I, ++PL)
- if (Visit(MakeCursorObjCProtocolRef(*I, *PL, TU)))
- return true;
-
- return false;
-}
-
-bool CursorVisitor::VisitObjCClassDecl(ObjCClassDecl *D) {
- if (Visit(MakeCursorObjCClassRef(D->getForwardInterfaceDecl(),
- D->getForwardDecl()->getLocation(), TU)))
- return true;
- return false;
-}
-
bool CursorVisitor::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD) {
if (ObjCIvarDecl *Ivar = PD->getPropertyIvarDecl())
return Visit(MakeCursorMemberRef(Ivar, PD->getPropertyIvarDeclLoc(), TU));
@@ -1147,8 +1150,8 @@ bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) {
// FIXME: Per-identifier location info?
return false;
}
-
- return false;
+
+ llvm_unreachable("Invalid DeclarationName::Kind!");
}
bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS,
@@ -1286,8 +1289,8 @@ bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) {
Name.getAsSubstTemplateTemplateParmPack()->getParameterPack(),
Loc, TU));
}
-
- return false;
+
+ llvm_unreachable("Invalid TemplateName::Kind!");
}
bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
@@ -1320,8 +1323,8 @@ bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) {
return VisitTemplateName(TAL.getArgument().getAsTemplateOrTemplatePattern(),
TAL.getTemplateNameLoc());
}
-
- return false;
+
+ llvm_unreachable("Invalid TemplateArgument::Kind!");
}
bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
@@ -1338,36 +1341,17 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
// Some builtin types (such as Objective-C's "id", "sel", and
// "Class") have associated declarations. Create cursors for those.
QualType VisitType;
- switch (TL.getType()->getAs<BuiltinType>()->getKind()) {
+ switch (TL.getTypePtr()->getKind()) {
+
case BuiltinType::Void:
- case BuiltinType::Bool:
- case BuiltinType::Char_U:
- case BuiltinType::UChar:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- case BuiltinType::UShort:
- case BuiltinType::UInt:
- case BuiltinType::ULong:
- case BuiltinType::ULongLong:
- case BuiltinType::UInt128:
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- case BuiltinType::WChar_U:
- case BuiltinType::WChar_S:
- case BuiltinType::Short:
- case BuiltinType::Int:
- case BuiltinType::Long:
- case BuiltinType::LongLong:
- case BuiltinType::Int128:
- case BuiltinType::Half:
- case BuiltinType::Float:
- case BuiltinType::Double:
- case BuiltinType::LongDouble:
case BuiltinType::NullPtr:
- case BuiltinType::Overload:
- case BuiltinType::BoundMember:
case BuiltinType::Dependent:
- case BuiltinType::UnknownAny:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define SIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
+#define UNSIGNED_TYPE(Id, SingletonId) case BuiltinType::Id:
+#define FLOATING_TYPE(Id, SingletonId) case BuiltinType::Id:
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
break;
case BuiltinType::ObjCId:
@@ -1634,6 +1618,7 @@ DEF_JOB(OverloadExprParts, OverloadExpr, OverloadExprPartsKind)
DEF_JOB(ExplicitTemplateArgsVisit, ASTTemplateArgumentListInfo,
ExplicitTemplateArgsVisitKind)
DEF_JOB(SizeOfPackExprParts, SizeOfPackExpr, SizeOfPackExprPartsKind)
+DEF_JOB(LambdaExprParts, LambdaExpr, LambdaExprPartsKind)
#undef DEF_JOB
class DeclVisit : public VisitorJob {
@@ -1706,6 +1691,8 @@ public:
switch (S->getStmtClass()) {
default:
llvm_unreachable("Unhandled Stmt");
+ case clang::Stmt::MSDependentExistsStmtClass:
+ return cast<MSDependentExistsStmt>(S)->getNameInfo();
case Stmt::CXXDependentScopeMemberExprClass:
return cast<CXXDependentScopeMemberExpr>(S)->getMemberNameInfo();
case Stmt::DependentScopeDeclRefExprClass:
@@ -1740,6 +1727,7 @@ public:
void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
void VisitCompoundStmt(CompoundStmt *S);
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { /* Do nothing. */ }
+ void VisitMSDependentExistsStmt(MSDependentExistsStmt *S);
void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
void VisitCXXNewExpr(CXXNewExpr *E);
void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
@@ -1749,6 +1737,7 @@ public:
void VisitCXXTypeidExpr(CXXTypeidExpr *E);
void VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E);
void VisitCXXUuidofExpr(CXXUuidofExpr *E);
+ void VisitCXXCatchStmt(CXXCatchStmt *S);
void VisitDeclRefExpr(DeclRefExpr *D);
void VisitDeclStmt(DeclStmt *S);
void VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E);
@@ -1769,11 +1758,15 @@ public:
void VisitWhileStmt(WhileStmt *W);
void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
+ void VisitTypeTraitExpr(TypeTraitExpr *E);
void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E);
void VisitExpressionTraitExpr(ExpressionTraitExpr *E);
void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U);
void VisitVAArgExpr(VAArgExpr *E);
void VisitSizeOfPackExpr(SizeOfPackExpr *E);
+ void VisitPseudoObjectExpr(PseudoObjectExpr *E);
+ void VisitOpaqueValueExpr(OpaqueValueExpr *E);
+ void VisitLambdaExpr(LambdaExpr *E);
private:
void AddDeclarationNameInfo(Stmt *S);
@@ -1850,6 +1843,14 @@ void EnqueueVisitor::VisitCompoundStmt(CompoundStmt *S) {
}
}
void EnqueueVisitor::
+VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
+ AddStmt(S->getSubStmt());
+ AddDeclarationNameInfo(S);
+ if (NestedNameSpecifierLoc QualifierLoc = S->getQualifierLoc())
+ AddNestedNameSpecifierLoc(QualifierLoc);
+}
+
+void EnqueueVisitor::
VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
AddDeclarationNameInfo(E);
@@ -1859,9 +1860,8 @@ VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
AddStmt(E->getBase());
}
void EnqueueVisitor::VisitCXXNewExpr(CXXNewExpr *E) {
- // Enqueue the initializer or constructor arguments.
- for (unsigned I = E->getNumConstructorArgs(); I > 0; --I)
- AddStmt(E->getConstructorArg(I-1));
+ // Enqueue the initializer , if any.
+ AddStmt(E->getInitializer());
// Enqueue the array size, if any.
AddStmt(E->getArraySize());
// Enqueue the allocated type.
@@ -1911,6 +1911,12 @@ void EnqueueVisitor::VisitCXXUuidofExpr(CXXUuidofExpr *E) {
if (E->isTypeOperand())
AddTypeLoc(E->getTypeOperandSourceInfo());
}
+
+void EnqueueVisitor::VisitCXXCatchStmt(CXXCatchStmt *S) {
+ EnqueueChildren(S);
+ AddDecl(S->getExceptionDecl());
+}
+
void EnqueueVisitor::VisitDeclRefExpr(DeclRefExpr *DR) {
if (DR->hasExplicitTemplateArgs()) {
AddExplicitTemplateArgs(&DR->getExplicitTemplateArgs());
@@ -2054,6 +2060,11 @@ void EnqueueVisitor::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
AddTypeLoc(E->getLhsTypeSourceInfo());
}
+void EnqueueVisitor::VisitTypeTraitExpr(TypeTraitExpr *E) {
+ for (unsigned I = E->getNumArgs(); I > 0; --I)
+ AddTypeLoc(E->getArg(I-1));
+}
+
void EnqueueVisitor::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
AddTypeLoc(E->getQueriedTypeSourceInfo());
}
@@ -2074,6 +2085,20 @@ void EnqueueVisitor::VisitVAArgExpr(VAArgExpr *E) {
void EnqueueVisitor::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
WL.push_back(SizeOfPackExprParts(E, Parent));
}
+void EnqueueVisitor::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+ // If the opaque value has a source expression, just transparently
+ // visit that. This is useful for (e.g.) pseudo-object expressions.
+ if (Expr *SourceExpr = E->getSourceExpr())
+ return Visit(SourceExpr);
+}
+void EnqueueVisitor::VisitLambdaExpr(LambdaExpr *E) {
+ AddStmt(E->getBody());
+ WL.push_back(LambdaExprParts(E, Parent));
+}
+void EnqueueVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
+ // Treat the expression like its syntactic form.
+ Visit(E->getSyntacticForm());
+}
void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, Stmt *S) {
EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S);
@@ -2247,6 +2272,45 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
// treated like DeclRefExpr cursors.
continue;
}
+
+ case VisitorJob::LambdaExprPartsKind: {
+ // Visit captures.
+ LambdaExpr *E = cast<LambdaExprParts>(&LI)->get();
+ for (LambdaExpr::capture_iterator C = E->explicit_capture_begin(),
+ CEnd = E->explicit_capture_end();
+ C != CEnd; ++C) {
+ if (C->capturesThis())
+ continue;
+
+ if (Visit(MakeCursorVariableRef(C->getCapturedVar(),
+ C->getLocation(),
+ TU)))
+ return true;
+ }
+
+ // Visit parameters and return type, if present.
+ if (E->hasExplicitParameters() || E->hasExplicitResultType()) {
+ TypeLoc TL = E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+ if (E->hasExplicitParameters() && E->hasExplicitResultType()) {
+ // Visit the whole type.
+ if (Visit(TL))
+ return true;
+ } else if (isa<FunctionProtoTypeLoc>(TL)) {
+ FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL);
+ if (E->hasExplicitParameters()) {
+ // Visit parameters.
+ for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I)
+ if (Visit(MakeCXCursor(Proto.getArg(I), TU)))
+ return true;
+ } else {
+ // Visit result type.
+ if (Visit(Proto.getResultLoc()))
+ return true;
+ }
+ }
+ }
+ break;
+ }
}
}
return false;
@@ -2317,6 +2381,13 @@ RefNamePieces buildPieces(unsigned NameFlags, bool IsMemberRefExpr,
static llvm::sys::Mutex EnableMultithreadingMutex;
static bool EnabledMultithreading;
+static void fatal_error_handler(void *user_data, const std::string& reason) {
+ // Write the result out to stderr avoiding errs() because raw_ostreams can
+ // call report_fatal_error.
+ fprintf(stderr, "LIBCLANG FATAL ERROR: %s\n", reason.c_str());
+ ::abort();
+}
+
extern "C" {
CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
int displayDiagnostics) {
@@ -2332,6 +2403,7 @@ CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
{
llvm::sys::ScopedLock L(EnableMultithreadingMutex);
if (!EnabledMultithreading) {
+ llvm::install_fatal_error_handler(fatal_error_handler, 0);
llvm::llvm_start_multithreaded();
EnabledMultithreading = true;
}
@@ -2342,6 +2414,14 @@ CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
CIdxr->setOnlyLocalDecls();
if (displayDiagnostics)
CIdxr->setDisplayDiagnostics();
+
+ if (getenv("LIBCLANG_BGPRIO_INDEX"))
+ CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() |
+ CXGlobalOpt_ThreadBackgroundPriorityForIndexing);
+ if (getenv("LIBCLANG_BGPRIO_EDIT"))
+ CIdxr->setCXGlobalOptFlags(CIdxr->getCXGlobalOptFlags() |
+ CXGlobalOpt_ThreadBackgroundPriorityForEditing);
+
return CIdxr;
}
@@ -2350,6 +2430,17 @@ void clang_disposeIndex(CXIndex CIdx) {
delete static_cast<CIndexer *>(CIdx);
}
+void clang_CXIndex_setGlobalOptions(CXIndex CIdx, unsigned options) {
+ if (CIdx)
+ static_cast<CIndexer *>(CIdx)->setCXGlobalOptFlags(options);
+}
+
+unsigned clang_CXIndex_getGlobalOptions(CXIndex CIdx) {
+ if (CIdx)
+ return static_cast<CIndexer *>(CIdx)->getCXGlobalOptFlags();
+ return 0;
+}
+
void clang_toggleCrashRecovery(unsigned isEnabled) {
if (isEnabled)
llvm::CrashRecoveryContext::Enable();
@@ -2366,11 +2457,13 @@ CXTranslationUnit clang_createTranslationUnit(CXIndex CIdx,
FileSystemOptions FileSystemOpts;
FileSystemOpts.WorkingDir = CXXIdx->getWorkingDirectory();
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
ASTUnit *TU = ASTUnit::LoadFromASTFile(ast_filename, Diags, FileSystemOpts,
CXXIdx->getOnlyLocalDecls(),
- 0, 0, true);
- return MakeCXTranslationUnit(TU);
+ 0, 0,
+ /*CaptureDiagnostics=*/true,
+ /*AllowPCHWithCompilerErrors=*/true);
+ return MakeCXTranslationUnit(CXXIdx, TU);
}
unsigned clang_defaultEditingTranslationUnitOptions() {
@@ -2385,14 +2478,13 @@ clang_createTranslationUnitFromSourceFile(CXIndex CIdx,
const char * const *command_line_args,
unsigned num_unsaved_files,
struct CXUnsavedFile *unsaved_files) {
- unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord |
- CXTranslationUnit_NestedMacroExpansions;
+ unsigned Options = CXTranslationUnit_DetailedPreprocessingRecord;
return clang_parseTranslationUnit(CIdx, source_filename,
command_line_args, num_command_line_args,
unsaved_files, num_unsaved_files,
Options);
}
-
+
struct ParseTranslationUnitInfo {
CXIndex CIdx;
const char *source_filename;
@@ -2420,16 +2512,20 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
+ setThreadBackgroundPriority();
+
bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble;
// FIXME: Add a flag for modules.
TranslationUnitKind TUKind
= (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete;
bool CacheCodeCompetionResults
= options & CXTranslationUnit_CacheCompletionResults;
-
+ bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies;
+
// Configure the diagnostics.
DiagnosticOptions DiagOpts;
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
+ IntrusiveRefCntPtr<DiagnosticsEngine>
Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
command_line_args));
@@ -2438,7 +2534,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
DiagCleanup(Diags.getPtr());
- llvm::OwningPtr<std::vector<ASTUnit::RemappedFile> >
+ OwningPtr<std::vector<ASTUnit::RemappedFile> >
RemappedFiles(new std::vector<ASTUnit::RemappedFile>());
// Recover resources if we crash before exiting this function.
@@ -2453,7 +2549,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
Buffer));
}
- llvm::OwningPtr<std::vector<const char *> >
+ OwningPtr<std::vector<const char *> >
Args(new std::vector<const char*>());
// Recover resources if we crash before exiting this method.
@@ -2488,16 +2584,14 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
Args->push_back(source_filename);
// Do we need the detailed preprocessing record?
- bool NestedMacroExpansions = false;
if (options & CXTranslationUnit_DetailedPreprocessingRecord) {
Args->push_back("-Xclang");
Args->push_back("-detailed-preprocessing-record");
- NestedMacroExpansions
- = (options & CXTranslationUnit_NestedMacroExpansions);
}
unsigned NumErrors = Diags->getClient()->getNumErrors();
- llvm::OwningPtr<ASTUnit> Unit(
+ OwningPtr<ASTUnit> ErrUnit;
+ OwningPtr<ASTUnit> Unit(
ASTUnit::LoadFromCommandLine(Args->size() ? &(*Args)[0] : 0
/* vector::data() not portable */,
Args->size() ? (&(*Args)[0] + Args->size()) :0,
@@ -2511,30 +2605,17 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
PrecompilePreamble,
TUKind,
CacheCodeCompetionResults,
- NestedMacroExpansions));
+ /*AllowPCHWithCompilerErrors=*/true,
+ SkipFunctionBodies,
+ &ErrUnit));
if (NumErrors != Diags->getClient()->getNumErrors()) {
// Make sure to check that 'Unit' is non-NULL.
- if (CXXIdx->getDisplayDiagnostics() && Unit.get()) {
- for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
- DEnd = Unit->stored_diag_end();
- D != DEnd; ++D) {
- CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOptions());
- CXString Msg = clang_formatDiagnostic(&Diag,
- clang_defaultDiagnosticDisplayOptions());
- fprintf(stderr, "%s\n", clang_getCString(Msg));
- clang_disposeString(Msg);
- }
-#ifdef LLVM_ON_WIN32
- // On Windows, force a flush, since there may be multiple copies of
- // stderr and stdout in the file system, all with different buffers
- // but writing to the same device.
- fflush(stderr);
-#endif
- }
+ if (CXXIdx->getDisplayDiagnostics())
+ printDiagsToStderr(Unit ? Unit.get() : ErrUnit.get());
}
- PTUI->result = MakeCXTranslationUnit(Unit.take());
+ PTUI->result = MakeCXTranslationUnit(CXXIdx, Unit.take());
}
CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx,
const char *source_filename,
@@ -2580,16 +2661,67 @@ CXTranslationUnit clang_parseTranslationUnit(CXIndex CIdx,
unsigned clang_defaultSaveOptions(CXTranslationUnit TU) {
return CXSaveTranslationUnit_None;
}
-
+
+namespace {
+
+struct SaveTranslationUnitInfo {
+ CXTranslationUnit TU;
+ const char *FileName;
+ unsigned options;
+ CXSaveError result;
+};
+
+}
+
+static void clang_saveTranslationUnit_Impl(void *UserData) {
+ SaveTranslationUnitInfo *STUI =
+ static_cast<SaveTranslationUnitInfo*>(UserData);
+
+ CIndexer *CXXIdx = (CIndexer*)STUI->TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
+ setThreadBackgroundPriority();
+
+ STUI->result = static_cast<ASTUnit *>(STUI->TU->TUData)->Save(STUI->FileName);
+}
+
int clang_saveTranslationUnit(CXTranslationUnit TU, const char *FileName,
unsigned options) {
if (!TU)
return CXSaveError_InvalidTU;
-
- CXSaveError result = static_cast<ASTUnit *>(TU->TUData)->Save(FileName);
- if (getenv("LIBCLANG_RESOURCE_USAGE"))
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ SaveTranslationUnitInfo STUI = { TU, FileName, options, CXSaveError_None };
+
+ if (!CXXUnit->getDiagnostics().hasUnrecoverableErrorOccurred() ||
+ getenv("LIBCLANG_NOTHREADS")) {
+ clang_saveTranslationUnit_Impl(&STUI);
+
+ if (getenv("LIBCLANG_RESOURCE_USAGE"))
+ PrintLibclangResourceUsage(TU);
+
+ return STUI.result;
+ }
+
+ // We have an AST that has invalid nodes due to compiler errors.
+ // Use a crash recovery thread for protection.
+
+ llvm::CrashRecoveryContext CRC;
+
+ if (!RunSafely(CRC, clang_saveTranslationUnit_Impl, &STUI)) {
+ fprintf(stderr, "libclang: crash detected during AST saving: {\n");
+ fprintf(stderr, " 'filename' : '%s'\n", FileName);
+ fprintf(stderr, " 'options' : %d,\n", options);
+ fprintf(stderr, "}\n");
+
+ return CXSaveError_Unknown;
+
+ } else if (getenv("LIBCLANG_RESOURCE_USAGE")) {
PrintLibclangResourceUsage(TU);
- return result;
+ }
+
+ return STUI.result;
}
void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
@@ -2601,6 +2733,7 @@ void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
delete static_cast<ASTUnit *>(CTUnit->TUData);
disposeCXStringPool(CTUnit->StringPool);
+ delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics);
delete CTUnit;
}
}
@@ -2621,6 +2754,11 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) {
ReparseTranslationUnitInfo *RTUI =
static_cast<ReparseTranslationUnitInfo*>(UserData);
CXTranslationUnit TU = RTUI->TU;
+
+ // Reset the associated diagnostics.
+ delete static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
+ TU->Diagnostics = 0;
+
unsigned num_unsaved_files = RTUI->num_unsaved_files;
struct CXUnsavedFile *unsaved_files = RTUI->unsaved_files;
unsigned options = RTUI->options;
@@ -2630,10 +2768,14 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) {
if (!TU)
return;
+ CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing))
+ setThreadBackgroundPriority();
+
ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU->TUData);
ASTUnit::ConcurrencyCheck Check(*CXXUnit);
- llvm::OwningPtr<std::vector<ASTUnit::RemappedFile> >
+ OwningPtr<std::vector<ASTUnit::RemappedFile> >
RemappedFiles(new std::vector<ASTUnit::RemappedFile>());
// Recover resources if we crash before exiting this function.
@@ -2659,6 +2801,12 @@ int clang_reparseTranslationUnit(CXTranslationUnit TU,
unsigned options) {
ReparseTranslationUnitInfo RTUI = { TU, num_unsaved_files, unsaved_files,
options, 0 };
+
+ if (getenv("LIBCLANG_NOTHREADS")) {
+ clang_reparseTranslationUnit_Impl(&RTUI);
+ return RTUI.result;
+ }
+
llvm::CrashRecoveryContext CRC;
if (!RunSafely(CRC, clang_reparseTranslationUnit_Impl, &RTUI)) {
@@ -2688,232 +2836,6 @@ CXCursor clang_getTranslationUnitCursor(CXTranslationUnit TU) {
} // end: extern "C"
//===----------------------------------------------------------------------===//
-// CXSourceLocation and CXSourceRange Operations.
-//===----------------------------------------------------------------------===//
-
-extern "C" {
-CXSourceLocation clang_getNullLocation() {
- CXSourceLocation Result = { { 0, 0 }, 0 };
- return Result;
-}
-
-unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
- return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
- loc1.ptr_data[1] == loc2.ptr_data[1] &&
- loc1.int_data == loc2.int_data);
-}
-
-CXSourceLocation clang_getLocation(CXTranslationUnit tu,
- CXFile file,
- unsigned line,
- unsigned column) {
- if (!tu || !file)
- return clang_getNullLocation();
-
- bool Logging = ::getenv("LIBCLANG_LOGGING");
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
- ASTUnit::ConcurrencyCheck Check(*CXXUnit);
- const FileEntry *File = static_cast<const FileEntry *>(file);
- SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
- if (SLoc.isInvalid()) {
- if (Logging)
- llvm::errs() << "clang_getLocation(\"" << File->getName()
- << "\", " << line << ", " << column << ") = invalid\n";
- return clang_getNullLocation();
- }
-
- if (Logging)
- llvm::errs() << "clang_getLocation(\"" << File->getName()
- << "\", " << line << ", " << column << ") = "
- << SLoc.getRawEncoding() << "\n";
-
- return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
-}
-
-CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
- CXFile file,
- unsigned offset) {
- if (!tu || !file)
- return clang_getNullLocation();
-
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
- SourceLocation SLoc
- = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
- if (SLoc.isInvalid()) return clang_getNullLocation();
-
- return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
-}
-
-CXSourceRange clang_getNullRange() {
- CXSourceRange Result = { { 0, 0 }, 0, 0 };
- return Result;
-}
-
-CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
- if (begin.ptr_data[0] != end.ptr_data[0] ||
- begin.ptr_data[1] != end.ptr_data[1])
- return clang_getNullRange();
-
- CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
- begin.int_data, end.int_data };
- return Result;
-}
-
-unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2)
-{
- return range1.ptr_data[0] == range2.ptr_data[0]
- && range1.ptr_data[1] == range2.ptr_data[1]
- && range1.begin_int_data == range2.begin_int_data
- && range1.end_int_data == range2.end_int_data;
-}
-
-int clang_Range_isNull(CXSourceRange range) {
- return clang_equalRanges(range, clang_getNullRange());
-}
-
-} // end: extern "C"
-
-static void createNullLocation(CXFile *file, unsigned *line,
- unsigned *column, unsigned *offset) {
- if (file)
- *file = 0;
- if (line)
- *line = 0;
- if (column)
- *column = 0;
- if (offset)
- *offset = 0;
- return;
-}
-
-extern "C" {
-void clang_getExpansionLocation(CXSourceLocation location,
- CXFile *file,
- unsigned *line,
- unsigned *column,
- unsigned *offset) {
- SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
-
- if (!location.ptr_data[0] || Loc.isInvalid()) {
- createNullLocation(file, line, column, offset);
- return;
- }
-
- const SourceManager &SM =
- *static_cast<const SourceManager*>(location.ptr_data[0]);
- SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
-
- // Check that the FileID is invalid on the expansion location.
- // This can manifest in invalid code.
- FileID fileID = SM.getFileID(ExpansionLoc);
- bool Invalid = false;
- const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
- if (!sloc.isFile() || Invalid) {
- createNullLocation(file, line, column, offset);
- return;
- }
-
- if (file)
- *file = (void *)SM.getFileEntryForSLocEntry(sloc);
- if (line)
- *line = SM.getExpansionLineNumber(ExpansionLoc);
- if (column)
- *column = SM.getExpansionColumnNumber(ExpansionLoc);
- if (offset)
- *offset = SM.getDecomposedLoc(ExpansionLoc).second;
-}
-
-void clang_getPresumedLocation(CXSourceLocation location,
- CXString *filename,
- unsigned *line,
- unsigned *column) {
- SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
-
- if (!location.ptr_data[0] || Loc.isInvalid()) {
- if (filename)
- *filename = createCXString("");
- if (line)
- *line = 0;
- if (column)
- *column = 0;
- }
- else {
- const SourceManager &SM =
- *static_cast<const SourceManager*>(location.ptr_data[0]);
- PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
-
- if (filename)
- *filename = createCXString(PreLoc.getFilename());
- if (line)
- *line = PreLoc.getLine();
- if (column)
- *column = PreLoc.getColumn();
- }
-}
-
-void clang_getInstantiationLocation(CXSourceLocation location,
- CXFile *file,
- unsigned *line,
- unsigned *column,
- unsigned *offset) {
- // Redirect to new API.
- clang_getExpansionLocation(location, file, line, column, offset);
-}
-
-void clang_getSpellingLocation(CXSourceLocation location,
- CXFile *file,
- unsigned *line,
- unsigned *column,
- unsigned *offset) {
- SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
-
- if (!location.ptr_data[0] || Loc.isInvalid())
- return createNullLocation(file, line, column, offset);
-
- const SourceManager &SM =
- *static_cast<const SourceManager*>(location.ptr_data[0]);
- SourceLocation SpellLoc = Loc;
- if (SpellLoc.isMacroID()) {
- SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
- if (SimpleSpellingLoc.isFileID() &&
- SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
- SpellLoc = SimpleSpellingLoc;
- else
- SpellLoc = SM.getExpansionLoc(SpellLoc);
- }
-
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
- FileID FID = LocInfo.first;
- unsigned FileOffset = LocInfo.second;
-
- if (FID.isInvalid())
- return createNullLocation(file, line, column, offset);
-
- if (file)
- *file = (void *)SM.getFileEntryForID(FID);
- if (line)
- *line = SM.getLineNumber(FID, FileOffset);
- if (column)
- *column = SM.getColumnNumber(FID, FileOffset);
- if (offset)
- *offset = FileOffset;
-}
-
-CXSourceLocation clang_getRangeStart(CXSourceRange range) {
- CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
- range.begin_int_data };
- return Result;
-}
-
-CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
- CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
- range.end_int_data };
- return Result;
-}
-
-} // end: extern "C"
-
-//===----------------------------------------------------------------------===//
// CXFile Operations.
//===----------------------------------------------------------------------===//
@@ -2966,14 +2888,26 @@ static Decl *getDeclFromExpr(Stmt *E) {
if (DeclRefExpr *RefExpr = dyn_cast<DeclRefExpr>(E))
return RefExpr->getDecl();
- if (BlockDeclRefExpr *RefExpr = dyn_cast<BlockDeclRefExpr>(E))
- return RefExpr->getDecl();
if (MemberExpr *ME = dyn_cast<MemberExpr>(E))
return ME->getMemberDecl();
if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(E))
return RE->getDecl();
- if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E))
- return PRE->isExplicitProperty() ? PRE->getExplicitProperty() : 0;
+ if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ if (PRE->isExplicitProperty())
+ return PRE->getExplicitProperty();
+ // It could be messaging both getter and setter as in:
+ // ++myobj.myprop;
+ // in which case prefer to associate the setter since it is less obvious
+ // from inspecting the source that the setter is going to get called.
+ if (PRE->isMessagingSetter())
+ return PRE->getImplicitPropertySetter();
+ return PRE->getImplicitPropertyGetter();
+ }
+ if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E))
+ return getDeclFromExpr(POE->getSyntacticForm());
+ if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+ if (Expr *Src = OVE->getSourceExpr())
+ return getDeclFromExpr(Src);
if (CallExpr *CE = dyn_cast<CallExpr>(E))
return getDeclFromExpr(CE->getCallee());
@@ -3004,14 +2938,14 @@ static SourceLocation getLocationFromExpr(Expr *E) {
return /*FIXME:*/Msg->getLeftLoc();
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
return DRE->getLocation();
- if (BlockDeclRefExpr *RefExpr = dyn_cast<BlockDeclRefExpr>(E))
- return RefExpr->getLocation();
if (MemberExpr *Member = dyn_cast<MemberExpr>(E))
return Member->getMemberLoc();
if (ObjCIvarRefExpr *Ivar = dyn_cast<ObjCIvarRefExpr>(E))
return Ivar->getLocation();
if (SizeOfPackExpr *SizeOfPack = dyn_cast<SizeOfPackExpr>(E))
return SizeOfPack->getPackLoc();
+ if (ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E))
+ return PropRef->getLocation();
return E->getLocStart();
}
@@ -3021,8 +2955,8 @@ extern "C" {
unsigned clang_visitChildren(CXCursor parent,
CXCursorVisitor visitor,
CXClientData client_data) {
- CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data,
- false);
+ CursorVisitor CursorVis(getCursorTU(parent), visitor, client_data,
+ /*VisitPreprocessorLast=*/false);
return CursorVis.VisitChildren(parent);
}
@@ -3064,7 +2998,10 @@ unsigned clang_visitChildrenWithBlock(CXCursor parent,
}
static CXString getDeclSpelling(Decl *D) {
- NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D);
+ if (!D)
+ return createCXString("");
+
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
if (!ND) {
if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D))
if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
@@ -3085,7 +3022,7 @@ static CXString getDeclSpelling(Decl *D) {
if (isa<UsingDirectiveDecl>(D))
return createCXString("");
- llvm::SmallString<1024> S;
+ SmallString<1024> S;
llvm::raw_svector_ostream os(S);
ND->printName(os);
@@ -3167,6 +3104,13 @@ CXString clang_getCursorSpelling(CXCursor C) {
return createCXString((*Ovl->begin())->getNameAsString());
}
+ case CXCursor_VariableRef: {
+ VarDecl *Var = getCursorVariableRef(C).first;
+ assert(Var && "Missing variable decl");
+
+ return createCXString(Var->getNameAsString());
+ }
+
default:
return createCXString("<not implemented>");
}
@@ -3206,9 +3150,71 @@ CXString clang_getCursorSpelling(CXCursor C) {
return createCXString(AA->getAnnotation());
}
+ if (C.kind == CXCursor_AsmLabelAttr) {
+ AsmLabelAttr *AA = cast<AsmLabelAttr>(cxcursor::getCursorAttr(C));
+ return createCXString(AA->getLabel());
+ }
+
return createCXString("");
}
+CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor C,
+ unsigned pieceIndex,
+ unsigned options) {
+ if (clang_Cursor_isNull(C))
+ return clang_getNullRange();
+
+ ASTContext &Ctx = getCursorContext(C);
+
+ if (clang_isStatement(C.kind)) {
+ Stmt *S = getCursorStmt(C);
+ if (LabelStmt *Label = dyn_cast_or_null<LabelStmt>(S)) {
+ if (pieceIndex > 0)
+ return clang_getNullRange();
+ return cxloc::translateSourceRange(Ctx, Label->getIdentLoc());
+ }
+
+ return clang_getNullRange();
+ }
+
+ if (C.kind == CXCursor_ObjCMessageExpr) {
+ if (ObjCMessageExpr *
+ ME = dyn_cast_or_null<ObjCMessageExpr>(getCursorExpr(C))) {
+ if (pieceIndex >= ME->getNumSelectorLocs())
+ return clang_getNullRange();
+ return cxloc::translateSourceRange(Ctx, ME->getSelectorLoc(pieceIndex));
+ }
+ }
+
+ if (C.kind == CXCursor_ObjCInstanceMethodDecl ||
+ C.kind == CXCursor_ObjCClassMethodDecl) {
+ if (ObjCMethodDecl *
+ MD = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(C))) {
+ if (pieceIndex >= MD->getNumSelectorLocs())
+ return clang_getNullRange();
+ return cxloc::translateSourceRange(Ctx, MD->getSelectorLoc(pieceIndex));
+ }
+ }
+
+ // FIXME: A CXCursor_InclusionDirective should give the location of the
+ // filename, but we don't keep track of this.
+
+ // FIXME: A CXCursor_AnnotateAttr should give the location of the annotation
+ // but we don't keep track of this.
+
+ // FIXME: A CXCursor_AsmLabelAttr should give the location of the label
+ // but we don't keep track of this.
+
+ // Default handling, give the location of the cursor.
+
+ if (pieceIndex > 0)
+ return clang_getNullRange();
+
+ CXSourceLocation CXLoc = clang_getCursorLocation(C);
+ SourceLocation Loc = cxloc::translateSourceLocation(CXLoc);
+ return cxloc::translateSourceRange(Ctx, Loc);
+}
+
CXString clang_getCursorDisplayName(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return clang_getCursorSpelling(C);
@@ -3222,9 +3228,9 @@ CXString clang_getCursorDisplayName(CXCursor C) {
D = FunTmpl->getTemplatedDecl();
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- llvm::SmallString<64> Str;
+ SmallString<64> Str;
llvm::raw_svector_ostream OS(Str);
- OS << Function->getNameAsString();
+ OS << *Function;
if (Function->getPrimaryTemplate())
OS << "<>";
OS << "(";
@@ -3244,9 +3250,9 @@ CXString clang_getCursorDisplayName(CXCursor C) {
}
if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(D)) {
- llvm::SmallString<64> Str;
+ SmallString<64> Str;
llvm::raw_svector_ostream OS(Str);
- OS << ClassTemplate->getNameAsString();
+ OS << *ClassTemplate;
OS << "<";
TemplateParameterList *Params = ClassTemplate->getTemplateParameters();
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
@@ -3280,9 +3286,9 @@ CXString clang_getCursorDisplayName(CXCursor C) {
if (TypeSourceInfo *TSInfo = ClassSpec->getTypeAsWritten())
return createCXString(TSInfo->getType().getAsString(Policy));
- llvm::SmallString<64> Str;
+ SmallString<64> Str;
llvm::raw_svector_ostream OS(Str);
- OS << ClassSpec->getNameAsString();
+ OS << *ClassSpec;
OS << TemplateSpecializationType::PrintTemplateArgumentList(
ClassSpec->getTemplateArgs().data(),
ClassSpec->getTemplateArgs().size(),
@@ -3355,6 +3361,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("LabelRef");
case CXCursor_OverloadedDeclRef:
return createCXString("OverloadedDeclRef");
+ case CXCursor_VariableRef:
+ return createCXString("VariableRef");
case CXCursor_IntegerLiteral:
return createCXString("IntegerLiteral");
case CXCursor_FloatingLiteral:
@@ -3419,6 +3427,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("UnaryExpr");
case CXCursor_ObjCStringLiteral:
return createCXString("ObjCStringLiteral");
+ case CXCursor_ObjCBoolLiteralExpr:
+ return createCXString("ObjCBoolLiteralExpr");
case CXCursor_ObjCEncodeExpr:
return createCXString("ObjCEncodeExpr");
case CXCursor_ObjCSelectorExpr:
@@ -3433,6 +3443,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("PackExpansionExpr");
case CXCursor_SizeOfPackExpr:
return createCXString("SizeOfPackExpr");
+ case CXCursor_LambdaExpr:
+ return createCXString("LambdaExpr");
case CXCursor_UnexposedExpr:
return createCXString("UnexposedExpr");
case CXCursor_DeclRefExpr:
@@ -3529,6 +3541,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("attribute(override)");
case CXCursor_AnnotateAttr:
return createCXString("attribute(annotate)");
+ case CXCursor_AsmLabelAttr:
+ return createCXString("asm label");
case CXCursor_PreprocessingDirective:
return createCXString("preprocessing directive");
case CXCursor_MacroDefinition:
@@ -3578,7 +3592,6 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
}
llvm_unreachable("Unhandled CXCursorKind");
- return createCXString((const char*) 0);
}
struct GetCursorData {
@@ -3607,23 +3620,23 @@ static enum CXChildVisitResult GetCursorVisitor(CXCursor cursor,
if (clang_isDeclaration(cursor.kind)) {
// Avoid having the implicit methods override the property decls.
- if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(getCursorDecl(cursor)))
+ if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(getCursorDecl(cursor)))
if (MD->isImplicit())
return CXChildVisit_Break;
}
if (clang_isExpression(cursor.kind) &&
clang_isDeclaration(BestCursor->kind)) {
- Decl *D = getCursorDecl(*BestCursor);
-
- // Avoid having the cursor of an expression replace the declaration cursor
- // when the expression source range overlaps the declaration range.
- // This can happen for C++ constructor expressions whose range generally
- // include the variable declaration, e.g.:
- // MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl cursor.
- if (D->getLocation().isValid() && Data->TokenBeginLoc.isValid() &&
- D->getLocation() == Data->TokenBeginLoc)
- return CXChildVisit_Break;
+ if (Decl *D = getCursorDecl(*BestCursor)) {
+ // Avoid having the cursor of an expression replace the declaration cursor
+ // when the expression source range overlaps the declaration range.
+ // This can happen for C++ constructor expressions whose range generally
+ // include the variable declaration, e.g.:
+ // MyCXXClass foo; // Make sure pointing at 'foo' returns a VarDecl cursor.
+ if (D->getLocation().isValid() && Data->TokenBeginLoc.isValid() &&
+ D->getLocation() == Data->TokenBeginLoc)
+ return CXChildVisit_Break;
+ }
}
// If our current best cursor is the construction of a temporary object,
@@ -3807,6 +3820,11 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
}
+ case CXCursor_VariableRef: {
+ std::pair<VarDecl *, SourceLocation> P = getCursorVariableRef(C);
+ return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
+ }
+
case CXCursor_CXXBaseSpecifier: {
CXXBaseSpecifier *BaseSpec = getCursorCXXBaseSpecifier(C);
if (!BaseSpec)
@@ -3817,7 +3835,7 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
TSInfo->getTypeLoc().getBeginLoc());
return cxloc::translateSourceLocation(getCursorContext(C),
- BaseSpec->getSourceRange().getBegin());
+ BaseSpec->getLocStart());
}
case CXCursor_LabelRef: {
@@ -3869,6 +3887,9 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return clang_getNullLocation();
Decl *D = getCursorDecl(C);
+ if (!D)
+ return clang_getNullLocation();
+
SourceLocation Loc = D->getLocation();
// FIXME: Multiple variables declared in a single declaration
// currently lack the information needed to correctly determine their
@@ -3880,6 +3901,10 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
Loc = VD->getLocation();
}
+ // For ObjC methods, give the start location of the method name.
+ if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ Loc = MD->getSelectorStartLoc();
+
return cxloc::translateSourceLocation(getCursorContext(C), Loc);
}
@@ -3898,19 +3923,16 @@ CXCursor cxcursor::getCursor(CXTranslationUnit TU, SourceLocation SLoc) {
// Translate the given source location to make it point at the beginning of
// the token under the cursor.
SLoc = Lexer::GetBeginningOfToken(SLoc, CXXUnit->getSourceManager(),
- CXXUnit->getASTContext().getLangOptions());
+ CXXUnit->getASTContext().getLangOpts());
CXCursor Result = MakeCXCursorInvalid(CXCursor_NoDeclFound);
if (SLoc.isValid()) {
- // FIXME: Would be great to have a "hint" cursor, then walk from that
- // hint cursor upward until we find a cursor whose source range encloses
- // the region of interest, rather than starting from the translation unit.
GetCursorData ResultData(CXXUnit->getSourceManager(), SLoc, Result);
- CXCursor Parent = clang_getTranslationUnitCursor(TU);
CursorVisitor CursorVis(TU, GetCursorVisitor, &ResultData,
/*VisitPreprocessorLast=*/true,
+ /*VisitIncludedEntities=*/false,
SourceLocation(SLoc));
- CursorVis.VisitChildren(Parent);
+ CursorVis.visitFileRegion();
}
return Result;
@@ -3949,6 +3971,9 @@ static SourceRange getRawCursorExtent(CXCursor C) {
case CXCursor_OverloadedDeclRef:
return getCursorOverloadedDeclRef(C).second;
+ case CXCursor_VariableRef:
+ return getCursorVariableRef(C).second;
+
default:
// FIXME: Need a way to enumerate all non-reference cases.
llvm_unreachable("Missed a reference kind");
@@ -3985,8 +4010,19 @@ static SourceRange getRawCursorExtent(CXCursor C) {
return TU->mapRangeFromPreamble(Range);
}
+ if (C.kind == CXCursor_TranslationUnit) {
+ ASTUnit *TU = getCursorASTUnit(C);
+ FileID MainID = TU->getSourceManager().getMainFileID();
+ SourceLocation Start = TU->getSourceManager().getLocForStartOfFile(MainID);
+ SourceLocation End = TU->getSourceManager().getLocForEndOfFile(MainID);
+ return SourceRange(Start, End);
+ }
+
if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) {
Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return SourceRange();
+
SourceRange R = D->getSourceRange();
// FIXME: Multiple variables declared in a single declaration
// currently lack the information needed to correctly determine their
@@ -4007,6 +4043,9 @@ static SourceRange getRawCursorExtent(CXCursor C) {
static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
if (C.kind >= CXCursor_FirstDecl && C.kind <= CXCursor_LastDecl) {
Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return SourceRange();
+
SourceRange R = D->getSourceRange();
// Adjust the start of the location for declarations preceded by
@@ -4014,10 +4053,10 @@ static SourceRange getFullCursorExtent(CXCursor C, SourceManager &SrcMgr) {
SourceLocation StartLoc;
if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
if (TypeSourceInfo *TI = DD->getTypeSourceInfo())
- StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
+ StartLoc = TI->getTypeLoc().getLocStart();
} else if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) {
if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo())
- StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
+ StartLoc = TI->getTypeLoc().getLocStart();
}
if (StartLoc.isValid() && R.getBegin().isValid() &&
@@ -4057,13 +4096,10 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
CXTranslationUnit tu = getCursorTU(C);
if (clang_isDeclaration(C.kind)) {
Decl *D = getCursorDecl(C);
+ if (!D)
+ return clang_getNullCursor();
if (UsingDecl *Using = dyn_cast<UsingDecl>(D))
return MakeCursorOverloadedDeclRef(Using, D->getLocation(), tu);
- if (ObjCClassDecl *Classes = dyn_cast<ObjCClassDecl>(D))
- return MakeCursorOverloadedDeclRef(Classes, D->getLocation(), tu);
- if (ObjCForwardProtocolDecl *Protocols
- = dyn_cast<ObjCForwardProtocolDecl>(D))
- return MakeCursorOverloadedDeclRef(Protocols, D->getLocation(), tu);
if (ObjCPropertyImplDecl *PropImpl =dyn_cast<ObjCPropertyImplDecl>(D))
if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl())
return MakeCXCursor(Property, tu);
@@ -4110,10 +4146,20 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
return MakeCXCursor(getCursorObjCSuperClassRef(C).first, tu);
case CXCursor_ObjCProtocolRef: {
- return MakeCXCursor(getCursorObjCProtocolRef(C).first, tu);
+ ObjCProtocolDecl *Prot = getCursorObjCProtocolRef(C).first;
+ if (ObjCProtocolDecl *Def = Prot->getDefinition())
+ return MakeCXCursor(Def, tu);
- case CXCursor_ObjCClassRef:
- return MakeCXCursor(getCursorObjCClassRef(C).first, tu );
+ return MakeCXCursor(Prot, tu);
+ }
+
+ case CXCursor_ObjCClassRef: {
+ ObjCInterfaceDecl *Class = getCursorObjCClassRef(C).first;
+ if (ObjCInterfaceDecl *Def = Class->getDefinition())
+ return MakeCXCursor(Def, tu);
+
+ return MakeCXCursor(Class, tu);
+ }
case CXCursor_TypeRef:
return MakeCXCursor(getCursorTypeRef(C).first, tu );
@@ -4143,15 +4189,14 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
case CXCursor_OverloadedDeclRef:
return C;
+
+ case CXCursor_VariableRef:
+ return MakeCXCursor(getCursorVariableRef(C).first, tu);
default:
// We would prefer to enumerate all non-reference cursor kinds here.
llvm_unreachable("Unhandled reference cursor kind");
- break;
- }
}
-
- return clang_getNullCursor();
}
CXCursor clang_getCursorDefinition(CXCursor C) {
@@ -4203,6 +4248,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Block:
case Decl::Label: // FIXME: Is this right??
case Decl::ClassScopeFunctionSpecialization:
+ case Decl::Import:
return C;
// Declaration kinds that don't make any sense here, but are
@@ -4299,23 +4345,24 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
return clang_getNullCursor();
case Decl::ObjCProtocol:
- if (!cast<ObjCProtocolDecl>(D)->isForwardDecl())
- return C;
+ if (ObjCProtocolDecl *Def = cast<ObjCProtocolDecl>(D)->getDefinition())
+ return MakeCXCursor(Def, TU);
return clang_getNullCursor();
- case Decl::ObjCInterface:
+ case Decl::ObjCInterface: {
// There are two notions of a "definition" for an Objective-C
// class: the interface and its implementation. When we resolved a
// reference to an Objective-C class, produce the @interface as
// the definition; when we were provided with the interface,
// produce the @implementation as the definition.
+ ObjCInterfaceDecl *IFace = cast<ObjCInterfaceDecl>(D);
if (WasReference) {
- if (!cast<ObjCInterfaceDecl>(D)->isForwardDecl())
- return C;
- } else if (ObjCImplementationDecl *Impl
- = cast<ObjCInterfaceDecl>(D)->getImplementation())
+ if (ObjCInterfaceDecl *Def = IFace->getDefinition())
+ return MakeCXCursor(Def, TU);
+ } else if (ObjCImplementationDecl *Impl = IFace->getImplementation())
return MakeCXCursor(Impl, TU);
return clang_getNullCursor();
+ }
case Decl::ObjCProperty:
// FIXME: We don't really know where to find the
@@ -4325,19 +4372,11 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::ObjCCompatibleAlias:
if (ObjCInterfaceDecl *Class
= cast<ObjCCompatibleAliasDecl>(D)->getClassInterface())
- if (!Class->isForwardDecl())
- return MakeCXCursor(Class, TU);
+ if (ObjCInterfaceDecl *Def = Class->getDefinition())
+ return MakeCXCursor(Def, TU);
return clang_getNullCursor();
- case Decl::ObjCForwardProtocol:
- return MakeCursorOverloadedDeclRef(cast<ObjCForwardProtocolDecl>(D),
- D->getLocation(), TU);
-
- case Decl::ObjCClass:
- return MakeCursorOverloadedDeclRef(cast<ObjCClassDecl>(D), D->getLocation(),
- TU);
-
case Decl::Friend:
if (NamedDecl *Friend = cast<FriendDecl>(D)->getFriendDecl())
return clang_getCursorDefinition(MakeCXCursor(Friend, TU));
@@ -4377,6 +4416,10 @@ CXCursor clang_getCanonicalCursor(CXCursor C) {
return C;
}
+
+int clang_Cursor_getObjCSelectorIndex(CXCursor cursor) {
+ return cxcursor::getSelectorIdentifierIndexAndLoc(cursor).first;
+}
unsigned clang_getNumOverloadedDecls(CXCursor C) {
if (C.kind != CXCursor_OverloadedDeclRef)
@@ -4393,10 +4436,6 @@ unsigned clang_getNumOverloadedDecls(CXCursor C) {
Decl *D = Storage.get<Decl*>();
if (UsingDecl *Using = dyn_cast<UsingDecl>(D))
return Using->shadow_size();
- if (isa<ObjCClassDecl>(D))
- return 1;
- if (ObjCForwardProtocolDecl *Protocols =dyn_cast<ObjCForwardProtocolDecl>(D))
- return Protocols->protocol_size();
return 0;
}
@@ -4424,10 +4463,6 @@ CXCursor clang_getOverloadedDecl(CXCursor cursor, unsigned index) {
std::advance(Pos, index);
return MakeCXCursor(cast<UsingShadowDecl>(*Pos)->getTargetDecl(), TU);
}
- if (ObjCClassDecl *Classes = dyn_cast<ObjCClassDecl>(D))
- return MakeCXCursor(Classes->getForwardInterfaceDecl(), TU);
- if (ObjCForwardProtocolDecl *Protocols = dyn_cast<ObjCForwardProtocolDecl>(D))
- return MakeCXCursor(Protocols->protocol_begin()[index], TU);
return clang_getNullCursor();
}
@@ -4469,7 +4504,7 @@ CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, unsigned NameFlags,
if (DeclRefExpr *E = dyn_cast<DeclRefExpr>(getCursorExpr(C)))
Pieces = buildPieces(NameFlags, false, E->getNameInfo(),
E->getQualifierLoc().getSourceRange(),
- E->getExplicitTemplateArgsOpt());
+ E->getOptionalExplicitTemplateArgs());
break;
case CXCursor_CallExpr:
@@ -4605,7 +4640,7 @@ static void getTokens(ASTUnit *CXXUnit, SourceRange Range,
return;
Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
- CXXUnit->getASTContext().getLangOptions(),
+ CXXUnit->getASTContext().getLangOpts(),
Buffer.begin(), Buffer.data() + BeginLocInfo.second, Buffer.end());
Lex.SetCommentRetentionState(true);
@@ -4736,16 +4771,16 @@ public:
: Annotated(annotated), Tokens(tokens), Cursors(cursors),
NumTokens(numTokens), TokIdx(0), PreprocessingTokIdx(0),
AnnotateVis(tu,
- AnnotateTokensVisitor, this, true, RegionOfInterest),
+ AnnotateTokensVisitor, this,
+ /*VisitPreprocessorLast=*/true,
+ /*VisitIncludedEntities=*/false,
+ RegionOfInterest),
SrcMgr(static_cast<ASTUnit*>(tu->TUData)->getSourceManager()),
HasContextSensitiveKeywords(false) { }
void VisitChildren(CXCursor C) { AnnotateVis.VisitChildren(C); }
enum CXChildVisitResult Visit(CXCursor cursor, CXCursor parent);
- void AnnotateTokens(CXCursor parent);
- void AnnotateTokens() {
- AnnotateTokens(clang_getTranslationUnitCursor(AnnotateVis.getTU()));
- }
+ void AnnotateTokens();
/// \brief Determine whether the annotator saw any cursors that have
/// context-sensitive keywords.
@@ -4755,10 +4790,10 @@ public:
};
}
-void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) {
+void AnnotateTokensWorker::AnnotateTokens() {
// Walk the AST within the region of interest, annotating tokens
// along the way.
- VisitChildren(parent);
+ AnnotateVis.visitFileRegion();
for (unsigned I = 0 ; I < TokIdx ; ++I) {
AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
@@ -4774,6 +4809,9 @@ void AnnotateTokensWorker::AnnotateTokens(CXCursor parent) {
const CXCursor &C = clang_getNullCursor();
for (unsigned I = TokIdx ; I < NumTokens ; ++I) {
+ if (I < PreprocessingTokIdx && clang_isPreprocessing(Cursors[I].kind))
+ continue;
+
AnnotateTokensData::iterator Pos = Annotated.find(Tokens[I].int_data[1]);
Cursors[I] = (Pos == Annotated.end()) ? C : Pos->second;
}
@@ -4954,12 +4992,12 @@ AnnotateTokensWorker::Visit(CXCursor cursor, CXCursor parent) {
Decl *D = cxcursor::getCursorDecl(cursor);
SourceLocation StartLoc;
- if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
+ if (const DeclaratorDecl *DD = dyn_cast_or_null<DeclaratorDecl>(D)) {
if (TypeSourceInfo *TI = DD->getTypeSourceInfo())
- StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
- } else if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(D)) {
+ StartLoc = TI->getTypeLoc().getLocStart();
+ } else if (TypedefDecl *Typedef = dyn_cast_or_null<TypedefDecl>(D)) {
if (TypeSourceInfo *TI = Typedef->getTypeSourceInfo())
- StartLoc = TI->getTypeLoc().getSourceRange().getBegin();
+ StartLoc = TI->getTypeLoc().getLocStart();
}
if (StartLoc.isValid() && L.isValid() &&
@@ -5135,7 +5173,7 @@ static void annotatePreprocessorTokens(CXTranslationUnit TU,
return;
Lexer Lex(SourceMgr.getLocForStartOfFile(BeginLocInfo.first),
- CXXUnit->getASTContext().getLangOptions(),
+ CXXUnit->getASTContext().getLangOpts(),
Buffer.begin(), Buffer.data() + BeginLocInfo.second,
Buffer.end());
Lex.SetCommentRetentionState(true);
@@ -5189,6 +5227,10 @@ static void clang_annotateTokensImpl(void *UserData) {
const unsigned NumTokens = ((clang_annotateTokens_Data*)UserData)->NumTokens;
CXCursor *Cursors = ((clang_annotateTokens_Data*)UserData)->Cursors;
+ CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing))
+ setThreadBackgroundPriority();
+
// Determine the region of interest, which contains all of the tokens.
SourceRange RegionOfInterest;
RegionOfInterest.setBegin(
@@ -5211,7 +5253,9 @@ static void clang_annotateTokensImpl(void *UserData) {
Tokens, NumTokens);
CursorVisitor MacroArgMarker(TU,
MarkMacroArgTokensVisitorDelegate, &Visitor,
- true, RegionOfInterest);
+ /*VisitPreprocessorLast=*/true,
+ /*VisitIncludedEntities=*/false,
+ RegionOfInterest);
MacroArgMarker.visitPreprocessedEntitiesInRegion();
}
@@ -5339,6 +5383,9 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) {
//===----------------------------------------------------------------------===//
static CXLanguageKind getDeclLanguage(const Decl *D) {
+ if (!D)
+ return CXLanguage_C;
+
switch (D->getKind()) {
default:
break;
@@ -5346,9 +5393,7 @@ static CXLanguageKind getDeclLanguage(const Decl *D) {
case Decl::ObjCAtDefsField:
case Decl::ObjCCategory:
case Decl::ObjCCategoryImpl:
- case Decl::ObjCClass:
case Decl::ObjCCompatibleAlias:
- case Decl::ObjCForwardProtocol:
case Decl::ObjCImplementation:
case Decl::ObjCInterface:
case Decl::ObjCIvar:
@@ -5481,10 +5526,16 @@ void clang_getOverriddenCursors(CXCursor cursor,
*num_overridden = 0;
if (!overridden || !num_overridden)
return;
+ if (!clang_isDeclaration(cursor.kind))
+ return;
SmallVector<CXCursor, 8> Overridden;
cxcursor::getOverriddenCursors(cursor, Overridden);
+ // Don't allocate memory if we have no overriden cursors.
+ if (Overridden.size() == 0)
+ return;
+
*num_overridden = Overridden.size();
*overridden = new CXCursor [Overridden.size()];
std::copy(Overridden.begin(), Overridden.end(), *overridden);
@@ -5624,7 +5675,7 @@ CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU) {
}
ASTUnit *astUnit = static_cast<ASTUnit*>(TU->TUData);
- llvm::OwningPtr<MemUsageEntries> entries(new MemUsageEntries());
+ OwningPtr<MemUsageEntries> entries(new MemUsageEntries());
ASTContext &astContext = astUnit->getASTContext();
// How much memory is used by AST nodes and types?
@@ -5755,6 +5806,34 @@ void SetSafetyThreadStackSize(unsigned Value) {
}
+void clang::setThreadBackgroundPriority() {
+ // FIXME: Move to llvm/Support and make it cross-platform.
+#ifdef __APPLE__
+ setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG);
+#endif
+}
+
+void cxindex::printDiagsToStderr(ASTUnit *Unit) {
+ if (!Unit)
+ return;
+
+ for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
+ DEnd = Unit->stored_diag_end();
+ D != DEnd; ++D) {
+ CXStoredDiagnostic Diag(*D, Unit->getASTContext().getLangOpts());
+ CXString Msg = clang_formatDiagnostic(&Diag,
+ clang_defaultDiagnosticDisplayOptions());
+ fprintf(stderr, "%s\n", clang_getCString(Msg));
+ clang_disposeString(Msg);
+ }
+#ifdef LLVM_ON_WIN32
+ // On Windows, force a flush, since there may be multiple copies of
+ // stderr and stdout in the file system, all with different buffers
+ // but writing to the same device.
+ fflush(stderr);
+#endif
+}
+
extern "C" {
CXString clang_getClangVersion() {
diff --git a/tools/libclang/CIndexCXX.cpp b/tools/libclang/CIndexCXX.cpp
index fb0ccb146f7d..240b0f6c1fe1 100644
--- a/tools/libclang/CIndexCXX.cpp
+++ b/tools/libclang/CIndexCXX.cpp
@@ -46,9 +46,8 @@ enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) {
case AS_private: return CX_CXXPrivate;
case AS_none: return CX_CXXInvalidAccessSpecifier;
}
-
- // FIXME: Clang currently thinks this is reachable.
- return CX_CXXInvalidAccessSpecifier;
+
+ llvm_unreachable("Invalid AccessSpecifier!");
}
enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) {
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index c19b3404920f..303fb1f9d5fe 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -104,8 +104,7 @@ clang_getCompletionChunkKind(CXCompletionString completion_string,
return CXCompletionChunk_VerticalSpace;
}
- // Should be unreachable, but let's be careful.
- return CXCompletionChunk_Text;
+ llvm_unreachable("Invalid CompletionKind!");
}
CXString clang_getCompletionChunkText(CXCompletionString completion_string,
@@ -142,8 +141,7 @@ CXString clang_getCompletionChunkText(CXCompletionString completion_string,
return createCXString("");
}
- // Should be unreachable, but let's be careful.
- return createCXString((const char*)0);
+ llvm_unreachable("Invalid CodeCompletionString Kind!");
}
@@ -182,8 +180,7 @@ clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
return (*CCStr)[chunk_number].Optional;
}
- // Should be unreachable, but let's be careful.
- return 0;
+ llvm_unreachable("Invalid CompletionKind!");
}
unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
@@ -216,7 +213,21 @@ CXString clang_getCompletionAnnotation(CXCompletionString completion_string,
: createCXString((const char *) 0);
}
-
+CXString
+clang_getCompletionParent(CXCompletionString completion_string,
+ CXCursorKind *kind) {
+ if (kind)
+ *kind = CXCursor_NotImplemented;
+
+ CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+ if (!CCStr)
+ return createCXString((const char *)0);
+
+ if (kind)
+ *kind = CCStr->getParentContextKind();
+ return createCXString(CCStr->getParentContextName(), /*DupString=*/false);
+}
+
/// \brief The CXCodeCompleteResults structure we allocate internally;
/// the client only sees the initial CXCodeCompleteResults structure.
struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
@@ -227,7 +238,7 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
SmallVector<StoredDiagnostic, 8> Diagnostics;
/// \brief Diag object
- llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diag;
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diag;
/// \brief Language options used to adjust source locations.
LangOptions LangOpts;
@@ -235,10 +246,10 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
FileSystemOptions FileSystemOpts;
/// \brief File manager, used for diagnostics.
- llvm::IntrusiveRefCntPtr<FileManager> FileMgr;
+ IntrusiveRefCntPtr<FileManager> FileMgr;
/// \brief Source manager, used for diagnostics.
- llvm::IntrusiveRefCntPtr<SourceManager> SourceMgr;
+ IntrusiveRefCntPtr<SourceManager> SourceMgr;
/// \brief Temporary files that should be removed once we have finished
/// with the code-completion results.
@@ -249,11 +260,12 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers;
/// \brief Allocator used to store globally cached code-completion results.
- llvm::IntrusiveRefCntPtr<clang::GlobalCodeCompletionAllocator>
+ IntrusiveRefCntPtr<clang::GlobalCodeCompletionAllocator>
CachedCompletionAllocator;
/// \brief Allocator used to store code completion results.
- clang::CodeCompletionAllocator CodeCompletionAllocator;
+ IntrusiveRefCntPtr<clang::GlobalCodeCompletionAllocator>
+ CodeCompletionAllocator;
/// \brief Context under which completion occurred.
enum clang::CodeCompletionContext::Kind ContextKind;
@@ -285,10 +297,11 @@ AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults(
const FileSystemOptions& FileSystemOpts)
: CXCodeCompleteResults(),
Diag(new DiagnosticsEngine(
- llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs))),
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs))),
FileSystemOpts(FileSystemOpts),
FileMgr(new FileManager(FileSystemOpts)),
SourceMgr(new SourceManager(*Diag, *FileMgr)),
+ CodeCompletionAllocator(new clang::GlobalCodeCompletionAllocator),
Contexts(CXCompletionContext_Unknown),
ContainerKind(CXCursor_InvalidCode),
ContainerUSR(createCXString("")),
@@ -335,7 +348,7 @@ static unsigned long long getContextsForContextKind(
case CodeCompletionContext::CCC_Type: {
contexts = CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface;
- if (S.getLangOptions().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus) {
contexts |= CXCompletionContext_EnumTag |
CXCompletionContext_UnionTag |
CXCompletionContext_StructTag |
@@ -348,7 +361,7 @@ static unsigned long long getContextsForContextKind(
contexts = CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface |
CXCompletionContext_AnyValue;
- if (S.getLangOptions().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus) {
contexts |= CXCompletionContext_EnumTag |
CXCompletionContext_UnionTag |
CXCompletionContext_StructTag |
@@ -359,7 +372,7 @@ static unsigned long long getContextsForContextKind(
}
case CodeCompletionContext::CCC_Expression: {
contexts = CXCompletionContext_AnyValue;
- if (S.getLangOptions().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus) {
contexts |= CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface |
CXCompletionContext_EnumTag |
@@ -374,7 +387,7 @@ static unsigned long long getContextsForContextKind(
contexts = CXCompletionContext_ObjCObjectValue |
CXCompletionContext_ObjCSelectorValue |
CXCompletionContext_ObjCInterface;
- if (S.getLangOptions().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus) {
contexts |= CXCompletionContext_CXXClassTypeValue |
CXCompletionContext_AnyType |
CXCompletionContext_EnumTag |
@@ -441,7 +454,7 @@ static unsigned long long getContextsForContextKind(
contexts = CXCompletionContext_AnyType |
CXCompletionContext_ObjCInterface |
CXCompletionContext_AnyValue;
- if (S.getLangOptions().CPlusPlus) {
+ if (S.getLangOpts().CPlusPlus) {
contexts |= CXCompletionContext_EnumTag |
CXCompletionContext_UnionTag |
CXCompletionContext_StructTag |
@@ -492,13 +505,15 @@ static unsigned long long getContextsForContextKind(
namespace {
class CaptureCompletionResults : public CodeCompleteConsumer {
AllocatedCXCodeCompleteResults &AllocatedResults;
+ CodeCompletionTUInfo CCTUInfo;
SmallVector<CXCompletionResult, 16> StoredResults;
CXTranslationUnit *TU;
public:
CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results,
CXTranslationUnit *TranslationUnit)
: CodeCompleteConsumer(true, false, true, false),
- AllocatedResults(Results), TU(TranslationUnit) { }
+ AllocatedResults(Results), CCTUInfo(Results.CodeCompletionAllocator),
+ TU(TranslationUnit) { }
~CaptureCompletionResults() { Finish(); }
virtual void ProcessCodeCompleteResults(Sema &S,
@@ -508,8 +523,8 @@ namespace {
StoredResults.reserve(StoredResults.size() + NumResults);
for (unsigned I = 0; I != NumResults; ++I) {
CodeCompletionString *StoredCompletion
- = Results[I].CreateCodeCompletionString(S,
- AllocatedResults.CodeCompletionAllocator);
+ = Results[I].CreateCodeCompletionString(S, getAllocator(),
+ getCodeCompletionTUInfo());
CXCompletionResult R;
R.CursorKind = Results[I].CursorKind;
@@ -596,8 +611,8 @@ namespace {
StoredResults.reserve(StoredResults.size() + NumCandidates);
for (unsigned I = 0; I != NumCandidates; ++I) {
CodeCompletionString *StoredCompletion
- = Candidates[I].CreateSignatureString(CurrentArg, S,
- AllocatedResults.CodeCompletionAllocator);
+ = Candidates[I].CreateSignatureString(CurrentArg, S, getAllocator(),
+ getCodeCompletionTUInfo());
CXCompletionResult R;
R.CursorKind = CXCursor_NotImplemented;
@@ -607,8 +622,10 @@ namespace {
}
virtual CodeCompletionAllocator &getAllocator() {
- return AllocatedResults.CodeCompletionAllocator;
+ return *AllocatedResults.CodeCompletionAllocator;
}
+
+ virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() { return CCTUInfo; }
private:
void Finish() {
@@ -655,6 +672,10 @@ void clang_codeCompleteAt_Impl(void *UserData) {
if (!AST)
return;
+ CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForEditing))
+ setThreadBackgroundPriority();
+
ASTUnit::ConcurrencyCheck Check(*AST);
// Perform the remapping of source files.
@@ -701,7 +722,7 @@ void clang_codeCompleteAt_Impl(void *UserData) {
#ifdef UDP_CODE_COMPLETION_LOGGER
#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime();
- llvm::SmallString<256> LogResult;
+ SmallString<256> LogResult;
llvm::raw_svector_ostream os(LogResult);
// Figure out the language and whether or not it uses PCH.
@@ -721,7 +742,7 @@ void clang_codeCompleteAt_Impl(void *UserData) {
else if (strcmp(*I, "-include") == 0) {
if (I+1 != E) {
const char *arg = *(++I);
- llvm::SmallString<512> pchName;
+ SmallString<512> pchName;
{
llvm::raw_svector_ostream os(pchName);
os << arg << ".pth";
@@ -886,7 +907,7 @@ CXString clang_codeCompleteGetObjCSelector(CXCodeCompleteResults *ResultsIn) {
/// \param Buffer A buffer that stores the actual, concatenated string. It will
/// be used if the old string is already-non-empty.
static void AppendToString(StringRef &Old, StringRef New,
- llvm::SmallString<256> &Buffer) {
+ SmallString<256> &Buffer) {
if (Old.empty()) {
Old = New;
return;
@@ -906,7 +927,7 @@ static void AppendToString(StringRef &Old, StringRef New,
///
/// \param Buffer A buffer used for storage of the completed name.
static StringRef GetTypedName(CodeCompletionString *String,
- llvm::SmallString<256> &Buffer) {
+ SmallString<256> &Buffer) {
StringRef Result;
for (CodeCompletionString::iterator C = String->begin(), CEnd = String->end();
C != CEnd; ++C) {
@@ -926,9 +947,9 @@ namespace {
CodeCompletionString *Y
= (CodeCompletionString *)YR.CompletionString;
- llvm::SmallString<256> XBuffer;
+ SmallString<256> XBuffer;
StringRef XText = GetTypedName(X, XBuffer);
- llvm::SmallString<256> YBuffer;
+ SmallString<256> YBuffer;
StringRef YText = GetTypedName(Y, YBuffer);
if (XText.empty() || YText.empty())
diff --git a/tools/libclang/CIndexDiagnostic.cpp b/tools/libclang/CIndexDiagnostic.cpp
index 26f69b06c195..8fbe3d8c3d38 100644
--- a/tools/libclang/CIndexDiagnostic.cpp
+++ b/tools/libclang/CIndexDiagnostic.cpp
@@ -18,6 +18,8 @@
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Frontend/DiagnosticOptions.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -26,30 +28,203 @@
using namespace clang;
using namespace clang::cxloc;
using namespace clang::cxstring;
+using namespace clang::cxdiag;
using namespace llvm;
+
+CXDiagnosticSetImpl::~CXDiagnosticSetImpl() {
+ for (std::vector<CXDiagnosticImpl *>::iterator it = Diagnostics.begin(),
+ et = Diagnostics.end();
+ it != et; ++it) {
+ delete *it;
+ }
+}
+
+CXDiagnosticImpl::~CXDiagnosticImpl() {}
+
+namespace {
+class CXDiagnosticCustomNoteImpl : public CXDiagnosticImpl {
+ std::string Message;
+ CXSourceLocation Loc;
+public:
+ CXDiagnosticCustomNoteImpl(StringRef Msg, CXSourceLocation L)
+ : CXDiagnosticImpl(CustomNoteDiagnosticKind),
+ Message(Msg), Loc(L) {}
+
+ virtual ~CXDiagnosticCustomNoteImpl() {}
+
+ CXDiagnosticSeverity getSeverity() const {
+ return CXDiagnostic_Note;
+ }
+
+ CXSourceLocation getLocation() const {
+ return Loc;
+ }
+
+ CXString getSpelling() const {
+ return createCXString(StringRef(Message), false);
+ }
+
+ CXString getDiagnosticOption(CXString *Disable) const {
+ if (Disable)
+ *Disable = createCXString("", false);
+ return createCXString("", false);
+ }
+
+ unsigned getCategory() const { return 0; }
+ CXString getCategoryText() const { return createCXString(""); }
+
+ unsigned getNumRanges() const { return 0; }
+ CXSourceRange getRange(unsigned Range) const { return clang_getNullRange(); }
+ unsigned getNumFixIts() const { return 0; }
+ CXString getFixIt(unsigned FixIt, CXSourceRange *ReplacementRange) const {
+ if (ReplacementRange)
+ *ReplacementRange = clang_getNullRange();
+ return createCXString("", false);
+ }
+};
+
+class CXDiagnosticRenderer : public DiagnosticNoteRenderer {
+public:
+ CXDiagnosticRenderer(const SourceManager &SM,
+ const LangOptions &LangOpts,
+ const DiagnosticOptions &DiagOpts,
+ CXDiagnosticSetImpl *mainSet)
+ : DiagnosticNoteRenderer(SM, LangOpts, DiagOpts),
+ CurrentSet(mainSet), MainSet(mainSet) {}
+
+ virtual ~CXDiagnosticRenderer() {}
+
+ virtual void beginDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level) {
+
+ const StoredDiagnostic *SD = D.dyn_cast<const StoredDiagnostic*>();
+ if (!SD)
+ return;
+
+ if (Level != DiagnosticsEngine::Note)
+ CurrentSet = MainSet;
+
+ CXStoredDiagnostic *CD = new CXStoredDiagnostic(*SD, LangOpts);
+ CurrentSet->appendDiagnostic(CD);
+
+ if (Level != DiagnosticsEngine::Note)
+ CurrentSet = &CD->getChildDiagnostics();
+ }
+
+ virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ StringRef Message,
+ ArrayRef<CharSourceRange> Ranges,
+ DiagOrStoredDiag D) {
+ if (!D.isNull())
+ return;
+
+ CXSourceLocation L = translateSourceLocation(SM, LangOpts, Loc);
+ CXDiagnosticImpl *CD = new CXDiagnosticCustomNoteImpl(Message, L);
+ CurrentSet->appendDiagnostic(CD);
+ }
+
+ virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges) {}
+
+ virtual void emitCodeContext(SourceLocation Loc,
+ DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange>& Ranges,
+ ArrayRef<FixItHint> Hints) {}
+
+ virtual void emitNote(SourceLocation Loc, StringRef Message) {
+ CXSourceLocation L = translateSourceLocation(SM, LangOpts, Loc);
+ CurrentSet->appendDiagnostic(new CXDiagnosticCustomNoteImpl(Message,
+ L));
+ }
+
+ CXDiagnosticSetImpl *CurrentSet;
+ CXDiagnosticSetImpl *MainSet;
+};
+}
+
+CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
+ bool checkIfChanged) {
+ ASTUnit *AU = static_cast<ASTUnit *>(TU->TUData);
+
+ if (TU->Diagnostics && checkIfChanged) {
+ // In normal use, ASTUnit's diagnostics should not change unless we reparse.
+ // Currently they can only change by using the internal testing flag
+ // '-error-on-deserialized-decl' which will error during deserialization of
+ // a declaration. What will happen is:
+ //
+ // -c-index-test gets a CXTranslationUnit
+ // -checks the diagnostics, the diagnostics set is lazily created,
+ // no errors are reported
+ // -later does an operation, like annotation of tokens, that triggers
+ // -error-on-deserialized-decl, that will emit a diagnostic error,
+ // that ASTUnit will catch and add to its stored diagnostics vector.
+ // -c-index-test wants to check whether an error occurred after performing
+ // the operation but can only query the lazily created set.
+ //
+ // We check here if a new diagnostic was appended since the last time the
+ // diagnostic set was created, in which case we reset it.
+
+ CXDiagnosticSetImpl *
+ Set = static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
+ if (AU->stored_diag_size() != Set->getNumDiagnostics()) {
+ // Diagnostics in the ASTUnit were updated, reset the associated
+ // diagnostics.
+ delete Set;
+ TU->Diagnostics = 0;
+ }
+ }
+
+ if (!TU->Diagnostics) {
+ CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
+ TU->Diagnostics = Set;
+ DiagnosticOptions DOpts;
+ CXDiagnosticRenderer Renderer(AU->getSourceManager(),
+ AU->getASTContext().getLangOpts(),
+ DOpts, Set);
+
+ for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
+ ei = AU->stored_diag_end(); it != ei; ++it) {
+ Renderer.emitStoredDiagnostic(*it);
+ }
+ }
+ return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
+}
+
//-----------------------------------------------------------------------------
// C Interface Routines
//-----------------------------------------------------------------------------
extern "C" {
unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData);
- return CXXUnit? CXXUnit->stored_diag_size() : 0;
+ if (!Unit->TUData)
+ return 0;
+ return lazyCreateDiags(Unit, /*checkIfChanged=*/true)->getNumDiagnostics();
}
CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
- ASTUnit *CXXUnit = static_cast<ASTUnit *>(Unit->TUData);
- if (!CXXUnit || Index >= CXXUnit->stored_diag_size())
+ CXDiagnosticSet D = clang_getDiagnosticSetFromTU(Unit);
+ if (!D)
return 0;
- return new CXStoredDiagnostic(CXXUnit->stored_diag_begin()[Index],
- CXXUnit->getASTContext().getLangOptions());
+ CXDiagnosticSetImpl *Diags = static_cast<CXDiagnosticSetImpl*>(D);
+ if (Index >= Diags->getNumDiagnostics())
+ return 0;
+
+ return Diags->getDiagnostic(Index);
+}
+
+CXDiagnosticSet clang_getDiagnosticSetFromTU(CXTranslationUnit Unit) {
+ if (!Unit->TUData)
+ return 0;
+ return static_cast<CXDiagnostic>(lazyCreateDiags(Unit));
}
void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
- CXStoredDiagnostic *Stored = static_cast<CXStoredDiagnostic *>(Diagnostic);
- delete Stored;
+ // No-op. Kept as a legacy API. CXDiagnostics are now managed
+ // by the enclosing CXDiagnosticSet.
}
CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
@@ -58,7 +233,7 @@ CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
- llvm::SmallString<256> Str;
+ SmallString<256> Str;
llvm::raw_svector_ostream Out(Str);
if (Options & CXDiagnostic_DisplaySourceLocation) {
@@ -151,7 +326,7 @@ CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
}
if (Options & CXDiagnostic_DisplayCategoryName) {
- CXString CategoryName = clang_getDiagnosticCategoryName(CategoryID);
+ CXString CategoryName = clang_getDiagnosticCategoryText(Diagnostic);
if (NeedBracket)
Out << " [";
if (NeedComma)
@@ -163,7 +338,8 @@ CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
}
}
}
-
+
+ (void) NeedComma; // Silence dead store warning.
if (!NeedBracket)
Out << "]";
}
@@ -177,133 +353,106 @@ unsigned clang_defaultDiagnosticDisplayOptions() {
}
enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag)
- return CXDiagnostic_Ignored;
-
- switch (StoredDiag->Diag.getLevel()) {
- case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;
- case DiagnosticsEngine::Note: return CXDiagnostic_Note;
- case DiagnosticsEngine::Warning: return CXDiagnostic_Warning;
- case DiagnosticsEngine::Error: return CXDiagnostic_Error;
- case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal;
- }
-
- llvm_unreachable("Invalid diagnostic level");
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
+ return D->getSeverity();
return CXDiagnostic_Ignored;
}
CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
- return clang_getNullLocation();
-
- return translateSourceLocation(StoredDiag->Diag.getLocation().getManager(),
- StoredDiag->LangOpts,
- StoredDiag->Diag.getLocation());
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
+ return D->getLocation();
+ return clang_getNullLocation();
}
CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag)
- return createCXString("");
-
- return createCXString(StoredDiag->Diag.getMessage(), false);
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getSpelling();
+ return createCXString("");
}
CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
if (Disable)
*Disable = createCXString("");
-
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag)
- return createCXString("");
-
- unsigned ID = StoredDiag->Diag.getID();
- StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID);
- if (!Option.empty()) {
- if (Disable)
- *Disable = createCXString((Twine("-Wno-") + Option).str());
- return createCXString((Twine("-W") + Option).str());
- }
-
- if (ID == diag::fatal_too_many_errors) {
- if (Disable)
- *Disable = createCXString("-ferror-limit=0");
- return createCXString("-ferror-limit=");
- }
-
- bool EnabledByDefault;
- if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) &&
- !EnabledByDefault)
- return createCXString("-pedantic");
+
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getDiagnosticOption(Disable);
return createCXString("");
}
unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag)
- return 0;
-
- return DiagnosticIDs::getCategoryNumberForDiag(StoredDiag->Diag.getID());
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getCategory();
+ return 0;
}
CXString clang_getDiagnosticCategoryName(unsigned Category) {
+ // Kept for backwards compatibility.
return createCXString(DiagnosticIDs::getCategoryNameFromID(Category));
}
+CXString clang_getDiagnosticCategoryText(CXDiagnostic Diag) {
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getCategoryText();
+ return createCXString("");
+}
+
unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid())
- return 0;
-
- return StoredDiag->Diag.range_size();
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getNumRanges();
+ return 0;
}
CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag || Range >= StoredDiag->Diag.range_size() ||
- StoredDiag->Diag.getLocation().isInvalid())
+ CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
+ if (!D || Range >= D->getNumRanges())
return clang_getNullRange();
-
- return translateSourceRange(StoredDiag->Diag.getLocation().getManager(),
- StoredDiag->LangOpts,
- StoredDiag->Diag.range_begin()[Range]);
+ return D->getRange(Range);
}
unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
- CXStoredDiagnostic *StoredDiag = static_cast<CXStoredDiagnostic *>(Diag);
- if (!StoredDiag)
- return 0;
-
- return StoredDiag->Diag.fixit_size();
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
+ return D->getNumFixIts();
+ return 0;
}
-CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, unsigned FixIt,
+CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt,
CXSourceRange *ReplacementRange) {
- CXStoredDiagnostic *StoredDiag
- = static_cast<CXStoredDiagnostic *>(Diagnostic);
- if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() ||
- StoredDiag->Diag.getLocation().isInvalid()) {
+ CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
+ if (!D || FixIt >= D->getNumFixIts()) {
if (ReplacementRange)
*ReplacementRange = clang_getNullRange();
-
return createCXString("");
}
+ return D->getFixIt(FixIt, ReplacementRange);
+}
- const FixItHint &Hint = StoredDiag->Diag.fixit_begin()[FixIt];
- if (ReplacementRange) {
- // 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);
+void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) {
+ CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags);
+ if (D->isExternallyManaged())
+ delete D;
+}
+
+CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
+ unsigned Index) {
+ if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
+ if (Index < D->getNumDiagnostics())
+ return D->getDiagnostic(Index);
+ return 0;
+}
+
+CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {
+ if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) {
+ CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics();
+ return ChildDiags.empty() ? 0 : (CXDiagnosticSet) &ChildDiags;
}
+ return 0;
+}
- return createCXString(Hint.CodeToInsert);
+unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
+ if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
+ return D->getNumDiagnostics();
+ return 0;
}
} // end extern "C"
diff --git a/tools/libclang/CIndexDiagnostic.h b/tools/libclang/CIndexDiagnostic.h
index 0d935fae660f..b1c3978e0ae8 100644
--- a/tools/libclang/CIndexDiagnostic.h
+++ b/tools/libclang/CIndexDiagnostic.h
@@ -13,21 +13,154 @@
#ifndef LLVM_CLANG_CINDEX_DIAGNOSTIC_H
#define LLVM_CLANG_CINDEX_DIAGNOSTIC_H
+#include "clang-c/Index.h"
+#include <vector>
+#include <assert.h>
+
namespace clang {
class LangOptions;
class StoredDiagnostic;
+class CXDiagnosticImpl;
+
+class CXDiagnosticSetImpl {
+ std::vector<CXDiagnosticImpl *> Diagnostics;
+ const bool IsExternallyManaged;
+public:
+ CXDiagnosticSetImpl(bool isManaged = false)
+ : IsExternallyManaged(isManaged) {}
+
+ virtual ~CXDiagnosticSetImpl();
+
+ size_t getNumDiagnostics() const {
+ return Diagnostics.size();
+ }
+
+ CXDiagnosticImpl *getDiagnostic(unsigned i) const {
+ assert(i < getNumDiagnostics());
+ return Diagnostics[i];
+ }
+
+ void appendDiagnostic(CXDiagnosticImpl *D) {
+ Diagnostics.push_back(D);
+ }
+
+ bool empty() const {
+ return Diagnostics.empty();
+ }
+
+ bool isExternallyManaged() const { return IsExternallyManaged; }
+};
+
+class CXDiagnosticImpl {
+public:
+ enum Kind { StoredDiagnosticKind, LoadedDiagnosticKind,
+ CustomNoteDiagnosticKind };
+
+ virtual ~CXDiagnosticImpl();
+
+ /// \brief Return the severity of the diagnostic.
+ virtual CXDiagnosticSeverity getSeverity() const = 0;
+
+ /// \brief Return the location of the diagnostic.
+ virtual CXSourceLocation getLocation() const = 0;
+
+ /// \brief Return the spelling of the diagnostic.
+ virtual CXString getSpelling() const = 0;
+
+ /// \brief Return the text for the diagnostic option.
+ virtual CXString getDiagnosticOption(CXString *Disable) const = 0;
+
+ /// \brief Return the category of the diagnostic.
+ virtual unsigned getCategory() const = 0;
+
+ /// \brief Return the category string of the diagnostic.
+ virtual CXString getCategoryText() const = 0;
+
+ /// \brief Return the number of source ranges for the diagnostic.
+ virtual unsigned getNumRanges() const = 0;
+
+ /// \brief Return the source ranges for the diagnostic.
+ virtual CXSourceRange getRange(unsigned Range) const = 0;
+
+ /// \brief Return the number of FixIts.
+ virtual unsigned getNumFixIts() const = 0;
+ /// \brief Return the FixIt information (source range and inserted text).
+ virtual CXString getFixIt(unsigned FixIt,
+ CXSourceRange *ReplacementRange) const = 0;
+
+ Kind getKind() const { return K; }
+
+ CXDiagnosticSetImpl &getChildDiagnostics() {
+ return ChildDiags;
+ }
+
+protected:
+ CXDiagnosticImpl(Kind k) : K(k) {}
+ CXDiagnosticSetImpl ChildDiags;
+
+ void append(CXDiagnosticImpl *D) {
+ ChildDiags.appendDiagnostic(D);
+ }
+
+private:
+ Kind K;
+};
+
/// \brief The storage behind a CXDiagnostic
-struct CXStoredDiagnostic {
+struct CXStoredDiagnostic : public CXDiagnosticImpl {
const StoredDiagnostic &Diag;
const LangOptions &LangOpts;
CXStoredDiagnostic(const StoredDiagnostic &Diag,
const LangOptions &LangOpts)
- : Diag(Diag), LangOpts(LangOpts) { }
+ : CXDiagnosticImpl(StoredDiagnosticKind),
+ Diag(Diag), LangOpts(LangOpts) { }
+
+ virtual ~CXStoredDiagnostic() {}
+
+ /// \brief Return the severity of the diagnostic.
+ virtual CXDiagnosticSeverity getSeverity() const;
+
+ /// \brief Return the location of the diagnostic.
+ virtual CXSourceLocation getLocation() const;
+
+ /// \brief Return the spelling of the diagnostic.
+ virtual CXString getSpelling() const;
+
+ /// \brief Return the text for the diagnostic option.
+ virtual CXString getDiagnosticOption(CXString *Disable) const;
+
+ /// \brief Return the category of the diagnostic.
+ virtual unsigned getCategory() const;
+
+ /// \brief Return the category string of the diagnostic.
+ virtual CXString getCategoryText() const;
+
+ /// \brief Return the number of source ranges for the diagnostic.
+ virtual unsigned getNumRanges() const;
+
+ /// \brief Return the source ranges for the diagnostic.
+ virtual CXSourceRange getRange(unsigned Range) const;
+
+ /// \brief Return the number of FixIts.
+ virtual unsigned getNumFixIts() const;
+
+ /// \brief Return the FixIt information (source range and inserted text).
+ virtual CXString getFixIt(unsigned FixIt,
+ CXSourceRange *ReplacementRange) const;
+
+ static bool classof(const CXDiagnosticImpl *D) {
+ return D->getKind() == StoredDiagnosticKind;
+ }
};
+namespace cxdiag {
+CXDiagnosticSetImpl *lazyCreateDiags(CXTranslationUnit TU,
+ bool checkIfChanged = false);
+} // end namespace cxdiag
+
} // end namespace clang
#endif // LLVM_CLANG_CINDEX_DIAGNOSTIC_H
diff --git a/tools/libclang/CIndexHigh.cpp b/tools/libclang/CIndexHigh.cpp
index b5a05eaafc0b..ec76898cc83b 100644
--- a/tools/libclang/CIndexHigh.cpp
+++ b/tools/libclang/CIndexHigh.cpp
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
-#include "Index_Internal.h"
+#include "CursorVisitor.h"
#include "CXCursor.h"
#include "CXSourceLocation.h"
#include "CXTranslationUnit.h"
@@ -16,10 +16,13 @@
#include "clang/AST/DeclObjC.h"
using namespace clang;
+using namespace cxcursor;
static void getTopOverriddenMethods(CXTranslationUnit TU,
Decl *D,
SmallVectorImpl<Decl *> &Methods) {
+ if (!D)
+ return;
if (!isa<ObjCMethodDecl>(D) && !isa<CXXMethodDecl>(D))
return;
@@ -72,17 +75,26 @@ struct FindFileIdRefVisitData {
/// we consider the canonical decl of the constructor decl to be the class
/// itself, so both 'C' can be highlighted.
Decl *getCanonical(Decl *D) const {
+ if (!D)
+ return 0;
+
D = D->getCanonicalDecl();
- if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D))
- return getCanonical(ImplD->getClassInterface());
- if (CXXConstructorDecl *CXXCtorD = dyn_cast<CXXConstructorDecl>(D))
+ if (ObjCImplDecl *ImplD = dyn_cast<ObjCImplDecl>(D)) {
+ if (ImplD->getClassInterface())
+ return getCanonical(ImplD->getClassInterface());
+
+ } else if (CXXConstructorDecl *CXXCtorD = dyn_cast<CXXConstructorDecl>(D)) {
return getCanonical(CXXCtorD->getParent());
+ }
return D;
}
bool isHit(Decl *D) const {
+ if (!D)
+ return false;
+
D = getCanonical(D);
if (D == Dcl)
return true;
@@ -137,6 +149,9 @@ static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
return CXChildVisit_Recurse;
Decl *D = cxcursor::getCursorDecl(declCursor);
+ if (!D)
+ return CXChildVisit_Continue;
+
FindFileIdRefVisitData *data = (FindFileIdRefVisitData *)client_data;
if (data->isHit(D)) {
cursor = cxcursor::getSelectorIdentifierCursor(data->SelectorIdIdx, cursor);
@@ -167,7 +182,8 @@ static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
if (SelIdLoc.isValid())
Loc = SelIdLoc;
- SourceManager &SM = data->getASTContext().getSourceManager();
+ ASTContext &Ctx = data->getASTContext();
+ SourceManager &SM = Ctx.getSourceManager();
bool isInMacroDef = false;
if (Loc.isMacroID()) {
bool isMacroArg;
@@ -183,11 +199,11 @@ static enum CXChildVisitResult findFileIdRefVisit(CXCursor cursor,
if (isInMacroDef) {
// FIXME: For a macro definition make sure that all expansions
// of it expand to the same reference before allowing to point to it.
- Loc = SourceLocation();
+ return CXChildVisit_Recurse;
}
data->visitor.visit(data->visitor.context, cursor,
- cxloc::translateSourceRange(D->getASTContext(), Loc));
+ cxloc::translateSourceRange(Ctx, Loc));
}
return CXChildVisit_Recurse;
}
@@ -197,11 +213,13 @@ static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
CXCursorAndRangeVisitor Visitor) {
assert(clang_isDeclaration(declCursor.kind));
ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
- ASTContext &Ctx = Unit->getASTContext();
SourceManager &SM = Unit->getSourceManager();
FileID FID = SM.translateFile(File);
Decl *Dcl = cxcursor::getCursorDecl(declCursor);
+ if (!Dcl)
+ return;
+
FindFileIdRefVisitData data(TU, FID, Dcl,
cxcursor::getSelectorIdentifierIndex(declCursor),
Visitor);
@@ -211,35 +229,108 @@ static void findIdRefsInFile(CXTranslationUnit TU, CXCursor declCursor,
findFileIdRefVisit, &data);
return;
}
-
- if (FID == SM.getMainFileID() && !Unit->isMainFileAST()) {
- SourceLocation FileLoc = SM.getLocForStartOfFile(FID);
- TranslationUnitDecl *TUD = Ctx.getTranslationUnitDecl();
- CXCursor TUCursor = clang_getTranslationUnitCursor(TU);
- for (DeclContext::decl_iterator
- I = TUD->noload_decls_begin(), E = TUD->noload_decls_end();
- I != E; ++I) {
- Decl *D = *I;
-
- SourceRange R = D->getSourceRange();
- if (R.isInvalid())
- continue;
- if (SM.isBeforeInTranslationUnit(R.getEnd(), FileLoc))
- continue;
-
- if (TagDecl *TD = dyn_cast<TagDecl>(D))
- if (!TD->isFreeStanding())
- continue;
-
- CXCursor CurCursor = cxcursor::MakeCXCursor(D, TU);
- findFileIdRefVisit(CurCursor, TUCursor, &data);
- clang_visitChildren(CurCursor, findFileIdRefVisit, &data);
- }
- return;
+
+ SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
+ CursorVisitor FindIdRefsVisitor(TU,
+ findFileIdRefVisit, &data,
+ /*VisitPreprocessorLast=*/true,
+ /*VisitIncludedEntities=*/false,
+ Range,
+ /*VisitDeclsOnly=*/true);
+ FindIdRefsVisitor.visitFileRegion();
+}
+
+namespace {
+
+struct FindFileMacroRefVisitData {
+ ASTUnit &Unit;
+ const FileEntry *File;
+ const IdentifierInfo *Macro;
+ CXCursorAndRangeVisitor visitor;
+
+ FindFileMacroRefVisitData(ASTUnit &Unit, const FileEntry *File,
+ const IdentifierInfo *Macro,
+ CXCursorAndRangeVisitor visitor)
+ : Unit(Unit), File(File), Macro(Macro), visitor(visitor) { }
+
+ ASTContext &getASTContext() const {
+ return Unit.getASTContext();
+ }
+};
+
+} // anonymous namespace
+
+static enum CXChildVisitResult findFileMacroRefVisit(CXCursor cursor,
+ CXCursor parent,
+ CXClientData client_data) {
+ const IdentifierInfo *Macro = 0;
+ if (cursor.kind == CXCursor_MacroDefinition)
+ Macro = getCursorMacroDefinition(cursor)->getName();
+ else if (cursor.kind == CXCursor_MacroExpansion)
+ Macro = getCursorMacroExpansion(cursor)->getName();
+ if (!Macro)
+ return CXChildVisit_Continue;
+
+ FindFileMacroRefVisitData *data = (FindFileMacroRefVisitData *)client_data;
+ if (data->Macro != Macro)
+ return CXChildVisit_Continue;
+
+ SourceLocation
+ Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor));
+
+ ASTContext &Ctx = data->getASTContext();
+ SourceManager &SM = Ctx.getSourceManager();
+ bool isInMacroDef = false;
+ if (Loc.isMacroID()) {
+ bool isMacroArg;
+ Loc = getFileSpellingLoc(SM, Loc, isMacroArg);
+ isInMacroDef = !isMacroArg;
+ }
+
+ // We are looking for identifiers in a specific file.
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ if (SM.getFileEntryForID(LocInfo.first) != data->File)
+ return CXChildVisit_Continue;
+
+ if (isInMacroDef) {
+ // FIXME: For a macro definition make sure that all expansions
+ // of it expand to the same reference before allowing to point to it.
+ return CXChildVisit_Continue;
}
- clang_visitChildren(clang_getTranslationUnitCursor(TU),
- findFileIdRefVisit, &data);
+ data->visitor.visit(data->visitor.context, cursor,
+ cxloc::translateSourceRange(Ctx, Loc));
+ return CXChildVisit_Continue;
+}
+
+static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor,
+ const FileEntry *File,
+ CXCursorAndRangeVisitor Visitor) {
+ if (Cursor.kind != CXCursor_MacroDefinition &&
+ Cursor.kind != CXCursor_MacroExpansion)
+ return;
+
+ ASTUnit *Unit = static_cast<ASTUnit*>(TU->TUData);
+ SourceManager &SM = Unit->getSourceManager();
+
+ FileID FID = SM.translateFile(File);
+ const IdentifierInfo *Macro = 0;
+ if (Cursor.kind == CXCursor_MacroDefinition)
+ Macro = getCursorMacroDefinition(Cursor)->getName();
+ else
+ Macro = getCursorMacroExpansion(Cursor)->getName();
+ if (!Macro)
+ return;
+
+ FindFileMacroRefVisitData data(*Unit, File, Macro, Visitor);
+
+ SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID));
+ CursorVisitor FindMacroRefsVisitor(TU,
+ findFileMacroRefVisit, &data,
+ /*VisitPreprocessorLast=*/false,
+ /*VisitIncludedEntities=*/false,
+ Range);
+ FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion();
}
@@ -258,6 +349,11 @@ void clang_findReferencesInFile(CXCursor cursor, CXFile file,
llvm::errs() << "clang_findReferencesInFile: Null cursor\n";
return;
}
+ if (cursor.kind == CXCursor_NoDeclFound) {
+ if (Logging)
+ llvm::errs() << "clang_findReferencesInFile: Got CXCursor_NoDeclFound\n";
+ return;
+ }
if (!file) {
if (Logging)
llvm::errs() << "clang_findReferencesInFile: Null file\n";
@@ -269,6 +365,21 @@ void clang_findReferencesInFile(CXCursor cursor, CXFile file,
return;
}
+ ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
+ if (!CXXUnit)
+ return;
+
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+
+ if (cursor.kind == CXCursor_MacroDefinition ||
+ cursor.kind == CXCursor_MacroExpansion) {
+ findMacroRefsInFile(cxcursor::getCursorTU(cursor),
+ cursor,
+ static_cast<const FileEntry *>(file),
+ visitor);
+ return;
+ }
+
// We are interested in semantics of identifiers so for C++ constructor exprs
// prefer type references, e.g.:
//
@@ -287,9 +398,6 @@ void clang_findReferencesInFile(CXCursor cursor, CXFile file,
return;
}
- ASTUnit *CXXUnit = cxcursor::getCursorASTUnit(cursor);
- ASTUnit::ConcurrencyCheck Check(*CXXUnit);
-
findIdRefsInFile(cxcursor::getCursorTU(cursor),
refCursor,
static_cast<const FileEntry *>(file),
diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp
index 121d67d1d2e7..7c79b69315dd 100644
--- a/tools/libclang/CIndexUSRs.cpp
+++ b/tools/libclang/CIndexUSRs.cpp
@@ -30,7 +30,7 @@ using namespace clang::cxstring;
namespace {
class USRGenerator : public DeclVisitor<USRGenerator> {
- llvm::OwningPtr<llvm::SmallString<128> > OwnedBuf;
+ OwningPtr<SmallString<128> > OwnedBuf;
SmallVectorImpl<char> &Buf;
llvm::raw_svector_ostream Out;
bool IgnoreResults;
@@ -41,7 +41,7 @@ class USRGenerator : public DeclVisitor<USRGenerator> {
public:
explicit USRGenerator(ASTContext *Ctx = 0, SmallVectorImpl<char> *extBuf = 0)
- : OwnedBuf(extBuf ? 0 : new llvm::SmallString<128>()),
+ : OwnedBuf(extBuf ? 0 : new SmallString<128>()),
Buf(extBuf ? *extBuf : *OwnedBuf.get()),
Out(Buf),
IgnoreResults(false),
@@ -75,9 +75,7 @@ public:
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
- void VisitObjCClassDecl(ObjCClassDecl *CD);
void VisitObjCContainerDecl(ObjCContainerDecl *CD);
- void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *P);
void VisitObjCMethodDecl(ObjCMethodDecl *MD);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
@@ -169,7 +167,12 @@ void USRGenerator::VisitDeclContext(DeclContext *DC) {
}
void USRGenerator::VisitFieldDecl(FieldDecl *D) {
- VisitDeclContext(D->getDeclContext());
+ // The USR for an ivar declared in a class extension is based on the
+ // ObjCInterfaceDecl, not the ObjCCategoryDecl.
+ if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
+ Visit(ID);
+ else
+ VisitDeclContext(D->getDeclContext());
Out << (isa<ObjCIvarDecl>(D) ? "@" : "@FI@");
if (EmitDeclName(D)) {
// Bit fields can be anonymous.
@@ -191,9 +194,19 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
D->printName(Out);
ASTContext &Ctx = *Context;
- if (!Ctx.getLangOptions().CPlusPlus || D->isExternC())
+ if (!Ctx.getLangOpts().CPlusPlus || D->isExternC())
return;
+ if (const TemplateArgumentList *
+ SpecArgs = D->getTemplateSpecializationArgs()) {
+ Out << '<';
+ for (unsigned I = 0, N = SpecArgs->size(); I != N; ++I) {
+ Out << '#';
+ VisitTemplateArgument(SpecArgs->get(I));
+ }
+ Out << '>';
+ }
+
// Mangle in type information for the arguments.
for (FunctionDecl::param_iterator I = D->param_begin(), E = D->param_end();
I != E; ++I) {
@@ -305,18 +318,6 @@ void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
N.printName(Out);
}
-void USRGenerator::VisitObjCClassDecl(ObjCClassDecl *D) {
- // FIXME: @class declarations can refer to multiple classes. We need
- // to be able to traverse these.
- IgnoreResults = true;
-}
-
-void USRGenerator::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
- // FIXME: @protocol declarations can refer to multiple protocols. We need
- // to be able to traverse these.
- IgnoreResults = true;
-}
-
void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
switch (D->getKind()) {
default:
@@ -368,7 +369,12 @@ void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
}
void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
- Visit(cast<Decl>(D->getDeclContext()));
+ // The USR for a property declared in a class extension or category is based
+ // on the ObjCInterfaceDecl, not the ObjCCategoryDecl.
+ if (ObjCInterfaceDecl *ID = Context->getObjContainingInterface(D))
+ Visit(ID);
+ else
+ Visit(cast<Decl>(D->getDeclContext()));
GenObjCProperty(D->getName());
}
@@ -399,7 +405,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
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;
+ case TTK_Enum: llvm_unreachable("enum template");
}
VisitTemplateParameterList(ClassTmpl->getTemplateParameters());
} else if (ClassTemplatePartialSpecializationDecl *PartialSpec
@@ -410,7 +416,7 @@ void USRGenerator::VisitTagDecl(TagDecl *D) {
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;
+ case TTK_Enum: llvm_unreachable("enum partial specialization");
}
VisitTemplateParameterList(PartialSpec->getTemplateParameters());
}
@@ -580,10 +586,10 @@ void USRGenerator::VisitType(QualType T) {
c = 'D'; break;
case BuiltinType::NullPtr:
c = 'n'; break;
- case BuiltinType::Overload:
- case BuiltinType::BoundMember:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Dependent:
- case BuiltinType::UnknownAny:
IgnoreResults = true;
return;
case BuiltinType::ObjCId:
@@ -789,7 +795,7 @@ static inline StringRef extractUSRSuffix(StringRef s) {
return s.startswith("c:") ? s.substr(2) : "";
}
-bool cxcursor::getDeclCursorUSR(Decl *D, SmallVectorImpl<char> &Buf) {
+bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf) {
// Don't generate USRs for things with invalid locations.
if (!D || D->getLocStart().isInvalid())
return true;
@@ -819,7 +825,7 @@ bool cxcursor::getDeclCursorUSR(Decl *D, SmallVectorImpl<char> &Buf) {
{
USRGenerator UG(&D->getASTContext(), &Buf);
- UG->Visit(D);
+ UG->Visit(const_cast<Decl*>(D));
if (UG->ignoreResults())
return true;
@@ -835,6 +841,9 @@ CXString clang_getCursorUSR(CXCursor C) {
if (clang_isDeclaration(K)) {
Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return createCXString("");
+
CXTranslationUnit TU = cxcursor::getCursorTU(C);
if (!TU)
return createCXString("");
diff --git a/tools/libclang/CIndexer.cpp b/tools/libclang/CIndexer.cpp
index 995a8febb088..d45878919e49 100644
--- a/tools/libclang/CIndexer.cpp
+++ b/tools/libclang/CIndexer.cpp
@@ -21,7 +21,7 @@
#include "clang/Basic/Version.h"
#include "clang/Sema/CodeCompleteConsumer.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Config/config.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/tools/libclang/CIndexer.h b/tools/libclang/CIndexer.h
index 45d0831b8869..1e5fb824bb1b 100644
--- a/tools/libclang/CIndexer.h
+++ b/tools/libclang/CIndexer.h
@@ -24,15 +24,20 @@ namespace llvm {
class CrashRecoveryContext;
}
+namespace clang {
+ class ASTUnit;
+
class CIndexer {
bool OnlyLocalDecls;
bool DisplayDiagnostics;
+ unsigned Options; // CXGlobalOptFlags.
llvm::sys::Path ResourcesPath;
std::string WorkingDir;
public:
- CIndexer() : OnlyLocalDecls(false), DisplayDiagnostics(false) { }
+ CIndexer() : OnlyLocalDecls(false), DisplayDiagnostics(false),
+ Options(CXGlobalOpt_None) { }
/// \brief Whether we only want to see "local" declarations (that did not
/// come from a previous precompiled header). If false, we want to see all
@@ -45,6 +50,13 @@ public:
DisplayDiagnostics = Display;
}
+ unsigned getCXGlobalOptFlags() const { return Options; }
+ void setCXGlobalOptFlags(unsigned options) { Options = options; }
+
+ bool isOptEnabled(CXGlobalOptFlags opt) const {
+ return Options & opt;
+ }
+
/// \brief Get the path of the clang resource files.
std::string getClangResourcesPath();
@@ -52,7 +64,6 @@ public:
void setWorkingDirectory(const std::string &Dir) { WorkingDir = Dir; }
};
-namespace clang {
/**
* \brief Given a set of "unsaved" files, create temporary files and
* construct the clang -cc1 argument list needed to perform the remapping.
@@ -78,8 +89,16 @@ namespace clang {
bool RunSafely(llvm::CrashRecoveryContext &CRC,
void (*Fn)(void*), void *UserData, unsigned Size = 0);
+ /// \brief Set the thread priority to background.
+ /// FIXME: Move to llvm/Support.
+ void setThreadBackgroundPriority();
+
/// \brief Print libclang's resource usage to standard error.
void PrintLibclangResourceUsage(CXTranslationUnit TU);
+
+ namespace cxindex {
+ void printDiagsToStderr(ASTUnit *Unit);
+ }
}
#endif
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index f754e980b93f..66a1710bac14 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_USED_LIBS
clangSerialization
clangIndex
clangSema
+ clangEdit
clangAST
clangLex
clangBasic)
@@ -21,13 +22,31 @@ set(SOURCES
CIndexCXX.cpp
CIndexCodeCompletion.cpp
CIndexDiagnostic.cpp
+ CIndexDiagnostic.h
CIndexHigh.cpp
CIndexInclusionStack.cpp
CIndexUSRs.cpp
CIndexer.cpp
+ CIndexer.h
CXCursor.cpp
+ CXCursor.h
+ CXLoadedDiagnostic.cpp
+ CXLoadedDiagnostic.h
+ CXSourceLocation.cpp
+ CXSourceLocation.h
+ CXStoredDiagnostic.cpp
CXString.cpp
+ CXString.h
+ CXTranslationUnit.h
CXType.cpp
+ CXType.h
+ IndexBody.cpp
+ IndexDecl.cpp
+ IndexTypeSourceInfo.cpp
+ Index_Internal.h
+ Indexing.cpp
+ IndexingContext.cpp
+ IndexingContext.h
../../include/clang-c/Index.h
)
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index db2750014351..d84cf29098fe 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -46,6 +46,7 @@ static CXCursorKind GetCursorKind(const Attr *A) {
case attr::Final: return CXCursor_CXXFinalAttr;
case attr::Override: return CXCursor_CXXOverrideAttr;
case attr::Annotate: return CXCursor_AnnotateAttr;
+ case attr::AsmLabel: return CXCursor_AsmLabelAttr;
}
return CXCursor_UnexposedAttr;
@@ -205,6 +206,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::AtomicExprClass:
case Stmt::BinaryConditionalOperatorClass:
case Stmt::BinaryTypeTraitExprClass:
+ case Stmt::TypeTraitExprClass:
case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXDefaultArgExprClass:
case Stmt::CXXScalarValueInitExprClass:
@@ -219,16 +221,29 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::MaterializeTemporaryExprClass:
case Stmt::ObjCIndirectCopyRestoreExprClass:
case Stmt::OffsetOfExprClass:
- case Stmt::OpaqueValueExprClass:
case Stmt::ParenListExprClass:
case Stmt::PredefinedExprClass:
case Stmt::ShuffleVectorExprClass:
case Stmt::UnaryExprOrTypeTraitExprClass:
case Stmt::UnaryTypeTraitExprClass:
case Stmt::VAArgExprClass:
+ case Stmt::ObjCArrayLiteralClass:
+ case Stmt::ObjCDictionaryLiteralClass:
+ case Stmt::ObjCNumericLiteralClass:
+ case Stmt::ObjCSubscriptRefExprClass:
+ K = CXCursor_UnexposedExpr;
+ break;
+
+ case Stmt::OpaqueValueExprClass:
+ if (Expr *Src = cast<OpaqueValueExpr>(S)->getSourceExpr())
+ return MakeCXCursor(Src, Parent, TU, RegionOfInterest);
K = CXCursor_UnexposedExpr;
break;
+ case Stmt::PseudoObjectExprClass:
+ return MakeCXCursor(cast<PseudoObjectExpr>(S)->getSyntacticForm(),
+ Parent, TU, RegionOfInterest);
+
case Stmt::CompoundStmtClass:
K = CXCursor_CompoundStmt;
break;
@@ -384,7 +399,11 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::ObjCProtocolExprClass:
K = CXCursor_ObjCProtocolExpr;
break;
-
+
+ case Stmt::ObjCBoolLiteralExprClass:
+ K = CXCursor_ObjCBoolLiteralExpr;
+ break;
+
case Stmt::ObjCBridgedCastExprClass:
K = CXCursor_ObjCBridgedCastExpr;
break;
@@ -401,7 +420,6 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
K = CXCursor_SizeOfPackExpr;
break;
- case Stmt::BlockDeclRefExprClass:
case Stmt::DeclRefExprClass:
case Stmt::DependentScopeDeclRefExprClass:
case Stmt::SubstNonTypeTemplateParmExprClass:
@@ -427,10 +445,15 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
case Stmt::CXXConstructExprClass:
case Stmt::CXXTemporaryObjectExprClass:
case Stmt::CXXUnresolvedConstructExprClass:
+ case Stmt::UserDefinedLiteralClass:
K = CXCursor_CallExpr;
break;
- case Stmt::ObjCMessageExprClass:
+ case Stmt::LambdaExprClass:
+ K = CXCursor_LambdaExpr;
+ break;
+
+ case Stmt::ObjCMessageExprClass: {
K = CXCursor_ObjCMessageExpr;
int SelectorIdIndex = -1;
// Check if cursor points to a selector id.
@@ -446,6 +469,11 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
CXCursor C = { K, 0, { Parent, S, TU } };
return getSelectorIdentifierCursor(SelectorIdIndex, C);
}
+
+ case Stmt::MSDependentExistsStmtClass:
+ K = CXCursor_UnexposedStmt;
+ break;
+ }
CXCursor C = { K, 0, { Parent, S, TU } };
return C;
@@ -468,12 +496,12 @@ cxcursor::getCursorObjCSuperClassRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorObjCProtocolRef(ObjCProtocolDecl *Super,
+CXCursor cxcursor::MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto,
SourceLocation Loc,
CXTranslationUnit TU) {
- assert(Super && TU && "Invalid arguments!");
+ assert(Proto && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCProtocolRef, 0, { Super, RawLoc, TU } };
+ CXCursor C = { CXCursor_ObjCProtocolRef, 0, { (void*)Proto, RawLoc, TU } };
return C;
}
@@ -485,7 +513,7 @@ cxcursor::getCursorObjCProtocolRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class,
+CXCursor cxcursor::MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class,
SourceLocation Loc,
CXTranslationUnit TU) {
// 'Class' can be null for invalid code.
@@ -493,7 +521,7 @@ CXCursor cxcursor::MakeCursorObjCClassRef(ObjCInterfaceDecl *Class,
return MakeCXCursorInvalid(CXCursor_InvalidCode);
assert(TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_ObjCClassRef, 0, { Class, RawLoc, TU } };
+ CXCursor C = { CXCursor_ObjCClassRef, 0, { (void*)Class, RawLoc, TU } };
return C;
}
@@ -505,11 +533,11 @@ cxcursor::getCursorObjCClassRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc,
+CXCursor cxcursor::MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc,
CXTranslationUnit TU) {
assert(Type && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_TypeRef, 0, { Type, RawLoc, TU } };
+ CXCursor C = { CXCursor_TypeRef, 0, { (void*)Type, RawLoc, TU } };
return C;
}
@@ -521,12 +549,12 @@ cxcursor::getCursorTypeRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorTemplateRef(TemplateDecl *Template,
+CXCursor cxcursor::MakeCursorTemplateRef(const TemplateDecl *Template,
SourceLocation Loc,
CXTranslationUnit TU) {
assert(Template && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_TemplateRef, 0, { Template, RawLoc, TU } };
+ CXCursor C = { CXCursor_TemplateRef, 0, { (void*)Template, RawLoc, TU } };
return C;
}
@@ -538,13 +566,14 @@ cxcursor::getCursorTemplateRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorNamespaceRef(NamedDecl *NS, SourceLocation Loc,
+CXCursor cxcursor::MakeCursorNamespaceRef(const NamedDecl *NS,
+ SourceLocation Loc,
CXTranslationUnit TU) {
assert(NS && (isa<NamespaceDecl>(NS) || isa<NamespaceAliasDecl>(NS)) && TU &&
"Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_NamespaceRef, 0, { NS, RawLoc, TU } };
+ CXCursor C = { CXCursor_NamespaceRef, 0, { (void*)NS, RawLoc, TU } };
return C;
}
@@ -556,12 +585,29 @@ cxcursor::getCursorNamespaceRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorMemberRef(FieldDecl *Field, SourceLocation Loc,
+CXCursor cxcursor::MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc,
+ CXTranslationUnit TU) {
+
+ assert(Var && TU && "Invalid arguments!");
+ void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
+ CXCursor C = { CXCursor_VariableRef, 0, { (void*)Var, RawLoc, TU } };
+ return C;
+}
+
+std::pair<VarDecl *, SourceLocation>
+cxcursor::getCursorVariableRef(CXCursor C) {
+ assert(C.kind == CXCursor_VariableRef);
+ return std::make_pair(static_cast<VarDecl *>(C.data[0]),
+ SourceLocation::getFromRawEncoding(
+ reinterpret_cast<uintptr_t>(C.data[1])));
+}
+
+CXCursor cxcursor::MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc,
CXTranslationUnit TU) {
assert(Field && TU && "Invalid arguments!");
void *RawLoc = reinterpret_cast<void *>(Loc.getRawEncoding());
- CXCursor C = { CXCursor_MemberRef, 0, { Field, RawLoc, TU } };
+ CXCursor C = { CXCursor_MemberRef, 0, { (void*)Field, RawLoc, TU } };
return C;
}
@@ -573,9 +619,9 @@ cxcursor::getCursorMemberRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1])));
}
-CXCursor cxcursor::MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B,
+CXCursor cxcursor::MakeCursorCXXBaseSpecifier(const CXXBaseSpecifier *B,
CXTranslationUnit TU){
- CXCursor C = { CXCursor_CXXBaseSpecifier, 0, { B, 0, TU } };
+ CXCursor C = { CXCursor_CXXBaseSpecifier, 0, { (void*)B, 0, TU } };
return C;
}
@@ -730,30 +776,47 @@ ASTContext &cxcursor::getCursorContext(CXCursor Cursor) {
}
ASTUnit *cxcursor::getCursorASTUnit(CXCursor Cursor) {
- return static_cast<ASTUnit *>(static_cast<CXTranslationUnit>(Cursor.data[2])
- ->TUData);
+ CXTranslationUnit TU = static_cast<CXTranslationUnit>(Cursor.data[2]);
+ if (!TU)
+ return 0;
+ return static_cast<ASTUnit *>(TU->TUData);
}
CXTranslationUnit cxcursor::getCursorTU(CXCursor Cursor) {
return static_cast<CXTranslationUnit>(Cursor.data[2]);
}
-static void CollectOverriddenMethods(CXTranslationUnit TU,
- DeclContext *Ctx,
+static void CollectOverriddenMethodsRecurse(CXTranslationUnit TU,
+ ObjCContainerDecl *Container,
ObjCMethodDecl *Method,
- SmallVectorImpl<CXCursor> &Methods) {
- if (!Ctx)
+ SmallVectorImpl<CXCursor> &Methods,
+ bool MovedToSuper) {
+ if (!Container)
return;
- // If we have a class or category implementation, jump straight to the
- // interface.
- if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(Ctx))
- return CollectOverriddenMethods(TU, Impl->getClassInterface(),
- Method, Methods);
-
- ObjCContainerDecl *Container = dyn_cast<ObjCContainerDecl>(Ctx);
- if (!Container)
+ // In categories look for overriden methods from protocols. A method from
+ // category is not "overriden" since it is considered as the "same" method
+ // (same USR) as the one from the interface.
+ if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
+ // Check whether we have a matching method at this category but only if we
+ // are at the super class level.
+ if (MovedToSuper)
+ if (ObjCMethodDecl *
+ Overridden = Container->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ if (Method != Overridden) {
+ // We found an override at this category; there is no need to look
+ // into its protocols.
+ Methods.push_back(MakeCXCursor(Overridden, TU));
+ return;
+ }
+
+ for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
+ PEnd = Category->protocol_end();
+ P != PEnd; ++P)
+ CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
return;
+ }
// Check whether we have a matching method at this level.
if (ObjCMethodDecl *Overridden = Container->getMethod(Method->getSelector(),
@@ -769,38 +832,37 @@ static void CollectOverriddenMethods(CXTranslationUnit TU,
for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(),
PEnd = Protocol->protocol_end();
P != PEnd; ++P)
- CollectOverriddenMethods(TU, *P, Method, Methods);
- }
-
- if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) {
- for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(),
- PEnd = Category->protocol_end();
- P != PEnd; ++P)
- CollectOverriddenMethods(TU, *P, Method, Methods);
+ CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
}
if (ObjCInterfaceDecl *Interface = dyn_cast<ObjCInterfaceDecl>(Container)) {
for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(),
PEnd = Interface->protocol_end();
P != PEnd; ++P)
- CollectOverriddenMethods(TU, *P, Method, Methods);
+ CollectOverriddenMethodsRecurse(TU, *P, Method, Methods, MovedToSuper);
for (ObjCCategoryDecl *Category = Interface->getCategoryList();
Category; Category = Category->getNextClassCategory())
- CollectOverriddenMethods(TU, Category, Method, Methods);
+ CollectOverriddenMethodsRecurse(TU, Category, Method, Methods,
+ MovedToSuper);
- // We only look into the superclass if we haven't found anything yet.
- if (Methods.empty())
- if (ObjCInterfaceDecl *Super = Interface->getSuperClass())
- return CollectOverriddenMethods(TU, Super, Method, Methods);
+ if (ObjCInterfaceDecl *Super = Interface->getSuperClass())
+ return CollectOverriddenMethodsRecurse(TU, Super, Method, Methods,
+ /*MovedToSuper=*/true);
}
}
+static inline void CollectOverriddenMethods(CXTranslationUnit TU,
+ ObjCContainerDecl *Container,
+ ObjCMethodDecl *Method,
+ SmallVectorImpl<CXCursor> &Methods) {
+ CollectOverriddenMethodsRecurse(TU, Container, Method, Methods,
+ /*MovedToSuper=*/false);
+}
+
void cxcursor::getOverriddenCursors(CXCursor cursor,
SmallVectorImpl<CXCursor> &overridden) {
- if (!clang_isDeclaration(cursor.kind))
- return;
-
+ assert(clang_isDeclaration(cursor.kind));
Decl *D = getCursorDecl(cursor);
if (!D)
return;
@@ -820,8 +882,39 @@ void cxcursor::getOverriddenCursors(CXCursor cursor,
if (!Method)
return;
- // Handle Objective-C methods.
- CollectOverriddenMethods(TU, Method->getDeclContext(), Method, overridden);
+ if (ObjCProtocolDecl *
+ ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) {
+ CollectOverriddenMethods(TU, ProtD, Method, overridden);
+
+ } else if (ObjCImplDecl *
+ IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) {
+ ObjCInterfaceDecl *ID = IMD->getClassInterface();
+ if (!ID)
+ return;
+ // Start searching for overridden methods using the method from the
+ // interface as starting point.
+ if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ Method = IFaceMeth;
+ CollectOverriddenMethods(TU, ID, Method, overridden);
+
+ } else if (ObjCCategoryDecl *
+ CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) {
+ ObjCInterfaceDecl *ID = CatD->getClassInterface();
+ if (!ID)
+ return;
+ // Start searching for overridden methods using the method from the
+ // interface as starting point.
+ if (ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
+ Method->isInstanceMethod()))
+ Method = IFaceMeth;
+ CollectOverriddenMethods(TU, ID, Method, overridden);
+
+ } else {
+ CollectOverriddenMethods(TU,
+ dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()),
+ Method, overridden);
+ }
}
std::pair<int, SourceLocation>
@@ -931,6 +1024,35 @@ CXTranslationUnit clang_Cursor_getTranslationUnit(CXCursor cursor) {
return getCursorTU(cursor);
}
+int clang_Cursor_getNumArguments(CXCursor C) {
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+ if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
+ return MD->param_size();
+ if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
+ return FD->param_size();
+ }
+
+ return -1;
+}
+
+CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i) {
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+ if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
+ if (i < MD->param_size())
+ return cxcursor::MakeCXCursor(MD->param_begin()[i],
+ cxcursor::getCursorTU(C));
+ } else if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) {
+ if (i < FD->param_size())
+ return cxcursor::MakeCXCursor(FD->param_begin()[i],
+ cxcursor::getCursorTU(C));
+ }
+ }
+
+ return clang_getNullCursor();
+}
+
} // end: extern "C"
//===----------------------------------------------------------------------===//
@@ -1001,33 +1123,28 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
enum CXCursorKind kind = clang_getCursorKind(cursor);
if (clang_isDeclaration(kind)) {
Decl *decl = getCursorDecl(cursor);
- if (isa<NamedDecl>(decl)) {
- NamedDecl *namedDecl = (NamedDecl *)decl;
+ if (NamedDecl *namedDecl = dyn_cast_or_null<NamedDecl>(decl)) {
ASTUnit *unit = getCursorASTUnit(cursor);
- if (unit->hasSema()) {
- Sema &S = unit->getSema();
- CodeCompletionAllocator *Allocator
- = unit->getCursorCompletionAllocator().getPtr();
- CodeCompletionResult Result(namedDecl);
- CodeCompletionString *String
- = Result.CreateCodeCompletionString(S, *Allocator);
- return String;
- }
+ CodeCompletionResult Result(namedDecl);
+ CodeCompletionString *String
+ = Result.CreateCodeCompletionString(unit->getASTContext(),
+ unit->getPreprocessor(),
+ unit->getCodeCompletionTUInfo().getAllocator(),
+ unit->getCodeCompletionTUInfo());
+ return String;
}
}
else if (kind == CXCursor_MacroDefinition) {
MacroDefinition *definition = getCursorMacroDefinition(cursor);
const IdentifierInfo *MacroInfo = definition->getName();
ASTUnit *unit = getCursorASTUnit(cursor);
- if (unit->hasSema()) {
- Sema &S = unit->getSema();
- CodeCompletionAllocator *Allocator
- = unit->getCursorCompletionAllocator().getPtr();
- CodeCompletionResult Result(const_cast<IdentifierInfo *>(MacroInfo));
- CodeCompletionString *String
- = Result.CreateCodeCompletionString(S, *Allocator);
- return String;
- }
+ CodeCompletionResult Result(const_cast<IdentifierInfo *>(MacroInfo));
+ CodeCompletionString *String
+ = Result.CreateCodeCompletionString(unit->getASTContext(),
+ unit->getPreprocessor(),
+ unit->getCodeCompletionTUInfo().getAllocator(),
+ unit->getCodeCompletionTUInfo());
+ return String;
}
return NULL;
}
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index e402d7f970ca..947b0a3eede6 100644
--- a/tools/libclang/CXCursor.h
+++ b/tools/libclang/CXCursor.h
@@ -41,6 +41,7 @@ class Stmt;
class TemplateDecl;
class TemplateName;
class TypeDecl;
+class VarDecl;
namespace cxcursor {
@@ -67,7 +68,8 @@ std::pair<ObjCInterfaceDecl *, SourceLocation>
getCursorObjCSuperClassRef(CXCursor C);
/// \brief Create an Objective-C protocol reference at the given location.
-CXCursor MakeCursorObjCProtocolRef(ObjCProtocolDecl *Proto, SourceLocation Loc,
+CXCursor MakeCursorObjCProtocolRef(const ObjCProtocolDecl *Proto,
+ SourceLocation Loc,
CXTranslationUnit TU);
/// \brief Unpack an ObjCProtocolRef cursor into the protocol it references
@@ -76,7 +78,8 @@ std::pair<ObjCProtocolDecl *, SourceLocation>
getCursorObjCProtocolRef(CXCursor C);
/// \brief Create an Objective-C class reference at the given location.
-CXCursor MakeCursorObjCClassRef(ObjCInterfaceDecl *Class, SourceLocation Loc,
+CXCursor MakeCursorObjCClassRef(const ObjCInterfaceDecl *Class,
+ SourceLocation Loc,
CXTranslationUnit TU);
/// \brief Unpack an ObjCClassRef cursor into the class it references
@@ -85,7 +88,7 @@ std::pair<ObjCInterfaceDecl *, SourceLocation>
getCursorObjCClassRef(CXCursor C);
/// \brief Create a type reference at the given location.
-CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc,
+CXCursor MakeCursorTypeRef(const TypeDecl *Type, SourceLocation Loc,
CXTranslationUnit TU);
/// \brief Unpack a TypeRef cursor into the class it references
@@ -93,7 +96,7 @@ CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc,
std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C);
/// \brief Create a reference to a template at the given location.
-CXCursor MakeCursorTemplateRef(TemplateDecl *Template, SourceLocation Loc,
+CXCursor MakeCursorTemplateRef(const TemplateDecl *Template, SourceLocation Loc,
CXTranslationUnit TU);
/// \brief Unpack a TemplateRef cursor into the template it references and
@@ -102,15 +105,23 @@ 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,
+CXCursor MakeCursorNamespaceRef(const NamedDecl *NS, SourceLocation Loc,
CXTranslationUnit 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 reference to a variable at the given location.
+CXCursor MakeCursorVariableRef(const VarDecl *Var, SourceLocation Loc,
+ CXTranslationUnit TU);
+
+/// \brief Unpack a VariableRef cursor into the variable it references and the
+/// location where the where the reference occurred.
+std::pair<VarDecl *, SourceLocation> getCursorVariableRef(CXCursor C);
+
/// \brief Create a reference to a field at the given location.
-CXCursor MakeCursorMemberRef(FieldDecl *Field, SourceLocation Loc,
+CXCursor MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc,
CXTranslationUnit TU);
/// \brief Unpack a MemberRef cursor into the field it references and the
@@ -118,7 +129,7 @@ CXCursor MakeCursorMemberRef(FieldDecl *Field, SourceLocation Loc,
std::pair<FieldDecl *, SourceLocation> getCursorMemberRef(CXCursor C);
/// \brief Create a CXX base specifier cursor.
-CXCursor MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B,
+CXCursor MakeCursorCXXBaseSpecifier(const CXXBaseSpecifier *B,
CXTranslationUnit TU);
/// \brief Unpack a CXXBaseSpecifier cursor into a CXXBaseSpecifier.
@@ -221,7 +232,7 @@ CXCursor getTypeRefCursor(CXCursor cursor);
/// \brief Generate a USR for \arg D and put it in \arg Buf.
/// \returns true if no USR was computed or the result should be ignored,
/// false otherwise.
-bool getDeclCursorUSR(Decl *D, SmallVectorImpl<char> &Buf);
+bool getDeclCursorUSR(const Decl *D, SmallVectorImpl<char> &Buf);
bool operator==(CXCursor X, CXCursor Y);
diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp
new file mode 100644
index 000000000000..e5b6ccc5b7e8
--- /dev/null
+++ b/tools/libclang/CXLoadedDiagnostic.cpp
@@ -0,0 +1,672 @@
+/*===-- CXLoadedDiagnostic.cpp - Handling of persisent diags -*- C++ -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* Implements handling of persisent diagnostics. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#include "CXLoadedDiagnostic.h"
+#include "CXString.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/SerializedDiagnosticPrinter.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/Optional.h"
+#include "clang/Basic/LLVM.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <assert.h>
+
+using namespace clang;
+using namespace clang::cxstring;
+
+//===----------------------------------------------------------------------===//
+// Extend CXDiagnosticSetImpl which contains strings for diagnostics.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::DenseMap<unsigned, llvm::StringRef> Strings;
+
+namespace {
+class CXLoadedDiagnosticSetImpl : public CXDiagnosticSetImpl {
+public:
+ CXLoadedDiagnosticSetImpl() : CXDiagnosticSetImpl(true), FakeFiles(FO) {}
+ virtual ~CXLoadedDiagnosticSetImpl() {}
+
+ llvm::StringRef makeString(const char *blob, unsigned blobLen);
+
+ llvm::BumpPtrAllocator Alloc;
+ Strings Categories;
+ Strings WarningFlags;
+ Strings FileNames;
+
+ FileSystemOptions FO;
+ FileManager FakeFiles;
+ llvm::DenseMap<unsigned, const FileEntry *> Files;
+};
+}
+
+llvm::StringRef CXLoadedDiagnosticSetImpl::makeString(const char *blob,
+ unsigned bloblen) {
+ char *mem = Alloc.Allocate<char>(bloblen + 1);
+ memcpy(mem, blob, bloblen);
+ // Add a null terminator for those clients accessing the buffer
+ // like a c-string.
+ mem[bloblen] = '\0';
+ return llvm::StringRef(mem, bloblen);
+}
+
+//===----------------------------------------------------------------------===//
+// Cleanup.
+//===----------------------------------------------------------------------===//
+
+CXLoadedDiagnostic::~CXLoadedDiagnostic() {}
+
+//===----------------------------------------------------------------------===//
+// Public CXLoadedDiagnostic methods.
+//===----------------------------------------------------------------------===//
+
+CXDiagnosticSeverity CXLoadedDiagnostic::getSeverity() const {
+ // FIXME: possibly refactor with logic in CXStoredDiagnostic.
+ switch (severity) {
+ case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;
+ case DiagnosticsEngine::Note: return CXDiagnostic_Note;
+ case DiagnosticsEngine::Warning: return CXDiagnostic_Warning;
+ case DiagnosticsEngine::Error: return CXDiagnostic_Error;
+ case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal;
+ }
+
+ llvm_unreachable("Invalid diagnostic level");
+}
+
+static CXSourceLocation makeLocation(const CXLoadedDiagnostic::Location *DLoc) {
+ // The lowest bit of ptr_data[0] is always set to 1 to indicate this
+ // is a persistent diagnostic.
+ uintptr_t V = (uintptr_t) DLoc;
+ V |= 0x1;
+ CXSourceLocation Loc = { { (void*) V, 0 }, 0 };
+ return Loc;
+}
+
+CXSourceLocation CXLoadedDiagnostic::getLocation() const {
+ // The lowest bit of ptr_data[0] is always set to 1 to indicate this
+ // is a persistent diagnostic.
+ return makeLocation(&DiagLoc);
+}
+
+CXString CXLoadedDiagnostic::getSpelling() const {
+ return cxstring::createCXString(Spelling, false);
+}
+
+CXString CXLoadedDiagnostic::getDiagnosticOption(CXString *Disable) const {
+ if (DiagOption.empty())
+ return createCXString("");
+
+ // FIXME: possibly refactor with logic in CXStoredDiagnostic.
+ if (Disable)
+ *Disable = createCXString((Twine("-Wno-") + DiagOption).str());
+ return createCXString((Twine("-W") + DiagOption).str());
+}
+
+unsigned CXLoadedDiagnostic::getCategory() const {
+ return category;
+}
+
+CXString CXLoadedDiagnostic::getCategoryText() const {
+ return cxstring::createCXString(CategoryText);
+}
+
+unsigned CXLoadedDiagnostic::getNumRanges() const {
+ return Ranges.size();
+}
+
+CXSourceRange CXLoadedDiagnostic::getRange(unsigned Range) const {
+ assert(Range < Ranges.size());
+ return Ranges[Range];
+}
+
+unsigned CXLoadedDiagnostic::getNumFixIts() const {
+ return FixIts.size();
+}
+
+CXString CXLoadedDiagnostic::getFixIt(unsigned FixIt,
+ CXSourceRange *ReplacementRange) const {
+ assert(FixIt < FixIts.size());
+ if (ReplacementRange)
+ *ReplacementRange = FixIts[FixIt].first;
+ return FixIts[FixIt].second;
+}
+
+void CXLoadedDiagnostic::decodeLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned int *line,
+ unsigned int *column,
+ unsigned int *offset) {
+
+
+ // CXSourceLocation consists of the following fields:
+ //
+ // void *ptr_data[2];
+ // unsigned int_data;
+ //
+ // The lowest bit of ptr_data[0] is always set to 1 to indicate this
+ // is a persistent diagnostic.
+ //
+ // For now, do the unoptimized approach and store the data in a side
+ // data structure. We can optimize this case later.
+
+ uintptr_t V = (uintptr_t) location.ptr_data[0];
+ assert((V & 0x1) == 1);
+ V &= ~(uintptr_t)1;
+
+ const Location &Loc = *((Location*)V);
+
+ if (file)
+ *file = Loc.file;
+ if (line)
+ *line = Loc.line;
+ if (column)
+ *column = Loc.column;
+ if (offset)
+ *offset = Loc.offset;
+}
+
+//===----------------------------------------------------------------------===//
+// Deserialize diagnostics.
+//===----------------------------------------------------------------------===//
+
+enum { MaxSupportedVersion = 1 };
+typedef SmallVector<uint64_t, 64> RecordData;
+enum LoadResult { Failure = 1, Success = 0 };
+enum StreamResult { Read_EndOfStream,
+ Read_BlockBegin,
+ Read_Failure,
+ Read_Record,
+ Read_BlockEnd };
+
+namespace {
+class DiagLoader {
+ enum CXLoadDiag_Error *error;
+ CXString *errorString;
+
+ void reportBad(enum CXLoadDiag_Error code, llvm::StringRef err) {
+ if (error)
+ *error = code;
+ if (errorString)
+ *errorString = createCXString(err);
+ }
+
+ void reportInvalidFile(llvm::StringRef err) {
+ return reportBad(CXLoadDiag_InvalidFile, err);
+ }
+
+ LoadResult readMetaBlock(llvm::BitstreamCursor &Stream);
+
+ LoadResult readDiagnosticBlock(llvm::BitstreamCursor &Stream,
+ CXDiagnosticSetImpl &Diags,
+ CXLoadedDiagnosticSetImpl &TopDiags);
+
+ StreamResult readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
+ llvm::StringRef errorContext,
+ unsigned &BlockOrRecordID,
+ const bool atTopLevel = false);
+
+
+ LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ Strings &strings, llvm::StringRef errorContext,
+ RecordData &Record,
+ const char *BlobStart,
+ unsigned BlobLen,
+ bool allowEmptyString = false);
+
+ LoadResult readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ llvm::StringRef &RetStr,
+ llvm::StringRef errorContext,
+ RecordData &Record,
+ const char *BlobStart,
+ unsigned BlobLen,
+ bool allowEmptyString = false);
+
+ LoadResult readRange(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record, unsigned RecStartIdx,
+ CXSourceRange &SR);
+
+ LoadResult readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record, unsigned &offset,
+ CXLoadedDiagnostic::Location &Loc);
+
+public:
+ DiagLoader(enum CXLoadDiag_Error *e, CXString *es)
+ : error(e), errorString(es) {
+ if (error)
+ *error = CXLoadDiag_None;
+ if (errorString)
+ *errorString = createCXString("");
+ }
+
+ CXDiagnosticSet load(const char *file);
+};
+}
+
+CXDiagnosticSet DiagLoader::load(const char *file) {
+ // Open the diagnostics file.
+ std::string ErrStr;
+ FileSystemOptions FO;
+ FileManager FileMgr(FO);
+
+ OwningPtr<llvm::MemoryBuffer> Buffer;
+ Buffer.reset(FileMgr.getBufferForFile(file));
+
+ if (!Buffer) {
+ reportBad(CXLoadDiag_CannotLoad, ErrStr);
+ return 0;
+ }
+
+ llvm::BitstreamReader StreamFile;
+ StreamFile.init((const unsigned char *)Buffer->getBufferStart(),
+ (const unsigned char *)Buffer->getBufferEnd());
+
+ llvm::BitstreamCursor Stream;
+ Stream.init(StreamFile);
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'D' ||
+ Stream.Read(8) != 'I' ||
+ Stream.Read(8) != 'A' ||
+ Stream.Read(8) != 'G') {
+ reportBad(CXLoadDiag_InvalidFile,
+ "Bad header in diagnostics file");
+ return 0;
+ }
+
+ OwningPtr<CXLoadedDiagnosticSetImpl>
+ Diags(new CXLoadedDiagnosticSetImpl());
+
+ while (true) {
+ unsigned BlockID = 0;
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Top-level",
+ BlockID, true);
+ switch (Res) {
+ case Read_EndOfStream:
+ return (CXDiagnosticSet) Diags.take();
+ case Read_Failure:
+ return 0;
+ case Read_Record:
+ llvm_unreachable("Top-level does not have records");
+ case Read_BlockEnd:
+ continue;
+ case Read_BlockBegin:
+ break;
+ }
+
+ switch (BlockID) {
+ case serialized_diags::BLOCK_META:
+ if (readMetaBlock(Stream))
+ return 0;
+ break;
+ case serialized_diags::BLOCK_DIAG:
+ if (readDiagnosticBlock(Stream, *Diags.get(), *Diags.get()))
+ return 0;
+ break;
+ default:
+ if (!Stream.SkipBlock()) {
+ reportInvalidFile("Malformed block at top-level of diagnostics file");
+ return 0;
+ }
+ break;
+ }
+ }
+}
+
+StreamResult DiagLoader::readToNextRecordOrBlock(llvm::BitstreamCursor &Stream,
+ llvm::StringRef errorContext,
+ unsigned &blockOrRecordID,
+ const bool atTopLevel) {
+
+ blockOrRecordID = 0;
+
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ // Handle the top-level specially.
+ if (atTopLevel) {
+ if (Code == llvm::bitc::ENTER_SUBBLOCK) {
+ unsigned BlockID = Stream.ReadSubBlockID();
+ if (BlockID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
+ if (Stream.ReadBlockInfoBlock()) {
+ reportInvalidFile("Malformed BlockInfoBlock in diagnostics file");
+ return Read_Failure;
+ }
+ continue;
+ }
+ blockOrRecordID = BlockID;
+ return Read_BlockBegin;
+ }
+ reportInvalidFile("Only blocks can appear at the top of a "
+ "diagnostic file");
+ return Read_Failure;
+ }
+
+ switch ((llvm::bitc::FixedAbbrevIDs)Code) {
+ case llvm::bitc::ENTER_SUBBLOCK:
+ blockOrRecordID = Stream.ReadSubBlockID();
+ return Read_BlockBegin;
+
+ case llvm::bitc::END_BLOCK:
+ if (Stream.ReadBlockEnd()) {
+ reportInvalidFile("Cannot read end of block");
+ return Read_Failure;
+ }
+ return Read_BlockEnd;
+
+ case llvm::bitc::DEFINE_ABBREV:
+ Stream.ReadAbbrevRecord();
+ continue;
+
+ case llvm::bitc::UNABBREV_RECORD:
+ reportInvalidFile("Diagnostics file should have no unabbreviated "
+ "records");
+ return Read_Failure;
+
+ default:
+ // We found a record.
+ blockOrRecordID = Code;
+ return Read_Record;
+ }
+ }
+
+ if (atTopLevel)
+ return Read_EndOfStream;
+
+ reportInvalidFile(Twine("Premature end of diagnostics file within ").str() +
+ errorContext.str());
+ return Read_Failure;
+}
+
+LoadResult DiagLoader::readMetaBlock(llvm::BitstreamCursor &Stream) {
+ if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_META)) {
+ reportInvalidFile("Malformed metadata block");
+ return Failure;
+ }
+
+ bool versionChecked = false;
+
+ while (true) {
+ unsigned blockOrCode = 0;
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Metadata Block",
+ blockOrCode);
+
+ switch(Res) {
+ case Read_EndOfStream:
+ llvm_unreachable("EndOfStream handled by readToNextRecordOrBlock");
+ case Read_Failure:
+ return Failure;
+ case Read_Record:
+ break;
+ case Read_BlockBegin:
+ if (Stream.SkipBlock()) {
+ reportInvalidFile("Malformed metadata block");
+ return Failure;
+ }
+ case Read_BlockEnd:
+ if (!versionChecked) {
+ reportInvalidFile("Diagnostics file does not contain version"
+ " information");
+ return Failure;
+ }
+ return Success;
+ }
+
+ RecordData Record;
+ const char *Blob;
+ unsigned BlobLen;
+ unsigned recordID = Stream.ReadRecord(blockOrCode, Record, &Blob, &BlobLen);
+
+ if (recordID == serialized_diags::RECORD_VERSION) {
+ if (Record.size() < 1) {
+ reportInvalidFile("malformed VERSION identifier in diagnostics file");
+ return Failure;
+ }
+ if (Record[0] > MaxSupportedVersion) {
+ reportInvalidFile("diagnosics file is a newer version than the one "
+ "supported");
+ return Failure;
+ }
+ versionChecked = true;
+ }
+ }
+}
+
+LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ llvm::StringRef &RetStr,
+ llvm::StringRef errorContext,
+ RecordData &Record,
+ const char *BlobStart,
+ unsigned BlobLen,
+ bool allowEmptyString) {
+
+ // Basic buffer overflow check.
+ if (BlobLen > 65536) {
+ reportInvalidFile(std::string("Out-of-bounds string in ") +
+ std::string(errorContext));
+ return Failure;
+ }
+
+ if (allowEmptyString && Record.size() >= 1 && BlobLen == 0) {
+ RetStr = "";
+ return Success;
+ }
+
+ if (Record.size() < 1 || BlobLen == 0) {
+ reportInvalidFile(std::string("Corrupted ") + std::string(errorContext)
+ + std::string(" entry"));
+ return Failure;
+ }
+
+ RetStr = TopDiags.makeString(BlobStart, BlobLen);
+ return Success;
+}
+
+LoadResult DiagLoader::readString(CXLoadedDiagnosticSetImpl &TopDiags,
+ Strings &strings,
+ llvm::StringRef errorContext,
+ RecordData &Record,
+ const char *BlobStart,
+ unsigned BlobLen,
+ bool allowEmptyString) {
+ llvm::StringRef RetStr;
+ if (readString(TopDiags, RetStr, errorContext, Record, BlobStart, BlobLen,
+ allowEmptyString))
+ return Failure;
+ strings[Record[0]] = RetStr;
+ return Success;
+}
+
+LoadResult DiagLoader::readLocation(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record, unsigned &offset,
+ CXLoadedDiagnostic::Location &Loc) {
+ if (Record.size() < offset + 3) {
+ reportInvalidFile("Corrupted source location");
+ return Failure;
+ }
+
+ unsigned fileID = Record[offset++];
+ if (fileID == 0) {
+ // Sentinel value.
+ Loc.file = 0;
+ Loc.line = 0;
+ Loc.column = 0;
+ Loc.offset = 0;
+ return Success;
+ }
+
+ const FileEntry *FE = TopDiags.Files[fileID];
+ if (!FE) {
+ reportInvalidFile("Corrupted file entry in source location");
+ return Failure;
+ }
+ Loc.file = (void*) FE;
+ Loc.line = Record[offset++];
+ Loc.column = Record[offset++];
+ Loc.offset = Record[offset++];
+ return Success;
+}
+
+LoadResult DiagLoader::readRange(CXLoadedDiagnosticSetImpl &TopDiags,
+ RecordData &Record,
+ unsigned int RecStartIdx,
+ CXSourceRange &SR) {
+ CXLoadedDiagnostic::Location *Start, *End;
+ Start = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
+ End = TopDiags.Alloc.Allocate<CXLoadedDiagnostic::Location>();
+
+ if (readLocation(TopDiags, Record, RecStartIdx, *Start))
+ return Failure;
+ if (readLocation(TopDiags, Record, RecStartIdx, *End))
+ return Failure;
+
+ CXSourceLocation startLoc = makeLocation(Start);
+ CXSourceLocation endLoc = makeLocation(End);
+ SR = clang_getRange(startLoc, endLoc);
+ return Success;
+}
+
+LoadResult DiagLoader::readDiagnosticBlock(llvm::BitstreamCursor &Stream,
+ CXDiagnosticSetImpl &Diags,
+ CXLoadedDiagnosticSetImpl &TopDiags){
+
+ if (Stream.EnterSubBlock(clang::serialized_diags::BLOCK_DIAG)) {
+ reportInvalidFile("malformed diagnostic block");
+ return Failure;
+ }
+
+ OwningPtr<CXLoadedDiagnostic> D(new CXLoadedDiagnostic());
+ RecordData Record;
+
+ while (true) {
+ unsigned blockOrCode = 0;
+ StreamResult Res = readToNextRecordOrBlock(Stream, "Diagnostic Block",
+ blockOrCode);
+ switch (Res) {
+ case Read_EndOfStream:
+ llvm_unreachable("EndOfStream handled in readToNextRecordOrBlock");
+ case Read_Failure:
+ return Failure;
+ case Read_BlockBegin: {
+ // The only blocks we care about are subdiagnostics.
+ if (blockOrCode != serialized_diags::BLOCK_DIAG) {
+ if (!Stream.SkipBlock()) {
+ reportInvalidFile("Invalid subblock in Diagnostics block");
+ return Failure;
+ }
+ } else if (readDiagnosticBlock(Stream, D->getChildDiagnostics(),
+ TopDiags)) {
+ return Failure;
+ }
+
+ continue;
+ }
+ case Read_BlockEnd:
+ Diags.appendDiagnostic(D.take());
+ return Success;
+ case Read_Record:
+ break;
+ }
+
+ // Read the record.
+ Record.clear();
+ const char *BlobStart = 0;
+ unsigned BlobLen = 0;
+ unsigned recID = Stream.ReadRecord(blockOrCode, Record,
+ BlobStart, BlobLen);
+
+ if (recID < serialized_diags::RECORD_FIRST ||
+ recID > serialized_diags::RECORD_LAST)
+ continue;
+
+ switch ((serialized_diags::RecordIDs)recID) {
+ case serialized_diags::RECORD_VERSION:
+ continue;
+ case serialized_diags::RECORD_CATEGORY:
+ if (readString(TopDiags, TopDiags.Categories, "category", Record,
+ BlobStart, BlobLen,
+ /* allowEmptyString */ true))
+ return Failure;
+ continue;
+
+ case serialized_diags::RECORD_DIAG_FLAG:
+ if (readString(TopDiags, TopDiags.WarningFlags, "warning flag", Record,
+ BlobStart, BlobLen))
+ return Failure;
+ continue;
+
+ case serialized_diags::RECORD_FILENAME: {
+ if (readString(TopDiags, TopDiags.FileNames, "filename", Record,
+ BlobStart, BlobLen))
+ return Failure;
+
+ if (Record.size() < 3) {
+ reportInvalidFile("Invalid file entry");
+ return Failure;
+ }
+
+ const FileEntry *FE =
+ TopDiags.FakeFiles.getVirtualFile(TopDiags.FileNames[Record[0]],
+ /* size */ Record[1],
+ /* time */ Record[2]);
+
+ TopDiags.Files[Record[0]] = FE;
+ continue;
+ }
+
+ case serialized_diags::RECORD_SOURCE_RANGE: {
+ CXSourceRange SR;
+ if (readRange(TopDiags, Record, 0, SR))
+ return Failure;
+ D->Ranges.push_back(SR);
+ continue;
+ }
+
+ case serialized_diags::RECORD_FIXIT: {
+ CXSourceRange SR;
+ if (readRange(TopDiags, Record, 0, SR))
+ return Failure;
+ llvm::StringRef RetStr;
+ if (readString(TopDiags, RetStr, "FIXIT", Record, BlobStart, BlobLen,
+ /* allowEmptyString */ true))
+ return Failure;
+ D->FixIts.push_back(std::make_pair(SR, createCXString(RetStr, false)));
+ continue;
+ }
+
+ case serialized_diags::RECORD_DIAG: {
+ D->severity = Record[0];
+ unsigned offset = 1;
+ if (readLocation(TopDiags, Record, offset, D->DiagLoc))
+ return Failure;
+ D->category = Record[offset++];
+ unsigned diagFlag = Record[offset++];
+ D->DiagOption = diagFlag ? TopDiags.WarningFlags[diagFlag] : "";
+ D->CategoryText = D->category ? TopDiags.Categories[D->category] : "";
+ D->Spelling = TopDiags.makeString(BlobStart, BlobLen);
+ continue;
+ }
+ }
+ }
+}
+
+extern "C" {
+CXDiagnosticSet clang_loadDiagnostics(const char *file,
+ enum CXLoadDiag_Error *error,
+ CXString *errorString) {
+ DiagLoader L(error, errorString);
+ return L.load(file);
+}
+} // end extern 'C'.
diff --git a/tools/libclang/CXLoadedDiagnostic.h b/tools/libclang/CXLoadedDiagnostic.h
new file mode 100644
index 000000000000..d4a321e0e1cd
--- /dev/null
+++ b/tools/libclang/CXLoadedDiagnostic.h
@@ -0,0 +1,94 @@
+/*===-- CXLoadedDiagnostic.h - Handling of persisent diags ------*- C++ -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* Implements handling of persisent diagnostics. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_CLANG_CINDEX_LOADED_DIAGNOSTIC_H
+#define LLVM_CLANG_CINDEX_LOADED_DIAGNOSTIC_H
+
+#include "CIndexDiagnostic.h"
+#include "llvm/ADT/StringRef.h"
+#include "clang/Basic/LLVM.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+class CXLoadedDiagnostic : public CXDiagnosticImpl {
+public:
+ CXLoadedDiagnostic() : CXDiagnosticImpl(LoadedDiagnosticKind),
+ severity(0), category(0) {}
+
+ virtual ~CXLoadedDiagnostic();
+
+ /// \brief Return the severity of the diagnostic.
+ virtual CXDiagnosticSeverity getSeverity() const;
+
+ /// \brief Return the location of the diagnostic.
+ virtual CXSourceLocation getLocation() const;
+
+ /// \brief Return the spelling of the diagnostic.
+ virtual CXString getSpelling() const;
+
+ /// \brief Return the text for the diagnostic option.
+ virtual CXString getDiagnosticOption(CXString *Disable) const;
+
+ /// \brief Return the category of the diagnostic.
+ virtual unsigned getCategory() const;
+
+ /// \brief Return the category string of the diagnostic.
+ virtual CXString getCategoryText() const;
+
+ /// \brief Return the number of source ranges for the diagnostic.
+ virtual unsigned getNumRanges() const;
+
+ /// \brief Return the source ranges for the diagnostic.
+ virtual CXSourceRange getRange(unsigned Range) const;
+
+ /// \brief Return the number of FixIts.
+ virtual unsigned getNumFixIts() const;
+
+ /// \brief Return the FixIt information (source range and inserted text).
+ virtual CXString getFixIt(unsigned FixIt,
+ CXSourceRange *ReplacementRange) const;
+
+ static bool classof(const CXDiagnosticImpl *D) {
+ return D->getKind() == LoadedDiagnosticKind;
+ }
+
+ /// \brief Decode the CXSourceLocation into file, line, column, and offset.
+ static void decodeLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset);
+
+ struct Location {
+ CXFile file;
+ unsigned line;
+ unsigned column;
+ unsigned offset;
+
+ Location() : line(0), column(0), offset(0) {}
+ };
+
+ Location DiagLoc;
+
+ std::vector<CXSourceRange> Ranges;
+ std::vector<std::pair<CXSourceRange, CXString> > FixIts;
+ llvm::StringRef Spelling;
+ llvm::StringRef DiagOption;
+ llvm::StringRef CategoryText;
+ unsigned severity;
+ unsigned category;
+};
+}
+
+#endif
diff --git a/tools/libclang/CXSourceLocation.cpp b/tools/libclang/CXSourceLocation.cpp
new file mode 100644
index 000000000000..a6bf8fcf1cc1
--- /dev/null
+++ b/tools/libclang/CXSourceLocation.cpp
@@ -0,0 +1,326 @@
+//===- CXSourceLocation.cpp - CXSourceLocations APIs ------------*- C++ -*-===//
+//
+// 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 CXSourceLocations.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/ASTUnit.h"
+
+#include "CIndexer.h"
+#include "CXString.h"
+#include "CXSourceLocation.h"
+#include "CXTranslationUnit.h"
+#include "CXLoadedDiagnostic.h"
+
+using namespace clang;
+using namespace clang::cxstring;
+
+//===----------------------------------------------------------------------===//
+// Internal predicates on CXSourceLocations.
+//===----------------------------------------------------------------------===//
+
+static bool isASTUnitSourceLocation(const CXSourceLocation &L) {
+ // If the lowest bit is clear then the first ptr_data entry is a SourceManager
+ // pointer, or the CXSourceLocation is a null location.
+ return ((uintptr_t)L.ptr_data[0] & 0x1) == 0;
+}
+
+//===----------------------------------------------------------------------===//
+// Basic construction and comparison of CXSourceLocations and CXSourceRanges.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+CXSourceLocation clang_getNullLocation() {
+ CXSourceLocation Result = { { 0, 0 }, 0 };
+ return Result;
+}
+
+unsigned clang_equalLocations(CXSourceLocation loc1, CXSourceLocation loc2) {
+ return (loc1.ptr_data[0] == loc2.ptr_data[0] &&
+ loc1.ptr_data[1] == loc2.ptr_data[1] &&
+ loc1.int_data == loc2.int_data);
+}
+
+CXSourceRange clang_getNullRange() {
+ CXSourceRange Result = { { 0, 0 }, 0, 0 };
+ return Result;
+}
+
+CXSourceRange clang_getRange(CXSourceLocation begin, CXSourceLocation end) {
+ if (!isASTUnitSourceLocation(begin)) {
+ if (isASTUnitSourceLocation(end))
+ return clang_getNullRange();
+ CXSourceRange Result = { { begin.ptr_data[0], end.ptr_data[0] }, 0, 0 };
+ return Result;
+ }
+
+ if (begin.ptr_data[0] != end.ptr_data[0] ||
+ begin.ptr_data[1] != end.ptr_data[1])
+ return clang_getNullRange();
+
+ CXSourceRange Result = { { begin.ptr_data[0], begin.ptr_data[1] },
+ begin.int_data, end.int_data };
+
+ return Result;
+}
+
+unsigned clang_equalRanges(CXSourceRange range1, CXSourceRange range2) {
+ return range1.ptr_data[0] == range2.ptr_data[0]
+ && range1.ptr_data[1] == range2.ptr_data[1]
+ && range1.begin_int_data == range2.begin_int_data
+ && range1.end_int_data == range2.end_int_data;
+}
+
+int clang_Range_isNull(CXSourceRange range) {
+ return clang_equalRanges(range, clang_getNullRange());
+}
+
+
+CXSourceLocation clang_getRangeStart(CXSourceRange range) {
+ // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
+ if ((uintptr_t)range.ptr_data[0] & 0x1) {
+ CXSourceLocation Result = { { range.ptr_data[0], 0 }, 0 };
+ return Result;
+ }
+
+ CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
+ range.begin_int_data };
+ return Result;
+}
+
+CXSourceLocation clang_getRangeEnd(CXSourceRange range) {
+ // Special decoding for CXSourceLocations for CXLoadedDiagnostics.
+ if ((uintptr_t)range.ptr_data[0] & 0x1) {
+ CXSourceLocation Result = { { range.ptr_data[1], 0 }, 0 };
+ return Result;
+ }
+
+ CXSourceLocation Result = { { range.ptr_data[0], range.ptr_data[1] },
+ range.end_int_data };
+ return Result;
+}
+
+} // end extern "C"
+
+//===----------------------------------------------------------------------===//
+// Getting CXSourceLocations and CXSourceRanges from a translation unit.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+CXSourceLocation clang_getLocation(CXTranslationUnit tu,
+ CXFile file,
+ unsigned line,
+ unsigned column) {
+ if (!tu || !file)
+ return clang_getNullLocation();
+
+ bool Logging = ::getenv("LIBCLANG_LOGGING");
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+ ASTUnit::ConcurrencyCheck Check(*CXXUnit);
+ const FileEntry *File = static_cast<const FileEntry *>(file);
+ SourceLocation SLoc = CXXUnit->getLocation(File, line, column);
+ if (SLoc.isInvalid()) {
+ if (Logging)
+ llvm::errs() << "clang_getLocation(\"" << File->getName()
+ << "\", " << line << ", " << column << ") = invalid\n";
+ return clang_getNullLocation();
+ }
+
+ if (Logging)
+ llvm::errs() << "clang_getLocation(\"" << File->getName()
+ << "\", " << line << ", " << column << ") = "
+ << SLoc.getRawEncoding() << "\n";
+
+ return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
+}
+
+CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu,
+ CXFile file,
+ unsigned offset) {
+ if (!tu || !file)
+ return clang_getNullLocation();
+
+ ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData);
+
+ SourceLocation SLoc
+ = CXXUnit->getLocation(static_cast<const FileEntry *>(file), offset);
+
+ if (SLoc.isInvalid())
+ return clang_getNullLocation();
+
+ return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);
+}
+
+} // end extern "C"
+
+//===----------------------------------------------------------------------===//
+// Routines for expanding and manipulating CXSourceLocations, regardless
+// of their origin.
+//===----------------------------------------------------------------------===//
+
+static void createNullLocation(CXFile *file, unsigned *line,
+ unsigned *column, unsigned *offset) {
+ if (file)
+ *file = 0;
+ if (line)
+ *line = 0;
+ if (column)
+ *column = 0;
+ if (offset)
+ *offset = 0;
+ return;
+}
+
+static void createNullLocation(CXString *filename, unsigned *line,
+ unsigned *column, unsigned *offset = 0) {
+ if (filename)
+ *filename = createCXString("");
+ if (line)
+ *line = 0;
+ if (column)
+ *column = 0;
+ if (offset)
+ *offset = 0;
+ return;
+}
+
+extern "C" {
+
+void clang_getExpansionLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset) {
+
+ if (!isASTUnitSourceLocation(location)) {
+ CXLoadedDiagnostic::decodeLocation(location, file, line, column, offset);
+ return;
+ }
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+
+ if (!location.ptr_data[0] || Loc.isInvalid()) {
+ createNullLocation(file, line, column, offset);
+ return;
+ }
+
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
+ SourceLocation ExpansionLoc = SM.getExpansionLoc(Loc);
+
+ // Check that the FileID is invalid on the expansion location.
+ // This can manifest in invalid code.
+ FileID fileID = SM.getFileID(ExpansionLoc);
+ bool Invalid = false;
+ const SrcMgr::SLocEntry &sloc = SM.getSLocEntry(fileID, &Invalid);
+ if (Invalid || !sloc.isFile()) {
+ createNullLocation(file, line, column, offset);
+ return;
+ }
+
+ if (file)
+ *file = (void *)SM.getFileEntryForSLocEntry(sloc);
+ if (line)
+ *line = SM.getExpansionLineNumber(ExpansionLoc);
+ if (column)
+ *column = SM.getExpansionColumnNumber(ExpansionLoc);
+ if (offset)
+ *offset = SM.getDecomposedLoc(ExpansionLoc).second;
+}
+
+void clang_getPresumedLocation(CXSourceLocation location,
+ CXString *filename,
+ unsigned *line,
+ unsigned *column) {
+
+ if (!isASTUnitSourceLocation(location)) {
+ // Other SourceLocation implementations do not support presumed locations
+ // at this time.
+ createNullLocation(filename, line, column);
+ return;
+ }
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+
+ if (!location.ptr_data[0] || Loc.isInvalid())
+ createNullLocation(filename, line, column);
+ else {
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
+ PresumedLoc PreLoc = SM.getPresumedLoc(Loc);
+
+ if (filename)
+ *filename = createCXString(PreLoc.getFilename());
+ if (line)
+ *line = PreLoc.getLine();
+ if (column)
+ *column = PreLoc.getColumn();
+ }
+}
+
+void clang_getInstantiationLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset) {
+ // Redirect to new API.
+ clang_getExpansionLocation(location, file, line, column, offset);
+}
+
+void clang_getSpellingLocation(CXSourceLocation location,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset) {
+
+ if (!isASTUnitSourceLocation(location)) {
+ CXLoadedDiagnostic::decodeLocation(location, file, line,
+ column, offset);
+ return;
+ }
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+
+ if (!location.ptr_data[0] || Loc.isInvalid())
+ return createNullLocation(file, line, column, offset);
+
+ const SourceManager &SM =
+ *static_cast<const SourceManager*>(location.ptr_data[0]);
+ SourceLocation SpellLoc = Loc;
+ if (SpellLoc.isMacroID()) {
+ SourceLocation SimpleSpellingLoc = SM.getImmediateSpellingLoc(SpellLoc);
+ if (SimpleSpellingLoc.isFileID() &&
+ SM.getFileEntryForID(SM.getDecomposedLoc(SimpleSpellingLoc).first))
+ SpellLoc = SimpleSpellingLoc;
+ else
+ SpellLoc = SM.getExpansionLoc(SpellLoc);
+ }
+
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SpellLoc);
+ FileID FID = LocInfo.first;
+ unsigned FileOffset = LocInfo.second;
+
+ if (FID.isInvalid())
+ return createNullLocation(file, line, column, offset);
+
+ if (file)
+ *file = (void *)SM.getFileEntryForID(FID);
+ if (line)
+ *line = SM.getLineNumber(FID, FileOffset);
+ if (column)
+ *column = SM.getColumnNumber(FID, FileOffset);
+ if (offset)
+ *offset = FileOffset;
+}
+
+} // end extern "C"
+
diff --git a/tools/libclang/CXSourceLocation.h b/tools/libclang/CXSourceLocation.h
index 7a502059634a..6c5e858aaae7 100644
--- a/tools/libclang/CXSourceLocation.h
+++ b/tools/libclang/CXSourceLocation.h
@@ -41,7 +41,7 @@ translateSourceLocation(const SourceManager &SM, const LangOptions &LangOpts,
static inline CXSourceLocation translateSourceLocation(ASTContext &Context,
SourceLocation Loc) {
return translateSourceLocation(Context.getSourceManager(),
- Context.getLangOptions(),
+ Context.getLangOpts(),
Loc);
}
@@ -59,7 +59,7 @@ CXSourceRange translateSourceRange(const SourceManager &SM,
static inline CXSourceRange translateSourceRange(ASTContext &Context,
SourceRange R) {
return translateSourceRange(Context.getSourceManager(),
- Context.getLangOptions(),
+ Context.getLangOpts(),
CharSourceRange::getTokenRange(R));
}
diff --git a/tools/libclang/CXStoredDiagnostic.cpp b/tools/libclang/CXStoredDiagnostic.cpp
new file mode 100644
index 000000000000..8284dc96180b
--- /dev/null
+++ b/tools/libclang/CXStoredDiagnostic.cpp
@@ -0,0 +1,119 @@
+/*===-- CXStoreDiagnostic.cpp - Diagnostics C Interface ----------*- C++ -*-===*\
+|* *|
+|* The LLVM Compiler Infrastructure *|
+|* *|
+|* This file is distributed under the University of Illinois Open Source *|
+|* License. See LICENSE.TXT for details. *|
+|* *|
+|*===----------------------------------------------------------------------===*|
+|* *|
+|* Implements part of the diagnostic functions of the Clang C interface. *|
+|* *|
+\*===----------------------------------------------------------------------===*/
+
+#include "CIndexDiagnostic.h"
+#include "CIndexer.h"
+#include "CXTranslationUnit.h"
+#include "CXSourceLocation.h"
+#include "CXString.h"
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::cxloc;
+using namespace clang::cxstring;
+
+CXDiagnosticSeverity CXStoredDiagnostic::getSeverity() const {
+ switch (Diag.getLevel()) {
+ case DiagnosticsEngine::Ignored: return CXDiagnostic_Ignored;
+ case DiagnosticsEngine::Note: return CXDiagnostic_Note;
+ case DiagnosticsEngine::Warning: return CXDiagnostic_Warning;
+ case DiagnosticsEngine::Error: return CXDiagnostic_Error;
+ case DiagnosticsEngine::Fatal: return CXDiagnostic_Fatal;
+ }
+
+ llvm_unreachable("Invalid diagnostic level");
+}
+
+CXSourceLocation CXStoredDiagnostic::getLocation() const {
+ if (Diag.getLocation().isInvalid())
+ return clang_getNullLocation();
+
+ return translateSourceLocation(Diag.getLocation().getManager(),
+ LangOpts, Diag.getLocation());
+}
+
+CXString CXStoredDiagnostic::getSpelling() const {
+ return createCXString(Diag.getMessage(), false);
+}
+
+CXString CXStoredDiagnostic::getDiagnosticOption(CXString *Disable) const {
+ unsigned ID = Diag.getID();
+ StringRef Option = DiagnosticIDs::getWarningOptionForDiag(ID);
+ if (!Option.empty()) {
+ if (Disable)
+ *Disable = createCXString((Twine("-Wno-") + Option).str());
+ return createCXString((Twine("-W") + Option).str());
+ }
+
+ if (ID == diag::fatal_too_many_errors) {
+ if (Disable)
+ *Disable = createCXString("-ferror-limit=0");
+ return createCXString("-ferror-limit=");
+ }
+
+ bool EnabledByDefault;
+ if (DiagnosticIDs::isBuiltinExtensionDiag(ID, EnabledByDefault) &&
+ !EnabledByDefault)
+ return createCXString("-pedantic");
+
+ return createCXString("");
+}
+
+unsigned CXStoredDiagnostic::getCategory() const {
+ return DiagnosticIDs::getCategoryNumberForDiag(Diag.getID());
+}
+
+CXString CXStoredDiagnostic::getCategoryText() const {
+ unsigned catID = DiagnosticIDs::getCategoryNumberForDiag(Diag.getID());
+ return createCXString(DiagnosticIDs::getCategoryNameFromID(catID));
+}
+
+unsigned CXStoredDiagnostic::getNumRanges() const {
+ if (Diag.getLocation().isInvalid())
+ return 0;
+
+ return Diag.range_size();
+}
+
+CXSourceRange CXStoredDiagnostic::getRange(unsigned int Range) const {
+ assert(Diag.getLocation().isValid());
+ return translateSourceRange(Diag.getLocation().getManager(),
+ LangOpts,
+ Diag.range_begin()[Range]);
+}
+
+unsigned CXStoredDiagnostic::getNumFixIts() const {
+ if (Diag.getLocation().isInvalid())
+ return 0;
+ return Diag.fixit_size();
+}
+
+CXString CXStoredDiagnostic::getFixIt(unsigned FixIt,
+ CXSourceRange *ReplacementRange) const {
+ const FixItHint &Hint = Diag.fixit_begin()[FixIt];
+ if (ReplacementRange) {
+ // 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(Diag.getLocation().getManager(),
+ LangOpts, Hint.RemoveRange);
+ }
+ return createCXString(Hint.CodeToInsert);
+}
+
diff --git a/tools/libclang/CXString.h b/tools/libclang/CXString.h
index d36c7c1e68ba..c354bd2334e0 100644
--- a/tools/libclang/CXString.h
+++ b/tools/libclang/CXString.h
@@ -23,7 +23,7 @@ namespace clang {
namespace cxstring {
struct CXStringBuf {
- llvm::SmallString<128> Data;
+ SmallString<128> Data;
CXTranslationUnit TU;
CXStringBuf(CXTranslationUnit tu) : TU(tu) {}
};
diff --git a/tools/libclang/CXTranslationUnit.h b/tools/libclang/CXTranslationUnit.h
index 2b8f977539c2..3ad867ca8bf1 100644
--- a/tools/libclang/CXTranslationUnit.h
+++ b/tools/libclang/CXTranslationUnit.h
@@ -16,17 +16,37 @@
extern "C" {
struct CXTranslationUnitImpl {
+ void *CIdx;
void *TUData;
void *StringPool;
+ void *Diagnostics;
};
}
namespace clang {
class ASTUnit;
+ class CIndexer;
namespace cxtu {
-CXTranslationUnitImpl *MakeCXTranslationUnit(ASTUnit *TU);
+CXTranslationUnitImpl *MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU);
+
+class CXTUOwner {
+ CXTranslationUnitImpl *TU;
+
+public:
+ CXTUOwner(CXTranslationUnitImpl *tu) : TU(tu) { }
+ ~CXTUOwner();
+
+ CXTranslationUnitImpl *getTU() const { return TU; }
+
+ CXTranslationUnitImpl *takeTU() {
+ CXTranslationUnitImpl *retTU = TU;
+ TU = 0;
+ return retTU;
+ }
+};
+
}} // end namespace clang::cxtu
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 0e62e2734b0c..850fac129ef1 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -85,6 +85,7 @@ static CXTypeKind GetTypeKind(QualType T) {
TKCASE(FunctionNoProto);
TKCASE(FunctionProto);
TKCASE(ConstantArray);
+ TKCASE(Vector);
default:
return CXType_Unexposed;
}
@@ -122,6 +123,8 @@ CXType clang_getCursorType(CXCursor C) {
if (clang_isDeclaration(C.kind)) {
Decl *D = cxcursor::getCursorDecl(C);
+ if (!D)
+ return MakeCXType(QualType(), TU);
if (TypeDecl *TD = dyn_cast<TypeDecl>(D))
return MakeCXType(Context.getTypeDeclType(TD), TU);
@@ -157,12 +160,17 @@ CXType clang_getCursorType(CXCursor C) {
case CXCursor_CXXBaseSpecifier:
return cxtype::MakeCXType(getCursorCXXBaseSpecifier(C)->getType(), TU);
-
- case CXCursor_ObjCProtocolRef:
+
+ case CXCursor_MemberRef:
+ return cxtype::MakeCXType(getCursorMemberRef(C).first->getType(), TU);
+
+ case CXCursor_VariableRef:
+ return cxtype::MakeCXType(getCursorVariableRef(C).first->getType(), TU);
+
+ case CXCursor_ObjCProtocolRef:
case CXCursor_TemplateRef:
case CXCursor_NamespaceRef:
- case CXCursor_MemberRef:
- case CXCursor_OverloadedDeclRef:
+ case CXCursor_OverloadedDeclRef:
default:
break;
}
@@ -173,6 +181,74 @@ CXType clang_getCursorType(CXCursor C) {
return MakeCXType(QualType(), TU);
}
+CXType clang_getTypedefDeclUnderlyingType(CXCursor C) {
+ using namespace cxcursor;
+ CXTranslationUnit TU = cxcursor::getCursorTU(C);
+
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+
+ if (TypedefNameDecl *TD = dyn_cast_or_null<TypedefNameDecl>(D)) {
+ QualType T = TD->getUnderlyingType();
+ return MakeCXType(T, TU);
+ }
+
+ return MakeCXType(QualType(), TU);
+ }
+
+ return MakeCXType(QualType(), TU);
+}
+
+CXType clang_getEnumDeclIntegerType(CXCursor C) {
+ using namespace cxcursor;
+ CXTranslationUnit TU = cxcursor::getCursorTU(C);
+
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+
+ if (EnumDecl *TD = dyn_cast_or_null<EnumDecl>(D)) {
+ QualType T = TD->getIntegerType();
+ return MakeCXType(T, TU);
+ }
+
+ return MakeCXType(QualType(), TU);
+ }
+
+ return MakeCXType(QualType(), TU);
+}
+
+long long clang_getEnumConstantDeclValue(CXCursor C) {
+ using namespace cxcursor;
+
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+
+ if (EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) {
+ return TD->getInitVal().getSExtValue();
+ }
+
+ return LLONG_MIN;
+ }
+
+ return LLONG_MIN;
+}
+
+unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C) {
+ using namespace cxcursor;
+
+ if (clang_isDeclaration(C.kind)) {
+ Decl *D = cxcursor::getCursorDecl(C);
+
+ if (EnumConstantDecl *TD = dyn_cast_or_null<EnumConstantDecl>(D)) {
+ return TD->getInitVal().getZExtValue();
+ }
+
+ return ULLONG_MAX;
+ }
+
+ return ULLONG_MAX;
+}
+
CXType clang_getCanonicalType(CXType CT) {
if (CT.kind == CXType_Invalid)
return CT;
@@ -332,6 +408,7 @@ CXString clang_getTypeKindSpelling(enum CXTypeKind K) {
TKIND(FunctionNoProto);
TKIND(FunctionProto);
TKIND(ConstantArray);
+ TKIND(Vector);
}
#undef TKIND
return cxstring::createCXString(s);
@@ -341,9 +418,78 @@ unsigned clang_equalTypes(CXType A, CXType B) {
return A.data[0] == B.data[0] && A.data[1] == B.data[1];;
}
+unsigned clang_isFunctionTypeVariadic(CXType X) {
+ QualType T = GetQualType(X);
+ if (T.isNull())
+ return 0;
+
+ if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>())
+ return (unsigned)FD->isVariadic();
+
+ if (T->getAs<FunctionNoProtoType>())
+ return 1;
+
+ return 0;
+}
+
+CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
+ QualType T = GetQualType(X);
+ if (T.isNull())
+ return CXCallingConv_Invalid;
+
+ if (const FunctionType *FD = T->getAs<FunctionType>()) {
+#define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X
+ switch (FD->getCallConv()) {
+ TCALLINGCONV(Default);
+ TCALLINGCONV(C);
+ TCALLINGCONV(X86StdCall);
+ TCALLINGCONV(X86FastCall);
+ TCALLINGCONV(X86ThisCall);
+ TCALLINGCONV(X86Pascal);
+ TCALLINGCONV(AAPCS);
+ TCALLINGCONV(AAPCS_VFP);
+ }
+#undef TCALLINGCONV
+ }
+
+ return CXCallingConv_Invalid;
+}
+
+int clang_getNumArgTypes(CXType X) {
+ QualType T = GetQualType(X);
+ if (T.isNull())
+ return -1;
+
+ if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) {
+ return FD->getNumArgs();
+ }
+
+ if (T->getAs<FunctionNoProtoType>()) {
+ return 0;
+ }
+
+ return -1;
+}
+
+CXType clang_getArgType(CXType X, unsigned i) {
+ QualType T = GetQualType(X);
+ if (T.isNull())
+ return MakeCXType(QualType(), GetTU(X));
+
+ if (const FunctionProtoType *FD = T->getAs<FunctionProtoType>()) {
+ unsigned numArgs = FD->getNumArgs();
+ if (i >= numArgs)
+ return MakeCXType(QualType(), GetTU(X));
+
+ return MakeCXType(FD->getArgType(i), GetTU(X));
+ }
+
+ return MakeCXType(QualType(), GetTU(X));
+}
+
CXType clang_getResultType(CXType X) {
QualType T = GetQualType(X);
- if (!T.getTypePtrOrNull())
+ if (T.isNull())
return MakeCXType(QualType(), GetTU(X));
if (const FunctionType *FD = T->getAs<FunctionType>())
@@ -355,7 +501,7 @@ CXType clang_getResultType(CXType X) {
CXType clang_getCursorResultType(CXCursor C) {
if (clang_isDeclaration(C.kind)) {
Decl *D = cxcursor::getCursorDecl(C);
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+ if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(D))
return MakeCXType(MD->getResultType(), cxcursor::getCursorTU(C));
return clang_getResultType(clang_getCursorType(C));
@@ -366,7 +512,7 @@ CXType clang_getCursorResultType(CXCursor C) {
unsigned clang_isPODType(CXType X) {
QualType T = GetQualType(X);
- if (!T.getTypePtrOrNull())
+ if (T.isNull())
return 0;
CXTranslationUnit TU = GetTU(X);
@@ -375,6 +521,49 @@ unsigned clang_isPODType(CXType X) {
return T.isPODType(AU->getASTContext()) ? 1 : 0;
}
+CXType clang_getElementType(CXType CT) {
+ QualType ET = QualType();
+ QualType T = GetQualType(CT);
+ const Type *TP = T.getTypePtrOrNull();
+
+ if (TP) {
+ switch (TP->getTypeClass()) {
+ case Type::ConstantArray:
+ ET = cast<ConstantArrayType> (TP)->getElementType();
+ break;
+ case Type::Vector:
+ ET = cast<VectorType> (TP)->getElementType();
+ break;
+ case Type::Complex:
+ ET = cast<ComplexType> (TP)->getElementType();
+ break;
+ default:
+ break;
+ }
+ }
+ return MakeCXType(ET, GetTU(CT));
+}
+
+long long clang_getNumElements(CXType CT) {
+ long long result = -1;
+ QualType T = GetQualType(CT);
+ const Type *TP = T.getTypePtrOrNull();
+
+ if (TP) {
+ switch (TP->getTypeClass()) {
+ case Type::ConstantArray:
+ result = cast<ConstantArrayType> (TP)->getSize().getSExtValue();
+ break;
+ case Type::Vector:
+ result = cast<VectorType> (TP)->getNumElements();
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+}
+
CXType clang_getArrayElementType(CXType CT) {
QualType ET = QualType();
QualType T = GetQualType(CT);
diff --git a/tools/libclang/CursorVisitor.h b/tools/libclang/CursorVisitor.h
new file mode 100644
index 000000000000..88b70a490eb7
--- /dev/null
+++ b/tools/libclang/CursorVisitor.h
@@ -0,0 +1,259 @@
+//===- CursorVisitor.h - CursorVisitor interface --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIBCLANG_CURSORVISITOR_H
+#define LLVM_CLANG_LIBCLANG_CURSORVISITOR_H
+
+#include "Index_Internal.h"
+#include "CXCursor.h"
+#include "CXTranslationUnit.h"
+
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/TypeLocVisitor.h"
+
+namespace clang {
+ class PreprocessingRecord;
+ class ASTUnit;
+
+namespace cxcursor {
+
+class VisitorJob {
+public:
+ enum Kind { DeclVisitKind, StmtVisitKind, MemberExprPartsKind,
+ TypeLocVisitKind, OverloadExprPartsKind,
+ DeclRefExprPartsKind, LabelRefVisitKind,
+ ExplicitTemplateArgsVisitKind,
+ NestedNameSpecifierLocVisitKind,
+ DeclarationNameInfoVisitKind,
+ MemberRefVisitKind, SizeOfPackExprPartsKind,
+ LambdaExprPartsKind };
+protected:
+ void *data[3];
+ CXCursor parent;
+ Kind K;
+ VisitorJob(CXCursor C, Kind k, void *d1, void *d2 = 0, void *d3 = 0)
+ : parent(C), K(k) {
+ data[0] = d1;
+ data[1] = d2;
+ data[2] = d3;
+ }
+public:
+ Kind getKind() const { return K; }
+ const CXCursor &getParent() const { return parent; }
+ static bool classof(VisitorJob *VJ) { return true; }
+};
+
+typedef SmallVector<VisitorJob, 10> VisitorWorkList;
+
+// Cursor visitor.
+class CursorVisitor : public DeclVisitor<CursorVisitor, bool>,
+ public TypeLocVisitor<CursorVisitor, bool>
+{
+ /// \brief The translation unit we are traversing.
+ CXTranslationUnit TU;
+ ASTUnit *AU;
+
+ /// \brief The parent cursor whose children we are traversing.
+ CXCursor Parent;
+
+ /// \brief The declaration that serves at the parent of any statement or
+ /// expression nodes.
+ Decl *StmtParent;
+
+ /// \brief The visitor function.
+ CXCursorVisitor Visitor;
+
+ /// \brief The opaque client data, to be passed along to the visitor.
+ CXClientData ClientData;
+
+ /// \brief Whether we should visit the preprocessing record entries last,
+ /// after visiting other declarations.
+ bool VisitPreprocessorLast;
+
+ /// \brief Whether we should visit declarations or preprocessing record
+ /// entries that are #included inside the \arg RegionOfInterest.
+ bool VisitIncludedEntities;
+
+ /// \brief When valid, a source range to which the cursor should restrict
+ /// its search.
+ SourceRange RegionOfInterest;
+
+ /// \brief Whether we should only visit declarations and not preprocessing
+ /// record entries.
+ bool VisitDeclsOnly;
+
+ // FIXME: Eventually remove. This part of a hack to support proper
+ // iteration over all Decls contained lexically within an ObjC container.
+ DeclContext::decl_iterator *DI_current;
+ DeclContext::decl_iterator DE_current;
+ SmallVectorImpl<Decl *>::iterator *FileDI_current;
+ SmallVectorImpl<Decl *>::iterator FileDE_current;
+
+ // Cache of pre-allocated worklists for data-recursion walk of Stmts.
+ SmallVector<VisitorWorkList*, 5> WorkListFreeList;
+ SmallVector<VisitorWorkList*, 5> WorkListCache;
+
+ using DeclVisitor<CursorVisitor, bool>::Visit;
+ using TypeLocVisitor<CursorVisitor, bool>::Visit;
+
+ /// \brief Determine whether this particular source range comes before, comes
+ /// after, or overlaps the region of interest.
+ ///
+ /// \param R a half-open source range retrieved from the abstract syntax tree.
+ RangeComparisonResult CompareRegionOfInterest(SourceRange R);
+
+ void visitDeclsFromFileRegion(FileID File, unsigned Offset, unsigned Length);
+
+ class SetParentRAII {
+ CXCursor &Parent;
+ Decl *&StmtParent;
+ CXCursor OldParent;
+
+ public:
+ SetParentRAII(CXCursor &Parent, Decl *&StmtParent, CXCursor NewParent)
+ : Parent(Parent), StmtParent(StmtParent), OldParent(Parent)
+ {
+ Parent = NewParent;
+ if (clang_isDeclaration(Parent.kind))
+ StmtParent = getCursorDecl(Parent);
+ }
+
+ ~SetParentRAII() {
+ Parent = OldParent;
+ if (clang_isDeclaration(Parent.kind))
+ StmtParent = getCursorDecl(Parent);
+ }
+ };
+
+public:
+ CursorVisitor(CXTranslationUnit TU, CXCursorVisitor Visitor,
+ CXClientData ClientData,
+ bool VisitPreprocessorLast,
+ bool VisitIncludedPreprocessingEntries = false,
+ SourceRange RegionOfInterest = SourceRange(),
+ bool VisitDeclsOnly = false)
+ : TU(TU), AU(static_cast<ASTUnit*>(TU->TUData)),
+ Visitor(Visitor), ClientData(ClientData),
+ VisitPreprocessorLast(VisitPreprocessorLast),
+ VisitIncludedEntities(VisitIncludedPreprocessingEntries),
+ RegionOfInterest(RegionOfInterest),
+ VisitDeclsOnly(VisitDeclsOnly),
+ DI_current(0), FileDI_current(0)
+ {
+ Parent.kind = CXCursor_NoDeclFound;
+ Parent.data[0] = 0;
+ Parent.data[1] = 0;
+ Parent.data[2] = 0;
+ StmtParent = 0;
+ }
+
+ ~CursorVisitor() {
+ // Free the pre-allocated worklists for data-recursion.
+ for (SmallVectorImpl<VisitorWorkList*>::iterator
+ I = WorkListCache.begin(), E = WorkListCache.end(); I != E; ++I) {
+ delete *I;
+ }
+ }
+
+ ASTUnit *getASTUnit() const { return static_cast<ASTUnit*>(TU->TUData); }
+ CXTranslationUnit getTU() const { return TU; }
+
+ bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false);
+
+ /// \brief Visit declarations and preprocessed entities for the file region
+ /// designated by \see RegionOfInterest.
+ void visitFileRegion();
+
+ bool visitPreprocessedEntitiesInRegion();
+
+ bool shouldVisitIncludedEntities() const {
+ return VisitIncludedEntities;
+ }
+
+ template<typename InputIterator>
+ bool visitPreprocessedEntities(InputIterator First, InputIterator Last,
+ PreprocessingRecord &PPRec,
+ FileID FID = FileID());
+
+ bool VisitChildren(CXCursor Parent);
+
+ // Declaration visitors
+ bool VisitTypeAliasDecl(TypeAliasDecl *D);
+ bool VisitAttributes(Decl *D);
+ bool VisitBlockDecl(BlockDecl *B);
+ bool VisitCXXRecordDecl(CXXRecordDecl *D);
+ llvm::Optional<bool> shouldVisitCursor(CXCursor C);
+ 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);
+ bool VisitObjCProtocolDecl(ObjCProtocolDecl *PID);
+ bool VisitObjCPropertyDecl(ObjCPropertyDecl *PD);
+ bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ bool VisitObjCImplDecl(ObjCImplDecl *D);
+ bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ bool VisitObjCImplementationDecl(ObjCImplementationDecl *D);
+ // FIXME: ObjCCompatibleAliasDecl requires aliased-class locations.
+ bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PD);
+ 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);
+ bool VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
+
+ // Template visitors
+ bool VisitTemplateParameters(const TemplateParameterList *Params);
+ bool VisitTemplateName(TemplateName Name, SourceLocation Loc);
+ bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL);
+
+ // Type visitors
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc);
+#include "clang/AST/TypeLocNodes.def"
+
+ bool VisitTagTypeLoc(TagTypeLoc TL);
+ bool VisitArrayTypeLoc(ArrayTypeLoc TL);
+ bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false);
+
+ // Data-recursive visitor functions.
+ bool IsInRegionOfInterest(CXCursor C);
+ bool RunVisitorWorkList(VisitorWorkList &WL);
+ void EnqueueWorkList(VisitorWorkList &WL, Stmt *S);
+ LLVM_ATTRIBUTE_NOINLINE bool Visit(Stmt *S);
+};
+
+}
+}
+
+#endif
+
diff --git a/tools/libclang/IndexBody.cpp b/tools/libclang/IndexBody.cpp
new file mode 100644
index 000000000000..74a8d37d42fc
--- /dev/null
+++ b/tools/libclang/IndexBody.cpp
@@ -0,0 +1,154 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexingContext.h"
+
+#include "clang/AST/RecursiveASTVisitor.h"
+
+using namespace clang;
+using namespace cxindex;
+
+namespace {
+
+class BodyIndexer : public RecursiveASTVisitor<BodyIndexer> {
+ IndexingContext &IndexCtx;
+ const NamedDecl *Parent;
+ const DeclContext *ParentDC;
+
+ typedef RecursiveASTVisitor<BodyIndexer> base;
+public:
+ BodyIndexer(IndexingContext &indexCtx,
+ const NamedDecl *Parent, const DeclContext *DC)
+ : IndexCtx(indexCtx), Parent(Parent), ParentDC(DC) { }
+
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool TraverseTypeLoc(TypeLoc TL) {
+ IndexCtx.indexTypeLoc(TL, Parent, ParentDC);
+ return true;
+ }
+
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
+ return true;
+ }
+
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ IndexCtx.handleReference(E->getDecl(), E->getLocation(),
+ Parent, ParentDC, E);
+ return true;
+ }
+
+ bool VisitMemberExpr(MemberExpr *E) {
+ IndexCtx.handleReference(E->getMemberDecl(), E->getMemberLoc(),
+ Parent, ParentDC, E);
+ return true;
+ }
+
+ bool VisitDesignatedInitExpr(DesignatedInitExpr *E) {
+ for (DesignatedInitExpr::reverse_designators_iterator
+ D = E->designators_rbegin(), DEnd = E->designators_rend();
+ D != DEnd; ++D) {
+ if (D->isFieldDesignator())
+ IndexCtx.handleReference(D->getField(), D->getFieldLoc(),
+ Parent, ParentDC, E);
+ }
+ return true;
+ }
+
+ bool VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ IndexCtx.handleReference(E->getDecl(), E->getLocation(),
+ Parent, ParentDC, E);
+ return true;
+ }
+
+ bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
+ if (TypeSourceInfo *Cls = E->getClassReceiverTypeInfo())
+ IndexCtx.indexTypeSourceInfo(Cls, Parent, ParentDC);
+
+ if (ObjCMethodDecl *MD = E->getMethodDecl())
+ IndexCtx.handleReference(MD, E->getSelectorStartLoc(),
+ Parent, ParentDC, E,
+ E->isImplicit() ? CXIdxEntityRef_Implicit
+ : CXIdxEntityRef_Direct);
+ return true;
+ }
+
+ bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ if (E->isExplicitProperty())
+ IndexCtx.handleReference(E->getExplicitProperty(), E->getLocation(),
+ Parent, ParentDC, E);
+
+ // No need to do a handleReference for the objc method, because there will
+ // be a message expr as part of PseudoObjectExpr.
+ return true;
+ }
+
+ bool VisitObjCNumericLiteral(ObjCNumericLiteral *E) {
+ if (ObjCMethodDecl *MD = E->getObjCNumericLiteralMethod())
+ IndexCtx.handleReference(MD, E->getLocStart(),
+ Parent, ParentDC, E, CXIdxEntityRef_Implicit);
+ return true;
+ }
+
+ bool VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
+ if (ObjCMethodDecl *MD = E->getDictWithObjectsMethod())
+ IndexCtx.handleReference(MD, E->getLocStart(),
+ Parent, ParentDC, E, CXIdxEntityRef_Implicit);
+ return true;
+ }
+
+ bool VisitObjCArrayLiteral(ObjCArrayLiteral *E) {
+ if (ObjCMethodDecl *MD = E->getArrayWithObjectsMethod())
+ IndexCtx.handleReference(MD, E->getLocStart(),
+ Parent, ParentDC, E, CXIdxEntityRef_Implicit);
+ return true;
+ }
+
+ bool VisitCXXConstructExpr(CXXConstructExpr *E) {
+ IndexCtx.handleReference(E->getConstructor(), E->getLocation(),
+ Parent, ParentDC, E);
+ return true;
+ }
+
+ bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
+ if (E->getOperatorLoc().isInvalid())
+ return true; // implicit.
+ return base::TraverseCXXOperatorCallExpr(E);
+ }
+
+ bool VisitDeclStmt(DeclStmt *S) {
+ if (IndexCtx.shouldIndexFunctionLocalSymbols())
+ IndexCtx.indexDeclGroupRef(S->getDeclGroup());
+ return true;
+ }
+
+ bool TraverseLambdaCapture(LambdaExpr::Capture C) {
+ if (C.capturesThis())
+ return true;
+
+ if (IndexCtx.shouldIndexFunctionLocalSymbols())
+ IndexCtx.handleReference(C.getCapturedVar(), C.getLocation(),
+ Parent, ParentDC);
+ return true;
+ }
+
+};
+
+} // anonymous namespace
+
+void IndexingContext::indexBody(const Stmt *S, const NamedDecl *Parent,
+ const DeclContext *DC) {
+ if (!S)
+ return;
+
+ if (DC == 0)
+ DC = Parent->getLexicalDeclContext();
+ BodyIndexer(*this, Parent, DC).TraverseStmt(const_cast<Stmt*>(S));
+}
diff --git a/tools/libclang/IndexDecl.cpp b/tools/libclang/IndexDecl.cpp
new file mode 100644
index 000000000000..c257c342aa72
--- /dev/null
+++ b/tools/libclang/IndexDecl.cpp
@@ -0,0 +1,336 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexingContext.h"
+
+#include "clang/AST/DeclVisitor.h"
+
+using namespace clang;
+using namespace cxindex;
+
+namespace {
+
+class IndexingDeclVisitor : public DeclVisitor<IndexingDeclVisitor, bool> {
+ IndexingContext &IndexCtx;
+
+public:
+ explicit IndexingDeclVisitor(IndexingContext &indexCtx)
+ : IndexCtx(indexCtx) { }
+
+ void handleDeclarator(DeclaratorDecl *D, const NamedDecl *Parent = 0) {
+ if (!Parent) Parent = D;
+
+ if (!IndexCtx.shouldIndexFunctionLocalSymbols()) {
+ IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent);
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent);
+ } else {
+ if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) {
+ IndexCtx.handleVar(Parm);
+ } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ for (FunctionDecl::param_iterator
+ PI = FD->param_begin(), PE = FD->param_end(); PI != PE; ++PI) {
+ IndexCtx.handleVar(*PI);
+ }
+ }
+ }
+ }
+
+ void handleObjCMethod(ObjCMethodDecl *D) {
+ IndexCtx.handleObjCMethod(D);
+ if (D->isImplicit())
+ return;
+
+ IndexCtx.indexTypeSourceInfo(D->getResultTypeSourceInfo(), D);
+ for (ObjCMethodDecl::param_iterator
+ I = D->param_begin(), E = D->param_end(); I != E; ++I)
+ handleDeclarator(*I, D);
+
+ if (D->isThisDeclarationADefinition()) {
+ const Stmt *Body = D->getBody();
+ if (Body) {
+ IndexCtx.indexBody(Body, D, D);
+ }
+ }
+ }
+
+ bool VisitFunctionDecl(FunctionDecl *D) {
+ IndexCtx.handleFunction(D);
+ handleDeclarator(D);
+
+ if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) {
+ // Constructor initializers.
+ for (CXXConstructorDecl::init_iterator I = Ctor->init_begin(),
+ E = Ctor->init_end();
+ I != E; ++I) {
+ CXXCtorInitializer *Init = *I;
+ if (Init->isWritten()) {
+ IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D);
+ if (const FieldDecl *Member = Init->getAnyMember())
+ IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D);
+ IndexCtx.indexBody(Init->getInit(), D, D);
+ }
+ }
+ }
+
+ if (D->isThisDeclarationADefinition()) {
+ const Stmt *Body = D->getBody();
+ if (Body) {
+ IndexCtx.indexBody(Body, D, D);
+ }
+ }
+ return true;
+ }
+
+ bool VisitVarDecl(VarDecl *D) {
+ IndexCtx.handleVar(D);
+ handleDeclarator(D);
+ IndexCtx.indexBody(D->getInit(), D);
+ return true;
+ }
+
+ bool VisitFieldDecl(FieldDecl *D) {
+ IndexCtx.handleField(D);
+ handleDeclarator(D);
+ if (D->isBitField())
+ IndexCtx.indexBody(D->getBitWidth(), D);
+ else if (D->hasInClassInitializer())
+ IndexCtx.indexBody(D->getInClassInitializer(), D);
+ return true;
+ }
+
+ bool VisitEnumConstantDecl(EnumConstantDecl *D) {
+ IndexCtx.handleEnumerator(D);
+ IndexCtx.indexBody(D->getInitExpr(), D);
+ return true;
+ }
+
+ bool VisitTypedefDecl(TypedefNameDecl *D) {
+ IndexCtx.handleTypedefName(D);
+ IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+ return true;
+ }
+
+ bool VisitTagDecl(TagDecl *D) {
+ // Non-free standing tags are handled in indexTypeSourceInfo.
+ if (D->isFreeStanding())
+ IndexCtx.indexTagDecl(D);
+ return true;
+ }
+
+ bool VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
+ IndexCtx.handleObjCInterface(D);
+
+ if (D->isThisDeclarationADefinition()) {
+ IndexCtx.indexTUDeclsInObjCContainer();
+ IndexCtx.indexDeclContext(D);
+ }
+ return true;
+ }
+
+ bool VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
+ IndexCtx.handleObjCProtocol(D);
+
+ if (D->isThisDeclarationADefinition()) {
+ IndexCtx.indexTUDeclsInObjCContainer();
+ IndexCtx.indexDeclContext(D);
+ }
+ return true;
+ }
+
+ bool VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ const ObjCInterfaceDecl *Class = D->getClassInterface();
+ if (!Class)
+ return true;
+
+ if (Class->isImplicitInterfaceDecl())
+ IndexCtx.handleObjCInterface(Class);
+
+ IndexCtx.handleObjCImplementation(D);
+
+ IndexCtx.indexTUDeclsInObjCContainer();
+ IndexCtx.indexDeclContext(D);
+ return true;
+ }
+
+ bool VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
+ IndexCtx.handleObjCCategory(D);
+
+ IndexCtx.indexTUDeclsInObjCContainer();
+ IndexCtx.indexDeclContext(D);
+ return true;
+ }
+
+ bool VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ const ObjCCategoryDecl *Cat = D->getCategoryDecl();
+ if (!Cat)
+ return true;
+
+ IndexCtx.handleObjCCategoryImpl(D);
+
+ IndexCtx.indexTUDeclsInObjCContainer();
+ IndexCtx.indexDeclContext(D);
+ return true;
+ }
+
+ bool VisitObjCMethodDecl(ObjCMethodDecl *D) {
+ // Methods associated with a property, even user-declared ones, are
+ // handled when we handle the property.
+ if (D->isSynthesized())
+ return true;
+
+ handleObjCMethod(D);
+ return true;
+ }
+
+ bool VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
+ if (ObjCMethodDecl *MD = D->getGetterMethodDecl())
+ if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
+ handleObjCMethod(MD);
+ if (ObjCMethodDecl *MD = D->getSetterMethodDecl())
+ if (MD->getLexicalDeclContext() == D->getLexicalDeclContext())
+ handleObjCMethod(MD);
+ IndexCtx.handleObjCProperty(D);
+ IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D);
+ return true;
+ }
+
+ bool VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ ObjCPropertyDecl *PD = D->getPropertyDecl();
+ IndexCtx.handleSynthesizedObjCProperty(D);
+
+ if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
+ return true;
+ assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize);
+
+ if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) {
+ if (!IvarD->getSynthesize())
+ IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), 0,
+ D->getDeclContext());
+ }
+
+ if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) {
+ if (MD->isSynthesized())
+ IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
+ D->getLexicalDeclContext());
+ }
+ if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) {
+ if (MD->isSynthesized())
+ IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(),
+ D->getLexicalDeclContext());
+ }
+ return true;
+ }
+
+ bool VisitNamespaceDecl(NamespaceDecl *D) {
+ IndexCtx.handleNamespace(D);
+ IndexCtx.indexDeclContext(D);
+ return true;
+ }
+
+ bool VisitUsingDecl(UsingDecl *D) {
+ // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR,
+ // we should do better.
+
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
+ for (UsingDecl::shadow_iterator
+ I = D->shadow_begin(), E = D->shadow_end(); I != E; ++I) {
+ IndexCtx.handleReference((*I)->getUnderlyingDecl(), D->getLocation(),
+ D, D->getLexicalDeclContext());
+ }
+ return true;
+ }
+
+ bool VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
+ // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR,
+ // we should do better.
+
+ IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D);
+ IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(),
+ D->getLocation(), D, D->getLexicalDeclContext());
+ return true;
+ }
+
+ bool VisitClassTemplateDecl(ClassTemplateDecl *D) {
+ IndexCtx.handleClassTemplate(D);
+ if (D->isThisDeclarationADefinition())
+ IndexCtx.indexDeclContext(D->getTemplatedDecl());
+ return true;
+ }
+
+ bool VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D) {
+ // FIXME: Notify subsequent callbacks if info comes from implicit
+ // instantiation.
+ if (D->isThisDeclarationADefinition() &&
+ (IndexCtx.shouldIndexImplicitTemplateInsts() ||
+ !IndexCtx.isTemplateImplicitInstantiation(D)))
+ IndexCtx.indexTagDecl(D);
+ return true;
+ }
+
+ bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
+ IndexCtx.handleFunctionTemplate(D);
+ FunctionDecl *FD = D->getTemplatedDecl();
+ handleDeclarator(FD, D);
+ if (FD->isThisDeclarationADefinition()) {
+ const Stmt *Body = FD->getBody();
+ if (Body) {
+ IndexCtx.indexBody(Body, D, FD);
+ }
+ }
+ return true;
+ }
+
+ bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
+ IndexCtx.handleTypeAliasTemplate(D);
+ IndexCtx.indexTypeSourceInfo(D->getTemplatedDecl()->getTypeSourceInfo(), D);
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void IndexingContext::indexDecl(const Decl *D) {
+ if (D->isImplicit() && shouldIgnoreIfImplicit(D))
+ return;
+
+ bool Handled = IndexingDeclVisitor(*this).Visit(const_cast<Decl*>(D));
+ if (!Handled && isa<DeclContext>(D))
+ indexDeclContext(cast<DeclContext>(D));
+}
+
+void IndexingContext::indexDeclContext(const DeclContext *DC) {
+ for (DeclContext::decl_iterator
+ I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) {
+ indexDecl(*I);
+ }
+}
+
+void IndexingContext::indexTopLevelDecl(Decl *D) {
+ if (isNotFromSourceFile(D->getLocation()))
+ return;
+
+ if (isa<ObjCMethodDecl>(D))
+ return; // Wait for the objc container.
+
+ indexDecl(D);
+}
+
+void IndexingContext::indexDeclGroupRef(DeclGroupRef DG) {
+ for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
+ indexTopLevelDecl(*I);
+}
+
+void IndexingContext::indexTUDeclsInObjCContainer() {
+ while (!TUDeclsInObjCContainer.empty()) {
+ DeclGroupRef DG = TUDeclsInObjCContainer.front();
+ TUDeclsInObjCContainer.pop_front();
+ indexDeclGroupRef(DG);
+ }
+}
diff --git a/tools/libclang/IndexTypeSourceInfo.cpp b/tools/libclang/IndexTypeSourceInfo.cpp
new file mode 100644
index 000000000000..b62d52156bc9
--- /dev/null
+++ b/tools/libclang/IndexTypeSourceInfo.cpp
@@ -0,0 +1,156 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexingContext.h"
+
+#include "clang/AST/RecursiveASTVisitor.h"
+
+using namespace clang;
+using namespace cxindex;
+
+namespace {
+
+class TypeIndexer : public RecursiveASTVisitor<TypeIndexer> {
+ IndexingContext &IndexCtx;
+ const NamedDecl *Parent;
+ const DeclContext *ParentDC;
+
+public:
+ TypeIndexer(IndexingContext &indexCtx, const NamedDecl *parent,
+ const DeclContext *DC)
+ : IndexCtx(indexCtx), Parent(parent), ParentDC(DC) { }
+
+ bool shouldWalkTypesOfTypeLocs() const { return false; }
+
+ bool VisitTypedefTypeLoc(TypedefTypeLoc TL) {
+ IndexCtx.handleReference(TL.getTypedefNameDecl(), TL.getNameLoc(),
+ Parent, ParentDC);
+ return true;
+ }
+
+ bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+ IndexCtx.indexNestedNameSpecifierLoc(NNS, Parent, ParentDC);
+ return true;
+ }
+
+ bool VisitTagTypeLoc(TagTypeLoc TL) {
+ TagDecl *D = TL.getDecl();
+ if (D->getParentFunctionOrMethod())
+ return true;
+
+ if (TL.isDefinition()) {
+ IndexCtx.indexTagDecl(D);
+ return true;
+ }
+
+ if (D->getLocation() == TL.getNameLoc())
+ IndexCtx.handleTagDecl(D);
+ else
+ IndexCtx.handleReference(D, TL.getNameLoc(),
+ Parent, ParentDC);
+ return true;
+ }
+
+ bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
+ IndexCtx.handleReference(TL.getIFaceDecl(), TL.getNameLoc(),
+ Parent, ParentDC);
+ return true;
+ }
+
+ bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
+ for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) {
+ IndexCtx.handleReference(TL.getProtocol(i), TL.getProtocolLoc(i),
+ Parent, ParentDC);
+ }
+ return true;
+ }
+
+ bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
+ if (const TemplateSpecializationType *T = TL.getTypePtr()) {
+ if (IndexCtx.shouldIndexImplicitTemplateInsts()) {
+ if (CXXRecordDecl *RD = T->getAsCXXRecordDecl())
+ IndexCtx.handleReference(RD, TL.getTemplateNameLoc(),
+ Parent, ParentDC);
+ } else {
+ if (const TemplateDecl *D = T->getTemplateName().getAsTemplateDecl())
+ IndexCtx.handleReference(D, TL.getTemplateNameLoc(),
+ Parent, ParentDC);
+ }
+ }
+ return true;
+ }
+
+ bool TraverseStmt(Stmt *S) {
+ IndexCtx.indexBody(S, Parent, ParentDC);
+ return true;
+ }
+};
+
+} // anonymous namespace
+
+void IndexingContext::indexTypeSourceInfo(TypeSourceInfo *TInfo,
+ const NamedDecl *Parent,
+ const DeclContext *DC) {
+ if (!TInfo || TInfo->getTypeLoc().isNull())
+ return;
+
+ indexTypeLoc(TInfo->getTypeLoc(), Parent, DC);
+}
+
+void IndexingContext::indexTypeLoc(TypeLoc TL,
+ const NamedDecl *Parent,
+ const DeclContext *DC) {
+ if (TL.isNull())
+ return;
+
+ if (DC == 0)
+ DC = Parent->getLexicalDeclContext();
+ TypeIndexer(*this, Parent, DC).TraverseTypeLoc(TL);
+}
+
+void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
+ const NamedDecl *Parent,
+ const DeclContext *DC) {
+ if (!NNS)
+ return;
+
+ if (NestedNameSpecifierLoc Prefix = NNS.getPrefix())
+ indexNestedNameSpecifierLoc(Prefix, Parent, DC);
+
+ if (DC == 0)
+ DC = Parent->getLexicalDeclContext();
+ SourceLocation Loc = NNS.getSourceRange().getBegin();
+
+ switch (NNS.getNestedNameSpecifier()->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Global:
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(),
+ Loc, Parent, DC);
+ break;
+ case NestedNameSpecifier::NamespaceAlias:
+ handleReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias(),
+ Loc, Parent, DC);
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ indexTypeLoc(NNS.getTypeLoc(), Parent, DC);
+ break;
+ }
+}
+
+void IndexingContext::indexTagDecl(const TagDecl *D) {
+ if (handleTagDecl(D)) {
+ if (D->isThisDeclarationADefinition())
+ indexDeclContext(D);
+ }
+}
diff --git a/tools/libclang/Index_Internal.h b/tools/libclang/Index_Internal.h
index df54d7c87965..2d42cb83c970 100644
--- a/tools/libclang/Index_Internal.h
+++ b/tools/libclang/Index_Internal.h
@@ -40,4 +40,16 @@ typedef struct _CXCursorAndRangeVisitorBlock {
#endif // !__has_feature(blocks)
+/// \brief The result of comparing two source ranges.
+enum RangeComparisonResult {
+ /// \brief Either the ranges overlap or one of the ranges is invalid.
+ RangeOverlap,
+
+ /// \brief The first range ends before the second range starts.
+ RangeBefore,
+
+ /// \brief The first range starts after the second range ends.
+ RangeAfter
+};
+
#endif
diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp
new file mode 100644
index 000000000000..e660c4d6eb48
--- /dev/null
+++ b/tools/libclang/Indexing.cpp
@@ -0,0 +1,818 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexingContext.h"
+#include "CXCursor.h"
+#include "CXSourceLocation.h"
+#include "CXTranslationUnit.h"
+#include "CXString.h"
+#include "CIndexDiagnostic.h"
+#include "CIndexer.h"
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Sema/SemaConsumer.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+
+using namespace clang;
+using namespace cxstring;
+using namespace cxtu;
+using namespace cxindex;
+
+static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx);
+
+namespace {
+
+//===----------------------------------------------------------------------===//
+// IndexPPCallbacks
+//===----------------------------------------------------------------------===//
+
+class IndexPPCallbacks : public PPCallbacks {
+ Preprocessor &PP;
+ IndexingContext &IndexCtx;
+ bool IsMainFileEntered;
+
+public:
+ IndexPPCallbacks(Preprocessor &PP, IndexingContext &indexCtx)
+ : PP(PP), IndexCtx(indexCtx), IsMainFileEntered(false) { }
+
+ virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+ SrcMgr::CharacteristicKind FileType, FileID PrevFID) {
+ if (IsMainFileEntered)
+ return;
+
+ SourceManager &SM = PP.getSourceManager();
+ SourceLocation MainFileLoc = SM.getLocForStartOfFile(SM.getMainFileID());
+
+ if (Loc == MainFileLoc && Reason == PPCallbacks::EnterFile) {
+ IsMainFileEntered = true;
+ IndexCtx.enteredMainFile(SM.getFileEntryForID(SM.getMainFileID()));
+ }
+ }
+
+ virtual void InclusionDirective(SourceLocation HashLoc,
+ const Token &IncludeTok,
+ StringRef FileName,
+ bool IsAngled,
+ const FileEntry *File,
+ SourceLocation EndLoc,
+ StringRef SearchPath,
+ StringRef RelativePath) {
+ bool isImport = (IncludeTok.is(tok::identifier) &&
+ IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import);
+ IndexCtx.ppIncludedFile(HashLoc, FileName, File, isImport, IsAngled);
+ }
+
+ /// MacroDefined - This hook is called whenever a macro definition is seen.
+ virtual void MacroDefined(const Token &Id, const MacroInfo *MI) {
+ }
+
+ /// MacroUndefined - This hook is called whenever a macro #undef is seen.
+ /// MI is released immediately following this callback.
+ virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) {
+ }
+
+ /// MacroExpands - This is called by when a macro invocation is found.
+ virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI,
+ SourceRange Range) {
+ }
+
+ /// SourceRangeSkipped - This hook is called when a source range is skipped.
+ /// \param Range The SourceRange that was skipped. The range begins at the
+ /// #if/#else directive and ends after the #endif/#else directive.
+ virtual void SourceRangeSkipped(SourceRange Range) {
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// IndexingConsumer
+//===----------------------------------------------------------------------===//
+
+class IndexingConsumer : public ASTConsumer {
+ IndexingContext &IndexCtx;
+
+public:
+ explicit IndexingConsumer(IndexingContext &indexCtx)
+ : IndexCtx(indexCtx) { }
+
+ // ASTConsumer Implementation
+
+ virtual void Initialize(ASTContext &Context) {
+ IndexCtx.setASTContext(Context);
+ IndexCtx.startedTranslationUnit();
+ }
+
+ virtual void HandleTranslationUnit(ASTContext &Ctx) {
+ }
+
+ virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
+ IndexCtx.indexDeclGroupRef(DG);
+ return !IndexCtx.shouldAbort();
+ }
+
+ /// \brief Handle the specified top-level declaration that occurred inside
+ /// and ObjC container.
+ virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
+ // They will be handled after the interface is seen first.
+ IndexCtx.addTUDeclInObjCContainer(D);
+ }
+
+ /// \brief This is called by the AST reader when deserializing things.
+ /// The default implementation forwards to HandleTopLevelDecl but we don't
+ /// care about them when indexing, so have an empty definition.
+ virtual void HandleInterestingDecl(DeclGroupRef D) {}
+
+ virtual void HandleTagDeclDefinition(TagDecl *D) {
+ if (!IndexCtx.shouldIndexImplicitTemplateInsts())
+ return;
+
+ if (IndexCtx.isTemplateImplicitInstantiation(D))
+ IndexCtx.indexDecl(D);
+ }
+
+ virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {
+ if (!IndexCtx.shouldIndexImplicitTemplateInsts())
+ return;
+
+ IndexCtx.indexDecl(D);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// CaptureDiagnosticConsumer
+//===----------------------------------------------------------------------===//
+
+class CaptureDiagnosticConsumer : public DiagnosticConsumer {
+ SmallVector<StoredDiagnostic, 4> Errors;
+public:
+
+ virtual void HandleDiagnostic(DiagnosticsEngine::Level level,
+ const Diagnostic &Info) {
+ if (level >= DiagnosticsEngine::Error)
+ Errors.push_back(StoredDiagnostic(level, Info));
+ }
+
+ DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
+ return new IgnoringDiagConsumer();
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// IndexingFrontendAction
+//===----------------------------------------------------------------------===//
+
+class IndexingFrontendAction : public ASTFrontendAction {
+ IndexingContext IndexCtx;
+ CXTranslationUnit CXTU;
+
+public:
+ IndexingFrontendAction(CXClientData clientData,
+ IndexerCallbacks &indexCallbacks,
+ unsigned indexOptions,
+ CXTranslationUnit cxTU)
+ : IndexCtx(clientData, indexCallbacks, indexOptions, cxTU),
+ CXTU(cxTU) { }
+
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ StringRef InFile) {
+ IndexCtx.setASTContext(CI.getASTContext());
+ Preprocessor &PP = CI.getPreprocessor();
+ PP.addPPCallbacks(new IndexPPCallbacks(PP, IndexCtx));
+ IndexCtx.setPreprocessor(PP);
+ return new IndexingConsumer(IndexCtx);
+ }
+
+ virtual void EndSourceFileAction() {
+ indexDiagnostics(CXTU, IndexCtx);
+ }
+
+ virtual TranslationUnitKind getTranslationUnitKind() {
+ if (IndexCtx.shouldIndexImplicitTemplateInsts())
+ return TU_Complete;
+ else
+ return TU_Prefix;
+ }
+ virtual bool hasCodeCompletionSupport() const { return false; }
+};
+
+//===----------------------------------------------------------------------===//
+// clang_indexSourceFileUnit Implementation
+//===----------------------------------------------------------------------===//
+
+struct IndexSourceFileInfo {
+ CXIndexAction idxAction;
+ CXClientData client_data;
+ IndexerCallbacks *index_callbacks;
+ unsigned index_callbacks_size;
+ unsigned index_options;
+ const char *source_filename;
+ const char *const *command_line_args;
+ int num_command_line_args;
+ struct CXUnsavedFile *unsaved_files;
+ unsigned num_unsaved_files;
+ CXTranslationUnit *out_TU;
+ unsigned TU_options;
+ int result;
+};
+
+struct MemBufferOwner {
+ SmallVector<const llvm::MemoryBuffer *, 8> Buffers;
+
+ ~MemBufferOwner() {
+ for (SmallVectorImpl<const llvm::MemoryBuffer *>::iterator
+ I = Buffers.begin(), E = Buffers.end(); I != E; ++I)
+ delete *I;
+ }
+};
+
+} // anonymous namespace
+
+static void clang_indexSourceFile_Impl(void *UserData) {
+ IndexSourceFileInfo *ITUI =
+ static_cast<IndexSourceFileInfo*>(UserData);
+ CXIndex CIdx = (CXIndex)ITUI->idxAction;
+ CXClientData client_data = ITUI->client_data;
+ IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks;
+ unsigned index_callbacks_size = ITUI->index_callbacks_size;
+ unsigned index_options = ITUI->index_options;
+ const char *source_filename = ITUI->source_filename;
+ const char * const *command_line_args = ITUI->command_line_args;
+ int num_command_line_args = ITUI->num_command_line_args;
+ struct CXUnsavedFile *unsaved_files = ITUI->unsaved_files;
+ unsigned num_unsaved_files = ITUI->num_unsaved_files;
+ CXTranslationUnit *out_TU = ITUI->out_TU;
+ unsigned TU_options = ITUI->TU_options;
+ ITUI->result = 1; // init as error.
+
+ if (out_TU)
+ *out_TU = 0;
+ bool requestedToGetTU = (out_TU != 0);
+
+ if (!CIdx)
+ return;
+ if (!client_index_callbacks || index_callbacks_size == 0)
+ return;
+
+ IndexerCallbacks CB;
+ memset(&CB, 0, sizeof(CB));
+ unsigned ClientCBSize = index_callbacks_size < sizeof(CB)
+ ? index_callbacks_size : sizeof(CB);
+ memcpy(&CB, client_index_callbacks, ClientCBSize);
+
+ CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
+
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
+ setThreadBackgroundPriority();
+
+ CaptureDiagnosticConsumer *CaptureDiag = new CaptureDiagnosticConsumer();
+
+ // Configure the diagnostics.
+ DiagnosticOptions DiagOpts;
+ IntrusiveRefCntPtr<DiagnosticsEngine>
+ Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args,
+ command_line_args,
+ CaptureDiag,
+ /*ShouldOwnClient=*/true,
+ /*ShouldCloneClient=*/false));
+
+ // Recover resources if we crash before exiting this function.
+ llvm::CrashRecoveryContextCleanupRegistrar<DiagnosticsEngine,
+ llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
+ DiagCleanup(Diags.getPtr());
+
+ OwningPtr<std::vector<const char *> >
+ Args(new std::vector<const char*>());
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<std::vector<const char*> >
+ ArgsCleanup(Args.get());
+
+ Args->insert(Args->end(), command_line_args,
+ command_line_args + num_command_line_args);
+
+ // The 'source_filename' argument is optional. If the caller does not
+ // specify it then it is assumed that the source file is specified
+ // in the actual argument list.
+ // Put the source file after command_line_args otherwise if '-x' flag is
+ // present it will be unused.
+ if (source_filename)
+ Args->push_back(source_filename);
+
+ IntrusiveRefCntPtr<CompilerInvocation>
+ CInvok(createInvocationFromCommandLine(*Args, Diags));
+
+ if (!CInvok)
+ return;
+
+ // Recover resources if we crash before exiting this function.
+ llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation,
+ llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> >
+ CInvokCleanup(CInvok.getPtr());
+
+ if (CInvok->getFrontendOpts().Inputs.empty())
+ return;
+
+ OwningPtr<MemBufferOwner> BufOwner(new MemBufferOwner());
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<MemBufferOwner>
+ BufOwnerCleanup(BufOwner.get());
+
+ for (unsigned I = 0; I != num_unsaved_files; ++I) {
+ StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
+ const llvm::MemoryBuffer *Buffer
+ = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
+ CInvok->getPreprocessorOpts().addRemappedFile(unsaved_files[I].Filename, Buffer);
+ BufOwner->Buffers.push_back(Buffer);
+ }
+
+ // Since libclang is primarily used by batch tools dealing with
+ // (often very broken) source code, where spell-checking can have a
+ // significant negative impact on performance (particularly when
+ // precompiled headers are involved), we disable it.
+ CInvok->getLangOpts()->SpellChecking = false;
+
+ if (!requestedToGetTU)
+ CInvok->getPreprocessorOpts().DetailedRecord = false;
+
+ if (index_options & CXIndexOpt_SuppressWarnings)
+ CInvok->getDiagnosticOpts().IgnoreWarnings = true;
+
+ ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags,
+ /*CaptureDiagnostics=*/true);
+ OwningPtr<CXTUOwner> CXTU(new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit)));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<CXTUOwner>
+ CXTUCleanup(CXTU.get());
+
+ OwningPtr<IndexingFrontendAction> IndexAction;
+ IndexAction.reset(new IndexingFrontendAction(client_data, CB,
+ index_options, CXTU->getTU()));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<IndexingFrontendAction>
+ IndexActionCleanup(IndexAction.get());
+
+ bool Persistent = requestedToGetTU;
+ StringRef ResourceFilesPath = CXXIdx->getClangResourcesPath();
+ bool OnlyLocalDecls = false;
+ bool PrecompilePreamble = false;
+ bool CacheCodeCompletionResults = false;
+ PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts();
+ PPOpts.DetailedRecord = false;
+ PPOpts.AllowPCHWithCompilerErrors = true;
+
+ if (requestedToGetTU) {
+ OnlyLocalDecls = CXXIdx->getOnlyLocalDecls();
+ PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble;
+ // FIXME: Add a flag for modules.
+ CacheCodeCompletionResults
+ = TU_options & CXTranslationUnit_CacheCompletionResults;
+ if (TU_options & CXTranslationUnit_DetailedPreprocessingRecord) {
+ PPOpts.DetailedRecord = true;
+ }
+ }
+
+ DiagnosticErrorTrap DiagTrap(*Diags);
+ bool Success = ASTUnit::LoadFromCompilerInvocationAction(CInvok.getPtr(), Diags,
+ IndexAction.get(),
+ Unit,
+ Persistent,
+ ResourceFilesPath,
+ OnlyLocalDecls,
+ /*CaptureDiagnostics=*/true,
+ PrecompilePreamble,
+ CacheCodeCompletionResults);
+ if (DiagTrap.hasErrorOccurred() && CXXIdx->getDisplayDiagnostics())
+ printDiagsToStderr(Unit);
+
+ if (!Success)
+ return;
+
+ if (out_TU)
+ *out_TU = CXTU->takeTU();
+
+ ITUI->result = 0; // success.
+}
+
+//===----------------------------------------------------------------------===//
+// clang_indexTranslationUnit Implementation
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+struct IndexTranslationUnitInfo {
+ CXIndexAction idxAction;
+ CXClientData client_data;
+ IndexerCallbacks *index_callbacks;
+ unsigned index_callbacks_size;
+ unsigned index_options;
+ CXTranslationUnit TU;
+ int result;
+};
+
+} // anonymous namespace
+
+static void indexPreprocessingRecord(ASTUnit &Unit, IndexingContext &IdxCtx) {
+ Preprocessor &PP = Unit.getPreprocessor();
+ if (!PP.getPreprocessingRecord())
+ return;
+
+ PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
+
+ // FIXME: Only deserialize inclusion directives.
+ // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module
+ // that it depends on.
+
+ bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls();
+ PreprocessingRecord::iterator I, E;
+ if (OnlyLocal) {
+ I = PPRec.local_begin();
+ E = PPRec.local_end();
+ } else {
+ I = PPRec.begin();
+ E = PPRec.end();
+ }
+
+ for (; I != E; ++I) {
+ PreprocessedEntity *PPE = *I;
+
+ if (InclusionDirective *ID = dyn_cast<InclusionDirective>(PPE)) {
+ IdxCtx.ppIncludedFile(ID->getSourceRange().getBegin(), ID->getFileName(),
+ ID->getFile(), ID->getKind() == InclusionDirective::Import,
+ !ID->wasInQuotes());
+ }
+ }
+}
+
+static void indexTranslationUnit(ASTUnit &Unit, IndexingContext &IdxCtx) {
+ // FIXME: Only deserialize stuff from the last chained PCH, not the PCH/Module
+ // that it depends on.
+
+ bool OnlyLocal = !Unit.isMainFileAST() && Unit.getOnlyLocalDecls();
+
+ if (OnlyLocal) {
+ for (ASTUnit::top_level_iterator TL = Unit.top_level_begin(),
+ TLEnd = Unit.top_level_end();
+ TL != TLEnd; ++TL) {
+ IdxCtx.indexTopLevelDecl(*TL);
+ if (IdxCtx.shouldAbort())
+ return;
+ }
+
+ } else {
+ TranslationUnitDecl *TUDecl = Unit.getASTContext().getTranslationUnitDecl();
+ for (TranslationUnitDecl::decl_iterator
+ I = TUDecl->decls_begin(), E = TUDecl->decls_end(); I != E; ++I) {
+ IdxCtx.indexTopLevelDecl(*I);
+ if (IdxCtx.shouldAbort())
+ return;
+ }
+ }
+}
+
+static void indexDiagnostics(CXTranslationUnit TU, IndexingContext &IdxCtx) {
+ if (!IdxCtx.hasDiagnosticCallback())
+ return;
+
+ CXDiagnosticSetImpl *DiagSet = cxdiag::lazyCreateDiags(TU);
+ IdxCtx.handleDiagnosticSet(DiagSet);
+}
+
+static void clang_indexTranslationUnit_Impl(void *UserData) {
+ IndexTranslationUnitInfo *ITUI =
+ static_cast<IndexTranslationUnitInfo*>(UserData);
+ CXTranslationUnit TU = ITUI->TU;
+ CXClientData client_data = ITUI->client_data;
+ IndexerCallbacks *client_index_callbacks = ITUI->index_callbacks;
+ unsigned index_callbacks_size = ITUI->index_callbacks_size;
+ unsigned index_options = ITUI->index_options;
+ ITUI->result = 1; // init as error.
+
+ if (!TU)
+ return;
+ if (!client_index_callbacks || index_callbacks_size == 0)
+ return;
+
+ CIndexer *CXXIdx = (CIndexer*)TU->CIdx;
+ if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing))
+ setThreadBackgroundPriority();
+
+ IndexerCallbacks CB;
+ memset(&CB, 0, sizeof(CB));
+ unsigned ClientCBSize = index_callbacks_size < sizeof(CB)
+ ? index_callbacks_size : sizeof(CB);
+ memcpy(&CB, client_index_callbacks, ClientCBSize);
+
+ OwningPtr<IndexingContext> IndexCtx;
+ IndexCtx.reset(new IndexingContext(client_data, CB, index_options, TU));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<IndexingContext>
+ IndexCtxCleanup(IndexCtx.get());
+
+ OwningPtr<IndexingConsumer> IndexConsumer;
+ IndexConsumer.reset(new IndexingConsumer(*IndexCtx));
+
+ // Recover resources if we crash before exiting this method.
+ llvm::CrashRecoveryContextCleanupRegistrar<IndexingConsumer>
+ IndexConsumerCleanup(IndexConsumer.get());
+
+ ASTUnit *Unit = static_cast<ASTUnit *>(TU->TUData);
+ if (!Unit)
+ return;
+
+ FileManager &FileMgr = Unit->getFileManager();
+
+ if (Unit->getOriginalSourceFileName().empty())
+ IndexCtx->enteredMainFile(0);
+ else
+ IndexCtx->enteredMainFile(FileMgr.getFile(Unit->getOriginalSourceFileName()));
+
+ IndexConsumer->Initialize(Unit->getASTContext());
+
+ indexPreprocessingRecord(*Unit, *IndexCtx);
+ indexTranslationUnit(*Unit, *IndexCtx);
+ indexDiagnostics(TU, *IndexCtx);
+
+ ITUI->result = 0;
+}
+
+//===----------------------------------------------------------------------===//
+// libclang public APIs.
+//===----------------------------------------------------------------------===//
+
+extern "C" {
+
+int clang_index_isEntityObjCContainerKind(CXIdxEntityKind K) {
+ return CXIdxEntity_ObjCClass <= K && K <= CXIdxEntity_ObjCCategory;
+}
+
+const CXIdxObjCContainerDeclInfo *
+clang_index_getObjCContainerDeclInfo(const CXIdxDeclInfo *DInfo) {
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+ if (const ObjCContainerDeclInfo *
+ ContInfo = dyn_cast<ObjCContainerDeclInfo>(DI))
+ return &ContInfo->ObjCContDeclInfo;
+
+ return 0;
+}
+
+const CXIdxObjCInterfaceDeclInfo *
+clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *DInfo) {
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+ if (const ObjCInterfaceDeclInfo *
+ InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI))
+ return &InterInfo->ObjCInterDeclInfo;
+
+ return 0;
+}
+
+const CXIdxObjCCategoryDeclInfo *
+clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *DInfo){
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+ if (const ObjCCategoryDeclInfo *
+ CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI))
+ return &CatInfo->ObjCCatDeclInfo;
+
+ return 0;
+}
+
+const CXIdxObjCProtocolRefListInfo *
+clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *DInfo) {
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+
+ if (const ObjCInterfaceDeclInfo *
+ InterInfo = dyn_cast<ObjCInterfaceDeclInfo>(DI))
+ return InterInfo->ObjCInterDeclInfo.protocols;
+
+ if (const ObjCProtocolDeclInfo *
+ ProtInfo = dyn_cast<ObjCProtocolDeclInfo>(DI))
+ return &ProtInfo->ObjCProtoRefListInfo;
+
+ if (const ObjCCategoryDeclInfo *CatInfo = dyn_cast<ObjCCategoryDeclInfo>(DI))
+ return CatInfo->ObjCCatDeclInfo.protocols;
+
+ return 0;
+}
+
+const CXIdxObjCPropertyDeclInfo *
+clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *DInfo) {
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+ if (const ObjCPropertyDeclInfo *PropInfo = dyn_cast<ObjCPropertyDeclInfo>(DI))
+ return &PropInfo->ObjCPropDeclInfo;
+
+ return 0;
+}
+
+const CXIdxIBOutletCollectionAttrInfo *
+clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *AInfo) {
+ if (!AInfo)
+ return 0;
+
+ const AttrInfo *DI = static_cast<const AttrInfo *>(AInfo);
+ if (const IBOutletCollectionInfo *
+ IBInfo = dyn_cast<IBOutletCollectionInfo>(DI))
+ return &IBInfo->IBCollInfo;
+
+ return 0;
+}
+
+const CXIdxCXXClassDeclInfo *
+clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *DInfo) {
+ if (!DInfo)
+ return 0;
+
+ const DeclInfo *DI = static_cast<const DeclInfo *>(DInfo);
+ if (const CXXClassDeclInfo *ClassInfo = dyn_cast<CXXClassDeclInfo>(DI))
+ return &ClassInfo->CXXClassInfo;
+
+ return 0;
+}
+
+CXIdxClientContainer
+clang_index_getClientContainer(const CXIdxContainerInfo *info) {
+ if (!info)
+ return 0;
+ const ContainerInfo *Container = static_cast<const ContainerInfo *>(info);
+ return Container->IndexCtx->getClientContainerForDC(Container->DC);
+}
+
+void clang_index_setClientContainer(const CXIdxContainerInfo *info,
+ CXIdxClientContainer client) {
+ if (!info)
+ return;
+ const ContainerInfo *Container = static_cast<const ContainerInfo *>(info);
+ Container->IndexCtx->addContainerInMap(Container->DC, client);
+}
+
+CXIdxClientEntity clang_index_getClientEntity(const CXIdxEntityInfo *info) {
+ if (!info)
+ return 0;
+ const EntityInfo *Entity = static_cast<const EntityInfo *>(info);
+ return Entity->IndexCtx->getClientEntity(Entity->Dcl);
+}
+
+void clang_index_setClientEntity(const CXIdxEntityInfo *info,
+ CXIdxClientEntity client) {
+ if (!info)
+ return;
+ const EntityInfo *Entity = static_cast<const EntityInfo *>(info);
+ Entity->IndexCtx->setClientEntity(Entity->Dcl, client);
+}
+
+CXIndexAction clang_IndexAction_create(CXIndex CIdx) {
+ // For now, CXIndexAction is featureless.
+ return CIdx;
+}
+
+void clang_IndexAction_dispose(CXIndexAction idxAction) {
+ // For now, CXIndexAction is featureless.
+}
+
+int clang_indexSourceFile(CXIndexAction idxAction,
+ CXClientData client_data,
+ IndexerCallbacks *index_callbacks,
+ unsigned index_callbacks_size,
+ unsigned index_options,
+ const char *source_filename,
+ const char * const *command_line_args,
+ int num_command_line_args,
+ struct CXUnsavedFile *unsaved_files,
+ unsigned num_unsaved_files,
+ CXTranslationUnit *out_TU,
+ unsigned TU_options) {
+
+ IndexSourceFileInfo ITUI = { idxAction, client_data, index_callbacks,
+ index_callbacks_size, index_options,
+ source_filename, command_line_args,
+ num_command_line_args, unsaved_files,
+ num_unsaved_files, out_TU, TU_options, 0 };
+
+ if (getenv("LIBCLANG_NOTHREADS")) {
+ clang_indexSourceFile_Impl(&ITUI);
+ return ITUI.result;
+ }
+
+ llvm::CrashRecoveryContext CRC;
+
+ if (!RunSafely(CRC, clang_indexSourceFile_Impl, &ITUI)) {
+ fprintf(stderr, "libclang: crash detected during indexing source file: {\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", TU_options);
+ fprintf(stderr, "}\n");
+
+ return 1;
+ } else if (getenv("LIBCLANG_RESOURCE_USAGE")) {
+ if (out_TU)
+ PrintLibclangResourceUsage(*out_TU);
+ }
+
+ return ITUI.result;
+}
+
+int clang_indexTranslationUnit(CXIndexAction idxAction,
+ CXClientData client_data,
+ IndexerCallbacks *index_callbacks,
+ unsigned index_callbacks_size,
+ unsigned index_options,
+ CXTranslationUnit TU) {
+
+ IndexTranslationUnitInfo ITUI = { idxAction, client_data, index_callbacks,
+ index_callbacks_size, index_options, TU,
+ 0 };
+
+ if (getenv("LIBCLANG_NOTHREADS")) {
+ clang_indexTranslationUnit_Impl(&ITUI);
+ return ITUI.result;
+ }
+
+ llvm::CrashRecoveryContext CRC;
+
+ if (!RunSafely(CRC, clang_indexTranslationUnit_Impl, &ITUI)) {
+ fprintf(stderr, "libclang: crash detected during indexing TU\n");
+
+ return 1;
+ }
+
+ return ITUI.result;
+}
+
+void clang_indexLoc_getFileLocation(CXIdxLoc location,
+ CXIdxClientFile *indexFile,
+ CXFile *file,
+ unsigned *line,
+ unsigned *column,
+ unsigned *offset) {
+ if (indexFile) *indexFile = 0;
+ if (file) *file = 0;
+ if (line) *line = 0;
+ if (column) *column = 0;
+ if (offset) *offset = 0;
+
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+ if (!location.ptr_data[0] || Loc.isInvalid())
+ return;
+
+ IndexingContext &IndexCtx =
+ *static_cast<IndexingContext*>(location.ptr_data[0]);
+ IndexCtx.translateLoc(Loc, indexFile, file, line, column, offset);
+}
+
+CXSourceLocation clang_indexLoc_getCXSourceLocation(CXIdxLoc location) {
+ SourceLocation Loc = SourceLocation::getFromRawEncoding(location.int_data);
+ if (!location.ptr_data[0] || Loc.isInvalid())
+ return clang_getNullLocation();
+
+ IndexingContext &IndexCtx =
+ *static_cast<IndexingContext*>(location.ptr_data[0]);
+ return cxloc::translateSourceLocation(IndexCtx.getASTContext(), Loc);
+}
+
+} // end: extern "C"
+
diff --git a/tools/libclang/IndexingContext.cpp b/tools/libclang/IndexingContext.cpp
new file mode 100644
index 000000000000..ace5c75a96f7
--- /dev/null
+++ b/tools/libclang/IndexingContext.cpp
@@ -0,0 +1,1080 @@
+//===- CIndexHigh.cpp - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexingContext.h"
+#include "CXTranslationUnit.h"
+#include "CIndexDiagnostic.h"
+
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+
+using namespace clang;
+using namespace cxindex;
+using namespace cxcursor;
+
+IndexingContext::ObjCProtocolListInfo::ObjCProtocolListInfo(
+ const ObjCProtocolList &ProtList,
+ IndexingContext &IdxCtx,
+ ScratchAlloc &SA) {
+ ObjCInterfaceDecl::protocol_loc_iterator LI = ProtList.loc_begin();
+ for (ObjCInterfaceDecl::protocol_iterator
+ I = ProtList.begin(), E = ProtList.end(); I != E; ++I, ++LI) {
+ SourceLocation Loc = *LI;
+ ObjCProtocolDecl *PD = *I;
+ ProtEntities.push_back(EntityInfo());
+ IdxCtx.getEntityInfo(PD, ProtEntities.back(), SA);
+ CXIdxObjCProtocolRefInfo ProtInfo = { 0,
+ MakeCursorObjCProtocolRef(PD, Loc, IdxCtx.CXTU),
+ IdxCtx.getIndexLoc(Loc) };
+ ProtInfos.push_back(ProtInfo);
+
+ if (IdxCtx.shouldSuppressRefs())
+ IdxCtx.markEntityOccurrenceInFile(PD, Loc);
+ }
+
+ for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i)
+ ProtInfos[i].protocol = &ProtEntities[i];
+
+ for (unsigned i = 0, e = ProtInfos.size(); i != e; ++i)
+ Prots.push_back(&ProtInfos[i]);
+}
+
+
+IBOutletCollectionInfo::IBOutletCollectionInfo(
+ const IBOutletCollectionInfo &other)
+ : AttrInfo(CXIdxAttr_IBOutletCollection, other.cursor, other.loc, other.A) {
+
+ IBCollInfo.attrInfo = this;
+ IBCollInfo.classCursor = other.IBCollInfo.classCursor;
+ IBCollInfo.classLoc = other.IBCollInfo.classLoc;
+ if (other.IBCollInfo.objcClass) {
+ ClassInfo = other.ClassInfo;
+ IBCollInfo.objcClass = &ClassInfo;
+ } else
+ IBCollInfo.objcClass = 0;
+}
+
+AttrListInfo::AttrListInfo(const Decl *D, IndexingContext &IdxCtx)
+ : SA(IdxCtx), ref_cnt(0) {
+
+ if (!D->hasAttrs())
+ return;
+
+ for (AttrVec::const_iterator AttrI = D->attr_begin(), AttrE = D->attr_end();
+ AttrI != AttrE; ++AttrI) {
+ const Attr *A = *AttrI;
+ CXCursor C = MakeCXCursor(A, const_cast<Decl *>(D), IdxCtx.CXTU);
+ CXIdxLoc Loc = IdxCtx.getIndexLoc(A->getLocation());
+ switch (C.kind) {
+ default:
+ Attrs.push_back(AttrInfo(CXIdxAttr_Unexposed, C, Loc, A));
+ break;
+ case CXCursor_IBActionAttr:
+ Attrs.push_back(AttrInfo(CXIdxAttr_IBAction, C, Loc, A));
+ break;
+ case CXCursor_IBOutletAttr:
+ Attrs.push_back(AttrInfo(CXIdxAttr_IBOutlet, C, Loc, A));
+ break;
+ case CXCursor_IBOutletCollectionAttr:
+ IBCollAttrs.push_back(IBOutletCollectionInfo(C, Loc, A));
+ break;
+ }
+ }
+
+ for (unsigned i = 0, e = IBCollAttrs.size(); i != e; ++i) {
+ IBOutletCollectionInfo &IBInfo = IBCollAttrs[i];
+ CXAttrs.push_back(&IBInfo);
+
+ const IBOutletCollectionAttr *
+ IBAttr = cast<IBOutletCollectionAttr>(IBInfo.A);
+ IBInfo.IBCollInfo.attrInfo = &IBInfo;
+ IBInfo.IBCollInfo.classLoc = IdxCtx.getIndexLoc(IBAttr->getInterfaceLoc());
+ IBInfo.IBCollInfo.objcClass = 0;
+ IBInfo.IBCollInfo.classCursor = clang_getNullCursor();
+ QualType Ty = IBAttr->getInterface();
+ if (const ObjCInterfaceType *InterTy = Ty->getAs<ObjCInterfaceType>()) {
+ if (const ObjCInterfaceDecl *InterD = InterTy->getInterface()) {
+ IdxCtx.getEntityInfo(InterD, IBInfo.ClassInfo, SA);
+ IBInfo.IBCollInfo.objcClass = &IBInfo.ClassInfo;
+ IBInfo.IBCollInfo.classCursor = MakeCursorObjCClassRef(InterD,
+ IBAttr->getInterfaceLoc(), IdxCtx.CXTU);
+ }
+ }
+ }
+
+ for (unsigned i = 0, e = Attrs.size(); i != e; ++i)
+ CXAttrs.push_back(&Attrs[i]);
+}
+
+IntrusiveRefCntPtr<AttrListInfo>
+AttrListInfo::create(const Decl *D, IndexingContext &IdxCtx) {
+ ScratchAlloc SA(IdxCtx);
+ AttrListInfo *attrs = SA.allocate<AttrListInfo>();
+ return new (attrs) AttrListInfo(D, IdxCtx);
+}
+
+IndexingContext::CXXBasesListInfo::CXXBasesListInfo(const CXXRecordDecl *D,
+ IndexingContext &IdxCtx,
+ ScratchAlloc &SA) {
+ for (CXXRecordDecl::base_class_const_iterator
+ I = D->bases_begin(), E = D->bases_end(); I != E; ++I) {
+ const CXXBaseSpecifier &Base = *I;
+ BaseEntities.push_back(EntityInfo());
+ const NamedDecl *BaseD = 0;
+ QualType T = Base.getType();
+ SourceLocation Loc = getBaseLoc(Base);
+
+ if (const TypedefType *TDT = T->getAs<TypedefType>()) {
+ BaseD = TDT->getDecl();
+ } else if (const TemplateSpecializationType *
+ TST = T->getAs<TemplateSpecializationType>()) {
+ BaseD = TST->getTemplateName().getAsTemplateDecl();
+ } else if (const RecordType *RT = T->getAs<RecordType>()) {
+ BaseD = RT->getDecl();
+ }
+
+ if (BaseD)
+ IdxCtx.getEntityInfo(BaseD, BaseEntities.back(), SA);
+ CXIdxBaseClassInfo BaseInfo = { 0,
+ MakeCursorCXXBaseSpecifier(&Base, IdxCtx.CXTU),
+ IdxCtx.getIndexLoc(Loc) };
+ BaseInfos.push_back(BaseInfo);
+ }
+
+ for (unsigned i = 0, e = BaseInfos.size(); i != e; ++i) {
+ if (BaseEntities[i].name && BaseEntities[i].USR)
+ BaseInfos[i].base = &BaseEntities[i];
+ }
+
+ for (unsigned i = 0, e = BaseInfos.size(); i != e; ++i)
+ CXBases.push_back(&BaseInfos[i]);
+}
+
+SourceLocation IndexingContext::CXXBasesListInfo::getBaseLoc(
+ const CXXBaseSpecifier &Base) const {
+ SourceLocation Loc = Base.getSourceRange().getBegin();
+ TypeLoc TL;
+ if (Base.getTypeSourceInfo())
+ TL = Base.getTypeSourceInfo()->getTypeLoc();
+ if (TL.isNull())
+ return Loc;
+
+ if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL))
+ TL = QL->getUnqualifiedLoc();
+
+ if (const ElaboratedTypeLoc *EL = dyn_cast<ElaboratedTypeLoc>(&TL))
+ return EL->getNamedTypeLoc().getBeginLoc();
+ if (const DependentNameTypeLoc *DL = dyn_cast<DependentNameTypeLoc>(&TL))
+ return DL->getNameLoc();
+ if (const DependentTemplateSpecializationTypeLoc *
+ DTL = dyn_cast<DependentTemplateSpecializationTypeLoc>(&TL))
+ return DTL->getTemplateNameLoc();
+
+ return Loc;
+}
+
+const char *ScratchAlloc::toCStr(StringRef Str) {
+ if (Str.empty())
+ return "";
+ if (Str.data()[Str.size()] == '\0')
+ return Str.data();
+ return copyCStr(Str);
+}
+
+const char *ScratchAlloc::copyCStr(StringRef Str) {
+ char *buf = IdxCtx.StrScratch.Allocate<char>(Str.size() + 1);
+ std::uninitialized_copy(Str.begin(), Str.end(), buf);
+ buf[Str.size()] = '\0';
+ return buf;
+}
+
+void IndexingContext::setASTContext(ASTContext &ctx) {
+ Ctx = &ctx;
+ static_cast<ASTUnit*>(CXTU->TUData)->setASTContext(&ctx);
+}
+
+void IndexingContext::setPreprocessor(Preprocessor &PP) {
+ static_cast<ASTUnit*>(CXTU->TUData)->setPreprocessor(&PP);
+}
+
+bool IndexingContext::shouldAbort() {
+ if (!CB.abortQuery)
+ return false;
+ return CB.abortQuery(ClientData, 0);
+}
+
+void IndexingContext::enteredMainFile(const FileEntry *File) {
+ if (File && CB.enteredMainFile) {
+ CXIdxClientFile idxFile = CB.enteredMainFile(ClientData, (CXFile)File, 0);
+ FileMap[File] = idxFile;
+ }
+}
+
+void IndexingContext::ppIncludedFile(SourceLocation hashLoc,
+ StringRef filename,
+ const FileEntry *File,
+ bool isImport, bool isAngled) {
+ if (!CB.ppIncludedFile)
+ return;
+
+ ScratchAlloc SA(*this);
+ CXIdxIncludedFileInfo Info = { getIndexLoc(hashLoc),
+ SA.toCStr(filename),
+ (CXFile)File,
+ isImport, isAngled };
+ CXIdxClientFile idxFile = CB.ppIncludedFile(ClientData, &Info);
+ FileMap[File] = idxFile;
+}
+
+void IndexingContext::startedTranslationUnit() {
+ CXIdxClientContainer idxCont = 0;
+ if (CB.startedTranslationUnit)
+ idxCont = CB.startedTranslationUnit(ClientData, 0);
+ addContainerInMap(Ctx->getTranslationUnitDecl(), idxCont);
+}
+
+void IndexingContext::handleDiagnosticSet(CXDiagnostic CXDiagSet) {
+ if (!CB.diagnostic)
+ return;
+
+ CB.diagnostic(ClientData, CXDiagSet, 0);
+}
+
+bool IndexingContext::handleDecl(const NamedDecl *D,
+ SourceLocation Loc, CXCursor Cursor,
+ DeclInfo &DInfo,
+ const DeclContext *LexicalDC) {
+ if (!CB.indexDeclaration || !D)
+ return false;
+ if (D->isImplicit() && shouldIgnoreIfImplicit(D))
+ return false;
+
+ ScratchAlloc SA(*this);
+ getEntityInfo(D, DInfo.EntInfo, SA);
+ if ((!shouldIndexFunctionLocalSymbols() && !DInfo.EntInfo.USR)
+ || Loc.isInvalid())
+ return false;
+
+ if (!LexicalDC)
+ LexicalDC = D->getLexicalDeclContext();
+
+ if (shouldSuppressRefs())
+ markEntityOccurrenceInFile(D, Loc);
+
+ DInfo.entityInfo = &DInfo.EntInfo;
+ DInfo.cursor = Cursor;
+ DInfo.loc = getIndexLoc(Loc);
+ DInfo.isImplicit = D->isImplicit();
+
+ DInfo.attributes = DInfo.EntInfo.attributes;
+ DInfo.numAttributes = DInfo.EntInfo.numAttributes;
+
+ getContainerInfo(D->getDeclContext(), DInfo.SemanticContainer);
+ DInfo.semanticContainer = &DInfo.SemanticContainer;
+
+ if (LexicalDC == D->getDeclContext()) {
+ DInfo.lexicalContainer = &DInfo.SemanticContainer;
+ } else if (isTemplateImplicitInstantiation(D)) {
+ // Implicit instantiations have the lexical context of where they were
+ // instantiated first. We choose instead the semantic context because:
+ // 1) at the time that we see the instantiation we have not seen the
+ // function where it occurred yet.
+ // 2) the lexical context of the first instantiation is not useful
+ // information anyway.
+ DInfo.lexicalContainer = &DInfo.SemanticContainer;
+ } else {
+ getContainerInfo(LexicalDC, DInfo.LexicalContainer);
+ DInfo.lexicalContainer = &DInfo.LexicalContainer;
+ }
+
+ if (DInfo.isContainer) {
+ getContainerInfo(getEntityContainer(D), DInfo.DeclAsContainer);
+ DInfo.declAsContainer = &DInfo.DeclAsContainer;
+ }
+
+ CB.indexDeclaration(ClientData, &DInfo);
+ return true;
+}
+
+bool IndexingContext::handleObjCContainer(const ObjCContainerDecl *D,
+ SourceLocation Loc, CXCursor Cursor,
+ ObjCContainerDeclInfo &ContDInfo) {
+ ContDInfo.ObjCContDeclInfo.declInfo = &ContDInfo;
+ return handleDecl(D, Loc, Cursor, ContDInfo);
+}
+
+bool IndexingContext::handleFunction(const FunctionDecl *D) {
+ DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(),
+ D->isThisDeclarationADefinition());
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleVar(const VarDecl *D) {
+ DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(),
+ /*isContainer=*/false);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleField(const FieldDecl *D) {
+ DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true,
+ /*isContainer=*/false);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleEnumerator(const EnumConstantDecl *D) {
+ DeclInfo DInfo(/*isRedeclaration=*/false, /*isDefinition=*/true,
+ /*isContainer=*/false);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleTagDecl(const TagDecl *D) {
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(D))
+ return handleCXXRecordDecl(CXXRD, D);
+
+ DeclInfo DInfo(!D->isFirstDeclaration(), D->isThisDeclarationADefinition(),
+ D->isThisDeclarationADefinition());
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleTypedefName(const TypedefNameDecl *D) {
+ DeclInfo DInfo(!D->isFirstDeclaration(), /*isDefinition=*/true,
+ /*isContainer=*/false);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleObjCInterface(const ObjCInterfaceDecl *D) {
+ // For @class forward declarations, suppress them the same way as references.
+ if (!D->isThisDeclarationADefinition()) {
+ if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, D->getLocation()))
+ return false; // already occurred.
+
+ // FIXME: This seems like the wrong definition for redeclaration.
+ bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl();
+ ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true, isRedeclaration,
+ /*isImplementation=*/false);
+ return handleObjCContainer(D, D->getLocation(),
+ MakeCursorObjCClassRef(D, D->getLocation(),
+ CXTU),
+ ContDInfo);
+ }
+
+ ScratchAlloc SA(*this);
+
+ CXIdxBaseClassInfo BaseClass;
+ EntityInfo BaseEntity;
+ BaseClass.cursor = clang_getNullCursor();
+ if (ObjCInterfaceDecl *SuperD = D->getSuperClass()) {
+ getEntityInfo(SuperD, BaseEntity, SA);
+ SourceLocation SuperLoc = D->getSuperClassLoc();
+ BaseClass.base = &BaseEntity;
+ BaseClass.cursor = MakeCursorObjCSuperClassRef(SuperD, SuperLoc, CXTU);
+ BaseClass.loc = getIndexLoc(SuperLoc);
+
+ if (shouldSuppressRefs())
+ markEntityOccurrenceInFile(SuperD, SuperLoc);
+ }
+
+ ObjCProtocolList EmptyProtoList;
+ ObjCProtocolListInfo ProtInfo(D->isThisDeclarationADefinition()
+ ? D->getReferencedProtocols()
+ : EmptyProtoList,
+ *this, SA);
+
+ ObjCInterfaceDeclInfo InterInfo(D);
+ InterInfo.ObjCProtoListInfo = ProtInfo.getListInfo();
+ InterInfo.ObjCInterDeclInfo.containerInfo = &InterInfo.ObjCContDeclInfo;
+ InterInfo.ObjCInterDeclInfo.superInfo = D->getSuperClass() ? &BaseClass : 0;
+ InterInfo.ObjCInterDeclInfo.protocols = &InterInfo.ObjCProtoListInfo;
+
+ return handleObjCContainer(D, D->getLocation(), getCursor(D), InterInfo);
+}
+
+bool IndexingContext::handleObjCImplementation(
+ const ObjCImplementationDecl *D) {
+ ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/false,
+ /*isRedeclaration=*/true,
+ /*isImplementation=*/true);
+ return handleObjCContainer(D, D->getLocation(), getCursor(D), ContDInfo);
+}
+
+bool IndexingContext::handleObjCProtocol(const ObjCProtocolDecl *D) {
+ if (!D->isThisDeclarationADefinition()) {
+ if (shouldSuppressRefs() && markEntityOccurrenceInFile(D, D->getLocation()))
+ return false; // already occurred.
+
+ // FIXME: This seems like the wrong definition for redeclaration.
+ bool isRedeclaration = D->hasDefinition() || D->getPreviousDecl();
+ ObjCContainerDeclInfo ContDInfo(/*isForwardRef=*/true,
+ isRedeclaration,
+ /*isImplementation=*/false);
+ return handleObjCContainer(D, D->getLocation(),
+ MakeCursorObjCProtocolRef(D, D->getLocation(),
+ CXTU),
+ ContDInfo);
+ }
+
+ ScratchAlloc SA(*this);
+ ObjCProtocolList EmptyProtoList;
+ ObjCProtocolListInfo ProtListInfo(D->isThisDeclarationADefinition()
+ ? D->getReferencedProtocols()
+ : EmptyProtoList,
+ *this, SA);
+
+ ObjCProtocolDeclInfo ProtInfo(D);
+ ProtInfo.ObjCProtoRefListInfo = ProtListInfo.getListInfo();
+
+ return handleObjCContainer(D, D->getLocation(), getCursor(D), ProtInfo);
+}
+
+bool IndexingContext::handleObjCCategory(const ObjCCategoryDecl *D) {
+ ScratchAlloc SA(*this);
+
+ ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/false);
+ EntityInfo ClassEntity;
+ const ObjCInterfaceDecl *IFaceD = D->getClassInterface();
+ SourceLocation ClassLoc = D->getLocation();
+ SourceLocation CategoryLoc = D->IsClassExtension() ? ClassLoc
+ : D->getCategoryNameLoc();
+ getEntityInfo(IFaceD, ClassEntity, SA);
+
+ if (shouldSuppressRefs())
+ markEntityOccurrenceInFile(IFaceD, ClassLoc);
+
+ ObjCProtocolListInfo ProtInfo(D->getReferencedProtocols(), *this, SA);
+
+ CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo;
+ if (IFaceD) {
+ CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity;
+ CatDInfo.ObjCCatDeclInfo.classCursor =
+ MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU);
+ } else {
+ CatDInfo.ObjCCatDeclInfo.objcClass = 0;
+ CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor();
+ }
+ CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc);
+ CatDInfo.ObjCProtoListInfo = ProtInfo.getListInfo();
+ CatDInfo.ObjCCatDeclInfo.protocols = &CatDInfo.ObjCProtoListInfo;
+
+ return handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo);
+}
+
+bool IndexingContext::handleObjCCategoryImpl(const ObjCCategoryImplDecl *D) {
+ ScratchAlloc SA(*this);
+
+ const ObjCCategoryDecl *CatD = D->getCategoryDecl();
+ ObjCCategoryDeclInfo CatDInfo(/*isImplementation=*/true);
+ EntityInfo ClassEntity;
+ const ObjCInterfaceDecl *IFaceD = CatD->getClassInterface();
+ SourceLocation ClassLoc = D->getLocation();
+ SourceLocation CategoryLoc = D->getCategoryNameLoc();
+ getEntityInfo(IFaceD, ClassEntity, SA);
+
+ if (shouldSuppressRefs())
+ markEntityOccurrenceInFile(IFaceD, ClassLoc);
+
+ CatDInfo.ObjCCatDeclInfo.containerInfo = &CatDInfo.ObjCContDeclInfo;
+ if (IFaceD) {
+ CatDInfo.ObjCCatDeclInfo.objcClass = &ClassEntity;
+ CatDInfo.ObjCCatDeclInfo.classCursor =
+ MakeCursorObjCClassRef(IFaceD, ClassLoc, CXTU);
+ } else {
+ CatDInfo.ObjCCatDeclInfo.objcClass = 0;
+ CatDInfo.ObjCCatDeclInfo.classCursor = clang_getNullCursor();
+ }
+ CatDInfo.ObjCCatDeclInfo.classLoc = getIndexLoc(ClassLoc);
+ CatDInfo.ObjCCatDeclInfo.protocols = 0;
+
+ return handleObjCContainer(D, CategoryLoc, getCursor(D), CatDInfo);
+}
+
+bool IndexingContext::handleObjCMethod(const ObjCMethodDecl *D) {
+ DeclInfo DInfo(!D->isCanonicalDecl(), D->isThisDeclarationADefinition(),
+ D->isThisDeclarationADefinition());
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleSynthesizedObjCProperty(
+ const ObjCPropertyImplDecl *D) {
+ ObjCPropertyDecl *PD = D->getPropertyDecl();
+ return handleReference(PD, D->getLocation(), getCursor(D), 0, D->getDeclContext());
+}
+
+bool IndexingContext::handleSynthesizedObjCMethod(const ObjCMethodDecl *D,
+ SourceLocation Loc,
+ const DeclContext *LexicalDC) {
+ DeclInfo DInfo(/*isRedeclaration=*/true, /*isDefinition=*/true,
+ /*isContainer=*/false);
+ return handleDecl(D, Loc, getCursor(D), DInfo, LexicalDC);
+}
+
+bool IndexingContext::handleObjCProperty(const ObjCPropertyDecl *D) {
+ ScratchAlloc SA(*this);
+
+ ObjCPropertyDeclInfo DInfo;
+ EntityInfo GetterEntity;
+ EntityInfo SetterEntity;
+
+ DInfo.ObjCPropDeclInfo.declInfo = &DInfo;
+
+ if (ObjCMethodDecl *Getter = D->getGetterMethodDecl()) {
+ getEntityInfo(Getter, GetterEntity, SA);
+ DInfo.ObjCPropDeclInfo.getter = &GetterEntity;
+ } else {
+ DInfo.ObjCPropDeclInfo.getter = 0;
+ }
+ if (ObjCMethodDecl *Setter = D->getSetterMethodDecl()) {
+ getEntityInfo(Setter, SetterEntity, SA);
+ DInfo.ObjCPropDeclInfo.setter = &SetterEntity;
+ } else {
+ DInfo.ObjCPropDeclInfo.setter = 0;
+ }
+
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleNamespace(const NamespaceDecl *D) {
+ DeclInfo DInfo(/*isRedeclaration=*/!D->isOriginalNamespace(),
+ /*isDefinition=*/true,
+ /*isContainer=*/true);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleClassTemplate(const ClassTemplateDecl *D) {
+ return handleCXXRecordDecl(D->getTemplatedDecl(), D);
+}
+
+bool IndexingContext::handleFunctionTemplate(const FunctionTemplateDecl *D) {
+ DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(),
+ /*isDefinition=*/D->isThisDeclarationADefinition(),
+ /*isContainer=*/D->isThisDeclarationADefinition());
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleTypeAliasTemplate(const TypeAliasTemplateDecl *D) {
+ DeclInfo DInfo(/*isRedeclaration=*/!D->isCanonicalDecl(),
+ /*isDefinition=*/true, /*isContainer=*/false);
+ return handleDecl(D, D->getLocation(), getCursor(D), DInfo);
+}
+
+bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
+ const NamedDecl *Parent,
+ const DeclContext *DC,
+ const Expr *E,
+ CXIdxEntityRefKind Kind) {
+ if (!D)
+ return false;
+
+ CXCursor Cursor = E ? MakeCXCursor(const_cast<Expr*>(E),
+ const_cast<Decl*>(cast<Decl>(DC)), CXTU)
+ : getRefCursor(D, Loc);
+ return handleReference(D, Loc, Cursor, Parent, DC, E, Kind);
+}
+
+bool IndexingContext::handleReference(const NamedDecl *D, SourceLocation Loc,
+ CXCursor Cursor,
+ const NamedDecl *Parent,
+ const DeclContext *DC,
+ const Expr *E,
+ CXIdxEntityRefKind Kind) {
+ if (!CB.indexEntityReference)
+ return false;
+
+ if (!D)
+ return false;
+ if (Loc.isInvalid())
+ return false;
+ if (!shouldIndexFunctionLocalSymbols() && D->getParentFunctionOrMethod())
+ return false;
+ if (isNotFromSourceFile(D->getLocation()))
+ return false;
+ if (D->isImplicit() && shouldIgnoreIfImplicit(D))
+ return false;
+
+ if (shouldSuppressRefs()) {
+ if (markEntityOccurrenceInFile(D, Loc))
+ return false; // already occurred.
+ }
+
+ ScratchAlloc SA(*this);
+ EntityInfo RefEntity, ParentEntity;
+ getEntityInfo(D, RefEntity, SA);
+ if (!RefEntity.USR)
+ return false;
+
+ getEntityInfo(Parent, ParentEntity, SA);
+
+ ContainerInfo Container;
+ getContainerInfo(DC, Container);
+
+ CXIdxEntityRefInfo Info = { Kind,
+ Cursor,
+ getIndexLoc(Loc),
+ &RefEntity,
+ Parent ? &ParentEntity : 0,
+ &Container };
+ CB.indexEntityReference(ClientData, &Info);
+ return true;
+}
+
+bool IndexingContext::isNotFromSourceFile(SourceLocation Loc) const {
+ if (Loc.isInvalid())
+ return true;
+ SourceManager &SM = Ctx->getSourceManager();
+ SourceLocation FileLoc = SM.getFileLoc(Loc);
+ FileID FID = SM.getFileID(FileLoc);
+ return SM.getFileEntryForID(FID) == 0;
+}
+
+void IndexingContext::addContainerInMap(const DeclContext *DC,
+ CXIdxClientContainer container) {
+ if (!DC)
+ return;
+
+ ContainerMapTy::iterator I = ContainerMap.find(DC);
+ if (I == ContainerMap.end()) {
+ if (container)
+ ContainerMap[DC] = container;
+ return;
+ }
+ // Allow changing the container of a previously seen DeclContext so we
+ // can handle invalid user code, like a function re-definition.
+ if (container)
+ I->second = container;
+ else
+ ContainerMap.erase(I);
+}
+
+CXIdxClientEntity IndexingContext::getClientEntity(const Decl *D) const {
+ if (!D)
+ return 0;
+ EntityMapTy::const_iterator I = EntityMap.find(D);
+ if (I == EntityMap.end())
+ return 0;
+ return I->second;
+}
+
+void IndexingContext::setClientEntity(const Decl *D, CXIdxClientEntity client) {
+ if (!D)
+ return;
+ EntityMap[D] = client;
+}
+
+bool IndexingContext::handleCXXRecordDecl(const CXXRecordDecl *RD,
+ const NamedDecl *OrigD) {
+ if (RD->isThisDeclarationADefinition()) {
+ ScratchAlloc SA(*this);
+ CXXClassDeclInfo CXXDInfo(/*isRedeclaration=*/!OrigD->isCanonicalDecl(),
+ /*isDefinition=*/RD->isThisDeclarationADefinition());
+ CXXBasesListInfo BaseList(RD, *this, SA);
+ CXXDInfo.CXXClassInfo.declInfo = &CXXDInfo;
+ CXXDInfo.CXXClassInfo.bases = BaseList.getBases();
+ CXXDInfo.CXXClassInfo.numBases = BaseList.getNumBases();
+
+ if (shouldSuppressRefs()) {
+ // Go through bases and mark them as referenced.
+ for (unsigned i = 0, e = BaseList.getNumBases(); i != e; ++i) {
+ const CXIdxBaseClassInfo *baseInfo = BaseList.getBases()[i];
+ if (baseInfo->base) {
+ const NamedDecl *BaseD = BaseList.BaseEntities[i].Dcl;
+ SourceLocation
+ Loc = SourceLocation::getFromRawEncoding(baseInfo->loc.int_data);
+ markEntityOccurrenceInFile(BaseD, Loc);
+ }
+ }
+ }
+
+ return handleDecl(OrigD, OrigD->getLocation(), getCursor(OrigD), CXXDInfo);
+ }
+
+ DeclInfo DInfo(/*isRedeclaration=*/!OrigD->isCanonicalDecl(),
+ /*isDefinition=*/RD->isThisDeclarationADefinition(),
+ /*isContainer=*/RD->isThisDeclarationADefinition());
+ return handleDecl(OrigD, OrigD->getLocation(), getCursor(OrigD), DInfo);
+}
+
+bool IndexingContext::markEntityOccurrenceInFile(const NamedDecl *D,
+ SourceLocation Loc) {
+ if (!D || Loc.isInvalid())
+ return true;
+
+ SourceManager &SM = Ctx->getSourceManager();
+ D = getEntityDecl(D);
+
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(SM.getFileLoc(Loc));
+ FileID FID = LocInfo.first;
+ if (FID.isInvalid())
+ return true;
+
+ const FileEntry *FE = SM.getFileEntryForID(FID);
+ if (!FE)
+ return true;
+ RefFileOccurence RefOccur(FE, D);
+ std::pair<llvm::DenseSet<RefFileOccurence>::iterator, bool>
+ res = RefFileOccurences.insert(RefOccur);
+ if (!res.second)
+ return true; // already in map.
+
+ return false;
+}
+
+const NamedDecl *IndexingContext::getEntityDecl(const NamedDecl *D) const {
+ assert(D);
+ D = cast<NamedDecl>(D->getCanonicalDecl());
+
+ if (const ObjCImplementationDecl *
+ ImplD = dyn_cast<ObjCImplementationDecl>(D)) {
+ return getEntityDecl(ImplD->getClassInterface());
+
+ } else if (const ObjCCategoryImplDecl *
+ CatImplD = dyn_cast<ObjCCategoryImplDecl>(D)) {
+ return getEntityDecl(CatImplD->getCategoryDecl());
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FunctionTemplateDecl *TemplD = FD->getDescribedFunctionTemplate())
+ return getEntityDecl(TemplD);
+ } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (ClassTemplateDecl *TemplD = RD->getDescribedClassTemplate())
+ return getEntityDecl(TemplD);
+ }
+
+ return D;
+}
+
+const DeclContext *
+IndexingContext::getEntityContainer(const Decl *D) const {
+ const DeclContext *DC = dyn_cast<DeclContext>(D);
+ if (DC)
+ return DC;
+
+ if (const ClassTemplateDecl *ClassTempl = dyn_cast<ClassTemplateDecl>(D)) {
+ DC = ClassTempl->getTemplatedDecl();
+ } if (const FunctionTemplateDecl *
+ FuncTempl = dyn_cast<FunctionTemplateDecl>(D)) {
+ DC = FuncTempl->getTemplatedDecl();
+ }
+
+ return DC;
+}
+
+CXIdxClientContainer
+IndexingContext::getClientContainerForDC(const DeclContext *DC) const {
+ if (!DC)
+ return 0;
+
+ ContainerMapTy::const_iterator I = ContainerMap.find(DC);
+ if (I == ContainerMap.end())
+ return 0;
+
+ return I->second;
+}
+
+CXIdxClientFile IndexingContext::getIndexFile(const FileEntry *File) {
+ if (!File)
+ return 0;
+
+ FileMapTy::iterator FI = FileMap.find(File);
+ if (FI != FileMap.end())
+ return FI->second;
+
+ return 0;
+}
+
+CXIdxLoc IndexingContext::getIndexLoc(SourceLocation Loc) const {
+ CXIdxLoc idxLoc = { {0, 0}, 0 };
+ if (Loc.isInvalid())
+ return idxLoc;
+
+ idxLoc.ptr_data[0] = (void*)this;
+ idxLoc.int_data = Loc.getRawEncoding();
+ return idxLoc;
+}
+
+void IndexingContext::translateLoc(SourceLocation Loc,
+ CXIdxClientFile *indexFile, CXFile *file,
+ unsigned *line, unsigned *column,
+ unsigned *offset) {
+ if (Loc.isInvalid())
+ return;
+
+ SourceManager &SM = Ctx->getSourceManager();
+ Loc = SM.getFileLoc(Loc);
+
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
+ FileID FID = LocInfo.first;
+ unsigned FileOffset = LocInfo.second;
+
+ if (FID.isInvalid())
+ return;
+
+ const FileEntry *FE = SM.getFileEntryForID(FID);
+ if (indexFile)
+ *indexFile = getIndexFile(FE);
+ if (file)
+ *file = (void *)FE;
+ if (line)
+ *line = SM.getLineNumber(FID, FileOffset);
+ if (column)
+ *column = SM.getColumnNumber(FID, FileOffset);
+ if (offset)
+ *offset = FileOffset;
+}
+
+void IndexingContext::getEntityInfo(const NamedDecl *D,
+ EntityInfo &EntityInfo,
+ ScratchAlloc &SA) {
+ if (!D)
+ return;
+
+ D = getEntityDecl(D);
+ EntityInfo.cursor = getCursor(D);
+ EntityInfo.Dcl = D;
+ EntityInfo.IndexCtx = this;
+ EntityInfo.kind = CXIdxEntity_Unexposed;
+ EntityInfo.templateKind = CXIdxEntity_NonTemplate;
+ EntityInfo.lang = CXIdxEntityLang_C;
+
+ if (D->hasAttrs()) {
+ EntityInfo.AttrList = AttrListInfo::create(D, *this);
+ EntityInfo.attributes = EntityInfo.AttrList->getAttrs();
+ EntityInfo.numAttributes = EntityInfo.AttrList->getNumAttrs();
+ }
+
+ if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
+ switch (TD->getTagKind()) {
+ case TTK_Struct:
+ EntityInfo.kind = CXIdxEntity_Struct; break;
+ case TTK_Union:
+ EntityInfo.kind = CXIdxEntity_Union; break;
+ case TTK_Class:
+ EntityInfo.kind = CXIdxEntity_CXXClass;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case TTK_Enum:
+ EntityInfo.kind = CXIdxEntity_Enum; break;
+ }
+
+ if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D))
+ if (!CXXRec->isCLike())
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+
+ if (isa<ClassTemplatePartialSpecializationDecl>(D)) {
+ EntityInfo.templateKind = CXIdxEntity_TemplatePartialSpecialization;
+ } else if (isa<ClassTemplateSpecializationDecl>(D)) {
+ EntityInfo.templateKind = CXIdxEntity_TemplateSpecialization;
+ }
+
+ } else {
+ switch (D->getKind()) {
+ case Decl::Typedef:
+ EntityInfo.kind = CXIdxEntity_Typedef; break;
+ case Decl::Function:
+ EntityInfo.kind = CXIdxEntity_Function;
+ break;
+ case Decl::ParmVar:
+ EntityInfo.kind = CXIdxEntity_Variable;
+ break;
+ case Decl::Var:
+ EntityInfo.kind = CXIdxEntity_Variable;
+ if (isa<CXXRecordDecl>(D->getDeclContext())) {
+ EntityInfo.kind = CXIdxEntity_CXXStaticVariable;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ }
+ break;
+ case Decl::Field:
+ EntityInfo.kind = CXIdxEntity_Field;
+ if (const CXXRecordDecl *
+ CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
+ // FIXME: isPOD check is not sufficient, a POD can contain methods,
+ // we want a isCStructLike check.
+ if (!CXXRec->isPOD())
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ }
+ break;
+ case Decl::EnumConstant:
+ EntityInfo.kind = CXIdxEntity_EnumConstant; break;
+ case Decl::ObjCInterface:
+ EntityInfo.kind = CXIdxEntity_ObjCClass;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::ObjCProtocol:
+ EntityInfo.kind = CXIdxEntity_ObjCProtocol;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::ObjCCategory:
+ EntityInfo.kind = CXIdxEntity_ObjCCategory;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::ObjCMethod:
+ if (cast<ObjCMethodDecl>(D)->isInstanceMethod())
+ EntityInfo.kind = CXIdxEntity_ObjCInstanceMethod;
+ else
+ EntityInfo.kind = CXIdxEntity_ObjCClassMethod;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::ObjCProperty:
+ EntityInfo.kind = CXIdxEntity_ObjCProperty;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::ObjCIvar:
+ EntityInfo.kind = CXIdxEntity_ObjCIvar;
+ EntityInfo.lang = CXIdxEntityLang_ObjC;
+ break;
+ case Decl::Namespace:
+ EntityInfo.kind = CXIdxEntity_CXXNamespace;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case Decl::NamespaceAlias:
+ EntityInfo.kind = CXIdxEntity_CXXNamespaceAlias;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case Decl::CXXConstructor:
+ EntityInfo.kind = CXIdxEntity_CXXConstructor;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case Decl::CXXDestructor:
+ EntityInfo.kind = CXIdxEntity_CXXDestructor;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case Decl::CXXConversion:
+ EntityInfo.kind = CXIdxEntity_CXXConversionFunction;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ case Decl::CXXMethod: {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
+ if (MD->isStatic())
+ EntityInfo.kind = CXIdxEntity_CXXStaticMethod;
+ else
+ EntityInfo.kind = CXIdxEntity_CXXInstanceMethod;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ }
+ case Decl::ClassTemplate:
+ EntityInfo.kind = CXIdxEntity_CXXClass;
+ EntityInfo.templateKind = CXIdxEntity_Template;
+ break;
+ case Decl::FunctionTemplate:
+ EntityInfo.kind = CXIdxEntity_Function;
+ EntityInfo.templateKind = CXIdxEntity_Template;
+ if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(
+ cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) {
+ if (isa<CXXConstructorDecl>(MD))
+ EntityInfo.kind = CXIdxEntity_CXXConstructor;
+ else if (isa<CXXDestructorDecl>(MD))
+ EntityInfo.kind = CXIdxEntity_CXXDestructor;
+ else if (isa<CXXConversionDecl>(MD))
+ EntityInfo.kind = CXIdxEntity_CXXConversionFunction;
+ else {
+ if (MD->isStatic())
+ EntityInfo.kind = CXIdxEntity_CXXStaticMethod;
+ else
+ EntityInfo.kind = CXIdxEntity_CXXInstanceMethod;
+ }
+ }
+ break;
+ case Decl::TypeAliasTemplate:
+ EntityInfo.kind = CXIdxEntity_CXXTypeAlias;
+ EntityInfo.templateKind = CXIdxEntity_Template;
+ break;
+ case Decl::TypeAlias:
+ EntityInfo.kind = CXIdxEntity_CXXTypeAlias;
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (EntityInfo.kind == CXIdxEntity_Unexposed)
+ return;
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ if (FD->getTemplatedKind() ==
+ FunctionDecl::TK_FunctionTemplateSpecialization)
+ EntityInfo.templateKind = CXIdxEntity_TemplateSpecialization;
+ }
+
+ if (EntityInfo.templateKind != CXIdxEntity_NonTemplate)
+ EntityInfo.lang = CXIdxEntityLang_CXX;
+
+ if (IdentifierInfo *II = D->getIdentifier()) {
+ EntityInfo.name = SA.toCStr(II->getName());
+
+ } else if (isa<TagDecl>(D) || isa<FieldDecl>(D) || isa<NamespaceDecl>(D)) {
+ EntityInfo.name = 0; // anonymous tag/field/namespace.
+
+ } else {
+ SmallString<256> StrBuf;
+ {
+ llvm::raw_svector_ostream OS(StrBuf);
+ D->printName(OS);
+ }
+ EntityInfo.name = SA.copyCStr(StrBuf.str());
+ }
+
+ {
+ SmallString<512> StrBuf;
+ bool Ignore = getDeclCursorUSR(D, StrBuf);
+ if (Ignore) {
+ EntityInfo.USR = 0;
+ } else {
+ EntityInfo.USR = SA.copyCStr(StrBuf.str());
+ }
+ }
+}
+
+void IndexingContext::getContainerInfo(const DeclContext *DC,
+ ContainerInfo &ContInfo) {
+ ContInfo.cursor = getCursor(cast<Decl>(DC));
+ ContInfo.DC = DC;
+ ContInfo.IndexCtx = this;
+}
+
+CXCursor IndexingContext::getRefCursor(const NamedDecl *D, SourceLocation Loc) {
+ if (const TypeDecl *TD = dyn_cast<TypeDecl>(D))
+ return MakeCursorTypeRef(TD, Loc, CXTU);
+ if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
+ return MakeCursorObjCClassRef(ID, Loc, CXTU);
+ if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D))
+ return MakeCursorObjCProtocolRef(PD, Loc, CXTU);
+ if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
+ return MakeCursorTemplateRef(Template, Loc, CXTU);
+ if (const NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(D))
+ return MakeCursorNamespaceRef(Namespace, Loc, CXTU);
+ if (const NamespaceAliasDecl *Namespace = dyn_cast<NamespaceAliasDecl>(D))
+ return MakeCursorNamespaceRef(Namespace, Loc, CXTU);
+ if (const FieldDecl *Field = dyn_cast<FieldDecl>(D))
+ return MakeCursorMemberRef(Field, Loc, CXTU);
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D))
+ return MakeCursorVariableRef(Var, Loc, CXTU);
+
+ return clang_getNullCursor();
+}
+
+bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) {
+ if (isa<ObjCInterfaceDecl>(D))
+ return false;
+ if (isa<ObjCCategoryDecl>(D))
+ return false;
+ if (isa<ObjCIvarDecl>(D))
+ return false;
+ if (isa<ObjCMethodDecl>(D))
+ return false;
+ return true;
+}
+
+bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
+ if (const ClassTemplateSpecializationDecl *
+ SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ return SD->getSpecializationKind() == TSK_ImplicitInstantiation;
+ }
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ return FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation;
+ }
+ return false;
+}
diff --git a/tools/libclang/IndexingContext.h b/tools/libclang/IndexingContext.h
new file mode 100644
index 000000000000..6271660c33ae
--- /dev/null
+++ b/tools/libclang/IndexingContext.h
@@ -0,0 +1,556 @@
+//===- IndexingContext.h - Higher level API functions ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Index_Internal.h"
+#include "CXCursor.h"
+
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclGroup.h"
+#include "llvm/ADT/DenseSet.h"
+#include <deque>
+
+namespace clang {
+ class FileEntry;
+ class ObjCPropertyDecl;
+ class ClassTemplateDecl;
+ class FunctionTemplateDecl;
+ class TypeAliasTemplateDecl;
+ class ClassTemplateSpecializationDecl;
+
+namespace cxindex {
+ class IndexingContext;
+ class AttrListInfo;
+
+class ScratchAlloc {
+ IndexingContext &IdxCtx;
+
+public:
+ explicit ScratchAlloc(IndexingContext &indexCtx);
+ ScratchAlloc(const ScratchAlloc &SA);
+
+ ~ScratchAlloc();
+
+ const char *toCStr(StringRef Str);
+ const char *copyCStr(StringRef Str);
+
+ template <typename T>
+ T *allocate();
+};
+
+struct EntityInfo : public CXIdxEntityInfo {
+ const NamedDecl *Dcl;
+ IndexingContext *IndexCtx;
+ IntrusiveRefCntPtr<AttrListInfo> AttrList;
+
+ EntityInfo() {
+ name = USR = 0;
+ attributes = 0;
+ numAttributes = 0;
+ }
+};
+
+struct ContainerInfo : public CXIdxContainerInfo {
+ const DeclContext *DC;
+ IndexingContext *IndexCtx;
+};
+
+struct DeclInfo : public CXIdxDeclInfo {
+ enum DInfoKind {
+ Info_Decl,
+
+ Info_ObjCContainer,
+ Info_ObjCInterface,
+ Info_ObjCProtocol,
+ Info_ObjCCategory,
+
+ Info_ObjCProperty,
+
+ Info_CXXClass
+ };
+
+ DInfoKind Kind;
+
+ EntityInfo EntInfo;
+ ContainerInfo SemanticContainer;
+ ContainerInfo LexicalContainer;
+ ContainerInfo DeclAsContainer;
+
+ DeclInfo(bool isRedeclaration, bool isDefinition, bool isContainer)
+ : Kind(Info_Decl) {
+ this->isRedeclaration = isRedeclaration;
+ this->isDefinition = isDefinition;
+ this->isContainer = isContainer;
+ attributes = 0;
+ numAttributes = 0;
+ declAsContainer = semanticContainer = lexicalContainer = 0;
+ }
+ DeclInfo(DInfoKind K,
+ bool isRedeclaration, bool isDefinition, bool isContainer)
+ : Kind(K) {
+ this->isRedeclaration = isRedeclaration;
+ this->isDefinition = isDefinition;
+ this->isContainer = isContainer;
+ attributes = 0;
+ numAttributes = 0;
+ declAsContainer = semanticContainer = lexicalContainer = 0;
+ }
+
+ static bool classof(const DeclInfo *) { return true; }
+};
+
+struct ObjCContainerDeclInfo : public DeclInfo {
+ CXIdxObjCContainerDeclInfo ObjCContDeclInfo;
+
+ ObjCContainerDeclInfo(bool isForwardRef,
+ bool isRedeclaration,
+ bool isImplementation)
+ : DeclInfo(Info_ObjCContainer, isRedeclaration,
+ /*isDefinition=*/!isForwardRef, /*isContainer=*/!isForwardRef) {
+ init(isForwardRef, isImplementation);
+ }
+ ObjCContainerDeclInfo(DInfoKind K,
+ bool isForwardRef,
+ bool isRedeclaration,
+ bool isImplementation)
+ : DeclInfo(K, isRedeclaration, /*isDefinition=*/!isForwardRef,
+ /*isContainer=*/!isForwardRef) {
+ init(isForwardRef, isImplementation);
+ }
+
+ static bool classof(const DeclInfo *D) {
+ return Info_ObjCContainer <= D->Kind && D->Kind <= Info_ObjCCategory;
+ }
+ static bool classof(const ObjCContainerDeclInfo *D) { return true; }
+
+private:
+ void init(bool isForwardRef, bool isImplementation) {
+ if (isForwardRef)
+ ObjCContDeclInfo.kind = CXIdxObjCContainer_ForwardRef;
+ else if (isImplementation)
+ ObjCContDeclInfo.kind = CXIdxObjCContainer_Implementation;
+ else
+ ObjCContDeclInfo.kind = CXIdxObjCContainer_Interface;
+ }
+};
+
+struct ObjCInterfaceDeclInfo : public ObjCContainerDeclInfo {
+ CXIdxObjCInterfaceDeclInfo ObjCInterDeclInfo;
+ CXIdxObjCProtocolRefListInfo ObjCProtoListInfo;
+
+ ObjCInterfaceDeclInfo(const ObjCInterfaceDecl *D)
+ : ObjCContainerDeclInfo(Info_ObjCInterface,
+ /*isForwardRef=*/false,
+ /*isRedeclaration=*/D->getPreviousDecl() != 0,
+ /*isImplementation=*/false) { }
+
+ static bool classof(const DeclInfo *D) {
+ return D->Kind == Info_ObjCInterface;
+ }
+ static bool classof(const ObjCInterfaceDeclInfo *D) { return true; }
+};
+
+struct ObjCProtocolDeclInfo : public ObjCContainerDeclInfo {
+ CXIdxObjCProtocolRefListInfo ObjCProtoRefListInfo;
+
+ ObjCProtocolDeclInfo(const ObjCProtocolDecl *D)
+ : ObjCContainerDeclInfo(Info_ObjCProtocol,
+ /*isForwardRef=*/false,
+ /*isRedeclaration=*/D->getPreviousDecl(),
+ /*isImplementation=*/false) { }
+
+ static bool classof(const DeclInfo *D) {
+ return D->Kind == Info_ObjCProtocol;
+ }
+ static bool classof(const ObjCProtocolDeclInfo *D) { return true; }
+};
+
+struct ObjCCategoryDeclInfo : public ObjCContainerDeclInfo {
+ CXIdxObjCCategoryDeclInfo ObjCCatDeclInfo;
+ CXIdxObjCProtocolRefListInfo ObjCProtoListInfo;
+
+ explicit ObjCCategoryDeclInfo(bool isImplementation)
+ : ObjCContainerDeclInfo(Info_ObjCCategory,
+ /*isForwardRef=*/false,
+ /*isRedeclaration=*/isImplementation,
+ /*isImplementation=*/isImplementation) { }
+
+ static bool classof(const DeclInfo *D) {
+ return D->Kind == Info_ObjCCategory;
+ }
+ static bool classof(const ObjCCategoryDeclInfo *D) { return true; }
+};
+
+struct ObjCPropertyDeclInfo : public DeclInfo {
+ CXIdxObjCPropertyDeclInfo ObjCPropDeclInfo;
+
+ ObjCPropertyDeclInfo()
+ : DeclInfo(Info_ObjCProperty,
+ /*isRedeclaration=*/false, /*isDefinition=*/false,
+ /*isContainer=*/false) { }
+
+ static bool classof(const DeclInfo *D) {
+ return D->Kind == Info_ObjCProperty;
+ }
+ static bool classof(const ObjCPropertyDeclInfo *D) { return true; }
+};
+
+struct CXXClassDeclInfo : public DeclInfo {
+ CXIdxCXXClassDeclInfo CXXClassInfo;
+
+ CXXClassDeclInfo(bool isRedeclaration, bool isDefinition)
+ : DeclInfo(Info_CXXClass, isRedeclaration, isDefinition, isDefinition) { }
+
+ static bool classof(const DeclInfo *D) {
+ return D->Kind == Info_CXXClass;
+ }
+ static bool classof(const CXXClassDeclInfo *D) { return true; }
+};
+
+struct AttrInfo : public CXIdxAttrInfo {
+ const Attr *A;
+
+ AttrInfo(CXIdxAttrKind Kind, CXCursor C, CXIdxLoc Loc, const Attr *A) {
+ kind = Kind;
+ cursor = C;
+ loc = Loc;
+ this->A = A;
+ }
+
+ static bool classof(const AttrInfo *) { return true; }
+};
+
+struct IBOutletCollectionInfo : public AttrInfo {
+ EntityInfo ClassInfo;
+ CXIdxIBOutletCollectionAttrInfo IBCollInfo;
+
+ IBOutletCollectionInfo(CXCursor C, CXIdxLoc Loc, const Attr *A) :
+ AttrInfo(CXIdxAttr_IBOutletCollection, C, Loc, A) {
+ assert(C.kind == CXCursor_IBOutletCollectionAttr);
+ IBCollInfo.objcClass = 0;
+ }
+
+ IBOutletCollectionInfo(const IBOutletCollectionInfo &other);
+
+ static bool classof(const AttrInfo *A) {
+ return A->kind == CXIdxAttr_IBOutletCollection;
+ }
+ static bool classof(const IBOutletCollectionInfo *D) { return true; }
+};
+
+class AttrListInfo {
+ ScratchAlloc SA;
+
+ SmallVector<AttrInfo, 2> Attrs;
+ SmallVector<IBOutletCollectionInfo, 2> IBCollAttrs;
+ SmallVector<CXIdxAttrInfo *, 2> CXAttrs;
+ unsigned ref_cnt;
+
+ AttrListInfo(const AttrListInfo&); // DO NOT IMPLEMENT
+ void operator=(const AttrListInfo&); // DO NOT IMPLEMENT
+public:
+ AttrListInfo(const Decl *D, IndexingContext &IdxCtx);
+
+ static IntrusiveRefCntPtr<AttrListInfo> create(const Decl *D,
+ IndexingContext &IdxCtx);
+
+ const CXIdxAttrInfo *const *getAttrs() const {
+ if (CXAttrs.empty())
+ return 0;
+ return CXAttrs.data();
+ }
+ unsigned getNumAttrs() const { return (unsigned)CXAttrs.size(); }
+
+ /// \brief Retain/Release only useful when we allocate a AttrListInfo from the
+ /// BumpPtrAllocator, and not from the stack; so that we keep a pointer
+ // in the EntityInfo
+ void Retain() { ++ref_cnt; }
+ void Release() {
+ assert (ref_cnt > 0 && "Reference count is already zero.");
+ if (--ref_cnt == 0) {
+ // Memory is allocated from a BumpPtrAllocator, no need to delete it.
+ this->~AttrListInfo();
+ }
+ }
+};
+
+struct RefFileOccurence {
+ const FileEntry *File;
+ const Decl *Dcl;
+
+ RefFileOccurence(const FileEntry *File, const Decl *Dcl)
+ : File(File), Dcl(Dcl) { }
+};
+
+class IndexingContext {
+ ASTContext *Ctx;
+ CXClientData ClientData;
+ IndexerCallbacks &CB;
+ unsigned IndexOptions;
+ CXTranslationUnit CXTU;
+
+ typedef llvm::DenseMap<const FileEntry *, CXIdxClientFile> FileMapTy;
+ typedef llvm::DenseMap<const DeclContext *, CXIdxClientContainer>
+ ContainerMapTy;
+ typedef llvm::DenseMap<const Decl *, CXIdxClientEntity> EntityMapTy;
+
+ FileMapTy FileMap;
+ ContainerMapTy ContainerMap;
+ EntityMapTy EntityMap;
+
+ llvm::DenseSet<RefFileOccurence> RefFileOccurences;
+
+ std::deque<DeclGroupRef> TUDeclsInObjCContainer;
+
+ llvm::BumpPtrAllocator StrScratch;
+ unsigned StrAdapterCount;
+ friend class ScratchAlloc;
+
+ struct ObjCProtocolListInfo {
+ SmallVector<CXIdxObjCProtocolRefInfo, 4> ProtInfos;
+ SmallVector<EntityInfo, 4> ProtEntities;
+ SmallVector<CXIdxObjCProtocolRefInfo *, 4> Prots;
+
+ CXIdxObjCProtocolRefListInfo getListInfo() const {
+ CXIdxObjCProtocolRefListInfo Info = { Prots.data(),
+ (unsigned)Prots.size() };
+ return Info;
+ }
+
+ ObjCProtocolListInfo(const ObjCProtocolList &ProtList,
+ IndexingContext &IdxCtx,
+ ScratchAlloc &SA);
+ };
+
+ struct CXXBasesListInfo {
+ SmallVector<CXIdxBaseClassInfo, 4> BaseInfos;
+ SmallVector<EntityInfo, 4> BaseEntities;
+ SmallVector<CXIdxBaseClassInfo *, 4> CXBases;
+
+ const CXIdxBaseClassInfo *const *getBases() const {
+ return CXBases.data();
+ }
+ unsigned getNumBases() const { return (unsigned)CXBases.size(); }
+
+ CXXBasesListInfo(const CXXRecordDecl *D,
+ IndexingContext &IdxCtx, ScratchAlloc &SA);
+
+ private:
+ SourceLocation getBaseLoc(const CXXBaseSpecifier &Base) const;
+ };
+
+ friend class AttrListInfo;
+
+public:
+ IndexingContext(CXClientData clientData, IndexerCallbacks &indexCallbacks,
+ unsigned indexOptions, CXTranslationUnit cxTU)
+ : Ctx(0), ClientData(clientData), CB(indexCallbacks),
+ IndexOptions(indexOptions), CXTU(cxTU),
+ StrScratch(/*size=*/1024), StrAdapterCount(0) { }
+
+ ASTContext &getASTContext() const { return *Ctx; }
+
+ void setASTContext(ASTContext &ctx);
+ void setPreprocessor(Preprocessor &PP);
+
+ bool shouldSuppressRefs() const {
+ return IndexOptions & CXIndexOpt_SuppressRedundantRefs;
+ }
+
+ bool shouldIndexFunctionLocalSymbols() const {
+ return IndexOptions & CXIndexOpt_IndexFunctionLocalSymbols;
+ }
+
+ bool shouldIndexImplicitTemplateInsts() const {
+ return IndexOptions & CXIndexOpt_IndexImplicitTemplateInstantiations;
+ }
+
+ bool shouldAbort();
+
+ bool hasDiagnosticCallback() const { return CB.diagnostic; }
+
+ void enteredMainFile(const FileEntry *File);
+
+ void ppIncludedFile(SourceLocation hashLoc,
+ StringRef filename, const FileEntry *File,
+ bool isImport, bool isAngled);
+
+ void startedTranslationUnit();
+
+ void indexDecl(const Decl *D);
+
+ void indexTagDecl(const TagDecl *D);
+
+ void indexTypeSourceInfo(TypeSourceInfo *TInfo, const NamedDecl *Parent,
+ const DeclContext *DC = 0);
+
+ void indexTypeLoc(TypeLoc TL, const NamedDecl *Parent,
+ const DeclContext *DC = 0);
+
+ void indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS,
+ const NamedDecl *Parent,
+ const DeclContext *DC = 0);
+
+ void indexDeclContext(const DeclContext *DC);
+
+ void indexBody(const Stmt *S, const NamedDecl *Parent,
+ const DeclContext *DC = 0);
+
+ void handleDiagnosticSet(CXDiagnosticSet CXDiagSet);
+
+ bool handleFunction(const FunctionDecl *FD);
+
+ bool handleVar(const VarDecl *D);
+
+ bool handleField(const FieldDecl *D);
+
+ bool handleEnumerator(const EnumConstantDecl *D);
+
+ bool handleTagDecl(const TagDecl *D);
+
+ bool handleTypedefName(const TypedefNameDecl *D);
+
+ bool handleObjCInterface(const ObjCInterfaceDecl *D);
+ bool handleObjCImplementation(const ObjCImplementationDecl *D);
+
+ bool handleObjCProtocol(const ObjCProtocolDecl *D);
+
+ bool handleObjCCategory(const ObjCCategoryDecl *D);
+ bool handleObjCCategoryImpl(const ObjCCategoryImplDecl *D);
+
+ bool handleObjCMethod(const ObjCMethodDecl *D);
+
+ bool handleSynthesizedObjCProperty(const ObjCPropertyImplDecl *D);
+ bool handleSynthesizedObjCMethod(const ObjCMethodDecl *D, SourceLocation Loc,
+ const DeclContext *LexicalDC);
+
+ bool handleObjCProperty(const ObjCPropertyDecl *D);
+
+ bool handleNamespace(const NamespaceDecl *D);
+
+ bool handleClassTemplate(const ClassTemplateDecl *D);
+ bool handleFunctionTemplate(const FunctionTemplateDecl *D);
+ bool handleTypeAliasTemplate(const TypeAliasTemplateDecl *D);
+
+ bool handleReference(const NamedDecl *D, SourceLocation Loc, CXCursor Cursor,
+ const NamedDecl *Parent,
+ const DeclContext *DC,
+ const Expr *E = 0,
+ CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct);
+
+ bool handleReference(const NamedDecl *D, SourceLocation Loc,
+ const NamedDecl *Parent,
+ const DeclContext *DC,
+ const Expr *E = 0,
+ CXIdxEntityRefKind Kind = CXIdxEntityRef_Direct);
+
+ bool isNotFromSourceFile(SourceLocation Loc) const;
+
+ void indexTopLevelDecl(Decl *D);
+ void indexTUDeclsInObjCContainer();
+ void indexDeclGroupRef(DeclGroupRef DG);
+
+ void addTUDeclInObjCContainer(DeclGroupRef DG) {
+ TUDeclsInObjCContainer.push_back(DG);
+ }
+
+ void translateLoc(SourceLocation Loc, CXIdxClientFile *indexFile, CXFile *file,
+ unsigned *line, unsigned *column, unsigned *offset);
+
+ CXIdxClientContainer getClientContainerForDC(const DeclContext *DC) const;
+ void addContainerInMap(const DeclContext *DC, CXIdxClientContainer container);
+
+ CXIdxClientEntity getClientEntity(const Decl *D) const;
+ void setClientEntity(const Decl *D, CXIdxClientEntity client);
+
+ static bool isTemplateImplicitInstantiation(const Decl *D);
+
+private:
+ bool handleDecl(const NamedDecl *D,
+ SourceLocation Loc, CXCursor Cursor,
+ DeclInfo &DInfo,
+ const DeclContext *LexicalDC = 0);
+
+ bool handleObjCContainer(const ObjCContainerDecl *D,
+ SourceLocation Loc, CXCursor Cursor,
+ ObjCContainerDeclInfo &ContDInfo);
+
+ bool handleCXXRecordDecl(const CXXRecordDecl *RD, const NamedDecl *OrigD);
+
+ bool markEntityOccurrenceInFile(const NamedDecl *D, SourceLocation Loc);
+
+ const NamedDecl *getEntityDecl(const NamedDecl *D) const;
+
+ const DeclContext *getEntityContainer(const Decl *D) const;
+
+ CXIdxClientFile getIndexFile(const FileEntry *File);
+
+ CXIdxLoc getIndexLoc(SourceLocation Loc) const;
+
+ void getEntityInfo(const NamedDecl *D,
+ EntityInfo &EntityInfo,
+ ScratchAlloc &SA);
+
+ void getContainerInfo(const DeclContext *DC, ContainerInfo &ContInfo);
+
+ CXCursor getCursor(const Decl *D) {
+ return cxcursor::MakeCXCursor(const_cast<Decl*>(D), CXTU);
+ }
+
+ CXCursor getRefCursor(const NamedDecl *D, SourceLocation Loc);
+
+ static bool shouldIgnoreIfImplicit(const Decl *D);
+};
+
+inline ScratchAlloc::ScratchAlloc(IndexingContext &idxCtx) : IdxCtx(idxCtx) {
+ ++IdxCtx.StrAdapterCount;
+}
+inline ScratchAlloc::ScratchAlloc(const ScratchAlloc &SA) : IdxCtx(SA.IdxCtx) {
+ ++IdxCtx.StrAdapterCount;
+}
+
+inline ScratchAlloc::~ScratchAlloc() {
+ --IdxCtx.StrAdapterCount;
+ if (IdxCtx.StrAdapterCount == 0)
+ IdxCtx.StrScratch.Reset();
+}
+
+template <typename T>
+inline T *ScratchAlloc::allocate() {
+ return IdxCtx.StrScratch.Allocate<T>();
+}
+
+}} // end clang::cxindex
+
+namespace llvm {
+ /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and
+ /// DenseSets.
+ template <>
+ struct DenseMapInfo<clang::cxindex::RefFileOccurence> {
+ static inline clang::cxindex::RefFileOccurence getEmptyKey() {
+ return clang::cxindex::RefFileOccurence(0, 0);
+ }
+
+ static inline clang::cxindex::RefFileOccurence getTombstoneKey() {
+ return clang::cxindex::RefFileOccurence((const clang::FileEntry *)~0,
+ (const clang::Decl *)~0);
+ }
+
+ static unsigned getHashValue(clang::cxindex::RefFileOccurence S) {
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(S.File);
+ ID.AddPointer(S.Dcl);
+ return ID.ComputeHash();
+ }
+
+ static bool isEqual(clang::cxindex::RefFileOccurence LHS,
+ clang::cxindex::RefFileOccurence RHS) {
+ return LHS.File == RHS.File && LHS.Dcl == RHS.Dcl;
+ }
+ };
+}
diff --git a/tools/libclang/Makefile b/tools/libclang/Makefile
index 375f7f20fe00..1fff166bbf8f 100644
--- a/tools/libclang/Makefile
+++ b/tools/libclang/Makefile
@@ -18,7 +18,8 @@ SHARED_LIBRARY = 1
LINK_COMPONENTS := support mc
USEDLIBS = clangARCMigrate.a clangRewrite.a clangFrontend.a clangDriver.a \
clangSerialization.a \
- clangParse.a clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a
+ clangParse.a clangSema.a clangEdit.a clangAnalysis.a \
+ clangAST.a clangLex.a clangBasic.a
include $(CLANG_LEVEL)/Makefile
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 989ed837ea24..d3b64dbd0f50 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -1,7 +1,18 @@
clang_CXCursorSet_contains
clang_CXCursorSet_insert
+clang_CXIndex_getGlobalOptions
+clang_CXIndex_setGlobalOptions
clang_CXXMethod_isStatic
clang_CXXMethod_isVirtual
+clang_Cursor_getArgument
+clang_Cursor_getNumArguments
+clang_Cursor_getObjCSelectorIndex
+clang_Cursor_getSpellingNameRange
+clang_Cursor_getTranslationUnit
+clang_Cursor_isNull
+clang_IndexAction_create
+clang_IndexAction_dispose
+clang_Range_isNull
clang_annotateTokens
clang_codeCompleteAt
clang_codeCompleteGetContainerKind
@@ -20,8 +31,6 @@ clang_createCXCursorSet
clang_createIndex
clang_createTranslationUnit
clang_createTranslationUnitFromSourceFile
-clang_Cursor_getTranslationUnit
-clang_Cursor_isNull
clang_defaultCodeCompleteOptions
clang_defaultDiagnosticDisplayOptions
clang_defaultEditingTranslationUnitOptions
@@ -31,6 +40,7 @@ clang_disposeCXCursorSet
clang_disposeCXTUResourceUsage
clang_disposeCodeCompleteResults
clang_disposeDiagnostic
+clang_disposeDiagnosticSet
clang_disposeIndex
clang_disposeOverriddenCursors
clang_disposeString
@@ -45,6 +55,7 @@ clang_executeOnThread
clang_findReferencesInFile
clang_findReferencesInFileWithBlock
clang_formatDiagnostic
+clang_getArgType
clang_getArrayElementType
clang_getArraySize
clang_getCString
@@ -52,13 +63,15 @@ clang_getCXTUResourceUsage
clang_getCXXAccessSpecifier
clang_getCanonicalCursor
clang_getCanonicalType
+clang_getChildDiagnostics
clang_getClangVersion
-clang_getCompletionAvailability
clang_getCompletionAnnotation
+clang_getCompletionAvailability
clang_getCompletionChunkCompletionString
clang_getCompletionChunkKind
clang_getCompletionChunkText
clang_getCompletionNumAnnotations
+clang_getCompletionParent
clang_getCompletionPriority
clang_getCursor
clang_getCursorAvailability
@@ -84,17 +97,26 @@ clang_getDefinitionSpellingAndExtent
clang_getDiagnostic
clang_getDiagnosticCategory
clang_getDiagnosticCategoryName
+clang_getDiagnosticCategoryText
clang_getDiagnosticFixIt
+clang_getDiagnosticInSet
clang_getDiagnosticLocation
clang_getDiagnosticNumFixIts
clang_getDiagnosticNumRanges
clang_getDiagnosticOption
clang_getDiagnosticRange
+clang_getDiagnosticSetFromTU
clang_getDiagnosticSeverity
clang_getDiagnosticSpelling
+clang_getElementType
+clang_getEnumConstantDeclUnsignedValue
+clang_getEnumConstantDeclValue
+clang_getEnumDeclIntegerType
+clang_getExpansionLocation
clang_getFile
clang_getFileName
clang_getFileTime
+clang_getFunctionTypeCallingConv
clang_getIBOutletCollectionType
clang_getIncludedFile
clang_getInclusions
@@ -104,8 +126,11 @@ clang_getLocationForOffset
clang_getNullCursor
clang_getNullLocation
clang_getNullRange
+clang_getNumArgTypes
clang_getNumCompletionChunks
clang_getNumDiagnostics
+clang_getNumDiagnosticsInSet
+clang_getNumElements
clang_getNumOverloadedDecls
clang_getOverloadedDecl
clang_getOverriddenCursors
@@ -115,6 +140,7 @@ clang_getRange
clang_getRangeEnd
clang_getRangeStart
clang_getRemappings
+clang_getRemappingsFromFileList
clang_getResultType
clang_getSpecializedCursorTemplate
clang_getSpellingLocation
@@ -128,13 +154,31 @@ clang_getTranslationUnitCursor
clang_getTranslationUnitSpelling
clang_getTypeDeclaration
clang_getTypeKindSpelling
+clang_getTypedefDeclUnderlyingType
clang_hashCursor
+clang_indexLoc_getCXSourceLocation
+clang_indexLoc_getFileLocation
+clang_indexSourceFile
+clang_indexTranslationUnit
+clang_index_getCXXClassDeclInfo
+clang_index_getClientContainer
+clang_index_getClientEntity
+clang_index_getIBOutletCollectionAttrInfo
+clang_index_getObjCCategoryDeclInfo
+clang_index_getObjCContainerDeclInfo
+clang_index_getObjCInterfaceDeclInfo
+clang_index_getObjCPropertyDeclInfo
+clang_index_getObjCProtocolRefListInfo
+clang_index_isEntityObjCContainerKind
+clang_index_setClientContainer
+clang_index_setClientEntity
clang_isAttribute
clang_isConstQualifiedType
clang_isCursorDefinition
clang_isDeclaration
clang_isExpression
clang_isFileMultipleIncludeGuarded
+clang_isFunctionTypeVariadic
clang_isInvalid
clang_isPODType
clang_isPreprocessing
@@ -145,8 +189,8 @@ clang_isTranslationUnit
clang_isUnexposed
clang_isVirtualBase
clang_isVolatileQualifiedType
+clang_loadDiagnostics
clang_parseTranslationUnit
-clang_Range_isNull
clang_remap_dispose
clang_remap_getFilenames
clang_remap_getNumFiles
diff --git a/tools/scan-build/ccc-analyzer b/tools/scan-build/ccc-analyzer
index c39e4179514e..32a7301362f6 100755
--- a/tools/scan-build/ccc-analyzer
+++ b/tools/scan-build/ccc-analyzer
@@ -27,17 +27,27 @@ use Text::ParseWords;
my $Compiler;
my $Clang;
+my $DefaultCCompiler;
+my $DefaultCXXCompiler;
+
+if (`uname -a` =~ m/Darwin/) {
+ $DefaultCCompiler = 'clang';
+ $DefaultCXXCompiler = 'clang++';
+} else {
+ $DefaultCCompiler = 'gcc';
+ $DefaultCXXCompiler = 'g++';
+}
if ($FindBin::Script =~ /c\+\+-analyzer/) {
$Compiler = $ENV{'CCC_CXX'};
- if (!defined $Compiler) { $Compiler = "g++"; }
+ if (!defined $Compiler) { $Compiler = $DefaultCXXCompiler; }
$Clang = $ENV{'CLANG_CXX'};
if (!defined $Clang) { $Clang = 'clang++'; }
}
else {
$Compiler = $ENV{'CCC_CC'};
- if (!defined $Compiler) { $Compiler = "gcc"; }
+ if (!defined $Compiler) { $Compiler = $DefaultCCompiler; }
$Clang = $ENV{'CLANG'};
if (!defined $Clang) { $Clang = 'clang'; }
@@ -78,8 +88,8 @@ sub GetPPExt {
# Set this to 1 if we want to include 'parser rejects' files.
my $IncludeParserRejects = 0;
my $ParserRejects = "Parser Rejects";
-
my $AttributeIgnored = "Attribute Ignored";
+my $OtherError = "Other Error";
sub ProcessClangFailure {
my ($Clang, $Lang, $file, $Args, $HtmlDir, $ErrorType, $ofile) = @_;
@@ -93,6 +103,9 @@ sub ProcessClangFailure {
elsif ($ErrorType eq $AttributeIgnored) {
$prefix = "clang_attribute_ignored";
}
+ elsif ($ErrorType eq $OtherError) {
+ $prefix = "clang_other_error";
+ }
# Generate the preprocessed file with Clang.
my ($PPH, $PPFile) = tempfile( $prefix . "_XXXXXX",
@@ -259,6 +272,9 @@ sub Analyze {
if ($IncludeParserRejects && !($file =~/conftest/)) {
ProcessClangFailure($Clang, $Lang, $file, \@CmdArgsSansAnalyses,
$HtmlDir, $ParserRejects, $ofile);
+ } else {
+ ProcessClangFailure($Clang, $Lang, $file, \@CmdArgsSansAnalyses,
+ $HtmlDir, $OtherError, $ofile);
}
}
else {
@@ -329,10 +345,13 @@ my %CompileOptionMap = (
);
my %LinkerOptionMap = (
- '-framework' => 1
+ '-framework' => 1,
+ '-fobjc-link-runtime' => 0
);
my %CompilerLinkerOptionMap = (
+ '-fobjc-arc' => 0,
+ '-fobjc-abi-version' => 0, # This is really a 1 argument, but always has '='
'-isysroot' => 1,
'-arch' => 1,
'-m32' => 0,
@@ -360,7 +379,8 @@ my %IgnoredOptionMap = (
'-multiply_defined' => 1,
'-sectorder' => 3,
'--param' => 1,
- '-u' => 1
+ '-u' => 1,
+ '--serialize-diagnostics' => 1
);
my %LangMap = (
diff --git a/tools/scan-build/scan-build b/tools/scan-build/scan-build
index dae86f4b5e9c..59b0bafaefe7 100755
--- a/tools/scan-build/scan-build
+++ b/tools/scan-build/scan-build
@@ -961,17 +961,21 @@ OPTIONS:
-plist - By default the output of scan-build is a set of HTML files.
This option outputs the results as a set of .plist files.
-
+
+ -plist-html - By default the output of scan-build is a set of HTML files.
+ This option outputs the results as a set of HTML
+ and .plist files.
+
--status-bugs - By default, the exit status of $Prog is the same as the
executed build command. Specifying this option causes the
exit status of $Prog to be 1 if it found potential bugs
and 0 otherwise.
- --use-cc [compiler path] - By default, $Prog uses 'gcc' to compile and link
+ --use-cc [compiler path] - $Prog attempts to guess the default compiler for
--use-cc=[compiler path] your C and Objective-C code. Use this option
to specify an alternate compiler.
- --use-c++ [compiler path] - By default, $Prog uses 'g++' to compile and link
+ --use-c++ [compiler path] - $Prog attempts to guess the default compiler for
--use-c++=[compiler path] your C++ and Objective-C++ code. Use this option
to specify an alternate compiler.
diff --git a/tools/scan-build/set-xcode-analyzer b/tools/scan-build/set-xcode-analyzer
index cc068a56adf9..06e1d857de91 100755
--- a/tools/scan-build/set-xcode-analyzer
+++ b/tools/scan-build/set-xcode-analyzer
@@ -1,6 +1,11 @@
-#!/usr/bin/env python
+#!/usr/bin/python
+
+# [PR 11661] Note that we hardwire to /usr/bin/python because we
+# want to the use the system version of Python on Mac OS X.
+# This one has the scripting bridge enabled.
import os
+import subprocess
import sys
import re
import tempfile
@@ -9,6 +14,7 @@ import stat
from AppKit import *
def FindClangSpecs(path):
+ print "(+) Searching for xcspec file in: ", path
for root, dirs, files in os.walk(path):
for f in files:
if f.endswith(".xcspec") and f.startswith("Clang LLVM"):
@@ -69,7 +75,13 @@ def main():
print "(+) Using the Clang bundled with Xcode"
path = options.default
- for x in FindClangSpecs('/Developer'):
+ xcode_path = subprocess.check_output(["xcode-select", "-print-path"])
+ if (re.search("Xcode.app", xcode_path)):
+ # Cut off the 'Developer' dir, as the xcspec lies in another part
+ # of the Xcode.app subtree.
+ xcode_path = os.path.dirname(xcode_path)
+
+ for x in FindClangSpecs(xcode_path):
ModifySpec(x, path)
if __name__ == '__main__':