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 SelectedASTNodeSelectedASTNode57 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. getParents()102 ArrayRef<SelectedASTNode::ReferenceType> getParents() { return Parents; } 103 104 /// Returns the number of selected statements. size()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: CodeRangeASTSelection(SelectedASTNode::ReferenceType SelectedNode,ArrayRef<SelectedASTNode::ReferenceType> Parents,bool AreChildrenSelected)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