cameron314 updated this revision to Diff 56964.
cameron314 added a comment.

Here's a test!


http://reviews.llvm.org/D20132

Files:
  include/clang-c/Index.h
  tools/libclang/CIndex.cpp
  unittests/libclang/LibclangTest.cpp

Index: unittests/libclang/LibclangTest.cpp
===================================================================
--- unittests/libclang/LibclangTest.cpp
+++ unittests/libclang/LibclangTest.cpp
@@ -15,6 +15,9 @@
 #include "gtest/gtest.h"
 #include <fstream>
 #include <set>
+#include <map>
+#include <memory>
+#include <functional>
 #define DEBUG_TYPE "libclang-test"
 
 TEST(libclang, clang_parseTranslationUnit2_InvalidArgs) {
@@ -349,21 +352,25 @@
   clang_ModuleMapDescriptor_dispose(MMD);
 }
 
-class LibclangReparseTest : public ::testing::Test {
+class LibclangParseTest : public ::testing::Test {
   std::set<std::string> Files;
+  typedef std::unique_ptr<std::string> fixed_addr_string;
+  std::map<fixed_addr_string, fixed_addr_string> UnsavedFileContents;
 public:
   std::string TestDir;
   CXIndex Index;
   CXTranslationUnit ClangTU;
   unsigned TUFlags;
+  std::vector<CXUnsavedFile> UnsavedFiles;
 
   void SetUp() override {
     llvm::SmallString<256> Dir;
     ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("libclang-test", Dir));
     TestDir = Dir.str();
     TUFlags = CXTranslationUnit_DetailedPreprocessingRecord |
-              clang_defaultEditingTranslationUnitOptions();
+      clang_defaultEditingTranslationUnitOptions();
     Index = clang_createIndex(0, 0);
+    ClangTU = nullptr;
   }
   void TearDown() override {
     clang_disposeTranslationUnit(ClangTU);
@@ -384,6 +391,77 @@
     OS << Contents;
     assert(OS.good());
   }
+  void MapUnsavedFile(std::string Filename, const std::string &Contents) {
+    if (!llvm::sys::path::is_absolute(Filename)) {
+      llvm::SmallString<256> Path(TestDir);
+      llvm::sys::path::append(Path, Filename);
+      Filename = Path.str();
+    }
+    auto it = UnsavedFileContents.emplace(
+        fixed_addr_string(new std::string(Filename)),
+        fixed_addr_string(new std::string(Contents)));
+    UnsavedFiles.push_back({
+        it.first->first->c_str(),   // filename
+        it.first->second->c_str(),  // contents
+        it.first->second->size()    // length
+    });
+  }
+  template<typename F>
+  void Traverse(const F &TraversalFunctor) {
+    CXCursor TuCursor = clang_getTranslationUnitCursor(ClangTU);
+    std::reference_wrapper<const F> FunctorRef = std::cref(TraversalFunctor);
+    clang_visitChildren(TuCursor,
+        &TraverseStateless<std::reference_wrapper<const F>>,
+        &FunctorRef);
+  }
+private:
+  template<typename TState>
+  static CXChildVisitResult TraverseStateless(CXCursor cx, CXCursor parent,
+      CXClientData data) {
+    TState *State = static_cast<TState*>(data);
+    return State->get()(cx, parent);
+  }
+};
+
+TEST_F(LibclangParseTest, AllSkippedRanges) {
+  std::string Header = "header.h", Main = "main.cpp";
+  WriteFile(Header,
+    "#ifdef MANGOS\n"
+    "printf(\"mmm\");\n"
+    "#endif");
+  WriteFile(Main,
+    "#include \"header.h\"\n"
+    "#ifdef KIWIS\n"
+    "printf(\"mmm!!\");\n"
+    "#endif");
+
+  ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0,
+                                       nullptr, 0, TUFlags);
+
+  CXSourceRangeList *Ranges = clang_getAllSkippedRanges(ClangTU);
+  EXPECT_EQ(2, Ranges->count);
+  
+  CXSourceLocation cxl;
+  unsigned line;
+  cxl = clang_getRangeStart(Ranges->ranges[0]);
+  clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
+  EXPECT_EQ(1, line);
+  cxl = clang_getRangeEnd(Ranges->ranges[0]);
+  clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
+  EXPECT_EQ(3, line);
+
+  cxl = clang_getRangeStart(Ranges->ranges[1]);
+  clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
+  EXPECT_EQ(2, line);
+  cxl = clang_getRangeEnd(Ranges->ranges[1]);
+  clang_getSpellingLocation(cxl, nullptr, &line, nullptr, nullptr);
+  EXPECT_EQ(4, line);
+
+  clang_disposeSourceRangeList(Ranges);
+}
+
+class LibclangReparseTest : public LibclangParseTest {
+public:
   void DisplayDiagnostics() {
     unsigned NumDiagnostics = clang_getNumDiagnostics(ClangTU);
     for (unsigned i = 0; i < NumDiagnostics; ++i) {
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -7680,6 +7680,33 @@
   return skipped;
 }
 
+CXSourceRangeList *clang_getAllSkippedRanges(CXTranslationUnit TU) {
+  CXSourceRangeList *skipped = new CXSourceRangeList;
+  skipped->count = 0;
+  skipped->ranges = nullptr;
+
+  if (isNotUsableTU(TU)) {
+    LOG_BAD_TU(TU);
+    return skipped;
+  }
+    
+  ASTUnit *astUnit = cxtu::getASTUnit(TU);
+  PreprocessingRecord *ppRec = astUnit->getPreprocessor().getPreprocessingRecord();
+  if (!ppRec)
+    return skipped;
+
+  ASTContext &Ctx = astUnit->getASTContext();
+
+  const std::vector<SourceRange> &SkippedRanges = ppRec->getSkippedRanges();
+
+  skipped->count = SkippedRanges.size();
+  skipped->ranges = new CXSourceRange[skipped->count];
+  for (unsigned i = 0, ei = skipped->count; i != ei; ++i)
+    skipped->ranges[i] = cxloc::translateSourceRange(Ctx, SkippedRanges[i]);
+
+  return skipped;
+}
+
 void clang_disposeSourceRangeList(CXSourceRangeList *ranges) {
   if (ranges) {
     delete[] ranges->ranges;
Index: include/clang-c/Index.h
===================================================================
--- include/clang-c/Index.h
+++ include/clang-c/Index.h
@@ -627,6 +627,15 @@
                                                          CXFile file);
 
 /**
+ * \brief Retrieve all ranges from all files 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.
+ */
+CINDEX_LINKAGE CXSourceRangeList *clang_getAllSkippedRanges(CXTranslationUnit tu);
+
+/**
  * \brief Destroy the given \c CXSourceRangeList.
  */
 CINDEX_LINKAGE void clang_disposeSourceRangeList(CXSourceRangeList *ranges);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to