// Copyright (C) 2020-2022 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-visibility-resolver.h" #include "rust-ast.h" #include "rust-hir.h" #include "rust-hir-item.h" namespace Rust { namespace Privacy { VisibilityResolver::VisibilityResolver (Analysis::Mappings &mappings, Resolver::Resolver &resolver) : mappings (mappings), resolver (resolver) {} void VisibilityResolver::go (HIR::Crate &crate) { mappings.insert_visibility (crate.get_mappings ().get_defid (), ModuleVisibility::create_public ()); for (auto &item : crate.items) { if (item->get_hir_kind () == HIR::Node::VIS_ITEM) { auto vis_item = static_cast (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 = UNKNOWN_NODEID; if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) { invalid_path.emit_error (); 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? Resolver::Definition def; rust_assert (resolver.lookup_definition (ref_node_id, &def)); // FIXME: Is that what we want? ref_node_id = def.parent; HirId ref; rust_assert ( mappings.lookup_node_to_hir (restriction.get_mappings ().get_crate_num (), ref_node_id, &ref)); auto module = mappings.lookup_module (restriction.get_mappings ().get_crate_num (), ref); if (!module) { invalid_path.emit_error (); return false; } // Fill in the resolved `DefId` id = module->get_mappings ().get_defid (); return true; } bool VisibilityResolver::resolve_visibility (const HIR::Visibility &visibility, ModuleVisibility &to_resolve) { switch (visibility.get_vis_type ()) { case HIR::Visibility::PRIVATE: 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 to_resolve = ModuleVisibility::create_public (); return resolve_module_path (visibility.get_path (), to_resolve.get_module_id ()); default: gcc_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_defid (), module_vis); } void VisibilityResolver::visit (HIR::Module &mod) { for (auto &item : mod.get_items ()) { if (item->get_hir_kind () == HIR::Node::VIS_ITEM) { auto vis_item = static_cast (item.get ()); vis_item->accept_vis (*this); } } } void VisibilityResolver::visit (HIR::ExternCrate &crate) {} void VisibilityResolver::visit (HIR::UseDeclaration &use_decl) {} 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_defid (), vis); for (auto &variant : enum_item.get_variants ()) mappings.insert_visibility (variant->get_mappings ().get_defid (), vis); } void VisibilityResolver::visit (HIR::Union &union_item) {} 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_defid (), vis); for (auto &item : trait.get_trait_items ()) mappings.insert_visibility (item->get_mappings ().get_defid (), 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 (item.get ()); break; case HIR::ImplItem::TYPE_ALIAS: vis_item = static_cast (item.get ()); break; case HIR::ImplItem::CONSTANT: vis_item = static_cast (item.get ()); break; default: gcc_unreachable (); return; } vis_item->accept_vis (*this); } } void VisibilityResolver::visit (HIR::ExternBlock &block) {} } // namespace Privacy } // namespace Rust