diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp --- a/clang-tools-extra/clangd/Selection.cpp +++ b/clang-tools-extra/clangd/Selection.cpp @@ -220,14 +220,26 @@ 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 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; diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -177,11 +177,29 @@ { 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 @@ 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 @@ auto AST = TU.build(); auto T = makeSelectionTree(Case, AST); - EXPECT_EQ("WhileStmt", T.commonAncestor()->kind()); + EXPECT_EQ(nullptr, T.commonAncestor()); } TEST(SelectionTest, MacroArgExpansion) {