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