diff --git a/clang-tools-extra/clangd/Selection.h b/clang-tools-extra/clangd/Selection.h --- a/clang-tools-extra/clangd/Selection.h +++ b/clang-tools-extra/clangd/Selection.h @@ -146,6 +146,7 @@ const Node *commonAncestor() const; // The selection node corresponding to TranslationUnitDecl. const Node &root() const { return *Root; } + bool TochesSourceLoc(SourceLocation Pos, const SourceManager &SM); private: // Creates a selection tree for the given range in the main file. 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 @@ -1104,6 +1104,29 @@ return Ancestor != Root ? Ancestor : nullptr; } +// Check if source line at Pos touches any node in SelectionTree. In the +// presence of compilation error, we will have only root nodes without the +// nodes that coresponds to tokens from Pos. In these cases, clangd cannot +// provide meaningful navigation and often jumps to the conataining scope +// identifier such as napespace. +bool SelectionTree::TochesSourceLoc(SourceLocation Pos, + const SourceManager &SM) { + const auto DecomposedPos = SM.getDecomposedSpellingLoc(Pos); + int Line = SM.getLineNumber(DecomposedPos.first, DecomposedPos.second); + for (const auto &Node : Nodes) { + const auto Begin = + SM.getDecomposedSpellingLoc(getSourceRange(Node.ASTNode).getBegin()); + const auto End = + SM.getDecomposedSpellingLoc(getSourceRange(Node.ASTNode).getEnd()); + int startLine = SM.getLineNumber(Begin.first, Begin.second); + int endLine = SM.getLineNumber(End.first, End.second); + if (startLine == Line || endLine == Line) { + return true; + } + } + return false; +} + const DeclContext &SelectionTree::Node::getDeclContext() const { for (const Node *CurrentNode = this; CurrentNode != nullptr; CurrentNode = CurrentNode->Parent) { diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -179,6 +179,12 @@ unsigned Offset = AST.getSourceManager().getDecomposedSpellingLoc(Pos).second; std::vector> Result; auto ResultFromTree = [&](SelectionTree ST) { + // If the SelectionTree does not have nodes from Pos, we will navigate to + // wrong locations. In these cases, it is better to return empty results + // rather than jumping to irrelevant location. + if (!ST.TochesSourceLoc(Pos, AST.getSourceManager())) { + return false; + } if (const SelectionTree::Node *N = ST.commonAncestor()) { if (NodeKind) *NodeKind = N->ASTNode.getNodeKind();