// Copyright (C) 2020-2025 Free Software Foundation, Inc. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #include "rust-reachability.h" #include "rust-tyty.h" namespace Rust { namespace Privacy { static HIR::VisItem * maybe_get_vis_item (std::unique_ptr &item) { if (item->get_hir_kind () != HIR::Node::VIS_ITEM) return nullptr; return static_cast (item.get ()); } ReachLevel ReachabilityVisitor::get_reachability_level ( const HIR::Visibility &item_visibility) { return item_visibility.is_public () ? current_level : ReachLevel::Unreachable; } void ReachabilityVisitor::visit_generic_predicates ( const std::vector> &generics, ReachLevel item_reach) { if (item_reach == ReachLevel::Unreachable) return; for (const auto &generic : generics) { if (generic->get_kind () == HIR::GenericParam::GenericKind::TYPE) { TyTy::BaseType *generic_ty = nullptr; auto ok = ty_ctx.lookup_type (generic->get_mappings ().get_hirid (), &generic_ty); rust_assert (ok); rust_assert (generic_ty->get_kind () == TyTy::PARAM); auto generic_param = static_cast (generic_ty); for (const auto &bound : generic_param->get_specified_bounds ()) { const auto trait = bound.get ()->get_hir_trait_ref (); ctx.update_reachability (trait->get_mappings (), item_reach); } } } } void ReachabilityVisitor::visit (HIR::Module &mod) { auto reach = get_reachability_level (mod.get_visibility ()); reach = ctx.update_reachability (mod.get_mappings (), reach); for (auto &item : mod.get_items ()) { // FIXME: Is that what we want to do? Yes? Only visit the items with // visibility? // // Imagine if we had `maybe_get_vis_item(item)?->accept_vis(*this)` ;) auto vis_item = maybe_get_vis_item (item); if (vis_item) vis_item->accept_vis (*this); } } void ReachabilityVisitor::visit (HIR::ExternCrate &crate) { auto reach = get_reachability_level (crate.get_visibility ()); reach = ctx.update_reachability (crate.get_mappings (), reach); } void ReachabilityVisitor::visit (HIR::UseDeclaration &use_decl) { auto reach = get_reachability_level (use_decl.get_visibility ()); reach = ctx.update_reachability (use_decl.get_mappings (), reach); } void ReachabilityVisitor::visit (HIR::Function &func) { auto fn_reach = get_reachability_level (func.get_visibility ()); fn_reach = ctx.update_reachability (func.get_mappings (), fn_reach); visit_generic_predicates (func.get_generic_params (), fn_reach); } void ReachabilityVisitor::visit (HIR::TypeAlias &type_alias) { auto type_reach = get_reachability_level (type_alias.get_visibility ()); visit_generic_predicates (type_alias.get_generic_params (), type_reach); } void ReachabilityVisitor::visit (HIR::StructStruct &struct_item) { auto struct_reach = get_reachability_level (struct_item.get_visibility ()); struct_reach = ctx.update_reachability (struct_item.get_mappings (), struct_reach); auto old_level = current_level; current_level = struct_reach; visit_generic_predicates (struct_item.get_generic_params (), struct_reach); if (struct_reach != ReachLevel::Unreachable) { for (auto &field : struct_item.get_fields ()) if (field.get_visibility ().is_public ()) ctx.update_reachability (field.get_field_type ().get_mappings (), struct_reach); } current_level = old_level; } void ReachabilityVisitor::visit (HIR::TupleStruct &) {} void ReachabilityVisitor::visit (HIR::Enum &enum_item) { auto enum_reach = get_reachability_level (enum_item.get_visibility ()); enum_reach = ctx.update_reachability (enum_item.get_mappings (), enum_reach); visit_generic_predicates (enum_item.get_generic_params (), enum_reach); for (const auto &variant : enum_item.get_variants ()) { auto variant_reach = ctx.update_reachability (variant->get_mappings (), enum_reach); switch (variant->get_enum_item_kind ()) { case HIR::EnumItem::Tuple: { // Should we update the fields only if they are public? Similarly to // what we do in the ReachabilityVisitor for HIR::TupleStruct? auto tuple_variant = static_cast (variant.get ()); for (const auto &field : tuple_variant->get_tuple_fields ()) ctx.update_reachability (field.get_mappings (), variant_reach); break; } case HIR::EnumItem::Struct: { // Should we update the fields only if they are public? Similarly to // what we do in the ReachabilityVisitor for HIR::StructStruct? auto struct_variant = static_cast (variant.get ()); for (const auto &field : struct_variant->get_struct_fields ()) ctx.update_reachability (field.get_mappings (), variant_reach); break; } // Nothing nested to visit in that case case HIR::EnumItem::Named: case HIR::EnumItem::Discriminant: break; } } } void ReachabilityVisitor::visit (HIR::Union &union_item) { auto union_reach = get_reachability_level (union_item.get_visibility ()); union_reach = ctx.update_reachability (union_item.get_mappings (), union_reach); visit_generic_predicates (union_item.get_generic_params (), union_reach); } void ReachabilityVisitor::visit (HIR::ConstantItem &const_item) { auto reach = get_reachability_level (const_item.get_visibility ()); reach = ctx.update_reachability (const_item.get_mappings (), reach); } void ReachabilityVisitor::visit (HIR::StaticItem &static_item) { auto reach = get_reachability_level (static_item.get_visibility ()); reach = ctx.update_reachability (static_item.get_mappings (), reach); } void ReachabilityVisitor::visit (HIR::Trait &trait) { auto trait_reach = get_reachability_level (trait.get_visibility ()); trait_reach = ctx.update_reachability (trait.get_mappings (), trait_reach); visit_generic_predicates (trait.get_generic_params (), trait_reach); } void ReachabilityVisitor::visit (HIR::ImplBlock &impl) { auto impl_reach = get_reachability_level (impl.get_visibility ()); impl_reach = ctx.update_reachability (impl.get_mappings (), impl_reach); visit_generic_predicates (impl.get_generic_params (), impl_reach); } void ReachabilityVisitor::visit (HIR::ExternBlock &) {} // FIXME: How can we visit Blocks in the current configuration? Have a full // visitor? } // namespace Privacy } // namespace Rust