diff --git a/clang-tools-extra/clangd/SemanticSelection.cpp b/clang-tools-extra/clangd/SemanticSelection.cpp --- a/clang-tools-extra/clangd/SemanticSelection.cpp +++ b/clang-tools-extra/clangd/SemanticSelection.cpp @@ -11,9 +11,15 @@ #include "Protocol.h" #include "Selection.h" #include "SourceCode.h" +#include "support/Logger.h" #include "clang/AST/DeclBase.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Syntax/BuildTree.h" +#include "clang/Tooling/Syntax/Tokens.h" +#include "clang/Tooling/Syntax/Tree.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" namespace clang { @@ -41,12 +47,31 @@ collectFoldingRanges(Child, Result); } +syntax::Leaf *leafContaining(const syntax::Token *Tok, syntax::Tree *Root, + syntax::Arena &A, const SourceManager &SM) { + if (!Tok) + return nullptr; + vlog("searching for {0} in:\n{1}", Tok->text(SM), Root->dump(A)); + for (auto *C = Root->firstChild(); C; C = C->nextSibling()) { + if (auto *L = llvm::dyn_cast(C)) { + if (L->token() == Tok) + return L; + } else if (auto *T = llvm::dyn_cast(C)) { + if (T->firstLeaf()->token() <= Tok && Tok <= T->lastLeaf()->token()) + return leafContaining(Tok, T, A, SM); + } + } + return nullptr; +} + } // namespace llvm::Expected getSemanticRanges(ParsedAST &AST, Position Pos) { + syntax::Arena A(AST.getSourceManager(), AST.getLangOpts(), AST.getTokens()); + auto *STree = + syntax::buildSyntaxTree(A, *AST.getASTContext().getTranslationUnitDecl()); std::vector Ranges; const auto &SM = AST.getSourceManager(); - const auto &LangOpts = AST.getLangOpts(); auto FID = SM.getMainFileID(); auto Offset = positionToOffset(SM.getBufferData(FID), Pos); @@ -55,24 +80,23 @@ } // Get node under the cursor. - SelectionTree ST = SelectionTree::createRight( - AST.getASTContext(), AST.getTokens(), *Offset, *Offset); - for (const auto *Node = ST.commonAncestor(); Node != nullptr; - Node = Node->Parent) { - if (const Decl *D = Node->ASTNode.get()) { - if (llvm::isa(D)) { - break; + auto Toks = AST.getTokens().expandedForSpelled(syntax::spelledTokensTouching( + SM.getComposedLoc(FID, *Offset), AST.getTokens())); + Toks.push_back({}); + for (const auto &Tok : Toks.front()) { + if (auto *L = leafContaining(&Tok, STree, A, SM)) { + for (const syntax::Tree *Node = L->parent(); Node != nullptr; + Node = Node->parent()) { + SourceRange SR(Node->firstLeaf()->token()->location(), + Node->lastLeaf()->token()->location()); + auto FR = toHalfOpenFileRange(SM, AST.getLangOpts(), SR); + if (!FR || SM.getFileID(SR.getBegin()) != SM.getMainFileID()) + continue; + addIfDistinct(halfOpenToRange(SM, CharSourceRange::getCharRange(*FR)), + Ranges); } + break; } - - auto SR = toHalfOpenFileRange(SM, LangOpts, Node->ASTNode.getSourceRange()); - if (!SR.hasValue() || SM.getFileID(SR->getBegin()) != SM.getMainFileID()) { - continue; - } - Range R; - R.start = sourceLocToPosition(SM, SR->getBegin()); - R.end = sourceLocToPosition(SM, SR->getEnd()); - addIfDistinct(R, Ranges); } if (Ranges.empty()) {