1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20 #ifndef T_STRUCT_H 21 #define T_STRUCT_H 22 23 #include <algorithm> 24 #include <vector> 25 #include <utility> 26 #include <string> 27 28 #include "thrift/parse/t_type.h" 29 #include "thrift/parse/t_field.h" 30 31 // Forward declare that puppy 32 class t_program; 33 34 /** 35 * A struct is a container for a set of member fields that has a name. Structs 36 * are also used to implement exception types. 37 * 38 */ 39 class t_struct : public t_type { 40 public: 41 typedef std::vector<t_field*> members_type; 42 t_struct(t_program * program)43 t_struct(t_program* program) 44 : t_type(program), 45 is_xception_(false), 46 is_union_(false), 47 is_method_xcepts_(false), 48 union_validated_(false), 49 xcepts_validated_(false), 50 members_with_value_(0), 51 xsd_all_(false) {} 52 t_struct(t_program * program,const std::string & name)53 t_struct(t_program* program, const std::string& name) 54 : t_type(program, name), 55 is_xception_(false), 56 is_union_(false), 57 is_method_xcepts_(false), 58 union_validated_(false), 59 xcepts_validated_(false), 60 members_with_value_(0), 61 xsd_all_(false) {} 62 set_name(const std::string & name)63 void set_name(const std::string& name) override { 64 name_ = name; 65 union_validated_= false; 66 validate_members(); 67 } 68 set_xception(bool is_xception)69 void set_xception(bool is_xception) { is_xception_ = is_xception; } 70 set_method_xcepts(bool is_method_xcepts)71 void set_method_xcepts(bool is_method_xcepts) { 72 is_method_xcepts_ = is_method_xcepts; 73 xcepts_validated_ = false; 74 validate_members(); 75 } 76 set_union(bool is_union)77 void set_union(bool is_union) { 78 is_union_ = is_union; 79 union_validated_= false; 80 validate_members(); 81 } 82 set_xsd_all(bool xsd_all)83 void set_xsd_all(bool xsd_all) { xsd_all_ = xsd_all; } 84 get_xsd_all()85 bool get_xsd_all() const { return xsd_all_; } 86 append(t_field * elem)87 bool append(t_field* elem) { 88 typedef members_type::iterator iter_type; 89 std::pair<iter_type, iter_type> bounds = std::equal_range(members_in_id_order_.begin(), 90 members_in_id_order_.end(), 91 elem, 92 t_field::key_compare()); 93 if (bounds.first != bounds.second) { 94 return false; 95 } 96 // returns false when there is a conflict of field names 97 if (get_field_by_name(elem->get_name()) != nullptr) { 98 return false; 99 } 100 members_.push_back(elem); 101 members_in_id_order_.insert(bounds.second, elem); 102 if (needs_validation()) { 103 validate_members(); 104 } else { 105 validate_member_field(elem); 106 } 107 return true; 108 } 109 get_members()110 const members_type& get_members() const { return members_; } 111 get_sorted_members()112 const members_type& get_sorted_members() const { return members_in_id_order_; } 113 is_struct()114 bool is_struct() const override { return !is_xception_; } 115 is_xception()116 bool is_xception() const override { return is_xception_; } 117 is_union()118 bool is_union() const { return is_union_; } 119 get_field_by_name(std::string field_name)120 t_field* get_field_by_name(std::string field_name) { 121 return const_cast<t_field*>(const_cast<const t_struct&>(*this).get_field_by_name(field_name)); 122 } 123 get_field_by_name(std::string field_name)124 const t_field* get_field_by_name(std::string field_name) const { 125 members_type::const_iterator m_iter; 126 for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { 127 if ((*m_iter)->get_name() == field_name) { 128 return *m_iter; 129 } 130 } 131 return nullptr; 132 } 133 134 private: 135 members_type members_; 136 members_type members_in_id_order_; 137 bool is_xception_; // struct is an IDL exception 138 bool is_union_; // struct is an IDL union 139 bool is_method_xcepts_; // struct holds the exceptions declared at a service method 140 bool union_validated_; 141 bool xcepts_validated_; 142 int members_with_value_; 143 144 bool xsd_all_; 145 validate_member_field(t_field * field)146 void validate_member_field(t_field* field) { 147 validate_union_member(field); 148 validate_method_exception_field(field); 149 } 150 validate_union_member(t_field * field)151 void validate_union_member(t_field* field) { 152 if (is_union_ && (!name_.empty())) { 153 union_validated_ = true; 154 155 // 1) unions can't have required fields 156 // 2) union members are implicitly optional, otherwise bugs like THRIFT-3650 wait to happen 157 if (field->get_req() != t_field::T_OPTIONAL) { 158 // no warning on default requiredness, but do warn on anything else that is explicitly asked for 159 if(field->get_req() != t_field::T_OPT_IN_REQ_OUT) { 160 pwarning(1, 161 "Union %s field %s: union members must be optional, ignoring specified requiredness.\n", 162 name_.c_str(), 163 field->get_name().c_str()); 164 } 165 field->set_req(t_field::T_OPTIONAL); 166 } 167 168 // unions may have up to one member defaulted, but not more 169 if (field->get_value() != nullptr) { 170 if (1 < ++members_with_value_) { 171 throw "Error: Field " + field->get_name() + " provides another default value for union " 172 + name_; 173 } 174 } 175 } 176 } 177 validate_method_exception_field(t_field * field)178 void validate_method_exception_field(t_field* field) { 179 if (is_method_xcepts_) { 180 xcepts_validated_ = true; 181 182 // THRIFT-5669: "required" makes no sense at "throws" clauses 183 if (field->get_req() == t_field::T_REQUIRED) { 184 field->set_req(t_field::T_OPT_IN_REQ_OUT); 185 pwarning(1, 186 "Exception field %s: \"required\" is illegal here, ignoring.\n", 187 field->get_name().c_str()); 188 } 189 } 190 } 191 needs_validation()192 bool needs_validation() { 193 if (is_method_xcepts_) { 194 return !xcepts_validated_; 195 } 196 if (is_union_) { 197 return !union_validated_; 198 } 199 return false; 200 } 201 validate_members()202 void validate_members() { 203 if (needs_validation()) { 204 members_type::const_iterator m_iter; 205 for (m_iter = members_in_id_order_.begin(); m_iter != members_in_id_order_.end(); ++m_iter) { 206 validate_member_field(*m_iter); 207 } 208 } 209 } 210 211 }; 212 213 #endif 214