diff --git a/clang-tools-extra/clangd/SemanticSelection.cpp b/clang-tools-extra/clangd/SemanticSelection.cpp index 3d687173b2be9..d2aefb51fd49a 100644 --- a/clang-tools-extra/clangd/SemanticSelection.cpp +++ b/clang-tools-extra/clangd/SemanticSelection.cpp @@ -220,6 +220,24 @@ getFoldingRanges(const std::string &Code, bool LineFoldingOnly) { auto EndPosition = [&](const pseudo::Token &T) { return offsetToPosition(Code, EndOffset(T)); }; + + // Preprocessor directives + auto PPRanges = pseudo::pairDirectiveRanges(DirectiveStructure, OrigStream); + for (const auto &R : PPRanges) { + auto BTok = OrigStream.tokens()[R.Begin]; + auto ETok = OrigStream.tokens()[R.End]; + if (ETok.Kind == tok::eof) + continue; + if (BTok.Line >= ETok.Line) + continue; + + Position Start = EndPosition(BTok); + Position End = StartPosition(ETok); + if (LineFoldingOnly) + End.line--; + AddFoldingRange(Start, End, FoldingRange::REGION_KIND); + } + auto Tokens = ParseableStream.tokens(); // Brackets. for (const auto &Tok : Tokens) { diff --git a/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h b/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h index 2b6cb63297915..2e5f007f94a76 100644 --- a/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h +++ b/clang-tools-extra/pseudo/include/clang-pseudo/DirectiveTree.h @@ -124,6 +124,9 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &, /// The choices are stored in Conditional::Taken nodes. void chooseConditionalBranches(DirectiveTree &, const TokenStream &Code); +std::vector pairDirectiveRanges(const DirectiveTree &Tree, + const TokenStream &Code); + } // namespace pseudo } // namespace clang diff --git a/clang-tools-extra/pseudo/lib/DirectiveTree.cpp b/clang-tools-extra/pseudo/lib/DirectiveTree.cpp index 9e853e46edc23..4882f01890654 100644 --- a/clang-tools-extra/pseudo/lib/DirectiveTree.cpp +++ b/clang-tools-extra/pseudo/lib/DirectiveTree.cpp @@ -353,5 +353,59 @@ TokenStream DirectiveTree::stripDirectives(const TokenStream &In) const { return Out; } +namespace { +class RangePairer { + std::vector &Ranges; + +public: + RangePairer(std::vector &Ranges) : Ranges(Ranges) {} + + void walk(const DirectiveTree &T) { + for (const auto &C : T.Chunks) + std::visit(*this, C); + } + + void operator()(const DirectiveTree::Code &C) {} + + void operator()(const DirectiveTree::Directive &) {} + + void operator()(const DirectiveTree::Conditional &C) { + Token::Range Range; + Token::Index Last; + auto First = true; + for (const auto &B : C.Branches) { + if (First) { + First = false; + } else { + Range = {Last, B.first.Tokens.Begin}; + Ranges.push_back(Range); + } + Last = B.first.Tokens.Begin; + } + Range = {Last, C.End.Tokens.Begin}; + Ranges.push_back(Range); + + for (const auto &B : C.Branches) + walk(B.second); + } +}; +} // namespace + +std::vector pairDirectiveRanges(const DirectiveTree &Tree, + const TokenStream &Code) { + std::vector Ranges; + RangePairer(Ranges).walk(Tree); + + // Transform paired ranges to start with last token in its logical line + for (auto &R : Ranges) { + const Token *Tok = &Code.tokens()[R.Begin + 1]; + while (Tok->Kind != tok::eof && !Tok->flag(LexFlags::StartsPPLine)) + ++Tok; + Tok = Tok - 1; + R.Begin = Tok->OriginalIndex; + } + return std::move(Ranges); +} + } // namespace pseudo } // namespace clang