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