1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <cassert> 20 #include <exception> 21 #include <functional> 22 #include <type_traits> 23 #include <vector> 24 25 #include <thrift/compiler/ast/detail/ast_visitor.h> 26 #include <thrift/compiler/ast/t_const.h> 27 #include <thrift/compiler/ast/t_enum.h> 28 #include <thrift/compiler/ast/t_enum_value.h> 29 #include <thrift/compiler/ast/t_exception.h> 30 #include <thrift/compiler/ast/t_field.h> 31 #include <thrift/compiler/ast/t_function.h> 32 #include <thrift/compiler/ast/t_interaction.h> 33 #include <thrift/compiler/ast/t_interface.h> 34 #include <thrift/compiler/ast/t_list.h> 35 #include <thrift/compiler/ast/t_map.h> 36 #include <thrift/compiler/ast/t_node.h> 37 #include <thrift/compiler/ast/t_program.h> 38 #include <thrift/compiler/ast/t_service.h> 39 #include <thrift/compiler/ast/t_set.h> 40 #include <thrift/compiler/ast/t_sink.h> 41 #include <thrift/compiler/ast/t_stream.h> 42 #include <thrift/compiler/ast/t_struct.h> 43 #include <thrift/compiler/ast/t_typedef.h> 44 #include <thrift/compiler/ast/t_union.h> 45 46 namespace apache { 47 namespace thrift { 48 namespace compiler { 49 50 // A list of visitor that accept the given arguments. 51 template <typename... Args> 52 using visitor_list = std::vector<std::function<void(Args...)>>; 53 54 template <bool is_const, typename... Args> 55 class basic_ast_visitor; 56 57 // A class that can traverse ast nodes, invoking registered visitors for each 58 // node visited. 59 // 60 // Visits AST nodes in 'preorder', visiting the parent node before children 61 // nodes. 62 // 63 // For each concrete node type, provides the following functions: 64 // - an operator() overload for visiting the node: 65 // void operator()(args..., t_{name}&) const; 66 // - a function to add a node-specific visitor: 67 // void add_{name}_visitor(std::function<void(args..., t_{name}&)>); 68 // 69 // Also provides helper functions for registering a visitor for multiple node 70 // types. For example: all interface, structured_declaration, and 71 // declaration visitors. 72 using ast_visitor = basic_ast_visitor<false>; 73 74 // Same as ast_visitor, except traverse a const AST. 75 using const_ast_visitor = basic_ast_visitor<true>; 76 77 // A class that can traverse an AST, calling registered visitors. 78 // See ast_visitor. 79 template <bool is_const, typename... Args> 80 class basic_ast_visitor { 81 template <typename N> 82 using node_type = ast_detail::node_type<is_const, N>; 83 84 public: 85 // Adds visitor for all interface node types. 86 // 87 // For example: t_service and t_interaction. 88 template <typename V> add_interface_visitor(V && visitor)89 void add_interface_visitor(V&& visitor) { 90 add_service_visitor(visitor); 91 add_interaction_visitor(std::forward<V>(visitor)); 92 } 93 94 // Adds a visitor for all structured IDL definition node types. 95 // 96 // For example: t_struct, t_union, and t_exception. 97 // Does not include other t_structured nodes like t_paramlist. 98 template <typename V> add_structured_definition_visitor(V && visitor)99 void add_structured_definition_visitor(V&& visitor) { 100 add_struct_visitor(visitor); 101 add_union_visitor(visitor); 102 add_exception_visitor(std::forward<V>(visitor)); 103 } 104 105 // Adds a visitor for all IDL definition node types. 106 template <typename V> add_definition_visitor(V && visitor)107 void add_definition_visitor(V&& visitor) { 108 add_interface_visitor(visitor); 109 add_function_visitor(visitor); 110 111 add_structured_definition_visitor(visitor); 112 add_field_visitor(visitor); 113 114 add_enum_visitor(visitor); 115 add_enum_value_visitor(visitor); 116 add_const_visitor(visitor); 117 118 add_typedef_visitor(std::forward<V>(visitor)); 119 } 120 121 template <typename V> add_container_visitor(V && visitor)122 void add_container_visitor(V&& visitor) { 123 add_set_visitor(visitor); 124 add_list_visitor(visitor); 125 add_map_visitor(std::forward<V>(visitor)); 126 } 127 128 template <typename V> add_type_instantiation_visitor(V && visitor)129 void add_type_instantiation_visitor(V&& visitor) { 130 add_container_visitor(visitor); 131 add_sink_visitor(visitor); 132 add_stream_response_visitor(std::forward<V>(visitor)); 133 } 134 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(program)135 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(program) { 136 begin_visit(program_visitors_, node, args...); 137 visit_children_ptrs(node.services(), args...); 138 visit_children_ptrs(node.interactions(), args...); 139 // TODO(afuller): Split structs and unions in t_program accessors. 140 for (auto* struct_or_union : node.structs()) { 141 if (auto* tunion = ast_detail::as<t_union>(struct_or_union)) { 142 this->operator()(args..., *tunion); 143 } else { 144 this->operator()(args..., *struct_or_union); 145 } 146 } 147 visit_children_ptrs(node.exceptions(), args...); 148 visit_children_ptrs(node.typedefs(), args...); 149 visit_children_ptrs(node.enums(), args...); 150 visit_children_ptrs(node.consts(), args...); 151 for (auto& type_inst : node.type_instantiations()) { 152 if (auto* set_node = ast_detail::as<t_set>(&type_inst)) { 153 visit_child(*set_node, args...); 154 } else if (auto* list_node = ast_detail::as<t_list>(&type_inst)) { 155 visit_child(*list_node, args...); 156 } else if (auto* map_node = ast_detail::as<t_map>(&type_inst)) { 157 visit_child(*map_node, args...); 158 } else if (auto* sink_node = ast_detail::as<t_sink>(&type_inst)) { 159 visit_child(*sink_node, args...); 160 } else if ( 161 auto* stream_node = ast_detail::as<t_stream_response>(&type_inst)) { 162 visit_child(*stream_node, args...); 163 } else { 164 std::terminate(); // Should be unreachable. 165 } 166 } 167 end_visit(node, args...); 168 } 169 170 // Interfaces FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(service)171 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(service) { 172 assert(typeid(node) == typeid(service_type)); // Must actually be a service. 173 begin_visit(service_visitors_, node, args...); 174 visit_children(node.functions(), args...); 175 end_visit(node, args...); 176 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(interaction)177 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(interaction) { 178 begin_visit(interaction_visitors_, node, args...); 179 visit_children(node.functions(), args...); 180 end_visit(node, args...); 181 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(function)182 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(function) { 183 begin_visit(function_visitors_, node, args...); 184 if (node.exceptions() != nullptr) { 185 visit_child(*node.exceptions(), args...); 186 } 187 end_visit(node, args...); 188 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(throws)189 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(throws) { 190 begin_visit(throws_visitors_, node, args...); 191 end_visit(node, args...); 192 } 193 194 // Types FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(struct)195 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(struct) { 196 assert(typeid(node) == typeid(struct_type)); // Must actually be a struct. 197 begin_visit(struct_visitors_, node, args...); 198 visit_children(node.fields(), args...); 199 end_visit(node, args...); 200 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(union)201 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(union) { 202 begin_visit(union_visitors_, node, args...); 203 visit_children(node.fields(), args...); 204 end_visit(node, args...); 205 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(exception)206 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(exception) { 207 begin_visit(exception_visitors_, node, args...); 208 visit_children(node.fields(), args...); 209 end_visit(node, args...); 210 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(field)211 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(field) { 212 begin_visit(field_visitors_, node, args...); 213 end_visit(node, args...); 214 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(enum)215 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(enum) { 216 begin_visit(enum_visitors_, node, args...); 217 visit_children(node.values(), args...); 218 end_visit(node, args...); 219 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(enum_value)220 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(enum_value) { 221 begin_visit(enum_value_visitors_, node, args...); 222 end_visit(node, args...); 223 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(const)224 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(const) { 225 begin_visit(const_visitors_, node, args...); 226 end_visit(node, args...); 227 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(typedef)228 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(typedef) { 229 begin_visit(typedef_visitors_, node, args...); 230 end_visit(node, args...); 231 } 232 233 // Templated type instantiations. FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(set)234 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(set) { 235 begin_visit(set_visitors_, node, args...); 236 end_visit(node, args...); 237 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(list)238 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(list) { 239 begin_visit(list_visitors_, node, args...); 240 end_visit(node, args...); 241 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(map)242 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(map) { 243 begin_visit(map_visitors_, node, args...); 244 end_visit(node, args...); 245 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(sink)246 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(sink) { 247 begin_visit(sink_visitors_, node, args...); 248 if (node.sink_exceptions() != nullptr) { 249 visit_child(*node.sink_exceptions(), args...); 250 } 251 if (node.final_response_exceptions() != nullptr) { 252 visit_child(*node.final_response_exceptions(), args...); 253 } 254 end_visit(node, args...); 255 } FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(stream_response)256 FBTHRIFT_AST_DETAIL_AST_VISITOR_NODE_T_(stream_response) { 257 begin_visit(stream_response_visitors_, node, args...); 258 if (node.exceptions() != nullptr) { 259 visit_child(*node.exceptions(), args...); 260 } 261 end_visit(node, args...); 262 } 263 264 private: 265 template <typename N> begin_visit(const visitor_list<Args...,N &> & visitors,N & node,Args...args)266 static void begin_visit( 267 const visitor_list<Args..., N&>& visitors, N& node, Args... args) { 268 // TODO(afuller): Replace with c++17 folding syntax when available. 269 using _ = int[]; 270 void(_{0, (ast_detail::begin_visit(node, args), 0)...}); 271 272 for (auto&& visitor : visitors) { 273 visitor(args..., node); 274 } 275 } 276 277 template <typename N> end_visit(N & node,Args...args)278 static void end_visit(N& node, Args... args) { 279 // TODO(afuller): Replace with c++17 folding syntax when available. 280 auto cb = [&](auto& arg) { 281 return make_scope_guard([&] { ast_detail::end_visit(node, arg); }); 282 }; 283 using _ = int[]; 284 void(_{0, (cb(args), 0)...}); 285 } 286 287 template <typename C> visit_child(C & child,Args...args)288 void visit_child(C& child, Args... args) const { 289 operator()(args..., child); 290 } 291 292 template <typename C> visit_children(const C & children,Args...args)293 void visit_children(const C& children, Args... args) const { 294 for (auto&& child : children) { 295 operator()(args..., child); 296 } 297 } 298 template <typename C> visit_children_ptrs(const C & children,Args...args)299 void visit_children_ptrs(const C& children, Args... args) const { 300 for (auto* child : children) { 301 operator()(args..., *child); 302 } 303 } 304 }; 305 306 template <bool is_const, typename N = t_node> 307 class basic_visitor_context { 308 using node_type = ast_detail::node_type<is_const, N>; 309 310 public: 311 // The first node visited. root()312 node_type* root() const noexcept { 313 assert(!context_.empty()); 314 return context_.empty() ? nullptr : context_.front(); 315 } 316 317 // The node currently being visited, or nullptr. current()318 node_type* current() const noexcept { 319 assert(!context_.empty()); 320 return context_.empty() ? nullptr : context_.back(); 321 } 322 323 // The parent of the current node, or nullptr. parent()324 node_type* parent() const noexcept { 325 return context_.size() < 2 ? nullptr : context_[context_.size() - 2]; 326 } 327 begin_visit(node_type & node)328 void begin_visit(node_type& node) { context_.emplace_back(&node); } end_visit(node_type &)329 void end_visit(node_type&) { context_.pop_back(); } 330 331 private: 332 std::vector<node_type*> context_; 333 }; 334 335 using visitor_context = basic_visitor_context<false>; 336 using const_visitor_context = basic_visitor_context<true>; 337 338 } // namespace compiler 339 } // namespace thrift 340 } // namespace apache 341