]> granicus.if.org Git - clang/commitdiff
[libclang] Introduce clang_findIncludesInFile, that can be used to retrieve all ...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Fri, 8 Mar 2013 02:32:34 +0000 (02:32 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Fri, 8 Mar 2013 02:32:34 +0000 (02:32 +0000)
It passes to the visitor, that the caller provides, CXCursor_InclusionDirective cursors for
all the include directives in a particular file.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176682 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang-c/Index.h
lib/Serialization/ASTReader.cpp
test/Index/file-includes.c [new file with mode: 0644]
tools/c-index-test/c-index-test.c
tools/libclang/CIndexHigh.cpp
tools/libclang/libclang.exports

index c382fb17c1c2ddd95dc065e19917877226834c5b..b9b4f8e26970375208aa9740a3eb32e07205daf2 100644 (file)
@@ -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
 
index 0389722bfd91c8735af6acec37d357d8972c0b9f..4ad51e5dea5afbe3792e339b828c56252a3f27d1 100644 (file)
@@ -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 (file)
index 0000000..3663398
--- /dev/null
@@ -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]
index 72a8c74fc02460b3dea1fec8bce7e974ee764754..b749bf50e96a4ed3f626c8c151d8dba431960ae7 100644 (file)
@@ -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)
index 7e12386841941495dc2c531d2b788a8bbb8818a6..6af55e8eb7fa6eab58a272f304bbb836b41e67f2 100644 (file)
@@ -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"
 
index e0c4db07f4e579eabd81720a604651c4abbc57ac..d99f24ef038201eb56b51280120d3cd496628e41 100644 (file)
@@ -98,6 +98,8 @@ clang_equalLocations
 clang_equalRanges
 clang_equalTypes
 clang_executeOnThread
+clang_findIncludesInFile
+clang_findIncludesInFileWithBlock
 clang_findReferencesInFile
 clang_findReferencesInFileWithBlock
 clang_formatDiagnostic