/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include namespace apache { namespace thrift { namespace compiler { namespace { std::string join_strings_by_commas( const std::unordered_set& strs) { std::ostringstream stream; std::copy( strs.begin(), strs.end(), std::ostream_iterator(stream, ", ")); std::string joined_str = stream.str(); // Remove the last comma. return joined_str.empty() ? joined_str : joined_str.substr(0, joined_str.size() - 2); } std::vector split_string_by_periods(const std::string& str) { std::istringstream iss(str); std::vector tokens; std::string token; while (std::getline(iss, token, '.')) { if (!token.empty()) { tokens.push_back(token); } } return tokens; } } // namespace t_type_ref t_scope::ref_type( t_program& program, const std::string& name, const source_range& range) { std::string scoped_name = name.find_first_of('.') != std::string::npos ? name : program.scope_name(name); // Try to resolve the type. if (const t_type* type = find_type(scoped_name)) { return {*type, range}; // We found the type! } /* Either this type isn't yet declared, or it's never declared. Either way allow it and we'll figure it out during generation. */ // NOTE(afuller): This assumes that, since the type was referenced by name, it // is safe to create a dummy typedef to use as a proxy for the original type. // However, this actually breaks dynamic casts. // TODO(afuller): Merge t_placeholder_typedef into t_type_ref and remove const // cast. auto ph = std::make_unique(&program, scoped_name); ph->set_src_range(range); return add_placeholder_typedef(std::move(ph)); } const t_named* t_scope::add_def(const t_named& node) { if (!node.uri().empty()) { auto result = definitions_by_uri_.emplace(node.uri(), &node); if (!result.second) { return result.first->second; } } return nullptr; } void t_scope::add_enum_value(std::string name, const t_const* constant) { assert(constant->value()->is_enum()); const std::string& enum_value_name = constant->value()->get_enum_value()->get_name(); if (enum_value_name != "UNKNOWN" && definitions_.find(name) != definitions_.end()) { redefined_enum_values_.insert(name); } if (std::count(name.begin(), name.end(), '.') == 2) { // The name has two periods and three components, take the last two. auto name_with_enum = name.substr(name.find('.') + 1); enum_values_[enum_value_name].insert(name_with_enum); } definitions_.insert(std::make_pair(std::move(name), constant)); } std::string t_scope::get_fully_qualified_enum_value_names( const std::string& name) const { // Get just the enum value name from name, which is // PROGRAM_NAME.ENUM_VALUE_NAME. auto name_split = split_string_by_periods(name); if (name_split.empty()) { return ""; } return join_strings_by_commas(enum_values_.at(name_split.back())); } } // namespace compiler } // namespace thrift } // namespace apache