aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang-c/Index.h19
-rw-r--r--lib/Serialization/ASTReader.cpp4
-rw-r--r--test/Index/file-includes.c24
-rw-r--r--tools/c-index-test/c-index-test.c98
-rw-r--r--tools/libclang/CIndexHigh.cpp106
-rw-r--r--tools/libclang/libclang.exports2
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