From: Argyrios Kyrtzidis Date: Thu, 5 Dec 2013 08:19:32 +0000 (+0000) Subject: [libclang] Record ranges skipped by the preprocessor and expose them with libclang. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=159fac64319694a9ba2105ffe3a5327ed5a26601;p=clang [libclang] Record ranges skipped by the preprocessor and expose them with libclang. Patch by Erik Verbruggen! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196487 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 95d54c279f..3ca92d83dc 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -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); + /** * @} */ diff --git a/include/clang/Lex/PreprocessingRecord.h b/include/clang/Lex/PreprocessingRecord.h index 2584340f6e..c14deecf69 100644 --- a/include/clang/Lex/PreprocessingRecord.h +++ b/include/clang/Lex/PreprocessingRecord.h @@ -304,6 +304,9 @@ namespace clang { /// and are referenced by the iterator using negative indices. std::vector LoadedPreprocessedEntities; + /// \brief The set of ranges that were skipped by the preprocessor, + std::vector 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 &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); diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp index 090aeedb71..db5a9f93cf 100644 --- a/lib/Lex/PreprocessingRecord.cpp +++ b/lib/Lex/PreprocessingRecord.cpp @@ -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 index 0000000000..bd16fb3856 --- /dev/null +++ b/test/Index/skipped-ranges.c @@ -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] diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 58eb0def3e..4079430806 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -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 = ""; CXString spelling = clang_getTokenSpelling(TU, tokens[i]); diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 656fbd1b1b..c8bff73935 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -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(file); + FileID wantedFileID = sm.translateFile(fileEntry); + + const std::vector &SkippedRanges = ppRec->getSkippedRanges(); + std::vector wantedRanges; + for (std::vector::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) { diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 9bf26c979d..896228ad3c 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -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