1 //===--- Selection.cpp ----------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "Selection.h" 10 #include "ClangdUnit.h" 11 #include "clang/AST/RecursiveASTVisitor.h" 12 13 namespace clang { 14 namespace clangd { 15 namespace { 16 using Node = SelectionTree::Node; 17 using ast_type_traits::DynTypedNode; 18 19 // We find the selection by visiting written nodes in the AST, looking for nodes 20 // that intersect with the selected character range. 21 // 22 // While traversing, we maintain a parent stack. As nodes pop off the stack, 23 // we decide whether to keep them or not. To be kept, they must either be 24 // selected or contain some nodes that are. 25 // 26 // For simple cases (not inside macros) we prune subtrees that don't intersect. 27 class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> { 28 public: 29 // Runs the visitor to gather selected nodes and their ancestors. 30 // If there is any selection, the root (TUDecl) is the first node. 31 static std::deque<Node> collect(ASTContext &AST, unsigned Begin, 32 unsigned End, FileID File) { 33 SelectionVisitor V(AST, Begin, End, File); 34 V.TraverseAST(AST); 35 assert(V.Stack.size() == 1 && "Unpaired push/pop?"); 36 assert(V.Stack.top() == &V.Nodes.front()); 37 if (V.Nodes.size() == 1) // TUDecl, but no nodes under it. 38 V.Nodes.clear(); 39 return std::move(V.Nodes); 40 } 41 42 // We traverse all "well-behaved" nodes the same way: 43 // - push the node onto the stack 44 // - traverse its children recursively 45 // - pop it from the stack 46 // - hit testing: is intersection(node, selection) - union(children) empty? 47 // - attach it to the tree if it or any children hit the selection 48 // 49 // Two categories of nodes are not "well-behaved": 50 // - those without source range information, we don't record those 51 // - those that can't be stored in DynTypedNode. 52 // We're missing some interesting things like Attr due to the latter. 53 bool TraverseDecl(Decl *X) { 54 if (X && isa<TranslationUnitDecl>(X)) 55 return Base::TraverseDecl(X); // Already pushed by constructor. 56 return traverseNode(X, [&] { return Base::TraverseDecl(X); }); 57 } 58 bool TraverseTypeLoc(TypeLoc X) { 59 return traverseNode(&X, [&] { return Base::TraverseTypeLoc(X); }); 60 } 61 bool TraverseTypeNestedNameSpecifierLoc(NestedNameSpecifierLoc X) { 62 return traverseNode( 63 &X, [&] { return Base::TraverseNestedNameSpecifierLoc(X); }); 64 } 65 bool TraverseConstructorInitializer(CXXCtorInitializer *X) { 66 return traverseNode( 67 X, [&] { return Base::TraverseConstructorInitializer(X); }); 68 } 69 // Stmt is the same, but this form allows the data recursion optimization. 70 bool dataTraverseStmtPre(Stmt *X) { 71 if (!X || canSafelySkipNode(X->getSourceRange())) 72 return false; 73 push(DynTypedNode::create(*X)); 74 return true; 75 } 76 bool dataTraverseStmtPost(Stmt *X) { 77 pop(); 78 return true; 79 } 80 // Uninteresting parts of the AST that don't have locations within them. 81 bool TraverseNestedNameSpecifier(NestedNameSpecifier *) { return true; } 82 bool TraverseType(QualType) { return true; } 83 84 private: 85 using Base = RecursiveASTVisitor<SelectionVisitor>; 86 SelectionVisitor(ASTContext &AST, unsigned SelBegin, unsigned SelEnd, 87 FileID SelFile) 88 : SM(AST.getSourceManager()), LangOpts(AST.getLangOpts()), 89 SelBegin(SelBegin), SelEnd(SelEnd), SelFile(SelFile), 90 SelBeginTokenStart(SM.getFileOffset(Lexer::GetBeginningOfToken( 91 SM.getComposedLoc(SelFile, SelBegin), SM, LangOpts))) { 92 // Ensure we have a node for the TU decl, regardless of traversal scope. 93 Nodes.emplace_back(); 94 Nodes.back().ASTNode = DynTypedNode::create(*AST.getTranslationUnitDecl()); 95 Nodes.back().Parent = nullptr; 96 Nodes.back().Selected = SelectionTree::Unselected; 97 Stack.push(&Nodes.back()); 98 } 99 100 // Generic case of TraverseFoo. Func should be the call to Base::TraverseFoo. 101 // Node is always a pointer so the generic code can handle any null checks. 102 template <typename T, typename Func> 103 bool traverseNode(T *Node, const Func &Body) { 104 if (Node == nullptr || canSafelySkipNode(Node->getSourceRange())) 105 return true; 106 push(DynTypedNode::create(*Node)); 107 bool Ret = Body(); 108 pop(); 109 return Ret; 110 } 111 112 // An optimization for a common case: nodes outside macro expansions that 113 // don't intersect the selection may be recursively skipped. 114 bool canSafelySkipNode(SourceRange S) { 115 auto B = SM.getDecomposedLoc(S.getBegin()); 116 auto E = SM.getDecomposedLoc(S.getEnd()); 117 if (B.first != SelFile || E.first != SelFile) 118 return false; 119 return B.second >= SelEnd || E.second < SelBeginTokenStart; 120 } 121 122 // Pushes a node onto the ancestor stack. Pairs with pop(). 123 void push(DynTypedNode Node) { 124 Nodes.emplace_back(); 125 Nodes.back().ASTNode = std::move(Node); 126 Nodes.back().Parent = Stack.top(); 127 Nodes.back().Selected = SelectionTree::Unselected; 128 Stack.push(&Nodes.back()); 129 } 130 131 // Pops a node off the ancestor stack, and finalizes it. Pairs with push(). 132 void pop() { 133 Node &N = *Stack.top(); 134 N.Selected = computeSelection(N); 135 if (N.Selected || !N.Children.empty()) { 136 // Attach to the tree. 137 N.Parent->Children.push_back(&N); 138 } else { 139 // Neither N any children are selected, it doesn't belong in the tree. 140 assert(&N == &Nodes.back()); 141 Nodes.pop_back(); 142 } 143 Stack.pop(); 144 } 145 146 // Perform hit-testing of a complete Node against the selection. 147 // This runs for every node in the AST, and must be fast in common cases. 148 // This is called from pop(), so we can take children into account. 149 SelectionTree::Selection computeSelection(const Node &N) { 150 SourceRange S = N.ASTNode.getSourceRange(); 151 if (!S.isValid()) 152 return SelectionTree::Unselected; 153 // getTopMacroCallerLoc() allows selection of constructs in macro args. e.g: 154 // #define LOOP_FOREVER(Body) for(;;) { Body } 155 // void IncrementLots(int &x) { 156 // LOOP_FOREVER( ++x; ) 157 // } 158 // Selecting "++x" or "x" will do the right thing. 159 auto B = SM.getDecomposedLoc(SM.getTopMacroCallerLoc(S.getBegin())); 160 auto E = SM.getDecomposedLoc(SM.getTopMacroCallerLoc(S.getEnd())); 161 // Otherwise, nodes in macro expansions can't be selected. 162 if (B.first != SelFile || E.first != SelFile) 163 return SelectionTree::Unselected; 164 // Cheap test: is there any overlap at all between the selection and range? 165 // Note that E.second is the *start* of the last token, which is why we 166 // compare against the "rounded-down" SelBegin. 167 if (B.second >= SelEnd || E.second < SelBeginTokenStart) 168 return SelectionTree::Unselected; 169 170 // We hit something, need some more precise checks. 171 // Adjust [B, E) to be a half-open character range. 172 E.second += Lexer::MeasureTokenLength(S.getEnd(), SM, LangOpts); 173 // This node's own selected text is (this range ^ selection) - child ranges. 174 // If that's empty, then we've only collided with children. 175 if (nodesCoverRange(N.Children, std::max(SelBegin, B.second), 176 std::min(SelEnd, E.second))) 177 return SelectionTree::Unselected; // Hit children only. 178 // Some of our own characters are covered, this is a true hit. 179 return (B.second >= SelBegin && E.second <= SelEnd) 180 ? SelectionTree::Complete 181 : SelectionTree::Partial; 182 } 183 184 // Is the range [Begin, End) entirely covered by the union of the Nodes? 185 // (The range is a parent node's extent, and the covering nodes are children). 186 bool nodesCoverRange(llvm::ArrayRef<const Node *> Nodes, unsigned Begin, 187 unsigned End) { 188 if (Begin >= End) 189 return true; 190 if (Nodes.empty()) 191 return false; 192 193 // Collect all the expansion ranges, as offsets. 194 SmallVector<std::pair<unsigned, unsigned>, 8> ChildRanges; 195 for (const Node *N : Nodes) { 196 CharSourceRange R = SM.getExpansionRange(N->ASTNode.getSourceRange()); 197 auto B = SM.getDecomposedLoc(R.getBegin()); 198 auto E = SM.getDecomposedLoc(R.getEnd()); 199 if (B.first != SelFile || E.first != SelFile) 200 continue; 201 // Try to cover up to the next token, spaces between children don't count. 202 if (auto Tok = Lexer::findNextToken(R.getEnd(), SM, LangOpts)) 203 E.second = SM.getFileOffset(Tok->getLocation()); 204 else if (R.isTokenRange()) 205 E.second += Lexer::MeasureTokenLength(R.getEnd(), SM, LangOpts); 206 ChildRanges.push_back({B.second, E.second}); 207 } 208 llvm::sort(ChildRanges); 209 210 // Scan through the child ranges, removing as we go. 211 for (const auto R : ChildRanges) { 212 if (R.first > Begin) 213 return false; // [Begin, R.first) is not covered. 214 Begin = R.second; // Eliminate [R.first, R.second). 215 if (Begin >= End) 216 return true; // Remaining range is empty. 217 } 218 return false; // Went through all children, trailing characters remain. 219 } 220 221 SourceManager &SM; 222 const LangOptions &LangOpts; 223 std::stack<Node *> Stack; 224 std::deque<Node> Nodes; // Stable pointers as we add more nodes. 225 // Half-open selection range. 226 unsigned SelBegin; 227 unsigned SelEnd; 228 FileID SelFile; 229 // If the selection start slices a token in half, the beginning of that token. 230 // This is useful for checking whether the end of a token range overlaps 231 // the selection: range.end < SelBeginTokenStart is equivalent to 232 // range.end + measureToken(range.end) < SelBegin (assuming range.end points 233 // to a token), and it saves a lex every time. 234 unsigned SelBeginTokenStart; 235 }; 236 237 } // namespace 238 239 void SelectionTree::print(llvm::raw_ostream &OS, const SelectionTree::Node &N, 240 int Indent) const { 241 if (N.Selected) 242 OS.indent(Indent - 1) << (N.Selected == SelectionTree::Complete ? '*' 243 : '.'); 244 else 245 OS.indent(Indent); 246 OS << N.ASTNode.getNodeKind().asStringRef() << " "; 247 N.ASTNode.print(OS, PrintPolicy); 248 OS << "\n"; 249 for (const Node *Child : N.Children) 250 print(OS, *Child, Indent + 2); 251 } 252 253 // Decide which selection emulates a "point" query in between characters. 254 static std::pair<unsigned, unsigned> pointBounds(unsigned Offset, FileID FID, 255 ASTContext &AST) { 256 StringRef Buf = AST.getSourceManager().getBufferData(FID); 257 // Edge-cases where the choice is forced. 258 if (Buf.size() == 0) 259 return {0, 0}; 260 if (Offset == 0) 261 return {0, 1}; 262 if (Offset == Buf.size()) 263 return {Offset - 1, Offset}; 264 // We could choose either this byte or the previous. Usually we prefer the 265 // character on the right of the cursor (or under a block cursor). 266 // But if that's whitespace, we likely want the token on the left. 267 if (isWhitespace(Buf[Offset]) && !isWhitespace(Buf[Offset - 1])) 268 return {Offset - 1, Offset}; 269 return {Offset, Offset + 1}; 270 } 271 272 SelectionTree::SelectionTree(ASTContext &AST, unsigned Begin, unsigned End) 273 : PrintPolicy(AST.getLangOpts()) { 274 // No fundamental reason the selection needs to be in the main file, 275 // but that's all clangd has needed so far. 276 FileID FID = AST.getSourceManager().getMainFileID(); 277 if (Begin == End) 278 std::tie(Begin, End) = pointBounds(Begin, FID, AST); 279 PrintPolicy.TerseOutput = true; 280 281 Nodes = SelectionVisitor::collect(AST, Begin, End, FID); 282 Root = Nodes.empty() ? nullptr : &Nodes.front(); 283 } 284 285 SelectionTree::SelectionTree(ASTContext &AST, unsigned Offset) 286 : SelectionTree(AST, Offset, Offset) {} 287 288 const Node *SelectionTree::commonAncestor() const { 289 if (!Root) 290 return nullptr; 291 for (const Node *Ancestor = Root;; Ancestor = Ancestor->Children.front()) { 292 if (Ancestor->Selected || Ancestor->Children.size() > 1) 293 return Ancestor; 294 // The tree only contains ancestors of the interesting nodes. 295 assert(!Ancestor->Children.empty() && "bad node in selection tree"); 296 } 297 } 298 299 } // namespace clangd 300 } // namespace clang 301