| // Copyright (C) 2020-2026 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 |
| // <http://www.gnu.org/licenses/>. |
| |
| #include "rust-visibility-resolver.h" |
| #include "rust-ast.h" |
| #include "rust-hir.h" |
| #include "rust-hir-item.h" |
| #include "rust-name-resolution-context.h" |
| |
| namespace Rust { |
| namespace Privacy { |
| |
| VisibilityResolver::VisibilityResolver ( |
| Analysis::Mappings &mappings, |
| const Resolver2_0::NameResolutionContext &resolver) |
| : mappings (mappings), resolver (resolver) |
| {} |
| |
| void |
| VisibilityResolver::go (HIR::Crate &crate) |
| { |
| mappings.insert_visibility (crate.get_mappings ().get_nodeid (), |
| ModuleVisibility::create_public ()); |
| |
| current_module = crate.get_mappings ().get_defid (); |
| |
| for (auto &item : crate.get_items ()) |
| { |
| if (item->get_hir_kind () == HIR::Node::VIS_ITEM) |
| { |
| auto vis_item = static_cast<HIR::VisItem *> (item.get ()); |
| vis_item->accept_vis (*this); |
| } |
| } |
| } |
| |
| bool |
| VisibilityResolver::resolve_module_path (const HIR::SimplePath &restriction, |
| DefId &id) |
| { |
| // We need, from the restriction, to figure out the actual Module it |
| // belongs to. |
| |
| NodeId ast_node_id = restriction.get_mappings ().get_nodeid (); |
| |
| auto invalid_path |
| = Error (restriction.get_locus (), |
| "cannot use non-module path as privacy restrictor"); |
| |
| NodeId ref_node_id; |
| if (auto id = resolver.lookup (ast_node_id)) |
| { |
| ref_node_id = *id; |
| } |
| else |
| { |
| invalid_path.emit (); |
| return false; |
| } |
| // FIXME: Add a hint here if we can find the path in another scope, such as |
| // a type or something else |
| // TODO: For the hint, can we point to the original item's definition if |
| // present? |
| |
| tl::optional<HirId> hid = mappings.lookup_node_to_hir (ref_node_id); |
| rust_assert (hid.has_value ()); |
| auto ref = hid.value (); |
| |
| auto crate = mappings.get_ast_crate (mappings.get_current_crate ()); |
| |
| // we may be dealing with pub(crate) |
| if (ref_node_id == crate.get_node_id ()) |
| // FIXME: What do we do here? There isn't a DefId for the Crate, so can we |
| // actually do anything? |
| // We basically want to return true always but just when exporting export |
| // these items as private? |
| return true; |
| |
| if (auto module = mappings.lookup_module (ref)) |
| { |
| // Fill in the resolved `DefId` |
| id = module.value ()->get_mappings ().get_defid (); |
| |
| return true; |
| } |
| invalid_path.emit (); |
| return false; |
| } |
| |
| bool |
| VisibilityResolver::resolve_visibility (const HIR::Visibility &visibility, |
| ModuleVisibility &to_resolve) |
| { |
| switch (visibility.get_vis_type ()) |
| { |
| case HIR::Visibility::PRIVATE: |
| to_resolve = ModuleVisibility::create_restricted (current_module); |
| return true; |
| case HIR::Visibility::PUBLIC: |
| to_resolve = ModuleVisibility::create_public (); |
| return true; |
| case HIR::Visibility::RESTRICTED: |
| { |
| // FIXME: We also need to handle 2015 vs 2018 edition conflicts |
| auto id = UNKNOWN_DEFID; |
| auto result = resolve_module_path (visibility.get_path (), id); |
| to_resolve = ModuleVisibility::create_restricted (id); |
| return result; |
| } |
| default: |
| rust_unreachable (); |
| return false; |
| } |
| } |
| |
| void |
| VisibilityResolver::resolve_and_update (const HIR::VisItem *item) |
| { |
| ModuleVisibility module_vis; |
| if (!resolve_visibility (item->get_visibility (), module_vis)) |
| return; // we will already have emitted errors |
| |
| mappings.insert_visibility (item->get_mappings ().get_nodeid (), module_vis); |
| } |
| |
| void |
| VisibilityResolver::visit (HIR::Module &mod) |
| { |
| auto old_module = current_module; |
| current_module = mod.get_mappings ().get_defid (); |
| |
| for (auto &item : mod.get_items ()) |
| { |
| if (item->get_hir_kind () == HIR::Node::VIS_ITEM) |
| { |
| auto vis_item = static_cast<HIR::VisItem *> (item.get ()); |
| vis_item->accept_vis (*this); |
| } |
| } |
| |
| current_module = old_module; |
| } |
| |
| void |
| VisibilityResolver::visit (HIR::ExternCrate &) |
| {} |
| |
| void |
| VisibilityResolver::visit (HIR::UseDeclaration &) |
| {} |
| |
| void |
| VisibilityResolver::visit (HIR::Function &func) |
| { |
| resolve_and_update (&func); |
| } |
| |
| void |
| VisibilityResolver::visit (HIR::TypeAlias &type_alias) |
| { |
| resolve_and_update (&type_alias); |
| } |
| |
| void |
| VisibilityResolver::visit (HIR::StructStruct &struct_item) |
| { |
| resolve_and_update (&struct_item); |
| } |
| |
| void |
| VisibilityResolver::visit (HIR::TupleStruct &tuple_struct) |
| { |
| resolve_and_update (&tuple_struct); |
| } |
| |
| void |
| VisibilityResolver::visit (HIR::Enum &enum_item) |
| { |
| ModuleVisibility vis; |
| if (!resolve_visibility (enum_item.get_visibility (), vis)) |
| return; |
| |
| mappings.insert_visibility (enum_item.get_mappings ().get_nodeid (), vis); |
| for (auto &variant : enum_item.get_variants ()) |
| mappings.insert_visibility (variant->get_mappings ().get_nodeid (), vis); |
| } |
| |
| void |
| VisibilityResolver::visit (HIR::Union &) |
| {} |
| |
| void |
| VisibilityResolver::visit (HIR::ConstantItem &const_item) |
| { |
| resolve_and_update (&const_item); |
| } |
| |
| void |
| VisibilityResolver::visit (HIR::StaticItem &static_item) |
| { |
| resolve_and_update (&static_item); |
| } |
| |
| void |
| VisibilityResolver::visit (HIR::Trait &trait) |
| { |
| ModuleVisibility vis; |
| if (!resolve_visibility (trait.get_visibility (), vis)) |
| return; |
| |
| mappings.insert_visibility (trait.get_mappings ().get_nodeid (), vis); |
| for (auto &item : trait.get_trait_items ()) |
| mappings.insert_visibility (item->get_mappings ().get_nodeid (), vis); |
| } |
| |
| void |
| VisibilityResolver::visit (HIR::ImplBlock &impl) |
| { |
| for (auto &item : impl.get_impl_items ()) |
| { |
| HIR::VisItem *vis_item; |
| switch (item->get_impl_item_type ()) |
| { |
| case HIR::ImplItem::FUNCTION: |
| vis_item = static_cast<HIR::Function *> (item.get ()); |
| break; |
| case HIR::ImplItem::TYPE_ALIAS: |
| vis_item = static_cast<HIR::TypeAlias *> (item.get ()); |
| break; |
| case HIR::ImplItem::CONSTANT: |
| vis_item = static_cast<HIR::ConstantItem *> (item.get ()); |
| break; |
| default: |
| rust_unreachable (); |
| return; |
| } |
| vis_item->accept_vis (*this); |
| } |
| } |
| |
| void |
| VisibilityResolver::visit (HIR::ExternBlock &) |
| {} |
| |
| } // namespace Privacy |
| } // namespace Rust |