diff options
-rw-r--r-- | include/clang-c/Index.h | 19 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 4 | ||||
-rw-r--r-- | test/Index/file-includes.c | 24 | ||||
-rw-r--r-- | tools/c-index-test/c-index-test.c | 98 | ||||
-rw-r--r-- | tools/libclang/CIndexHigh.cpp | 106 | ||||
-rw-r--r-- | tools/libclang/libclang.exports | 2 |
6 files changed, 249 insertions, 4 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index c382fb17c1..b9b4f8e269 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -32,7 +32,7 @@ * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. */ #define CINDEX_VERSION_MAJOR 0 -#define CINDEX_VERSION_MINOR 12 +#define CINDEX_VERSION_MINOR 13 #define CINDEX_VERSION_ENCODE(major, minor) ( \ ((major) * 10000) \ @@ -5021,6 +5021,19 @@ typedef struct { CINDEX_LINKAGE void clang_findReferencesInFile(CXCursor cursor, CXFile file, CXCursorAndRangeVisitor visitor); +/** + * \brief Find #import/#include directives in a specific file. + * + * \param TU translation unit containing the file to query. + * + * \param file to search for #import/#include directives. + * + * \param visitor callback that will receive pairs of CXCursor/CXSourceRange for + * each directive found. + */ +CINDEX_LINKAGE void clang_findIncludesInFile(CXTranslationUnit TU, CXFile file, + CXCursorAndRangeVisitor visitor); + #ifdef __has_feature # if __has_feature(blocks) @@ -5031,6 +5044,10 @@ CINDEX_LINKAGE void clang_findReferencesInFileWithBlock(CXCursor, CXFile, CXCursorAndRangeVisitorBlock); +CINDEX_LINKAGE +void clang_findIncludesInFileWithBlock(CXTranslationUnit, CXFile, + CXCursorAndRangeVisitorBlock); + # endif #endif diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 0389722bfd..4ad51e5dea 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -4000,7 +4000,7 @@ ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const { GlobalSLocOffsetMapType::const_iterator SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - - BLoc.getOffset()); + BLoc.getOffset() - 1); assert(SLocMapI != GlobalSLocOffsetMap.end() && "Corrupted global sloc offset map"); @@ -4048,7 +4048,7 @@ ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const { GlobalSLocOffsetMapType::const_iterator SLocMapI = GlobalSLocOffsetMap.find(SourceManager::MaxLoadedOffset - - ELoc.getOffset()); + ELoc.getOffset() - 1); assert(SLocMapI != GlobalSLocOffsetMap.end() && "Corrupted global sloc offset map"); diff --git a/test/Index/file-includes.c b/test/Index/file-includes.c new file mode 100644 index 0000000000..3663398a3b --- /dev/null +++ b/test/Index/file-includes.c @@ -0,0 +1,24 @@ + +#include "targeted-top.h" +#include "targeted-preamble.h" + +extern int LocalVar; +int LocalVar; + +// RUN: c-index-test -write-pch %t.h.pch %S/targeted-top.h -Xclang -detailed-preprocessing-record + +// RUN: c-index-test -file-includes-in=%s %s | FileCheck %s -check-prefix=LOCAL +// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%s %s | FileCheck %s -check-prefix=LOCAL +// RUN: c-index-test -file-includes-in=%s %s -include %t.h | FileCheck %s -check-prefix=LOCAL +// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%s %s -include %t.h | FileCheck %s -check-prefix=LOCAL + +// LOCAL: inclusion directive=targeted-top.h ({{.*}}/test/Index/targeted-top.h) {{.*}}=[2:1 - 2:2] +// LOCAL: inclusion directive=targeted-preamble.h ({{.*}}/test/Index/targeted-preamble.h) =[3:1 - 3:2] + +// RUN: c-index-test -file-includes-in=%S/targeted-top.h %s | FileCheck %s -check-prefix=TOP +// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%S/targeted-top.h %s | FileCheck %s -check-prefix=TOP +// RUN: c-index-test -file-includes-in=%S/targeted-top.h %s -include %t.h | FileCheck %s -check-prefix=TOP +// RUN: env CINDEXTEST_EDITING=1 c-index-test -file-includes-in=%S/targeted-top.h %s -include %t.h | FileCheck %s -check-prefix=TOP + +// TOP: inclusion directive=targeted-nested1.h ({{.*}}/test/Index/targeted-nested1.h) =[5:1 - 5:2] +// TOP: inclusion directive=targeted-fields.h ({{.*}}/test/Index/targeted-fields.h) =[16:1 - 16:2] diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 72a8c74fc0..b749bf50e9 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -2135,6 +2135,99 @@ static int find_file_refs_at(int argc, const char **argv) { return 0; } +static enum CXVisitorResult findFileIncludesVisit(void *context, + CXCursor cursor, CXSourceRange range) { + PrintCursor(cursor, NULL); + PrintRange(range, ""); + printf("\n"); + return CXVisit_Continue; +} + +static int find_file_includes_in(int argc, const char **argv) { + CXIndex CIdx; + struct CXUnsavedFile *unsaved_files = 0; + int num_unsaved_files = 0; + CXTranslationUnit TU; + const char **Filenames = 0; + unsigned NumFilenames = 0; + unsigned Repeats = 1; + unsigned I, FI; + + /* Count the number of locations. */ + while (strstr(argv[NumFilenames+1], "-file-includes-in=") == argv[NumFilenames+1]) + ++NumFilenames; + + /* Parse the locations. */ + assert(NumFilenames > 0 && "Unable to count filenames?"); + Filenames = (const char **)malloc(NumFilenames * sizeof(const char *)); + for (I = 0; I < NumFilenames; ++I) { + const char *input = argv[I + 1] + strlen("-file-includes-in="); + /* Copy the file name. */ + Filenames[I] = input; + } + + if (parse_remapped_files(argc, argv, NumFilenames + 1, &unsaved_files, + &num_unsaved_files)) + return -1; + + if (getenv("CINDEXTEST_EDITING")) + Repeats = 2; + + /* Parse the translation unit. When we're testing clang_getCursor() after + reparsing, don't remap unsaved files until the second parse. */ + CIdx = clang_createIndex(1, 1); + TU = clang_parseTranslationUnit(CIdx, argv[argc - 1], + argv + num_unsaved_files + 1 + NumFilenames, + argc - num_unsaved_files - 2 - NumFilenames, + unsaved_files, + Repeats > 1? 0 : num_unsaved_files, + getDefaultParsingOptions()); + + if (!TU) { + fprintf(stderr, "unable to parse input\n"); + 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, + clang_defaultReparseOptions(TU))) { + clang_disposeTranslationUnit(TU); + return 1; + } + + if (checkForErrors(TU) != 0) + return -1; + + for (FI = 0; FI < NumFilenames; ++FI) { + CXFile file = clang_getFile(TU, Filenames[FI]); + if (!file) + continue; + + if (checkForErrors(TU) != 0) + return -1; + + if (I + 1 == Repeats) { + CXCursorAndRangeVisitor visitor = { 0, findFileIncludesVisit }; + clang_findIncludesInFile(TU, file, visitor); + + if (checkForErrors(TU) != 0) + return -1; + } + } + } + + PrintDiagnostics(TU); + clang_disposeTranslationUnit(TU); + clang_disposeIndex(CIdx); + free(Filenames); + free_remapped_files(unsaved_files, num_unsaved_files); + return 0; +} + #define MAX_IMPORTED_ASTFILES 200 typedef struct { @@ -3520,7 +3613,8 @@ static void print_usage(void) { "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n" " c-index-test -code-completion-timing=<site> <compiler arguments>\n" " c-index-test -cursor-at=<site> <compiler arguments>\n" - " c-index-test -file-refs-at=<site> <compiler arguments>\n"); + " c-index-test -file-refs-at=<site> <compiler arguments>\n" + " c-index-test -file-includes-in=<filename> <compiler arguments>\n"); fprintf(stderr, " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n" " c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n" @@ -3582,6 +3676,8 @@ 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 && strstr(argv[1], "-file-includes-in=") == argv[1]) + return find_file_includes_in(argc, argv); if (argc > 2 && strcmp(argv[1], "-index-file") == 0) return index_file(argc - 2, argv + 2, /*full=*/0); if (argc > 2 && strcmp(argv[1], "-index-file-full") == 0) diff --git a/tools/libclang/CIndexHigh.cpp b/tools/libclang/CIndexHigh.cpp index 7e12386841..6af55e8eb7 100644 --- a/tools/libclang/CIndexHigh.cpp +++ b/tools/libclang/CIndexHigh.cpp @@ -337,6 +337,72 @@ static void findMacroRefsInFile(CXTranslationUnit TU, CXCursor Cursor, FindMacroRefsVisitor.visitPreprocessedEntitiesInRegion(); } +namespace { + +struct FindFileIncludesVisitor { + ASTUnit &Unit; + const FileEntry *File; + CXCursorAndRangeVisitor visitor; + + FindFileIncludesVisitor(ASTUnit &Unit, const FileEntry *File, + CXCursorAndRangeVisitor visitor) + : Unit(Unit), File(File), visitor(visitor) { } + + ASTContext &getASTContext() const { + return Unit.getASTContext(); + } + + enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent) { + if (cursor.kind != CXCursor_InclusionDirective) + return CXChildVisit_Continue; + + SourceLocation + Loc = cxloc::translateSourceLocation(clang_getCursorLocation(cursor)); + + ASTContext &Ctx = getASTContext(); + SourceManager &SM = Ctx.getSourceManager(); + + // We are looking for includes in a specific file. + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + if (SM.getFileEntryForID(LocInfo.first) != File) + return CXChildVisit_Continue; + + if (visitor.visit(visitor.context, cursor, + cxloc::translateSourceRange(Ctx, Loc)) == CXVisit_Break) + return CXChildVisit_Break; + return CXChildVisit_Continue; + } + + static enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent, + CXClientData client_data) { + return static_cast<FindFileIncludesVisitor*>(client_data)-> + visit(cursor, parent); + } +}; + +} // anonymous namespace + +static void findIncludesInFile(CXTranslationUnit TU, const FileEntry *File, + CXCursorAndRangeVisitor Visitor) { + assert(TU && File && Visitor.visit); + + ASTUnit *Unit = cxtu::getASTUnit(TU); + SourceManager &SM = Unit->getSourceManager(); + + FileID FID = SM.translateFile(File); + + FindFileIncludesVisitor IncludesVisitor(*Unit, File, Visitor); + + SourceRange Range(SM.getLocForStartOfFile(FID), SM.getLocForEndOfFile(FID)); + CursorVisitor InclusionCursorsVisitor(TU, + FindFileIncludesVisitor::visit, + &IncludesVisitor, + /*VisitPreprocessorLast=*/false, + /*VisitIncludedEntities=*/false, + Range); + InclusionCursorsVisitor.visitPreprocessedEntitiesInRegion(); +} + //===----------------------------------------------------------------------===// // libclang public APIs. @@ -410,6 +476,38 @@ void clang_findReferencesInFile(CXCursor cursor, CXFile file, visitor); } +void clang_findIncludesInFile(CXTranslationUnit TU, CXFile file, + CXCursorAndRangeVisitor visitor) { + LogRef Log = Logger::make(LLVM_FUNCTION_NAME); + + if (!TU) { + if (Log) + *Log << "Null CXTranslationUnit"; + return; + } + if (!file) { + if (Log) + *Log << "Null file"; + return; + } + if (!visitor.visit) { + if (Log) + *Log << "Null visitor"; + return; + } + + if (Log) + *Log << TU << " @" << static_cast<const FileEntry *>(file); + + ASTUnit *CXXUnit = cxtu::getASTUnit(TU); + if (!CXXUnit) + return; + + ASTUnit::ConcurrencyCheck Check(*CXXUnit); + + findIncludesInFile(TU, static_cast<const FileEntry *>(file), visitor); +} + static enum CXVisitorResult _visitCursorAndRange(void *context, CXCursor cursor, CXSourceRange range) { @@ -425,5 +523,13 @@ void clang_findReferencesInFileWithBlock(CXCursor cursor, return clang_findReferencesInFile(cursor, file, visitor); } +void clang_findIncludesInFileWithBlock(CXTranslationUnit TU, + CXFile file, + CXCursorAndRangeVisitorBlock block) { + CXCursorAndRangeVisitor visitor = { block, + block ? _visitCursorAndRange : 0 }; + return clang_findIncludesInFile(TU, file, visitor); +} + } // end: extern "C" diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index e0c4db07f4..d99f24ef03 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -98,6 +98,8 @@ clang_equalLocations clang_equalRanges clang_equalTypes clang_executeOnThread +clang_findIncludesInFile +clang_findIncludesInFileWithBlock clang_findReferencesInFile clang_findReferencesInFileWithBlock clang_formatDiagnostic |