1 //===--- ASTSelection.h - Clang refactoring library -----------------------===//
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 #ifndef LLVM_CLANG_TOOLING_REFACTORING_ASTSELECTION_H
10 #define LLVM_CLANG_TOOLING_REFACTORING_ASTSELECTION_H
11 
12 #include "clang/AST/ASTTypeTraits.h"
13 #include "clang/AST/Stmt.h"
14 #include "clang/Basic/LLVM.h"
15 #include "clang/Basic/SourceLocation.h"
16 #include "llvm/Support/raw_ostream.h"
17 #include <optional>
18 #include <vector>
19 
20 namespace clang {
21 
22 class ASTContext;
23 
24 namespace tooling {
25 
26 enum class SourceSelectionKind {
27   /// A node that's not selected.
28   None,
29 
30   /// A node that's considered to be selected because the whole selection range
31   /// is inside of its source range.
32   ContainsSelection,
33   /// A node that's considered to be selected because the start of the selection
34   /// range is inside its source range.
35   ContainsSelectionStart,
36   /// A node that's considered to be selected because the end of the selection
37   /// range is inside its source range.
38   ContainsSelectionEnd,
39 
40   /// A node that's considered to be selected because the node is entirely in
41   /// the selection range.
42   InsideSelection,
43 };
44 
45 /// Represents a selected AST node.
46 ///
47 /// AST selection is represented using a tree of \c SelectedASTNode. The tree
48 /// follows the top-down shape of the actual AST. Each selected node has
49 /// a selection kind. The kind might be none as the node itself might not
50 /// actually be selected, e.g. a statement in macro whose child is in a macro
51 /// argument.
52 struct SelectedASTNode {
53   DynTypedNode Node;
54   SourceSelectionKind SelectionKind;
55   std::vector<SelectedASTNode> Children;
56 
57   SelectedASTNode(const DynTypedNode &Node, SourceSelectionKind SelectionKind)
58       : Node(Node), SelectionKind(SelectionKind) {}
59   SelectedASTNode(SelectedASTNode &&) = default;
60   SelectedASTNode &operator=(SelectedASTNode &&) = default;
61 
62   void dump(llvm::raw_ostream &OS = llvm::errs()) const;
63 
64   using ReferenceType = std::reference_wrapper<const SelectedASTNode>;
65 };
66 
67 /// Traverses the given ASTContext and creates a tree of selected AST nodes.
68 ///
69 /// \returns std::nullopt if no nodes are selected in the AST, or a selected AST
70 /// node that corresponds to the TranslationUnitDecl otherwise.
71 std::optional<SelectedASTNode> findSelectedASTNodes(const ASTContext &Context,
72                                                     SourceRange SelectionRange);
73 
74 /// An AST selection value that corresponds to a selection of a set of
75 /// statements that belong to one body of code (like one function).
76 ///
77 /// For example, the following selection in the source.
78 ///
79 /// \code
80 /// void function() {
81 ///  // selection begin:
82 ///  int x = 0;
83 ///  {
84 ///     // selection end
85 ///     x = 1;
86 ///  }
87 ///  x = 2;
88 /// }
89 /// \endcode
90 ///
91 /// Would correspond to a code range selection of statements "int x = 0"
92 /// and the entire compound statement that follows it.
93 ///
94 /// A \c CodeRangeASTSelection value stores references to the full
95 /// \c SelectedASTNode tree and should not outlive it.
96 class CodeRangeASTSelection {
97 public:
98   CodeRangeASTSelection(CodeRangeASTSelection &&) = default;
99   CodeRangeASTSelection &operator=(CodeRangeASTSelection &&) = default;
100 
101   /// Returns the parent hierarchy (top to bottom) for the selected nodes.
102   ArrayRef<SelectedASTNode::ReferenceType> getParents() { return Parents; }
103 
104   /// Returns the number of selected statements.
105   size_t size() const {
106     if (!AreChildrenSelected)
107       return 1;
108     return SelectedNode.get().Children.size();
109   }
110 
111   const Stmt *operator[](size_t I) const {
112     if (!AreChildrenSelected) {
113       assert(I == 0 && "Invalid index");
114       return SelectedNode.get().Node.get<Stmt>();
115     }
116     return SelectedNode.get().Children[I].Node.get<Stmt>();
117   }
118 
119   /// Returns true when a selected code range is in a function-like body
120   /// of code, like a function, method or a block.
121   ///
122   /// This function can be used to test against selected expressions that are
123   /// located outside of a function, e.g. global variable initializers, default
124   /// argument values, or even template arguments.
125   ///
126   /// Use the \c getFunctionLikeNearestParent to get the function-like parent
127   /// declaration.
128   bool isInFunctionLikeBodyOfCode() const;
129 
130   /// Returns the nearest function-like parent declaration or null if such
131   /// declaration doesn't exist.
132   const Decl *getFunctionLikeNearestParent() const;
133 
134   static std::optional<CodeRangeASTSelection>
135   create(SourceRange SelectionRange, const SelectedASTNode &ASTSelection);
136 
137 private:
138   CodeRangeASTSelection(SelectedASTNode::ReferenceType SelectedNode,
139                         ArrayRef<SelectedASTNode::ReferenceType> Parents,
140                         bool AreChildrenSelected)
141       : SelectedNode(SelectedNode), Parents(Parents.begin(), Parents.end()),
142         AreChildrenSelected(AreChildrenSelected) {}
143 
144   /// The reference to the selected node (or reference to the selected
145   /// child nodes).
146   SelectedASTNode::ReferenceType SelectedNode;
147   /// The parent hierarchy (top to bottom) for the selected noe.
148   llvm::SmallVector<SelectedASTNode::ReferenceType, 8> Parents;
149   /// True only when the children of the selected node are actually selected.
150   bool AreChildrenSelected;
151 };
152 
153 } // end namespace tooling
154 } // end namespace clang
155 
156 #endif // LLVM_CLANG_TOOLING_REFACTORING_ASTSELECTION_H
157