forked from OSchip/llvm-project
[clangd] Exclude preprocessed-to-nothing tokens from selection
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
This commit is contained in:
parent
f0ab336e74
commit
72f2fb1db4
|
@ -220,14 +220,26 @@ public:
|
|||
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;
|
||||
|
|
|
@ -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*); };
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue