From d80912871d9a96fa06b904ee73113defe3ff8689 Mon Sep 17 00:00:00 2001 From: Cameron Desrochers Date: Thu, 18 Aug 2016 15:43:55 +0000 Subject: [PATCH] [libclang] Add clang_getAllSkippedRanges function This complements the clang_getSkippedRanges function which returns skipped ranges filtered by a specific file. This function is useful when all the ranges are desired (and a lot more efficient than the equivalent of asking for the ranges file by file, since the implementation of clang_getSkippedRanges iterates over all ranges anyway). Differential Revision: https://reviews.llvm.org/D20132 llvm-svn: 279076 --- clang/include/clang-c/Index.h | 9 ++++ clang/tools/libclang/CIndex.cpp | 27 ++++++++++ clang/unittests/libclang/LibclangTest.cpp | 82 ++++++++++++++++++++++++++++++- 3 files changed, 116 insertions(+), 2 deletions(-) diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 170e4e7..192560e 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -627,6 +627,15 @@ CINDEX_LINKAGE CXSourceRangeList *clang_getSkippedRanges(CXTranslationUnit tu, 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); diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 4a35929..22a17ad 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -7773,6 +7773,33 @@ CXSourceRangeList *clang_getSkippedRanges(CXTranslationUnit TU, CXFile file) { 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 &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; diff --git a/clang/unittests/libclang/LibclangTest.cpp b/clang/unittests/libclang/LibclangTest.cpp index d5c7827..78229a1 100644 --- a/clang/unittests/libclang/LibclangTest.cpp +++ b/clang/unittests/libclang/LibclangTest.cpp @@ -14,6 +14,9 @@ #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" #include +#include +#include +#include #include #define DEBUG_TYPE "libclang-test" @@ -349,21 +352,25 @@ TEST(libclang, ModuleMapDescriptor) { clang_ModuleMapDescriptor_dispose(MMD); } -class LibclangReparseTest : public ::testing::Test { +class LibclangParseTest : public ::testing::Test { std::set Files; + typedef std::unique_ptr fixed_addr_string; + std::map UnsavedFileContents; public: std::string TestDir; CXIndex Index; CXTranslationUnit ClangTU; unsigned TUFlags; + std::vector 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 @@ public: 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 + void Traverse(const F &TraversalFunctor) { + CXCursor TuCursor = clang_getTranslationUnitCursor(ClangTU); + std::reference_wrapper FunctorRef = std::cref(TraversalFunctor); + clang_visitChildren(TuCursor, + &TraverseStateless>, + &FunctorRef); + } +private: + template + static CXChildVisitResult TraverseStateless(CXCursor cx, CXCursor parent, + CXClientData data) { + TState *State = static_cast(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) { -- 2.7.4