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 "llvm/Support/raw_ostream.h" 17 #include <vector> 18 19 namespace clang { 20 21 class ASTContext; 22 23 namespace tooling { 24 25 enum class SourceSelectionKind { 26 /// A node that's not selected. 27 None, 28 29 /// A node that's considered to be selected because the whole selection range 30 /// is inside of its source range. 31 ContainsSelection, 32 /// A node that's considered to be selected because the start of the selection 33 /// range is inside its source range. 34 ContainsSelectionStart, 35 /// A node that's considered to be selected because the end of the selection 36 /// range is inside its source range. 37 ContainsSelectionEnd, 38 39 /// A node that's considered to be selected because the node is entirely in 40 /// the selection range. 41 InsideSelection, 42 }; 43 44 /// Represents a selected AST node. 45 /// 46 /// AST selection is represented using a tree of \c SelectedASTNode. The tree 47 /// follows the top-down shape of the actual AST. Each selected node has 48 /// a selection kind. The kind might be none as the node itself might not 49 /// actually be selected, e.g. a statement in macro whose child is in a macro 50 /// argument. 51 struct SelectedASTNode { 52 DynTypedNode Node; 53 SourceSelectionKind SelectionKind; 54 std::vector<SelectedASTNode> Children; 55 SelectedASTNodeSelectedASTNode56 SelectedASTNode(const DynTypedNode &Node, 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. 70 Optional<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. 95 class CodeRangeASTSelection { 96 public: 97 CodeRangeASTSelection(CodeRangeASTSelection &&) = default; 98 CodeRangeASTSelection &operator=(CodeRangeASTSelection &&) = default; 99 100 /// Returns the parent hierarchy (top to bottom) for the selected nodes. getParents()101 ArrayRef<SelectedASTNode::ReferenceType> getParents() { return Parents; } 102 103 /// Returns the number of selected statements. size()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 136 private: CodeRangeASTSelection(SelectedASTNode::ReferenceType SelectedNode,ArrayRef<SelectedASTNode::ReferenceType> Parents,bool AreChildrenSelected)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