blob: ff1c1eaa5b926c4cdc5bb058e17c05b3cd429e82 [file] [log] [blame]
// 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