]> granicus.if.org Git - clang/commitdiff
[libclang] Record ranges skipped by the preprocessor and expose them with libclang.
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 5 Dec 2013 08:19:32 +0000 (08:19 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Thu, 5 Dec 2013 08:19:32 +0000 (08:19 +0000)
Patch by Erik Verbruggen!

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

include/clang-c/Index.h
include/clang/Lex/PreprocessingRecord.h
lib/Lex/PreprocessingRecord.cpp
test/Index/skipped-ranges.c [new file with mode: 0644]
tools/c-index-test/c-index-test.c
tools/libclang/CIndex.cpp
tools/libclang/libclang.exports

index 95d54c279f03be7236a5251956b9da72c0abacaf..3ca92d83dce2d146df1852ed90572e68bd6bb71f 100644 (file)
@@ -30,7 +30,7 @@
  * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
  */
 #define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 20
+#define CINDEX_VERSION_MINOR 21
 
 #define CINDEX_VERSION_ENCODE(major, minor) ( \
       ((major) * 10000)                       \
@@ -598,6 +598,33 @@ CINDEX_LINKAGE CXSourceLocation clang_getRangeStart(CXSourceRange range);
  */
 CINDEX_LINKAGE CXSourceLocation clang_getRangeEnd(CXSourceRange range);
 
+/**
+ * \brief Identifies an array of ranges that were skipped by the preprocessor.
+ *
+ * The preprocessor will skip lines when they are surrounded by an
+ * if/ifdef/ifndef directive whose condition does not evaluate to true.
+ */
+typedef struct {
+  /** \brief The number of ranges in the \c ranges array. */
+  unsigned count;
+  /**
+   * \brief An array of \c CXSourceRange, where each range starts at the
+   * preprocessor directive after the # token, and ends at the end of the
+   * corresponding endif.
+   */
+  CXSourceRange *ranges;
+} CXSkippedRanges;
+
+/**
+ * \brief Retrieve all ranges that were skipped by the preprocessor.
+ */
+CINDEX_LINKAGE CXSkippedRanges *clang_getSkippedRanges(CXTranslationUnit tu, CXFile file);
+
+/**
+ * \brief Destroy the given \c CXSkippedRanges.
+ */
+CINDEX_LINKAGE void clang_disposeSkippedRanges(CXSkippedRanges *skipped);
+
 /**
  * @}
  */
index 2584340f6ec72d3ac24da1d5c5637d91258e42f7..c14deecf696a458efcaa318f16210f94b5e75c42 100644 (file)
@@ -304,6 +304,9 @@ namespace clang {
     /// and are referenced by the iterator using negative indices.
     std::vector<PreprocessedEntity *> LoadedPreprocessedEntities;
 
+    /// \brief The set of ranges that were skipped by the preprocessor,
+    std::vector<SourceRange> SkippedRanges;
+
     /// \brief Global (loaded or local) ID for a preprocessed entity.
     /// Negative values are used to indicate preprocessed entities
     /// loaded from the external source while non-negative values are used to
@@ -556,6 +559,11 @@ namespace clang {
     /// \brief Retrieve the macro definition that corresponds to the given
     /// \c MacroInfo.
     MacroDefinition *findMacroDefinition(const MacroInfo *MI);
+
+    /// \brief Retrieve all ranges that got skipped while preprocessing.
+    const std::vector<SourceRange> &getSkippedRanges() const {
+      return SkippedRanges;
+    }
         
   private:
     virtual void MacroExpands(const Token &Id, const MacroDirective *MD,
@@ -579,6 +587,8 @@ namespace clang {
     virtual void Defined(const Token &MacroNameTok, const MacroDirective *MD,
                          SourceRange Range);
 
+    virtual void SourceRangeSkipped(SourceRange Range);
+
     void addMacroExpansion(const Token &Id, const MacroInfo *MI,
                            SourceRange Range);
 
index 090aeedb7150257117219aebf8bcc594e86ee952..db5a9f93cf0378da8332b5c01616ce605b8a017e 100644 (file)
@@ -406,6 +406,10 @@ void PreprocessingRecord::Defined(const Token &MacroNameTok,
                       MacroNameTok.getLocation());
 }
 
+void PreprocessingRecord::SourceRangeSkipped(SourceRange Range) {
+  SkippedRanges.push_back(Range);
+}
+
 void PreprocessingRecord::MacroExpands(const Token &Id,const MacroDirective *MD,
                                        SourceRange Range,
                                        const MacroArgs *Args) {
diff --git a/test/Index/skipped-ranges.c b/test/Index/skipped-ranges.c
new file mode 100644 (file)
index 0000000..bd16fb3
--- /dev/null
@@ -0,0 +1,25 @@
+#define cool
+
+#if defined(cool)
+
+#if defined(really_cool)
+#endif // really_cool
+
+#elif defined(hot)
+// hot
+
+
+#endif // trailing comment
+
+#ifndef cool
+#ifndef uncool
+
+int probably_hot = 1;
+
+#endif // uncool
+#endif // cool
+
+// RUN: env CINDEXTEST_SHOW_SKIPPED_RANGES=1 c-index-test -test-annotate-tokens=%s:1:1:16:1 %s | FileCheck %s
+// CHECK: Skipping: [5:2 - 6:7]
+// CHECK: Skipping: [8:2 - 12:7]
+// CHECK: Skipping: [14:2 - 20:7]
index 58eb0def3e3dbe1f6be243d6ac34ea41f516c31e..40794308065a875f686fcfb6d51a8a2fe68d611d 100644 (file)
@@ -3183,6 +3183,7 @@ int perform_token_annotation(int argc, const char **argv) {
   CXSourceLocation startLoc, endLoc;
   CXFile file = 0;
   CXCursor *cursors = 0;
+  CXSkippedRanges *skipped_ranges = 0;
   unsigned i;
 
   input += strlen("-test-annotate-tokens=");
@@ -3271,6 +3272,19 @@ int perform_token_annotation(int argc, const char **argv) {
     goto teardown;
   }
 
+  skipped_ranges = clang_getSkippedRanges(TU, file);
+  for (i = 0; i != skipped_ranges->count; ++i) {
+    unsigned start_line, start_column, end_line, end_column;
+    clang_getSpellingLocation(clang_getRangeStart(skipped_ranges->ranges[i]),
+                              0, &start_line, &start_column, 0);
+    clang_getSpellingLocation(clang_getRangeEnd(skipped_ranges->ranges[i]),
+                              0, &end_line, &end_column, 0);
+    printf("Skipping: ");
+    PrintExtent(stdout, start_line, start_column, end_line, end_column);
+    printf("\n");
+  }
+  clang_disposeSkippedRanges(skipped_ranges);
+
   for (i = 0; i != num_tokens; ++i) {
     const char *kind = "<unknown>";
     CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
index 656fbd1b1b7ff6737dc4e67a34c9d6388af9b98b..c8bff73935643a4843ef06867f7b37895ae262b0 100644 (file)
@@ -6494,6 +6494,47 @@ void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage) {
     delete (MemUsageEntries*) usage.data;
 }
 
+CXSkippedRanges *clang_getSkippedRanges(CXTranslationUnit TU, CXFile file) {
+  CXSkippedRanges *skipped = new CXSkippedRanges;
+  skipped->count = 0;
+  skipped->ranges = 0;
+
+  if (!file)
+    return skipped;
+
+  ASTUnit *astUnit = cxtu::getASTUnit(TU);
+  PreprocessingRecord *ppRec = astUnit->getPreprocessor().getPreprocessingRecord();
+  if (!ppRec)
+    return skipped;
+
+  ASTContext &Ctx = astUnit->getASTContext();
+  SourceManager &sm = Ctx.getSourceManager();
+  FileEntry *fileEntry = static_cast<FileEntry *>(file);
+  FileID wantedFileID = sm.translateFile(fileEntry);
+
+  const std::vector<SourceRange> &SkippedRanges = ppRec->getSkippedRanges();
+  std::vector<SourceRange> wantedRanges;
+  for (std::vector<SourceRange>::const_iterator i = SkippedRanges.begin(), ei = SkippedRanges.end();
+       i != ei; ++i) {
+    if (sm.getFileID(i->getBegin()) == wantedFileID || sm.getFileID(i->getEnd()) == wantedFileID)
+      wantedRanges.push_back(*i);
+  }
+
+  skipped->count = wantedRanges.size();
+  skipped->ranges = new CXSourceRange[skipped->count];
+  for (unsigned i = 0, ei = skipped->count; i != ei; ++i)
+    skipped->ranges[i] = cxloc::translateSourceRange(Ctx, wantedRanges[i]);
+
+  return skipped;
+}
+
+void clang_disposeSkippedRanges(CXSkippedRanges *skipped) {
+  if (skipped) {
+    delete[] skipped->ranges;
+    delete skipped;
+  }
+}
+
 } // end extern "C"
 
 void clang::PrintLibclangResourceUsage(CXTranslationUnit TU) {
index 9bf26c979d29be5a21ee5080bb18cb621d5780f6..896228ad3c5ba8bd5b67ba1e6a06e13492d41c12 100644 (file)
@@ -101,6 +101,7 @@ clang_disposeDiagnosticSet
 clang_disposeIndex
 clang_disposeOverriddenCursors
 clang_disposeCXPlatformAvailability
+clang_disposeSkippedRanges
 clang_disposeString
 clang_disposeTokens
 clang_disposeTranslationUnit
@@ -207,6 +208,7 @@ clang_getRangeStart
 clang_getRemappings
 clang_getRemappingsFromFileList
 clang_getResultType
+clang_getSkippedRanges
 clang_getSpecializedCursorTemplate
 clang_getSpellingLocation
 clang_getTUResourceUsageName