From 50b73317314e889cf39c7b1d6cbf419fa7502f22 Mon Sep 17 00:00:00 2001 From: dim Date: Sat, 14 Apr 2012 14:01:31 +0000 Subject: Vendor import of clang trunk r154661: http://llvm.org/svn/llvm-project/cfe/trunk@r154661 --- tools/CMakeLists.txt | 1 + tools/Makefile | 7 +- tools/arcmt-test/CMakeLists.txt | 1 + tools/arcmt-test/Makefile | 2 +- tools/arcmt-test/arcmt-test.cpp | 39 +- tools/c-arcmt-test/Makefile | 2 +- tools/c-arcmt-test/c-arcmt-test.c | 36 +- tools/c-index-test/Makefile | 6 +- tools/c-index-test/c-index-test.c | 863 ++++++++++++++++++- tools/clang-check/CMakeLists.txt | 5 + tools/clang-check/ClangCheck.cpp | 62 ++ tools/clang-check/Makefile | 24 + tools/diagtool/ListWarnings.cpp | 34 +- tools/diagtool/Makefile | 5 +- tools/driver/CMakeLists.txt | 16 +- tools/driver/Makefile | 4 +- tools/driver/cc1_main.cpp | 22 +- tools/driver/cc1as_main.cpp | 80 +- tools/driver/driver.cpp | 38 +- tools/libclang/ARCMigrate.cpp | 43 +- tools/libclang/CIndex.cpp | 1407 ++++++++++++++++--------------- tools/libclang/CIndexCXX.cpp | 5 +- tools/libclang/CIndexCodeCompletion.cpp | 81 +- tools/libclang/CIndexDiagnostic.cpp | 343 +++++--- tools/libclang/CIndexDiagnostic.h | 137 ++- tools/libclang/CIndexHigh.cpp | 184 +++- tools/libclang/CIndexUSRs.cpp | 61 +- tools/libclang/CIndexer.cpp | 2 +- tools/libclang/CIndexer.h | 23 +- tools/libclang/CMakeLists.txt | 19 + tools/libclang/CXCursor.cpp | 261 ++++-- tools/libclang/CXCursor.h | 27 +- tools/libclang/CXLoadedDiagnostic.cpp | 672 +++++++++++++++ tools/libclang/CXLoadedDiagnostic.h | 94 +++ tools/libclang/CXSourceLocation.cpp | 326 +++++++ tools/libclang/CXSourceLocation.h | 4 +- tools/libclang/CXStoredDiagnostic.cpp | 119 +++ tools/libclang/CXString.h | 2 +- tools/libclang/CXTranslationUnit.h | 22 +- tools/libclang/CXType.cpp | 203 ++++- tools/libclang/CursorVisitor.h | 259 ++++++ tools/libclang/IndexBody.cpp | 154 ++++ tools/libclang/IndexDecl.cpp | 336 ++++++++ tools/libclang/IndexTypeSourceInfo.cpp | 156 ++++ tools/libclang/Index_Internal.h | 12 + tools/libclang/Indexing.cpp | 818 ++++++++++++++++++ tools/libclang/IndexingContext.cpp | 1080 ++++++++++++++++++++++++ tools/libclang/IndexingContext.h | 556 ++++++++++++ tools/libclang/Makefile | 3 +- tools/libclang/libclang.exports | 52 +- tools/scan-build/ccc-analyzer | 30 +- tools/scan-build/scan-build | 10 +- tools/scan-build/set-xcode-analyzer | 16 +- 53 files changed, 7699 insertions(+), 1065 deletions(-) create mode 100644 tools/clang-check/CMakeLists.txt create mode 100644 tools/clang-check/ClangCheck.cpp create mode 100644 tools/clang-check/Makefile create mode 100644 tools/libclang/CXLoadedDiagnostic.cpp create mode 100644 tools/libclang/CXLoadedDiagnostic.h create mode 100644 tools/libclang/CXSourceLocation.cpp create mode 100644 tools/libclang/CXStoredDiagnostic.cpp create mode 100644 tools/libclang/CursorVisitor.h create mode 100644 tools/libclang/IndexBody.cpp create mode 100644 tools/libclang/IndexDecl.cpp create mode 100644 tools/libclang/IndexTypeSourceInfo.cpp create mode 100644 tools/libclang/Indexing.cpp create mode 100644 tools/libclang/IndexingContext.cpp create mode 100644 tools/libclang/IndexingContext.h (limited to 'tools') diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 117d10a..ab4748d 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 4ea2cdd..5059ade 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 9227f8e..a0029b4 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 c143e27..f5ca81a 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 d27483f..3983c24 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 Args) { DiagnosticConsumer *DiagClient = new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); - llvm::IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr Diags( + IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + IntrusiveRefCntPtr 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 DiagID(new DiagnosticIDs()); - llvm::IntrusiveRefCntPtr TopDiags( + IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + IntrusiveRefCntPtr 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 transforms = arcmt::getAllTransformations(); + std::vector + transforms = arcmt::getAllTransformations(origCI.getLangOpts()->getGC(), + origCI.getMigratorOpts().NoFinalizeRemoval); assert(!transforms.empty()); - llvm::OwningPtr transformPrinter; + OwningPtr 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(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 b72a08a..878eb6f 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 5522b33..56a4132 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 \n\n\n"); + "usage: c-arcmt-test -mt-migrate-directory \n" + " c-arcmt-test ...\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 c21b327..95a961f 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 2a3584b..573e6dc 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(""); + return; + } + if (!file) { + printf(""); + 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 = ""; + + 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("[<>]"); + else + printf("[%s]", (const char *)container); +} + +static const char *getEntityKindString(CXIdxEntityKind kind) { + switch (kind) { + case CXIdxEntity_Unexposed: return "<>"; + 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 ""; + 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: <>", cb); + return; + } + + name = info->name; + if (!name) + name = ""; + + 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(" : "); + PrintCursor(Attr->cursor); + } +} + +static void printBaseClassInfo(CXClientData client_data, + const CXIdxBaseClassInfo *info) { + printEntityInfo(" ", 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(" ", 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(" : "); + 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(" : kind: %s\n", kindName); + } + + if ((CatInfo = clang_index_getObjCCategoryDeclInfo(info))) { + printEntityInfo(" : 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(" ", client_data, PropInfo->getter); + printf("\n"); + } + if (PropInfo->setter) { + printEntityInfo(" ", 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(" | :", 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 = ""; 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= \n" " c-index-test -cursor-at= \n" " c-index-test -file-refs-at= \n" + " c-index-test -index-file [-check-prefix=] \n" + " c-index-test -index-tu [-check-prefix=] \n" " c-index-test -test-file-scan " "[FileCheck prefix]\n"); fprintf(stderr, @@ -1872,7 +2700,9 @@ static void print_usage(void) { " c-index-test -test-print-typekind {}*\n" " c-index-test -print-usr [ {}]*\n" " c-index-test -print-usr-file \n" - " c-index-test -write-pch \n\n"); + " c-index-test -write-pch \n"); + fprintf(stderr, + " c-index-test -read-diagnostics \n\n"); fprintf(stderr, " 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 0000000..851d6cd --- /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 0000000..b5b6bd5 --- /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 ... +// +// Where 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). +// +// ... 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 BuildPath( + cl::Positional, + cl::desc("")); + +cl::list SourcePaths( + cl::Positional, + cl::desc(" [... ]"), + cl::OneOrMore); + +int main(int argc, char **argv) { + cl::ParseCommandLineOptions(argc, argv); + std::string ErrorMessage; + llvm::OwningPtr Compilations( + CompilationDatabase::loadFromDirectory(BuildPath, ErrorMessage)); + if (!Compilations) + llvm::report_fatal_error(ErrorMessage); + ClangTool Tool(*Compilations, SourcePaths); + return Tool.run(newFrontendActionFactory()); +} diff --git a/tools/clang-check/Makefile b/tools/clang-check/Makefile new file mode 100644 index 0000000..49b1ada --- /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 7f7db8e..2bbeca8 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 &entries, llvm::raw_ostream &out) { } int ListWarnings::run(unsigned int argc, char **argv, llvm::raw_ostream &out) { - llvm::IntrusiveRefCntPtr Diags(new DiagnosticIDs); - DiagnosticsEngine D(Diags); - std::vector Flagged, Unflagged; llvm::StringMap > 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 22d7411..6e3bcfc 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 e6d0f1a..c4c864b 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 6b34a99..d828f67 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 27f79b7..a211090 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 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 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 Clang(new CompilerInstance()); - llvm::IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + OwningPtr Clang(new CompilerInstance()); + IntrusiveRefCntPtr 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(&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 7cc42aa..508d6da 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 Features; + /// @} /// @name Language Options /// @{ @@ -72,6 +81,8 @@ struct AssemblerInvocation { std::vector 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 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 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 Str; OwningPtr MCII(TheTarget->createMCInstrInfo()); OwningPtr - 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 DiagID(new DiagnosticIDs()); + IntrusiveRefCntPtr 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 Opts(driver::createCC1AsOptTable()); + OwningPtr 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(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 bd1d2a2..8c05fff 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 &ArgVector, std::set &SavedStrings) { const char *FName = Arg + 1; - llvm::OwningPtr MemBuf; + OwningPtr MemBuf; if (llvm::MemoryBuffer::getFile(FName, MemBuf)) { ArgVector.push_back(SaveStringInSet(SavedStrings, Arg)); return; @@ -272,7 +276,7 @@ static void ParseProgName(SmallVectorImpl &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 &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 CC1Opts(createCC1OptTable()); + unsigned MissingArgIndex, MissingArgCount; + OwningPtr 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 DiagID(new DiagnosticIDs()); + IntrusiveRefCntPtr 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 C(TheDriver.BuildCompilation(argv)); + OwningPtr 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 39c7d84..5ee5cf6 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(new Remap()); + OwningPtr 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(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 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(map)->Vec.size(); diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 46ba3d5..ece91ce 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 VisitorWorkList; - -// Cursor visitor. -class CursorVisitor : public DeclVisitor, - public TypeLocVisitor -{ - /// \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 WorkListFreeList; - SmallVector WorkListCache; - - using DeclVisitor::Visit; - using TypeLocVisitor::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(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::iterator - I = WorkListCache.begin(), E = WorkListCache.end(); I != E; ++I) { - delete *I; - } - } - - ASTUnit *getASTUnit() const { return static_cast(TU->TUData); } - CXTranslationUnit getTU() const { return TU; } - - bool Visit(CXCursor Cursor, bool CheckedRegionOfInterest = false); - - bool visitPreprocessedEntitiesInRegion(); - - template - 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 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(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 + Entities = PPRec.getPreprocessedEntitiesInRange(R); + return Visitor.visitPreprocessedEntities(Entities.first, Entities.second, + PPRec, FID); +} + +void CursorVisitor::visitFileRegion() { + if (RegionOfInterest.isInvalid()) + return; + + ASTUnit *Unit = static_cast(TU->TUData); + SourceManager &SM = Unit->getSourceManager(); + + std::pair + 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(TU->TUData); + SourceManager &SM = Unit->getSourceManager(); + SourceRange Range = RegionOfInterest; + + SmallVector 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::iterator DIt = Decls.begin(); + for (SmallVector::iterator DE = Decls.end(); DIt != DE; ++DIt) { + Decl *D = *DIt; + if (D->getSourceRange().isInvalid()) + continue; + + if (isInLexicalContext(D, CurDC)) + continue; + + CurDC = dyn_cast(D); + + if (TagDecl *TD = dyn_cast(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(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(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 - 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 bool CursorVisitor::visitPreprocessedEntities(InputIterator First, - InputIterator Last) { + InputIterator Last, + PreprocessingRecord &PPRec, + FileID FID) { for (; First != Last; ++First) { - if (MacroExpansion *ME = dyn_cast(*First)) { + if (!FID.isInvalid() && !PPRec.isEntityInFileID(First, FID)) + continue; + + PreprocessedEntity *PPE = *First; + if (MacroExpansion *ME = dyn_cast(PPE)) { if (Visit(MakeMacroExpansionCursor(ME, TU))) return true; continue; } - if (MacroDefinition *MD = dyn_cast(*First)) { + if (MacroDefinition *MD = dyn_cast(PPE)) { if (Visit(MakeMacroDefinitionCursor(MD, TU))) return true; continue; } - if (InclusionDirective *ID = dyn_cast(*First)) { + if (InclusionDirective *ID = dyn_cast(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(D); + if (!ID->isThisDeclarationADefinition()) + Cursor = MakeCursorObjCClassRef(ID, ID->getLocation(), TU); + + } else if (Cursor.kind == CXCursor_ObjCProtocolDecl) { + ObjCProtocolDecl *PD = cast(D); + if (!PD->isThisDeclarationADefinition()) + Cursor = MakeCursorObjCProtocolRef(PD, PD->getLocation(), TU); + } + const llvm::Optional &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 +static void addRangedDeclsInContainer(DeclIt *DI_current, DeclIt DE_current, + SourceManager &SM, SourceLocation EndLoc, + SmallVectorImpl &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()->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(S)->getNameInfo(); case Stmt::CXXDependentScopeMemberExprClass: return cast(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(&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(TL)) { + FunctionProtoTypeLoc Proto = cast(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(CIdx); } +void clang_CXIndex_setGlobalOptions(CXIndex CIdx, unsigned options) { + if (CIdx) + static_cast(CIdx)->setCXGlobalOptFlags(options); +} + +unsigned clang_CXIndex_getGlobalOptions(CXIndex CIdx) { + if (CIdx) + return static_cast(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 Diags; + IntrusiveRefCntPtr 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(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 + IntrusiveRefCntPtr Diags(CompilerInstance::createDiagnostics(DiagOpts, num_command_line_args, command_line_args)); @@ -2438,7 +2534,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { llvm::CrashRecoveryContextReleaseRefCleanup > DiagCleanup(Diags.getPtr()); - llvm::OwningPtr > + OwningPtr > RemappedFiles(new std::vector()); // Recover resources if we crash before exiting this function. @@ -2453,7 +2549,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { Buffer)); } - llvm::OwningPtr > + OwningPtr > Args(new std::vector()); // 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 Unit( + OwningPtr ErrUnit; + OwningPtr 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(UserData); + + CIndexer *CXXIdx = (CIndexer*)STUI->TU->CIdx; + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) + setThreadBackgroundPriority(); + + STUI->result = static_cast(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(TU->TUData)->Save(FileName); - if (getenv("LIBCLANG_RESOURCE_USAGE")) + + ASTUnit *CXXUnit = static_cast(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(CTUnit->TUData); disposeCXStringPool(CTUnit->StringPool); + delete static_cast(CTUnit->Diagnostics); delete CTUnit; } } @@ -2621,6 +2754,11 @@ static void clang_reparseTranslationUnit_Impl(void *UserData) { ReparseTranslationUnitInfo *RTUI = static_cast(UserData); CXTranslationUnit TU = RTUI->TU; + + // Reset the associated diagnostics. + delete static_cast(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(TU->TUData); ASTUnit::ConcurrencyCheck Check(*CXXUnit); - llvm::OwningPtr > + OwningPtr > RemappedFiles(new std::vector()); // 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(tu->TUData); - ASTUnit::ConcurrencyCheck Check(*CXXUnit); - const FileEntry *File = static_cast(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(tu->TUData); - SourceLocation SLoc - = CXXUnit->getLocation(static_cast(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(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(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(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 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(E)) return RefExpr->getDecl(); - if (BlockDeclRefExpr *RefExpr = dyn_cast(E)) - return RefExpr->getDecl(); if (MemberExpr *ME = dyn_cast(E)) return ME->getMemberDecl(); if (ObjCIvarRefExpr *RE = dyn_cast(E)) return RE->getDecl(); - if (ObjCPropertyRefExpr *PRE = dyn_cast(E)) - return PRE->isExplicitProperty() ? PRE->getExplicitProperty() : 0; + if (ObjCPropertyRefExpr *PRE = dyn_cast(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(E)) + return getDeclFromExpr(POE->getSyntacticForm()); + if (OpaqueValueExpr *OVE = dyn_cast(E)) + if (Expr *Src = OVE->getSourceExpr()) + return getDeclFromExpr(Src); if (CallExpr *CE = dyn_cast(E)) return getDeclFromExpr(CE->getCallee()); @@ -3004,14 +2938,14 @@ static SourceLocation getLocationFromExpr(Expr *E) { return /*FIXME:*/Msg->getLeftLoc(); if (DeclRefExpr *DRE = dyn_cast(E)) return DRE->getLocation(); - if (BlockDeclRefExpr *RefExpr = dyn_cast(E)) - return RefExpr->getLocation(); if (MemberExpr *Member = dyn_cast(E)) return Member->getMemberLoc(); if (ObjCIvarRefExpr *Ivar = dyn_cast(E)) return Ivar->getLocation(); if (SizeOfPackExpr *SizeOfPack = dyn_cast(E)) return SizeOfPack->getPackLoc(); + if (ObjCPropertyRefExpr *PropRef = dyn_cast(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(D); + if (!D) + return createCXString(""); + + NamedDecl *ND = dyn_cast(D); if (!ND) { if (ObjCPropertyImplDecl *PropImpl =dyn_cast(D)) if (ObjCPropertyDecl *Property = PropImpl->getPropertyDecl()) @@ -3085,7 +3022,7 @@ static CXString getDeclSpelling(Decl *D) { if (isa(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(""); } @@ -3206,9 +3150,71 @@ CXString clang_getCursorSpelling(CXCursor C) { return createCXString(AA->getAnnotation()); } + if (C.kind == CXCursor_AsmLabelAttr) { + AsmLabelAttr *AA = cast(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(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(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(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(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(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(getCursorDecl(cursor))) + if (ObjCMethodDecl *MD = dyn_cast_or_null(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 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(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(D)) { if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) - StartLoc = TI->getTypeLoc().getSourceRange().getBegin(); + StartLoc = TI->getTypeLoc().getLocStart(); } else if (TypedefDecl *Typedef = dyn_cast(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(D)) return MakeCursorOverloadedDeclRef(Using, D->getLocation(), tu); - if (ObjCClassDecl *Classes = dyn_cast(D)) - return MakeCursorOverloadedDeclRef(Classes, D->getLocation(), tu); - if (ObjCForwardProtocolDecl *Protocols - = dyn_cast(D)) - return MakeCursorOverloadedDeclRef(Protocols, D->getLocation(), tu); if (ObjCPropertyImplDecl *PropImpl =dyn_cast(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(D)->isForwardDecl()) - return C; + if (ObjCProtocolDecl *Def = cast(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(D); if (WasReference) { - if (!cast(D)->isForwardDecl()) - return C; - } else if (ObjCImplementationDecl *Impl - = cast(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(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(D), - D->getLocation(), TU); - - case Decl::ObjCClass: - return MakeCursorOverloadedDeclRef(cast(D), D->getLocation(), - TU); - case Decl::Friend: if (NamedDecl *Friend = cast(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(); if (UsingDecl *Using = dyn_cast(D)) return Using->shadow_size(); - if (isa(D)) - return 1; - if (ObjCForwardProtocolDecl *Protocols =dyn_cast(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(*Pos)->getTargetDecl(), TU); } - if (ObjCClassDecl *Classes = dyn_cast(D)) - return MakeCXCursor(Classes->getForwardInterfaceDecl(), TU); - if (ObjCForwardProtocolDecl *Protocols = dyn_cast(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(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(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(D)) { + if (const DeclaratorDecl *DD = dyn_cast_or_null(D)) { if (TypeSourceInfo *TI = DD->getTypeSourceInfo()) - StartLoc = TI->getTypeLoc().getSourceRange().getBegin(); - } else if (TypedefDecl *Typedef = dyn_cast(D)) { + StartLoc = TI->getTypeLoc().getLocStart(); + } else if (TypedefDecl *Typedef = dyn_cast_or_null(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 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(TU->TUData); - llvm::OwningPtr entries(new MemUsageEntries()); + OwningPtr 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 fb0ccb1..240b0f6 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 c19b340..303fb1f 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 Diagnostics; /// \brief Diag object - llvm::IntrusiveRefCntPtr Diag; + IntrusiveRefCntPtr 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 FileMgr; + IntrusiveRefCntPtr FileMgr; /// \brief Source manager, used for diagnostics. - llvm::IntrusiveRefCntPtr SourceMgr; + IntrusiveRefCntPtr 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 TemporaryBuffers; /// \brief Allocator used to store globally cached code-completion results. - llvm::IntrusiveRefCntPtr + IntrusiveRefCntPtr CachedCompletionAllocator; /// \brief Allocator used to store code completion results. - clang::CodeCompletionAllocator CodeCompletionAllocator; + IntrusiveRefCntPtr + 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(new DiagnosticIDs))), + IntrusiveRefCntPtr(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 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 26f69b0..8fbe3d8 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::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(); + 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 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 Ranges) {} + + virtual void emitCodeContext(SourceLocation Loc, + DiagnosticsEngine::Level Level, + SmallVectorImpl& Ranges, + ArrayRef 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(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(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(TU->Diagnostics); +} + //----------------------------------------------------------------------------- // C Interface Routines //----------------------------------------------------------------------------- extern "C" { unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) { - ASTUnit *CXXUnit = static_cast(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(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(D); + if (Index >= Diags->getNumDiagnostics()) + return 0; + + return Diags->getDiagnostic(Index); +} + +CXDiagnosticSet clang_getDiagnosticSetFromTU(CXTranslationUnit Unit) { + if (!Unit->TUData) + return 0; + return static_cast(lazyCreateDiags(Unit)); } void clang_disposeDiagnostic(CXDiagnostic Diagnostic) { - CXStoredDiagnostic *Stored = static_cast(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(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(Diag)) + return D->getSeverity(); return CXDiagnostic_Ignored; } CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) { - CXStoredDiagnostic *StoredDiag = static_cast(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(Diag)) + return D->getLocation(); + return clang_getNullLocation(); } CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) { - CXStoredDiagnostic *StoredDiag = static_cast(Diag); - if (!StoredDiag) - return createCXString(""); - - return createCXString(StoredDiag->Diag.getMessage(), false); + if (CXDiagnosticImpl *D = static_cast(Diag)) + return D->getSpelling(); + return createCXString(""); } CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) { if (Disable) *Disable = createCXString(""); - - CXStoredDiagnostic *StoredDiag = static_cast(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(Diag)) + return D->getDiagnosticOption(Disable); return createCXString(""); } unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) { - CXStoredDiagnostic *StoredDiag = static_cast(Diag); - if (!StoredDiag) - return 0; - - return DiagnosticIDs::getCategoryNumberForDiag(StoredDiag->Diag.getID()); + if (CXDiagnosticImpl *D = static_cast(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(Diag)) + return D->getCategoryText(); + return createCXString(""); +} + unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) { - CXStoredDiagnostic *StoredDiag = static_cast(Diag); - if (!StoredDiag || StoredDiag->Diag.getLocation().isInvalid()) - return 0; - - return StoredDiag->Diag.range_size(); + if (CXDiagnosticImpl *D = static_cast(Diag)) + return D->getNumRanges(); + return 0; } CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) { - CXStoredDiagnostic *StoredDiag = static_cast(Diag); - if (!StoredDiag || Range >= StoredDiag->Diag.range_size() || - StoredDiag->Diag.getLocation().isInvalid()) + CXDiagnosticImpl *D = static_cast(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(Diag); - if (!StoredDiag) - return 0; - - return StoredDiag->Diag.fixit_size(); + if (CXDiagnosticImpl *D = static_cast(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(Diagnostic); - if (!StoredDiag || FixIt >= StoredDiag->Diag.fixit_size() || - StoredDiag->Diag.getLocation().isInvalid()) { + CXDiagnosticImpl *D = static_cast(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(Diags); + if (D->isExternallyManaged()) + delete D; +} + +CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags, + unsigned Index) { + if (CXDiagnosticSetImpl *D = static_cast(Diags)) + if (Index < D->getNumDiagnostics()) + return D->getDiagnostic(Index); + return 0; +} + +CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) { + if (CXDiagnosticImpl *D = static_cast(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(Diags)) + return D->getNumDiagnostics(); + return 0; } } // end extern "C" diff --git a/tools/libclang/CIndexDiagnostic.h b/tools/libclang/CIndexDiagnostic.h index 0d935fa..b1c3978 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 +#include + namespace clang { class LangOptions; class StoredDiagnostic; +class CXDiagnosticImpl; + +class CXDiagnosticSetImpl { + std::vector 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 b5a05ea..ec76898 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 &Methods) { + if (!D) + return; if (!isa(D) && !isa(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(D)) - return getCanonical(ImplD->getClassInterface()); - if (CXXConstructorDecl *CXXCtorD = dyn_cast(D)) + if (ObjCImplDecl *ImplD = dyn_cast(D)) { + if (ImplD->getClassInterface()) + return getCanonical(ImplD->getClassInterface()); + + } else if (CXXConstructorDecl *CXXCtorD = dyn_cast(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(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(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 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(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(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(file), diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index 121d67d..7c79b69 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -30,7 +30,7 @@ using namespace clang::cxstring; namespace { class USRGenerator : public DeclVisitor { - llvm::OwningPtr > OwnedBuf; + OwningPtr > OwnedBuf; SmallVectorImpl &Buf; llvm::raw_svector_ostream Out; bool IgnoreResults; @@ -41,7 +41,7 @@ class USRGenerator : public DeclVisitor { public: explicit USRGenerator(ASTContext *Ctx = 0, SmallVectorImpl *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(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(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(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 &Buf) { +bool cxcursor::getDeclCursorUSR(const Decl *D, SmallVectorImpl &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 &Buf) { { USRGenerator UG(&D->getASTContext(), &Buf); - UG->Visit(D); + UG->Visit(const_cast(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 995a8fe..d458789 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 45d0831..1e5fb82 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 f754e98..66a1710 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 db275001..d84cf29 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(S)->getSourceExpr()) + return MakeCXCursor(Src, Parent, TU, RegionOfInterest); K = CXCursor_UnexposedExpr; break; + case Stmt::PseudoObjectExprClass: + return MakeCXCursor(cast(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(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(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(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(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(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(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(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(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(C.data[1]))); } -CXCursor cxcursor::MakeCursorNamespaceRef(NamedDecl *NS, SourceLocation Loc, +CXCursor cxcursor::MakeCursorNamespaceRef(const NamedDecl *NS, + SourceLocation Loc, CXTranslationUnit TU) { assert(NS && (isa(NS) || isa(NS)) && TU && "Invalid arguments!"); void *RawLoc = reinterpret_cast(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(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(Loc.getRawEncoding()); + CXCursor C = { CXCursor_VariableRef, 0, { (void*)Var, RawLoc, TU } }; + return C; +} + +std::pair +cxcursor::getCursorVariableRef(CXCursor C) { + assert(C.kind == CXCursor_VariableRef); + return std::make_pair(static_cast(C.data[0]), + SourceLocation::getFromRawEncoding( + reinterpret_cast(C.data[1]))); +} + +CXCursor cxcursor::MakeCursorMemberRef(const FieldDecl *Field, SourceLocation Loc, CXTranslationUnit TU) { assert(Field && TU && "Invalid arguments!"); void *RawLoc = reinterpret_cast(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(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(static_cast(Cursor.data[2]) - ->TUData); + CXTranslationUnit TU = static_cast(Cursor.data[2]); + if (!TU) + return 0; + return static_cast(TU->TUData); } CXTranslationUnit cxcursor::getCursorTU(CXCursor Cursor) { return static_cast(Cursor.data[2]); } -static void CollectOverriddenMethods(CXTranslationUnit TU, - DeclContext *Ctx, +static void CollectOverriddenMethodsRecurse(CXTranslationUnit TU, + ObjCContainerDecl *Container, ObjCMethodDecl *Method, - SmallVectorImpl &Methods) { - if (!Ctx) + SmallVectorImpl &Methods, + bool MovedToSuper) { + if (!Container) return; - // If we have a class or category implementation, jump straight to the - // interface. - if (ObjCImplDecl *Impl = dyn_cast(Ctx)) - return CollectOverriddenMethods(TU, Impl->getClassInterface(), - Method, Methods); - - ObjCContainerDecl *Container = dyn_cast(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(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(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(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 &Methods) { + CollectOverriddenMethodsRecurse(TU, Container, Method, Methods, + /*MovedToSuper=*/false); +} + void cxcursor::getOverriddenCursors(CXCursor cursor, SmallVectorImpl &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(Method->getDeclContext())) { + CollectOverriddenMethods(TU, ProtD, Method, overridden); + + } else if (ObjCImplDecl * + IMD = dyn_cast(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(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(Method->getDeclContext()), + Method, overridden); + } } std::pair @@ -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(D)) + return MD->param_size(); + if (const FunctionDecl *FD = dyn_cast_or_null(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(D)) { + if (i < MD->param_size()) + return cxcursor::MakeCXCursor(MD->param_begin()[i], + cxcursor::getCursorTU(C)); + } else if (FunctionDecl *FD = dyn_cast_or_null(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(decl)) { - NamedDecl *namedDecl = (NamedDecl *)decl; + if (NamedDecl *namedDecl = dyn_cast_or_null(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(MacroInfo)); - CodeCompletionString *String - = Result.CreateCodeCompletionString(S, *Allocator); - return String; - } + CodeCompletionResult Result(const_cast(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 e402d7f..947b0a3 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 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 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 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 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 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 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 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 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 &Buf); +bool getDeclCursorUSR(const Decl *D, SmallVectorImpl &Buf); bool operator==(CXCursor X, CXCursor Y); diff --git a/tools/libclang/CXLoadedDiagnostic.cpp b/tools/libclang/CXLoadedDiagnostic.cpp new file mode 100644 index 0000000..e5b6ccc --- /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 + +using namespace clang; +using namespace clang::cxstring; + +//===----------------------------------------------------------------------===// +// Extend CXDiagnosticSetImpl which contains strings for diagnostics. +//===----------------------------------------------------------------------===// + +typedef llvm::DenseMap 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 Files; +}; +} + +llvm::StringRef CXLoadedDiagnosticSetImpl::makeString(const char *blob, + unsigned bloblen) { + char *mem = Alloc.Allocate(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 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 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 + 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(); + End = TopDiags.Alloc.Allocate(); + + 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 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 0000000..d4a321e --- /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 +#include + +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 Ranges; + std::vector > 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 0000000..a6bf8fc --- /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(tu->TUData); + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + const FileEntry *File = static_cast(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(tu->TUData); + + SourceLocation SLoc + = CXXUnit->getLocation(static_cast(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(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(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(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 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 7a50205..6c5e858 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 0000000..8284dc9 --- /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 d36c7c1..c354bd2 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 2b8f977..3ad867c 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 0e62e27..850fac1 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(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(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(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(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(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()) + return (unsigned)FD->isVariadic(); + + if (T->getAs()) + 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()) { +#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()) { + return FD->getNumArgs(); + } + + if (T->getAs()) { + 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()) { + 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()) @@ -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(D)) + if (const ObjCMethodDecl *MD = dyn_cast_or_null(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 (TP)->getElementType(); + break; + case Type::Vector: + ET = cast (TP)->getElementType(); + break; + case Type::Complex: + ET = cast (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 (TP)->getSize().getSExtValue(); + break; + case Type::Vector: + result = cast (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 0000000..88b70a4 --- /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 VisitorWorkList; + +// Cursor visitor. +class CursorVisitor : public DeclVisitor, + public TypeLocVisitor +{ + /// \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::iterator *FileDI_current; + SmallVectorImpl::iterator FileDE_current; + + // Cache of pre-allocated worklists for data-recursion walk of Stmts. + SmallVector WorkListFreeList; + SmallVector WorkListCache; + + using DeclVisitor::Visit; + using TypeLocVisitor::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(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::iterator + I = WorkListCache.begin(), E = WorkListCache.end(); I != E; ++I) { + delete *I; + } + } + + ASTUnit *getASTUnit() const { return static_cast(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 + 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 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 0000000..74a8d37 --- /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 { + IndexingContext &IndexCtx; + const NamedDecl *Parent; + const DeclContext *ParentDC; + + typedef RecursiveASTVisitor 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(S)); +} diff --git a/tools/libclang/IndexDecl.cpp b/tools/libclang/IndexDecl.cpp new file mode 100644 index 0000000..c257c34 --- /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 { + 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(D)) { + IndexCtx.handleVar(Parm); + } else if (FunctionDecl *FD = dyn_cast(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(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(D)); + if (!Handled && isa(D)) + indexDeclContext(cast(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(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 0000000..b62d521 --- /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 { + 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 df54d7c..2d42cb8 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 0000000..e660c4d --- /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 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 Buffers; + + ~MemBufferOwner() { + for (SmallVectorImpl::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(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(CIdx); + + if (CXXIdx->isOptEnabled(CXGlobalOpt_ThreadBackgroundPriorityForIndexing)) + setThreadBackgroundPriority(); + + CaptureDiagnosticConsumer *CaptureDiag = new CaptureDiagnosticConsumer(); + + // Configure the diagnostics. + DiagnosticOptions DiagOpts; + IntrusiveRefCntPtr + 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 > + DiagCleanup(Diags.getPtr()); + + OwningPtr > + Args(new std::vector()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar > + 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 + CInvok(createInvocationFromCommandLine(*Args, Diags)); + + if (!CInvok) + return; + + // Recover resources if we crash before exiting this function. + llvm::CrashRecoveryContextCleanupRegistrar > + CInvokCleanup(CInvok.getPtr()); + + if (CInvok->getFrontendOpts().Inputs.empty()) + return; + + OwningPtr BufOwner(new MemBufferOwner()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + 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 CXTU(new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit))); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + CXTUCleanup(CXTU.get()); + + OwningPtr IndexAction; + IndexAction.reset(new IndexingFrontendAction(client_data, CB, + index_options, CXTU->getTU())); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + 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(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(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 IndexCtx; + IndexCtx.reset(new IndexingContext(client_data, CB, index_options, TU)); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + IndexCtxCleanup(IndexCtx.get()); + + OwningPtr IndexConsumer; + IndexConsumer.reset(new IndexingConsumer(*IndexCtx)); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + IndexConsumerCleanup(IndexConsumer.get()); + + ASTUnit *Unit = static_cast(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(DInfo); + if (const ObjCContainerDeclInfo * + ContInfo = dyn_cast(DI)) + return &ContInfo->ObjCContDeclInfo; + + return 0; +} + +const CXIdxObjCInterfaceDeclInfo * +clang_index_getObjCInterfaceDeclInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return 0; + + const DeclInfo *DI = static_cast(DInfo); + if (const ObjCInterfaceDeclInfo * + InterInfo = dyn_cast(DI)) + return &InterInfo->ObjCInterDeclInfo; + + return 0; +} + +const CXIdxObjCCategoryDeclInfo * +clang_index_getObjCCategoryDeclInfo(const CXIdxDeclInfo *DInfo){ + if (!DInfo) + return 0; + + const DeclInfo *DI = static_cast(DInfo); + if (const ObjCCategoryDeclInfo * + CatInfo = dyn_cast(DI)) + return &CatInfo->ObjCCatDeclInfo; + + return 0; +} + +const CXIdxObjCProtocolRefListInfo * +clang_index_getObjCProtocolRefListInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return 0; + + const DeclInfo *DI = static_cast(DInfo); + + if (const ObjCInterfaceDeclInfo * + InterInfo = dyn_cast(DI)) + return InterInfo->ObjCInterDeclInfo.protocols; + + if (const ObjCProtocolDeclInfo * + ProtInfo = dyn_cast(DI)) + return &ProtInfo->ObjCProtoRefListInfo; + + if (const ObjCCategoryDeclInfo *CatInfo = dyn_cast(DI)) + return CatInfo->ObjCCatDeclInfo.protocols; + + return 0; +} + +const CXIdxObjCPropertyDeclInfo * +clang_index_getObjCPropertyDeclInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return 0; + + const DeclInfo *DI = static_cast(DInfo); + if (const ObjCPropertyDeclInfo *PropInfo = dyn_cast(DI)) + return &PropInfo->ObjCPropDeclInfo; + + return 0; +} + +const CXIdxIBOutletCollectionAttrInfo * +clang_index_getIBOutletCollectionAttrInfo(const CXIdxAttrInfo *AInfo) { + if (!AInfo) + return 0; + + const AttrInfo *DI = static_cast(AInfo); + if (const IBOutletCollectionInfo * + IBInfo = dyn_cast(DI)) + return &IBInfo->IBCollInfo; + + return 0; +} + +const CXIdxCXXClassDeclInfo * +clang_index_getCXXClassDeclInfo(const CXIdxDeclInfo *DInfo) { + if (!DInfo) + return 0; + + const DeclInfo *DI = static_cast(DInfo); + if (const CXXClassDeclInfo *ClassInfo = dyn_cast(DI)) + return &ClassInfo->CXXClassInfo; + + return 0; +} + +CXIdxClientContainer +clang_index_getClientContainer(const CXIdxContainerInfo *info) { + if (!info) + return 0; + const ContainerInfo *Container = static_cast(info); + return Container->IndexCtx->getClientContainerForDC(Container->DC); +} + +void clang_index_setClientContainer(const CXIdxContainerInfo *info, + CXIdxClientContainer client) { + if (!info) + return; + const ContainerInfo *Container = static_cast(info); + Container->IndexCtx->addContainerInMap(Container->DC, client); +} + +CXIdxClientEntity clang_index_getClientEntity(const CXIdxEntityInfo *info) { + if (!info) + return 0; + const EntityInfo *Entity = static_cast(info); + return Entity->IndexCtx->getClientEntity(Entity->Dcl); +} + +void clang_index_setClientEntity(const CXIdxEntityInfo *info, + CXIdxClientEntity client) { + if (!info) + return; + const EntityInfo *Entity = static_cast(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(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(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 0000000..ace5c75 --- /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(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(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()) { + 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::create(const Decl *D, IndexingContext &IdxCtx) { + ScratchAlloc SA(IdxCtx); + AttrListInfo *attrs = SA.allocate(); + 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()) { + BaseD = TDT->getDecl(); + } else if (const TemplateSpecializationType * + TST = T->getAs()) { + BaseD = TST->getTemplateName().getAsTemplateDecl(); + } else if (const RecordType *RT = T->getAs()) { + 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(&TL)) + TL = QL->getUnqualifiedLoc(); + + if (const ElaboratedTypeLoc *EL = dyn_cast(&TL)) + return EL->getNamedTypeLoc().getBeginLoc(); + if (const DependentNameTypeLoc *DL = dyn_cast(&TL)) + return DL->getNameLoc(); + if (const DependentTemplateSpecializationTypeLoc * + DTL = dyn_cast(&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(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(CXTU->TUData)->setASTContext(&ctx); +} + +void IndexingContext::setPreprocessor(Preprocessor &PP) { + static_cast(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(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(E), + const_cast(cast(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 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::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(D->getCanonicalDecl()); + + if (const ObjCImplementationDecl * + ImplD = dyn_cast(D)) { + return getEntityDecl(ImplD->getClassInterface()); + + } else if (const ObjCCategoryImplDecl * + CatImplD = dyn_cast(D)) { + return getEntityDecl(CatImplD->getCategoryDecl()); + } else if (const FunctionDecl *FD = dyn_cast(D)) { + if (FunctionTemplateDecl *TemplD = FD->getDescribedFunctionTemplate()) + return getEntityDecl(TemplD); + } else if (const CXXRecordDecl *RD = dyn_cast(D)) { + if (ClassTemplateDecl *TemplD = RD->getDescribedClassTemplate()) + return getEntityDecl(TemplD); + } + + return D; +} + +const DeclContext * +IndexingContext::getEntityContainer(const Decl *D) const { + const DeclContext *DC = dyn_cast(D); + if (DC) + return DC; + + if (const ClassTemplateDecl *ClassTempl = dyn_cast(D)) { + DC = ClassTempl->getTemplatedDecl(); + } if (const FunctionTemplateDecl * + FuncTempl = dyn_cast(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 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(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(D)) + if (!CXXRec->isCLike()) + EntityInfo.lang = CXIdxEntityLang_CXX; + + if (isa(D)) { + EntityInfo.templateKind = CXIdxEntity_TemplatePartialSpecialization; + } else if (isa(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(D->getDeclContext())) { + EntityInfo.kind = CXIdxEntity_CXXStaticVariable; + EntityInfo.lang = CXIdxEntityLang_CXX; + } + break; + case Decl::Field: + EntityInfo.kind = CXIdxEntity_Field; + if (const CXXRecordDecl * + CXXRec = dyn_cast(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(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(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( + cast(D)->getTemplatedDecl())) { + if (isa(MD)) + EntityInfo.kind = CXIdxEntity_CXXConstructor; + else if (isa(MD)) + EntityInfo.kind = CXIdxEntity_CXXDestructor; + else if (isa(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(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(D) || isa(D) || isa(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(DC)); + ContInfo.DC = DC; + ContInfo.IndexCtx = this; +} + +CXCursor IndexingContext::getRefCursor(const NamedDecl *D, SourceLocation Loc) { + if (const TypeDecl *TD = dyn_cast(D)) + return MakeCursorTypeRef(TD, Loc, CXTU); + if (const ObjCInterfaceDecl *ID = dyn_cast(D)) + return MakeCursorObjCClassRef(ID, Loc, CXTU); + if (const ObjCProtocolDecl *PD = dyn_cast(D)) + return MakeCursorObjCProtocolRef(PD, Loc, CXTU); + if (const TemplateDecl *Template = dyn_cast(D)) + return MakeCursorTemplateRef(Template, Loc, CXTU); + if (const NamespaceDecl *Namespace = dyn_cast(D)) + return MakeCursorNamespaceRef(Namespace, Loc, CXTU); + if (const NamespaceAliasDecl *Namespace = dyn_cast(D)) + return MakeCursorNamespaceRef(Namespace, Loc, CXTU); + if (const FieldDecl *Field = dyn_cast(D)) + return MakeCursorMemberRef(Field, Loc, CXTU); + if (const VarDecl *Var = dyn_cast(D)) + return MakeCursorVariableRef(Var, Loc, CXTU); + + return clang_getNullCursor(); +} + +bool IndexingContext::shouldIgnoreIfImplicit(const Decl *D) { + if (isa(D)) + return false; + if (isa(D)) + return false; + if (isa(D)) + return false; + if (isa(D)) + return false; + return true; +} + +bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) { + if (const ClassTemplateSpecializationDecl * + SD = dyn_cast(D)) { + return SD->getSpecializationKind() == TSK_ImplicitInstantiation; + } + if (const FunctionDecl *FD = dyn_cast(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 0000000..6271660 --- /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 + +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 + T *allocate(); +}; + +struct EntityInfo : public CXIdxEntityInfo { + const NamedDecl *Dcl; + IndexingContext *IndexCtx; + IntrusiveRefCntPtr 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 Attrs; + SmallVector IBCollAttrs; + SmallVector 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 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 FileMapTy; + typedef llvm::DenseMap + ContainerMapTy; + typedef llvm::DenseMap EntityMapTy; + + FileMapTy FileMap; + ContainerMapTy ContainerMap; + EntityMapTy EntityMap; + + llvm::DenseSet RefFileOccurences; + + std::deque TUDeclsInObjCContainer; + + llvm::BumpPtrAllocator StrScratch; + unsigned StrAdapterCount; + friend class ScratchAlloc; + + struct ObjCProtocolListInfo { + SmallVector ProtInfos; + SmallVector ProtEntities; + SmallVector Prots; + + CXIdxObjCProtocolRefListInfo getListInfo() const { + CXIdxObjCProtocolRefListInfo Info = { Prots.data(), + (unsigned)Prots.size() }; + return Info; + } + + ObjCProtocolListInfo(const ObjCProtocolList &ProtList, + IndexingContext &IdxCtx, + ScratchAlloc &SA); + }; + + struct CXXBasesListInfo { + SmallVector BaseInfos; + SmallVector BaseEntities; + SmallVector 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(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 +inline T *ScratchAlloc::allocate() { + return IdxCtx.StrScratch.Allocate(); +} + +}} // end clang::cxindex + +namespace llvm { + /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and + /// DenseSets. + template <> + struct DenseMapInfo { + 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 375f7f2..1fff166 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 989ed83..d3b64db 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 c39e417..32a7301 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 dae86f4..59b0baf 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 cc068a5..06e1d85 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__': -- cgit v1.1