Skip to content

Commit f6abf49

Browse files
144026sr-tream
authored andcommitted
[clangd] Implement simple folding of preprocessor branches
Extract directive branches information from DirectiveTree, fold branches that don't end with eof. Fixes clangd/clangd#1661
1 parent e899930 commit f6abf49

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

clang-tools-extra/clangd/SemanticSelection.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,24 @@ getFoldingRanges(const std::string &Code, bool LineFoldingOnly) {
220220
auto EndPosition = [&](const Token &T) {
221221
return offsetToPosition(Code, EndOffset(T));
222222
};
223+
224+
// Preprocessor directives
225+
auto PPRanges = pairDirectiveRanges(DirectiveStructure, OrigStream);
226+
for (const auto &R : PPRanges) {
227+
auto BTok = OrigStream.tokens()[R.Begin];
228+
auto ETok = OrigStream.tokens()[R.End];
229+
if (ETok.Kind == tok::eof)
230+
continue;
231+
if (BTok.Line >= ETok.Line)
232+
continue;
233+
234+
Position Start = EndPosition(BTok);
235+
Position End = StartPosition(ETok);
236+
if (LineFoldingOnly)
237+
End.line--;
238+
AddFoldingRange(Start, End, FoldingRange::REGION_KIND);
239+
}
240+
223241
auto Tokens = ParseableStream.tokens();
224242
// Brackets.
225243
for (const auto &Tok : Tokens) {

clang-tools-extra/clangd/support/DirectiveTree.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,5 +356,59 @@ TokenStream DirectiveTree::stripDirectives(const TokenStream &In) const {
356356
return Out;
357357
}
358358

359+
namespace {
360+
class RangePairer {
361+
std::vector<Token::Range> &Ranges;
362+
363+
public:
364+
RangePairer(std::vector<Token::Range> &Ranges) : Ranges(Ranges) {}
365+
366+
void walk(const DirectiveTree &T) {
367+
for (const auto &C : T.Chunks)
368+
std::visit(*this, C);
369+
}
370+
371+
void operator()(const DirectiveTree::Code &C) {}
372+
373+
void operator()(const DirectiveTree::Directive &) {}
374+
375+
void operator()(const DirectiveTree::Conditional &C) {
376+
Token::Range Range;
377+
Token::Index Last;
378+
auto First = true;
379+
for (const auto &B : C.Branches) {
380+
if (First) {
381+
First = false;
382+
} else {
383+
Range = {Last, B.first.Tokens.Begin};
384+
Ranges.push_back(Range);
385+
}
386+
Last = B.first.Tokens.Begin;
387+
}
388+
Range = {Last, C.End.Tokens.Begin};
389+
Ranges.push_back(Range);
390+
391+
for (const auto &B : C.Branches)
392+
walk(B.second);
393+
}
394+
};
395+
} // namespace
396+
397+
std::vector<Token::Range> pairDirectiveRanges(const DirectiveTree &Tree,
398+
const TokenStream &Code) {
399+
std::vector<Token::Range> Ranges;
400+
RangePairer(Ranges).walk(Tree);
401+
402+
// Transform paired ranges to start with last token in its logical line
403+
for (auto &R : Ranges) {
404+
const Token *Tok = &Code.tokens()[R.Begin + 1];
405+
while (Tok->Kind != tok::eof && !Tok->flag(LexFlags::StartsPPLine))
406+
++Tok;
407+
Tok = Tok - 1;
408+
R.Begin = Tok->OriginalIndex;
409+
}
410+
return Ranges;
411+
}
412+
359413
} // namespace clangd
360414
} // namespace clang

clang-tools-extra/clangd/support/DirectiveTree.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &,
124124
/// The choices are stored in Conditional::Taken nodes.
125125
void chooseConditionalBranches(DirectiveTree &, const TokenStream &Code);
126126

127+
/// Pairs preprocessor conditional directives and computes their token ranges.
128+
std::vector<Token::Range> pairDirectiveRanges(const DirectiveTree &Tree,
129+
const TokenStream &Code);
130+
127131
} // namespace clangd
128132
} // namespace clang
129133

0 commit comments

Comments
 (0)