diff --git a/clang-tools-extra/clangd/SemanticSelection.cpp b/clang-tools-extra/clangd/SemanticSelection.cpp --- a/clang-tools-extra/clangd/SemanticSelection.cpp +++ b/clang-tools-extra/clangd/SemanticSelection.cpp @@ -175,7 +175,32 @@ return collectFoldingRanges(SyntaxTree, TM); } -// FIXME( usaxena95): Collect PP conditional regions, includes and other code +namespace { +struct IncludeCollector { + explicit IncludeCollector(const pseudo::DirectiveTree &T) { walk(T); } + + void walk(const pseudo::DirectiveTree &T) { + for (const auto &C : T.Chunks) + std::visit(*this, C); + } + + void operator()(const pseudo::DirectiveTree::Code &) {} + + void operator()(const pseudo::DirectiveTree::Directive &D) { + if (D.Kind == tok::pp_include) + Results.push_back(D); + } + + void operator()(const pseudo::DirectiveTree::Conditional &C) { + if (C.Taken) + walk(C.Branches[*C.Taken].second); + } + + std::vector Results; +}; +} // namespace + +// FIXME( usaxena95): Collect PP conditional regions and other code // regions (e.g. public/private/protected sections of classes, control flow // statement bodies). // Related issue: https://github.com/clangd/clangd/issues/310 @@ -267,6 +292,20 @@ } AddFoldingRange(Start, End, FoldingRange::COMMENT_KIND); } + // Multi-line `#include` + auto Includes = IncludeCollector{DirectiveStructure}.Results; + for (auto It = Includes.begin(); It != Includes.end();) { + Position Start = StartPosition(OrigStream.tokens(It->Tokens).front()); + Position End = EndPosition(OrigStream.tokens(It->Tokens).back()); + It++; + while (It != Includes.end() && + StartPosition(OrigStream.tokens(It->Tokens).front()).line == + End.line + 1) { + End = EndPosition(OrigStream.tokens(It->Tokens).back()); + It++; + } + AddFoldingRange(Start, End, FoldingRange::IMPORT_KIND); + } return Result; } diff --git a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp --- a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp @@ -453,6 +453,31 @@ << Test; } } + +TEST(FoldingRanges, Includes) { + const char *Test = R"cpp( + [[#include + #include + #include ]] + + #include + + [[#include "external/Logger.h" + #include "external/Vector.h" + #include "project/DataStructures/Trie.h"]] + + [[#include "project/File.h" + #include + #include ]] + + #include "math.h" + )cpp"; + auto T = Annotations{Test}; + EXPECT_THAT(gatherFoldingRanges( + llvm::cantFail(getFoldingRanges(T.code().str(), false))), + UnorderedElementsAreArray(T.ranges())) + << Test; +} } // namespace } // namespace clangd } // namespace clang