Author: sammccall Date: Fri Feb 1 07:09:41 2019 New Revision: 352875 URL: http://llvm.org/viewvc/llvm-project?rev=352875&view=rev Log: [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 Modified: clang-tools-extra/trunk/clangd/Selection.cpp Modified: clang-tools-extra/trunk/clangd/Selection.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Selection.cpp?rev=352875&r1=352874&r2=352875&view=diff ============================================================================== --- clang-tools-extra/trunk/clangd/Selection.cpp (original) +++ clang-tools-extra/trunk/clangd/Selection.cpp Fri Feb 1 07:09:41 2019 @@ -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_ostr } // 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> poi 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 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::commonAncesto } } +<<<<<<< HEAD +======= +SelectionTree::SelectionTree(ASTContext &AST, unsigned Offset) + : SelectionTree(AST, Offset, Offset) {} + +>>>>>>> [clangd] Lib to compute and represent selection under cursor. } // namespace clangd } // namespace clang _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits