forked from OSchip/llvm-project
[clangd] Lib to compute and represent selection under cursor.
Summary: The primary problem this solves is to expose the codeAction selection to AST-based refactorings in a way that makes it easy and efficient for them to bind to the right parts of the AST. It should also allow us to make XRefs based features (textDocument/definition) more robust, more easily implement textDocument/typeDefinition etc. As an example, template parameter references can be identified without special handling. There should be slight speedup too: we can prune most of the AST traversal in most cases. Elephant in the room: this is similar-but-different to Tooling/Refactoring/ASTSelection. That captures a smaller set of AST nodes, has a slightly different way of representing selections, and generally has mare features and does more work. The overall shape is pretty similar, and yet I can't quite get to behave as I expect. Reviewers: ilya-biryukov, kadircet Subscribers: mgorny, ioeric, MaskRay, jkorous, mgrang, arphaman Tags: #clang Differential Revision: https://reviews.llvm.org/D57562 llvm-svn: 352875
This commit is contained in:
parent
3186e3ceb8
commit
2048f22892
|
@ -112,9 +112,15 @@ private:
|
|||
// An optimization for a common case: nodes outside macro expansions that
|
||||
// don't intersect the selection may be recursively skipped.
|
||||
bool canSafelySkipNode(SourceRange S) {
|
||||
<<<<<<< HEAD
|
||||
auto B = SM.getDecomposedLoc(S.getBegin());
|
||||
auto E = SM.getDecomposedLoc(S.getEnd());
|
||||
if (B.first != SelFile || E.first != SelFile)
|
||||
=======
|
||||
auto B = SM.getDecomposedLoc(S.getBegin()),
|
||||
E = SM.getDecomposedLoc(S.getEnd());
|
||||
if (B.first != SM.getMainFileID() || E.first != SM.getMainFileID())
|
||||
>>>>>>> [clangd] Lib to compute and represent selection under cursor.
|
||||
return false;
|
||||
return B.second >= SelEnd || E.second < SelBeginTokenStart;
|
||||
}
|
||||
|
@ -156,6 +162,7 @@ private:
|
|||
// LOOP_FOREVER( ++x; )
|
||||
// }
|
||||
// Selecting "++x" or "x" will do the right thing.
|
||||
<<<<<<< HEAD
|
||||
auto B = SM.getDecomposedLoc(SM.getTopMacroCallerLoc(S.getBegin()));
|
||||
auto E = SM.getDecomposedLoc(SM.getTopMacroCallerLoc(S.getEnd()));
|
||||
// Otherwise, nodes in macro expansions can't be selected.
|
||||
|
@ -164,6 +171,16 @@ private:
|
|||
// Cheap test: is there any overlap at all between the selection and range?
|
||||
// Note that E.second is the *start* of the last token, which is why we
|
||||
// compare against the "rounded-down" SelBegin.
|
||||
=======
|
||||
auto B = SM.getDecomposedLoc(SM.getTopMacroCallerLoc(S.getBegin())),
|
||||
E = SM.getDecomposedLoc(SM.getTopMacroCallerLoc(S.getEnd()));
|
||||
// Otherwise, nodes in macro expansions can't be selected.
|
||||
if (B.first != SM.getMainFileID() || E.first != SM.getMainFileID())
|
||||
return SelectionTree::Unselected;
|
||||
// Cheap test: is there any overlap at all between the selection and range?
|
||||
// Note that E.second is the *start* of the last token, which is why we
|
||||
// compare against the "rounded-down" MinOffset.
|
||||
>>>>>>> [clangd] Lib to compute and represent selection under cursor.
|
||||
if (B.second >= SelEnd || E.second < SelBeginTokenStart)
|
||||
return SelectionTree::Unselected;
|
||||
|
||||
|
@ -196,7 +213,11 @@ private:
|
|||
CharSourceRange R = SM.getExpansionRange(N->ASTNode.getSourceRange());
|
||||
auto B = SM.getDecomposedLoc(R.getBegin());
|
||||
auto E = SM.getDecomposedLoc(R.getEnd());
|
||||
<<<<<<< HEAD
|
||||
if (B.first != SelFile || E.first != SelFile)
|
||||
=======
|
||||
if (B.first != SM.getMainFileID() || E.first != SM.getMainFileID())
|
||||
>>>>>>> [clangd] Lib to compute and represent selection under cursor.
|
||||
continue;
|
||||
assert(R.isTokenRange());
|
||||
// Try to cover up to the next token, spaces between children don't count.
|
||||
|
@ -222,6 +243,7 @@ private:
|
|||
SourceManager &SM;
|
||||
const LangOptions &LangOpts;
|
||||
std::stack<Node *> Stack;
|
||||
<<<<<<< HEAD
|
||||
std::deque<Node> Nodes; // Stable pointers as we add more nodes.
|
||||
// Half-open selection range.
|
||||
unsigned SelBegin;
|
||||
|
@ -233,6 +255,10 @@ private:
|
|||
// range.end + measureToken(range.end) < SelBegin (assuming range.end points
|
||||
// to a token), and it saves a lex every time.
|
||||
unsigned SelBeginTokenStart;
|
||||
=======
|
||||
std::deque<Node> Nodes;
|
||||
unsigned SelBegin, SelEnd, SelBeginTokenStart;
|
||||
>>>>>>> [clangd] Lib to compute and represent selection under cursor.
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
@ -252,9 +278,16 @@ void SelectionTree::print(llvm::raw_ostream &OS, const SelectionTree::Node &N,
|
|||
}
|
||||
|
||||
// Decide which selection emulates a "point" query in between characters.
|
||||
<<<<<<< HEAD
|
||||
static std::pair<unsigned, unsigned> pointBounds(unsigned Offset, FileID FID,
|
||||
ASTContext &AST) {
|
||||
StringRef Buf = AST.getSourceManager().getBufferData(FID);
|
||||
=======
|
||||
static std::pair<unsigned, unsigned> pointBounds(unsigned Offset,
|
||||
ASTContext &AST) {
|
||||
StringRef Buf = AST.getSourceManager().getBufferData(
|
||||
AST.getSourceManager().getMainFileID());
|
||||
>>>>>>> [clangd] Lib to compute and represent selection under cursor.
|
||||
// Edge-cases where the choice is forced.
|
||||
if (Buf.size() == 0)
|
||||
return {0, 0};
|
||||
|
@ -272,6 +305,7 @@ static std::pair<unsigned, unsigned> pointBounds(unsigned Offset, FileID FID,
|
|||
|
||||
SelectionTree::SelectionTree(ASTContext &AST, unsigned Begin, unsigned End)
|
||||
: PrintPolicy(AST.getLangOpts()) {
|
||||
<<<<<<< HEAD
|
||||
// No fundamental reason the selection needs to be in the main file,
|
||||
// but that's all clangd has needed so far.
|
||||
FileID FID = AST.getSourceManager().getMainFileID();
|
||||
|
@ -286,6 +320,16 @@ SelectionTree::SelectionTree(ASTContext &AST, unsigned Begin, unsigned End)
|
|||
SelectionTree::SelectionTree(ASTContext &AST, unsigned Offset)
|
||||
: SelectionTree(AST, Offset, Offset) {}
|
||||
|
||||
=======
|
||||
if (Begin == End)
|
||||
std::tie(Begin, End) = pointBounds(Begin, AST);
|
||||
PrintPolicy.TerseOutput = true;
|
||||
|
||||
Nodes = SelectionVisitor(AST, Begin, End).take();
|
||||
Root = Nodes.empty() ? nullptr : &Nodes.front();
|
||||
}
|
||||
|
||||
>>>>>>> [clangd] Lib to compute and represent selection under cursor.
|
||||
const Node *SelectionTree::commonAncestor() const {
|
||||
if (!Root)
|
||||
return nullptr;
|
||||
|
@ -297,5 +341,11 @@ const Node *SelectionTree::commonAncestor() const {
|
|||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
SelectionTree::SelectionTree(ASTContext &AST, unsigned Offset)
|
||||
: SelectionTree(AST, Offset, Offset) {}
|
||||
|
||||
>>>>>>> [clangd] Lib to compute and represent selection under cursor.
|
||||
} // namespace clangd
|
||||
} // namespace clang
|
||||
|
|
Loading…
Reference in New Issue