/* * 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. */ #pragma once #include #include #include #include #include #include namespace apache { namespace thrift { namespace compiler { class t_node; // A cache for metadata associated with an AST node. // // Useful for avoiding re-computation during a traversal of an AST. class node_metadata_cache { template using element_type = typename decltype(std::declval()())::element_type; template using if_is_constructible = std::enable_if_t::value, T&>; using key_type = std::pair; public: // Gets or creates a cache entry of the given type T for the specified node. // // If the entry is not already present in the cache, a new entry is created // using the provided loader, which must return a std::unique_ptr. template element_type& get(N& node, const F& loader) { // `node` must be an lvalue. using T = element_type; key_type key(&node, typeid(T)); auto itr = data_.find(key); if (itr == data_.end()) { itr = data_.emplace(std::move(key), to_any_data(loader())).first; } return *static_cast(itr->second.get()); } // Gets or creates a cache entry of the given type T for the specified node. // // T must be constructible in exactly one of the following ways: // - T() // - T(const N&) // - T(node_metadata_cache&, const N&) template if_is_constructible get(N& node) { // `node` must be an lvalue. return get(node, [] { return std::make_unique(); }); } template if_is_constructible get(N& node) { // `node` must be an lvalue. return get(node, [&node] { return std::make_unique(node); }); } template if_is_constructible get( N& node) { // `node` must be an lvalue. return get(node, [this, &node] { return std::make_unique(*this, static_cast(node)); }); } private: // TODO(afuller): Use std::any when c++17 can be used. using any_data = std::unique_ptr; std::map data_; template any_data to_any_data(std::unique_ptr value) { return {value.release(), [](void* ptr) { delete static_cast(ptr); }}; } }; // A context aware reporter for diagnostic results. class diagnostic_context : public diagnostics_engine, public const_visitor_context { public: using diagnostics_engine::diagnostics_engine; explicit diagnostic_context(diagnostics_engine& diags) : diagnostics_engine( diags.source_mgr(), [&diags](diagnostic diag) { diags.report(std::move(diag)); }, diags.params()) {} // A cache for traversal-specific metadata. node_metadata_cache& cache() { return cache_; } using diagnostics_engine::warning; template void warning(fmt::format_string msg, T&&... args) { warning(*current(), msg, std::forward(args)...); } using diagnostics_engine::error; template void error(fmt::format_string msg, T&&... args) { error(*current(), msg, std::forward(args)...); } using diagnostics_engine::check; template bool check(bool condition, fmt::format_string msg, T&&... args) { return check(condition, *current(), msg, std::forward(args)...); } using diagnostics_engine::report; private: node_metadata_cache cache_; }; } // namespace compiler } // namespace thrift } // namespace apache