Skip to content

Commit

Permalink
[clangd] Exclude preprocessed-to-nothing tokens from selection
Browse files Browse the repository at this point in the history
This prevents selection of empty preprocessor entities (like #define directives,
or text in disabled sections) creating a selection in the parent element.

Summary: Based on D83508 by Aleksandr Platonov.

Reviewers: ArcsinX, kadircet

Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D84012
  • Loading branch information
sam-mccall committed Jul 20, 2020
1 parent f0ab336 commit 72f2fb1
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 7 deletions.
20 changes: 16 additions & 4 deletions clang-tools-extra/clangd/Selection.cpp
Expand Up @@ -220,14 +220,26 @@ class SelectionTester {
SelFirst, AllSpelledTokens.end(), [&](const syntax::Token &Tok) {
return SM.getFileOffset(Tok.location()) < SelEnd;
});
auto Sel = llvm::makeArrayRef(SelFirst, SelLimit);
// Find which of these are preprocessed to nothing and should be ignored.
std::vector<bool> PPIgnored(Sel.size(), false);
for (const syntax::TokenBuffer::Expansion &X :
Buf.expansionsAffecting(Sel)) {
if (X.Expanded.empty()) {
for (const syntax::Token &Tok : X.Spelled) {
if (&Tok >= SelFirst && &Tok < SelLimit)
PPIgnored[&Tok - SelFirst] = true;
}
}
}
// Precompute selectedness and offset for selected spelled tokens.
for (const syntax::Token *T = SelFirst; T < SelLimit; ++T) {
if (shouldIgnore(*T))
for (unsigned I = 0; I < Sel.size(); ++I) {
if (shouldIgnore(Sel[I]) || PPIgnored[I])
continue;
SpelledTokens.emplace_back();
Tok &S = SpelledTokens.back();
S.Offset = SM.getFileOffset(T->location());
if (S.Offset >= SelBegin && S.Offset + T->length() <= SelEnd)
S.Offset = SM.getFileOffset(Sel[I].location());
if (S.Offset >= SelBegin && S.Offset + Sel[I].length() <= SelEnd)
S.Selected = SelectionTree::Complete;
else
S.Selected = SelectionTree::Partial;
Expand Down
25 changes: 22 additions & 3 deletions clang-tools-extra/clangd/unittests/SelectionTests.cpp
Expand Up @@ -177,11 +177,29 @@ TEST(SelectionTest, CommonAncestor) {
{
R"cpp(
void foo();
#define CALL_FUNCTION(X) X^()^
#^define CALL_FUNCTION(X) X(^)
void bar() { CALL_FUNCTION(foo); }
)cpp",
nullptr,
},
{
R"cpp(
void foo();
#define CALL_FUNCTION(X) X()
void bar() { CALL_FUNCTION(foo^)^; }
)cpp",
nullptr,
},
{
R"cpp(
namespace ns {
#if 0
void fo^o() {}
#endif
}
)cpp",
nullptr,
},
{
R"cpp(
struct S { S(const char*); };
Expand Down Expand Up @@ -388,7 +406,8 @@ TEST(SelectionTest, CommonAncestor) {
void test(S2 s2) {
s2[[-^>]]f();
}
)cpp", "DeclRefExpr"} // DeclRefExpr to the "operator->" method.
)cpp",
"DeclRefExpr"} // DeclRefExpr to the "operator->" method.
};
for (const Case &C : Cases) {
trace::TestTracer Tracer;
Expand Down Expand Up @@ -538,7 +557,7 @@ TEST(SelectionTest, IncludedFile) {
auto AST = TU.build();
auto T = makeSelectionTree(Case, AST);

EXPECT_EQ("WhileStmt", T.commonAncestor()->kind());
EXPECT_EQ(nullptr, T.commonAncestor());
}

TEST(SelectionTest, MacroArgExpansion) {
Expand Down

0 comments on commit 72f2fb1

Please sign in to comment.