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