1 // Copyright (C) 2020-2023 Free Software Foundation, Inc.
3 // This file is part of GCC.
5 // GCC is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free
7 // Software Foundation; either version 3, or (at your option) any later
10 // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 // You should have received a copy of the GNU General Public License
16 // along with GCC; see the file COPYING3. If not see
17 // <http://www.gnu.org/licenses/>.
19 #include "rust-privacy-reporter.h"
20 #include "rust-hir-expr.h"
21 #include "rust-hir-stmt.h"
22 #include "rust-hir-item.h"
27 PrivacyReporter::PrivacyReporter (
28 Analysis::Mappings
&mappings
, Resolver::Resolver
&resolver
,
29 const Rust::Resolver::TypeCheckContext
&ty_ctx
)
30 : mappings (mappings
), resolver (resolver
), ty_ctx (ty_ctx
),
31 current_module (Optional
<NodeId
>::none ())
35 PrivacyReporter::go (HIR::Crate
&crate
)
37 for (auto &item
: crate
.items
)
38 item
->accept_vis (*this);
42 is_child_module (Analysis::Mappings
&mappings
, NodeId parent
,
43 NodeId possible_child
)
45 auto children
= mappings
.lookup_module_children (parent
);
50 // Visit all toplevel children
51 for (auto &child
: *children
)
52 if (child
== possible_child
)
55 // Now descend recursively in the child module tree
56 for (auto &child
: *children
)
57 if (is_child_module (mappings
, child
, possible_child
))
63 // FIXME: This function needs a lot of refactoring
65 PrivacyReporter::check_for_privacy_violation (const NodeId
&use_id
,
66 const Location
&locus
)
68 NodeId ref_node_id
= UNKNOWN_NODEID
;
70 // FIXME: Don't assert here - we might be dealing with a type
71 if (!resolver
.lookup_resolved_name (use_id
, &ref_node_id
))
72 resolver
.lookup_resolved_type (use_id
, &ref_node_id
);
74 // FIXME: Assert here. For now, we return since this causes issues when
75 // checking inferred types (#1260)
76 // rust_assert (ref_node_id != UNKNOWN_NODEID);
77 if (ref_node_id
== UNKNOWN_NODEID
)
82 // FIXME: Can we really return here if the item has no visibility?
83 if (!mappings
.lookup_visibility (ref_node_id
, vis
))
88 switch (vis
.get_kind ())
90 case ModuleVisibility::Public
:
92 case ModuleVisibility::Restricted
: {
93 // If we are in the crate, everything is restricted correctly, but we
94 // can't get a module for it
95 if (current_module
.is_none ())
98 auto module
= mappings
.lookup_defid (vis
.get_module_id ());
99 rust_assert (module
!= nullptr);
101 auto mod_node_id
= module
->get_mappings ().get_nodeid ();
103 // We are in the module referenced by the pub(restricted) visibility.
105 if (mod_node_id
== current_module
.get ())
108 // FIXME: This needs a LOT of TLC: hinting about the definition, a
109 // string to say if it's a module, function, type, etc...
110 if (!is_child_module (mappings
, mod_node_id
, current_module
.get ()))
114 case ModuleVisibility::Unknown
:
120 rust_error_at (locus
, "definition is private in this context");
124 PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping
&node_mappings
,
125 const TyTy::BaseType
*ty
,
126 const Location
&locus
)
128 // Avoids repeating commong argument such as `use_id` or `locus` since we're
129 // doing a lot of recursive calls here
131 = [this, &node_mappings
, &locus
] (const TyTy::BaseType
*ty
) {
132 return check_base_type_privacy (node_mappings
, ty
, locus
);
135 switch (ty
->get_kind ())
137 // These "simple" types are our stop condition
147 auto ref_id
= ty
->get_ref ();
150 bool ok
= mappings
.lookup_hir_to_node (ref_id
, &lookup_id
);
153 return check_for_privacy_violation (lookup_id
, locus
);
156 return recursive_check (
157 static_cast<const TyTy::ReferenceType
*> (ty
)->get_base ());
159 return recursive_check (
160 static_cast<const TyTy::PointerType
*> (ty
)->get_base ());
162 return recursive_check (
163 static_cast<const TyTy::ArrayType
*> (ty
)->get_element_type ());
165 return recursive_check (
166 static_cast<const TyTy::SliceType
*> (ty
)->get_element_type ());
168 for (auto ¶m
: static_cast<const TyTy::FnPtr
*> (ty
)->get_params ())
169 recursive_check (param
.get_tyty ());
170 return recursive_check (
171 static_cast<const TyTy::FnPtr
*> (ty
)->get_return_type ());
174 static_cast<const TyTy::TupleType
*> (ty
)->get_fields ())
175 recursive_check (param
.get_tyty ());
177 case TyTy::PLACEHOLDER
:
178 return recursive_check (
179 // FIXME: Can we use `resolve` here? Is that what we should do?
180 static_cast<const TyTy::PlaceholderType
*> (ty
)->resolve ());
181 case TyTy::PROJECTION
:
182 return recursive_check (
183 static_cast<const TyTy::ProjectionType
*> (ty
)->get ());
185 rust_sorry_at (locus
, "privacy pass for closures is not handled yet");
188 // If we're dealing with a generic param, there's nothing we should be
191 // We are dealing with a function definition that has been assigned
192 // somewhere else. Nothing to resolve privacy-wise other than the actual
193 // function, which is resolved as an expression
195 // FIXME: Can we really not resolve Dynamic types here? Shouldn't we have
196 // a look at the path and perform proper privacy analysis?
198 // The never type is builtin and always available
200 // We shouldn't have inference types here, ever
209 PrivacyReporter::check_type_privacy (const HIR::Type
*type
)
213 TyTy::BaseType
*lookup
= nullptr;
215 ty_ctx
.lookup_type (type
->get_mappings ().get_hirid (), &lookup
));
217 auto node_mappings
= type
->get_mappings ();
218 return check_base_type_privacy (node_mappings
, lookup
, type
->get_locus ());
222 PrivacyReporter::visit (HIR::PathInExpression
&path
)
224 check_for_privacy_violation (path
.get_mappings ().get_nodeid (),
229 PrivacyReporter::visit (HIR::TypePathSegmentFunction
&segment
)
231 // FIXME: Do we need to do anything for this?
235 PrivacyReporter::visit (HIR::TypePath
&path
)
237 check_for_privacy_violation (path
.get_mappings ().get_nodeid (),
242 PrivacyReporter::visit (HIR::QualifiedPathInExpression
&path
)
244 check_for_privacy_violation (path
.get_mappings ().get_nodeid (),
249 PrivacyReporter::visit (HIR::QualifiedPathInType
&path
)
251 check_for_privacy_violation (path
.get_mappings ().get_nodeid (),
256 PrivacyReporter::visit (HIR::LiteralExpr
&expr
)
258 // Literals cannot contain any sort of privacy violation
262 PrivacyReporter::visit (HIR::BorrowExpr
&expr
)
264 expr
.get_expr ()->accept_vis (*this);
268 PrivacyReporter::visit (HIR::DereferenceExpr
&expr
)
270 expr
.get_expr ()->accept_vis (*this);
274 PrivacyReporter::visit (HIR::ErrorPropagationExpr
&expr
)
276 expr
.get_expr ()->accept_vis (*this);
280 PrivacyReporter::visit (HIR::NegationExpr
&expr
)
282 expr
.get_expr ()->accept_vis (*this);
286 PrivacyReporter::visit (HIR::ArithmeticOrLogicalExpr
&expr
)
288 expr
.get_lhs ()->accept_vis (*this);
289 expr
.get_rhs ()->accept_vis (*this);
293 PrivacyReporter::visit (HIR::ComparisonExpr
&expr
)
295 expr
.get_lhs ()->accept_vis (*this);
296 expr
.get_rhs ()->accept_vis (*this);
300 PrivacyReporter::visit (HIR::LazyBooleanExpr
&expr
)
302 expr
.get_lhs ()->accept_vis (*this);
303 expr
.get_rhs ()->accept_vis (*this);
307 PrivacyReporter::visit (HIR::TypeCastExpr
&expr
)
309 expr
.get_expr ()->accept_vis (*this);
313 PrivacyReporter::visit (HIR::AssignmentExpr
&expr
)
315 expr
.get_lhs ()->accept_vis (*this);
316 expr
.get_rhs ()->accept_vis (*this);
320 PrivacyReporter::visit (HIR::CompoundAssignmentExpr
&expr
)
322 expr
.get_left_expr ()->accept_vis (*this);
323 expr
.get_right_expr ()->accept_vis (*this);
327 PrivacyReporter::visit (HIR::GroupedExpr
&expr
)
329 expr
.get_expr_in_parens ()->accept_vis (*this);
333 PrivacyReporter::visit (HIR::ArrayExpr
&expr
)
335 HIR::ArrayElems
&elements
= *expr
.get_internal_elements ();
336 switch (elements
.get_array_expr_type ())
338 case HIR::ArrayElems::ArrayExprType::VALUES
: {
339 HIR::ArrayElemsValues
&elems
340 = static_cast<HIR::ArrayElemsValues
&> (elements
);
341 for (auto &value
: elems
.get_values ())
342 value
->accept_vis (*this);
346 case HIR::ArrayElems::ArrayExprType::COPIED
:
347 HIR::ArrayElemsCopied
&elems
348 = static_cast<HIR::ArrayElemsCopied
&> (elements
);
349 elems
.get_elem_to_copy ()->accept_vis (*this);
354 PrivacyReporter::visit (HIR::ArrayIndexExpr
&expr
)
356 expr
.get_array_expr ()->accept_vis (*this);
357 expr
.get_index_expr ()->accept_vis (*this);
361 PrivacyReporter::visit (HIR::TupleExpr
&expr
)
363 for (auto &value
: expr
.get_tuple_elems ())
364 value
->accept_vis (*this);
368 PrivacyReporter::visit (HIR::TupleIndexExpr
&expr
)
370 expr
.get_tuple_expr ()->accept_vis (*this);
374 PrivacyReporter::visit (HIR::StructExprStruct
&expr
)
376 // FIXME: We need to check the visibility of the type it refers to here
380 PrivacyReporter::visit (HIR::StructExprFieldIdentifier
&field
)
384 PrivacyReporter::visit (HIR::StructExprFieldIdentifierValue
&field
)
386 field
.get_value ()->accept_vis (*this);
390 PrivacyReporter::visit (HIR::StructExprFieldIndexValue
&field
)
392 field
.get_value ()->accept_vis (*this);
396 PrivacyReporter::visit (HIR::StructExprStructFields
&expr
)
398 for (auto &field
: expr
.get_fields ())
399 field
->accept_vis (*this);
403 PrivacyReporter::visit (HIR::CallExpr
&expr
)
405 expr
.get_fnexpr ()->accept_vis (*this);
407 for (auto ¶m
: expr
.get_arguments ())
408 param
->accept_vis (*this);
412 PrivacyReporter::visit (HIR::MethodCallExpr
&expr
)
414 expr
.get_receiver ()->accept_vis (*this);
416 for (auto ¶m
: expr
.get_arguments ())
417 param
->accept_vis (*this);
421 PrivacyReporter::visit (HIR::FieldAccessExpr
&expr
)
423 expr
.get_receiver_expr ()->accept_vis (*this);
425 // FIXME: We should also check if the field is public?
429 PrivacyReporter::visit (HIR::ClosureExprInner
&expr
)
435 PrivacyReporter::visit (HIR::BlockExpr
&expr
)
437 for (auto &stmt
: expr
.get_statements ())
438 stmt
->accept_vis (*this);
440 auto &last_expr
= expr
.get_final_expr ();
442 last_expr
->accept_vis (*this);
446 PrivacyReporter::visit (HIR::ClosureExprInnerTyped
&expr
)
452 PrivacyReporter::visit (HIR::ContinueExpr
&expr
)
456 PrivacyReporter::visit (HIR::BreakExpr
&expr
)
458 auto &break_expr
= expr
.get_expr ();
460 break_expr
->accept_vis (*this);
464 PrivacyReporter::visit (HIR::RangeFromToExpr
&expr
)
466 expr
.get_from_expr ()->accept_vis (*this);
467 expr
.get_to_expr ()->accept_vis (*this);
471 PrivacyReporter::visit (HIR::RangeFromExpr
&expr
)
473 expr
.get_from_expr ()->accept_vis (*this);
477 PrivacyReporter::visit (HIR::RangeToExpr
&expr
)
479 expr
.get_to_expr ()->accept_vis (*this);
483 PrivacyReporter::visit (HIR::RangeFullExpr
&expr
)
487 PrivacyReporter::visit (HIR::RangeFromToInclExpr
&expr
)
489 expr
.get_from_expr ()->accept_vis (*this);
490 expr
.get_to_expr ()->accept_vis (*this);
494 PrivacyReporter::visit (HIR::RangeToInclExpr
&expr
)
500 PrivacyReporter::visit (HIR::ReturnExpr
&expr
)
502 auto return_expr
= expr
.get_expr ();
504 return_expr
->accept_vis (*this);
508 PrivacyReporter::visit (HIR::UnsafeBlockExpr
&expr
)
510 expr
.get_block_expr ()->accept_vis (*this);
514 PrivacyReporter::visit (HIR::LoopExpr
&expr
)
516 expr
.get_loop_block ()->accept_vis (*this);
520 PrivacyReporter::visit (HIR::WhileLoopExpr
&expr
)
522 expr
.get_predicate_expr ()->accept_vis (*this);
523 expr
.get_loop_block ()->accept_vis (*this);
527 PrivacyReporter::visit (HIR::WhileLetLoopExpr
&expr
)
529 expr
.get_cond ()->accept_vis (*this);
530 expr
.get_loop_block ()->accept_vis (*this);
534 PrivacyReporter::visit (HIR::ForLoopExpr
&expr
)
536 expr
.get_iterator_expr ()->accept_vis (*this);
537 expr
.get_loop_block ()->accept_vis (*this);
541 PrivacyReporter::visit (HIR::IfExpr
&expr
)
543 expr
.get_if_condition ()->accept_vis (*this);
544 expr
.get_if_block ()->accept_vis (*this);
548 PrivacyReporter::visit (HIR::IfExprConseqElse
&expr
)
550 expr
.get_if_condition ()->accept_vis (*this);
551 expr
.get_if_block ()->accept_vis (*this);
552 expr
.get_else_block ()->accept_vis (*this);
556 PrivacyReporter::visit (HIR::IfExprConseqIf
&expr
)
558 expr
.get_if_condition ()->accept_vis (*this);
559 expr
.get_if_block ()->accept_vis (*this);
560 expr
.get_conseq_if_expr ()->accept_vis (*this);
564 PrivacyReporter::visit (HIR::IfExprConseqIfLet
&expr
)
566 expr
.get_if_condition ()->accept_vis (*this);
567 expr
.get_if_block ()->accept_vis (*this);
569 // TODO: We need to visit the if_let_expr as well
573 PrivacyReporter::visit (HIR::IfLetExpr
&expr
)
575 // TODO: We need to visit the if_let_expr
576 // TODO: We need to visit the block as well
580 PrivacyReporter::visit (HIR::IfLetExprConseqElse
&expr
)
582 // TODO: We need to visit the if_let_expr
583 // TODO: We need to visit the if_block as well
584 // TODO: We need to visit the else_block as well
588 PrivacyReporter::visit (HIR::IfLetExprConseqIf
&expr
)
590 // TODO: We need to visit the if_let_expr
591 // TODO: We need to visit the if_block as well
592 // TODO: We need to visit the else_block as well
596 PrivacyReporter::visit (HIR::IfLetExprConseqIfLet
&expr
)
598 // TODO: We need to visit the if_let_expr
599 // TODO: We need to visit the if_block as well
600 // TODO: We need to visit the else_block as well
604 PrivacyReporter::visit (HIR::MatchExpr
&expr
)
606 expr
.get_scrutinee_expr ()->accept_vis (*this);
610 PrivacyReporter::visit (HIR::AwaitExpr
&expr
)
616 PrivacyReporter::visit (HIR::AsyncBlockExpr
&expr
)
622 PrivacyReporter::visit (HIR::Module
&module
)
624 // FIXME: We also need to think about module privacy
626 auto old_module
= current_module
;
628 = Optional
<NodeId
>::some (module
.get_mappings ().get_nodeid ());
630 for (auto &item
: module
.get_items ())
631 item
->accept_vis (*this);
633 current_module
= old_module
;
637 PrivacyReporter::visit (HIR::ExternCrate
&crate
)
641 PrivacyReporter::visit (HIR::UseDeclaration
&use_decl
)
643 // FIXME: Is there anything we need to do here?
647 PrivacyReporter::visit (HIR::Function
&function
)
649 for (auto ¶m
: function
.get_function_params ())
650 check_type_privacy (param
.get_type ());
652 function
.get_definition ()->accept_vis (*this);
656 PrivacyReporter::visit (HIR::TypeAlias
&type_alias
)
658 // TODO: Check the type here
662 PrivacyReporter::visit (HIR::StructStruct
&struct_item
)
664 // TODO: Check the type of all fields
668 PrivacyReporter::visit (HIR::TupleStruct
&tuple_struct
)
670 // TODO: Check the type of all fields
674 PrivacyReporter::visit (HIR::EnumItem
&item
)
676 // TODO: Check the type of all variants
680 PrivacyReporter::visit (HIR::EnumItemTuple
&item
)
682 // TODO: Check the type
686 PrivacyReporter::visit (HIR::EnumItemStruct
&item
)
688 // TODO: Check the type
692 PrivacyReporter::visit (HIR::EnumItemDiscriminant
&item
)
696 PrivacyReporter::visit (HIR::Enum
&enum_item
)
700 PrivacyReporter::visit (HIR::Union
&union_item
)
702 // TODO: Check the type
706 PrivacyReporter::visit (HIR::ConstantItem
&const_item
)
708 // TODO: We need to visit the type
709 const_item
.get_expr ()->accept_vis (*this);
713 PrivacyReporter::visit (HIR::StaticItem
&static_item
)
715 // TODO: We need to visit the type
716 static_item
.get_expr ()->accept_vis (*this);
720 PrivacyReporter::visit (HIR::Trait
&trait
)
722 // FIXME: We need to be an ItemVisitor as well
723 // for (auto &item : trait.get_trait_items ())
724 // item->accept_vis (*this);
728 PrivacyReporter::visit (HIR::ImplBlock
&impl
)
730 for (auto &item
: impl
.get_impl_items ())
731 item
->accept_vis (*this);
735 PrivacyReporter::visit (HIR::ExternBlock
&block
)
737 // FIXME: We need to be an ItemVisitor as well
738 // for (auto &item : block.get_extern_items ())
739 // item->accept_vis (*this);
743 PrivacyReporter::visit (HIR::EmptyStmt
&stmt
)
747 PrivacyReporter::visit (HIR::LetStmt
&stmt
)
749 auto type
= stmt
.get_type ();
751 check_type_privacy (type
);
753 auto init_expr
= stmt
.get_init_expr ();
755 init_expr
->accept_vis (*this);
759 PrivacyReporter::visit (HIR::ExprStmtWithoutBlock
&stmt
)
761 stmt
.get_expr ()->accept_vis (*this);
765 PrivacyReporter::visit (HIR::ExprStmtWithBlock
&stmt
)
767 stmt
.get_expr ()->accept_vis (*this);
770 } // namespace Privacy