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
20namespace clang {
21
22class ASTContext;
23
24namespace tooling {
25
26enum 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.
52struct 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.
71std::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.
96class CodeRangeASTSelection {
97public:
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
137private:
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