]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / rust / checks / errors / privacy / rust-privacy-reporter.cc
1 // Copyright (C) 2020-2024 Free Software Foundation, Inc.
2
3 // This file is part of GCC.
4
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
8 // version.
9
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
13 // for more details.
14
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/>.
18
19 #include "rust-privacy-reporter.h"
20 #include "rust-hir-expr.h"
21 #include "rust-hir-stmt.h"
22 #include "rust-hir-item.h"
23
24 namespace Rust {
25 namespace Privacy {
26
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 ())
32 {}
33
34 void
35 PrivacyReporter::go (HIR::Crate &crate)
36 {
37 for (auto &item : crate.items)
38 item->accept_vis (*this);
39 }
40
41 static bool
42 is_child_module (Analysis::Mappings &mappings, NodeId parent,
43 NodeId possible_child)
44 {
45 auto children = mappings.lookup_module_children (parent);
46
47 if (!children)
48 return false;
49
50 // Visit all toplevel children
51 for (auto &child : *children)
52 if (child == possible_child)
53 return true;
54
55 // Now descend recursively in the child module tree
56 for (auto &child : *children)
57 if (is_child_module (mappings, child, possible_child))
58 return true;
59
60 return false;
61 }
62
63 // FIXME: This function needs a lot of refactoring
64 void
65 PrivacyReporter::check_for_privacy_violation (const NodeId &use_id,
66 const Location &locus)
67 {
68 NodeId ref_node_id = UNKNOWN_NODEID;
69
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);
73
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)
78 return;
79
80 ModuleVisibility vis;
81
82 // FIXME: Can we really return here if the item has no visibility?
83 if (!mappings.lookup_visibility (ref_node_id, vis))
84 return;
85
86 auto valid = true;
87
88 switch (vis.get_kind ())
89 {
90 case ModuleVisibility::Public:
91 break;
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 ())
96 return;
97
98 auto module = mappings.lookup_defid (vis.get_module_id ());
99 rust_assert (module != nullptr);
100
101 auto mod_node_id = module->get_mappings ().get_nodeid ();
102
103 // We are in the module referenced by the pub(restricted) visibility.
104 // This is valid
105 if (mod_node_id == current_module.get ())
106 break;
107
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 ()))
111 valid = false;
112 }
113 break;
114 case ModuleVisibility::Unknown:
115 rust_unreachable ();
116 break;
117 }
118
119 if (!valid)
120 rust_error_at (locus, "definition is private in this context");
121 }
122
123 void
124 PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping &node_mappings,
125 const TyTy::BaseType *ty,
126 const Location &locus)
127 {
128 // Avoids repeating commong argument such as `use_id` or `locus` since we're
129 // doing a lot of recursive calls here
130 auto recursive_check
131 = [this, &node_mappings, &locus] (const TyTy::BaseType *ty) {
132 return check_base_type_privacy (node_mappings, ty, locus);
133 };
134
135 switch (ty->get_kind ())
136 {
137 // These "simple" types are our stop condition
138 case TyTy::BOOL:
139 case TyTy::CHAR:
140 case TyTy::INT:
141 case TyTy::UINT:
142 case TyTy::FLOAT:
143 case TyTy::USIZE:
144 case TyTy::ISIZE:
145 case TyTy::ADT:
146 case TyTy::STR: {
147 auto ref_id = ty->get_ref ();
148 NodeId lookup_id;
149
150 bool ok = mappings.lookup_hir_to_node (ref_id, &lookup_id);
151 rust_assert (ok);
152
153 return check_for_privacy_violation (lookup_id, locus);
154 }
155 case TyTy::REF:
156 return recursive_check (
157 static_cast<const TyTy::ReferenceType *> (ty)->get_base ());
158 case TyTy::POINTER:
159 return recursive_check (
160 static_cast<const TyTy::PointerType *> (ty)->get_base ());
161 case TyTy::ARRAY:
162 return recursive_check (
163 static_cast<const TyTy::ArrayType *> (ty)->get_element_type ());
164 case TyTy::SLICE:
165 return recursive_check (
166 static_cast<const TyTy::SliceType *> (ty)->get_element_type ());
167 case TyTy::FNPTR:
168 for (auto &param : 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 ());
172 case TyTy::TUPLE:
173 for (auto &param :
174 static_cast<const TyTy::TupleType *> (ty)->get_fields ())
175 recursive_check (param.get_tyty ());
176 return;
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 ());
184 case TyTy::CLOSURE:
185 rust_sorry_at (locus, "privacy pass for closures is not handled yet");
186 break;
187
188 // If we're dealing with a generic param, there's nothing we should be
189 // doing here
190 case TyTy::PARAM:
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
194 case TyTy::FNDEF:
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?
197 case TyTy::DYNAMIC:
198 // The never type is builtin and always available
199 case TyTy::NEVER:
200 // We shouldn't have inference types here, ever
201 case TyTy::INFER:
202 return;
203 case TyTy::ERROR:
204 rust_unreachable ();
205 }
206 }
207
208 void
209 PrivacyReporter::check_type_privacy (const HIR::Type *type)
210 {
211 rust_assert (type);
212
213 TyTy::BaseType *lookup = nullptr;
214 rust_assert (
215 ty_ctx.lookup_type (type->get_mappings ().get_hirid (), &lookup));
216
217 auto node_mappings = type->get_mappings ();
218 return check_base_type_privacy (node_mappings, lookup, type->get_locus ());
219 }
220
221 void
222 PrivacyReporter::visit (HIR::PathInExpression &path)
223 {
224 check_for_privacy_violation (path.get_mappings ().get_nodeid (),
225 path.get_locus ());
226 }
227
228 void
229 PrivacyReporter::visit (HIR::TypePathSegmentFunction &)
230 {
231 // FIXME: Do we need to do anything for this?
232 }
233
234 void
235 PrivacyReporter::visit (HIR::TypePath &path)
236 {
237 check_for_privacy_violation (path.get_mappings ().get_nodeid (),
238 path.get_locus ());
239 }
240
241 void
242 PrivacyReporter::visit (HIR::QualifiedPathInExpression &path)
243 {
244 check_for_privacy_violation (path.get_mappings ().get_nodeid (),
245 path.get_locus ());
246 }
247
248 void
249 PrivacyReporter::visit (HIR::QualifiedPathInType &path)
250 {
251 check_for_privacy_violation (path.get_mappings ().get_nodeid (),
252 path.get_locus ());
253 }
254
255 void
256 PrivacyReporter::visit (HIR::LiteralExpr &)
257 {
258 // Literals cannot contain any sort of privacy violation
259 }
260
261 void
262 PrivacyReporter::visit (HIR::BorrowExpr &expr)
263 {
264 expr.get_expr ()->accept_vis (*this);
265 }
266
267 void
268 PrivacyReporter::visit (HIR::DereferenceExpr &expr)
269 {
270 expr.get_expr ()->accept_vis (*this);
271 }
272
273 void
274 PrivacyReporter::visit (HIR::ErrorPropagationExpr &expr)
275 {
276 expr.get_expr ()->accept_vis (*this);
277 }
278
279 void
280 PrivacyReporter::visit (HIR::NegationExpr &expr)
281 {
282 expr.get_expr ()->accept_vis (*this);
283 }
284
285 void
286 PrivacyReporter::visit (HIR::ArithmeticOrLogicalExpr &expr)
287 {
288 expr.get_lhs ()->accept_vis (*this);
289 expr.get_rhs ()->accept_vis (*this);
290 }
291
292 void
293 PrivacyReporter::visit (HIR::ComparisonExpr &expr)
294 {
295 expr.get_lhs ()->accept_vis (*this);
296 expr.get_rhs ()->accept_vis (*this);
297 }
298
299 void
300 PrivacyReporter::visit (HIR::LazyBooleanExpr &expr)
301 {
302 expr.get_lhs ()->accept_vis (*this);
303 expr.get_rhs ()->accept_vis (*this);
304 }
305
306 void
307 PrivacyReporter::visit (HIR::TypeCastExpr &expr)
308 {
309 expr.get_expr ()->accept_vis (*this);
310 }
311
312 void
313 PrivacyReporter::visit (HIR::AssignmentExpr &expr)
314 {
315 expr.get_lhs ()->accept_vis (*this);
316 expr.get_rhs ()->accept_vis (*this);
317 }
318
319 void
320 PrivacyReporter::visit (HIR::CompoundAssignmentExpr &expr)
321 {
322 expr.get_left_expr ()->accept_vis (*this);
323 expr.get_right_expr ()->accept_vis (*this);
324 }
325
326 void
327 PrivacyReporter::visit (HIR::GroupedExpr &expr)
328 {
329 expr.get_expr_in_parens ()->accept_vis (*this);
330 }
331
332 void
333 PrivacyReporter::visit (HIR::ArrayExpr &expr)
334 {
335 HIR::ArrayElems &elements = *expr.get_internal_elements ();
336 switch (elements.get_array_expr_type ())
337 {
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);
343 }
344 return;
345
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);
350 }
351 }
352
353 void
354 PrivacyReporter::visit (HIR::ArrayIndexExpr &expr)
355 {
356 expr.get_array_expr ()->accept_vis (*this);
357 expr.get_index_expr ()->accept_vis (*this);
358 }
359
360 void
361 PrivacyReporter::visit (HIR::TupleExpr &expr)
362 {
363 for (auto &value : expr.get_tuple_elems ())
364 value->accept_vis (*this);
365 }
366
367 void
368 PrivacyReporter::visit (HIR::TupleIndexExpr &expr)
369 {
370 expr.get_tuple_expr ()->accept_vis (*this);
371 }
372
373 void
374 PrivacyReporter::visit (HIR::StructExprStruct &)
375 {
376 // FIXME: We need to check the visibility of the type it refers to here
377 }
378
379 void
380 PrivacyReporter::visit (HIR::StructExprFieldIdentifier &)
381 {}
382
383 void
384 PrivacyReporter::visit (HIR::StructExprFieldIdentifierValue &field)
385 {
386 field.get_value ()->accept_vis (*this);
387 }
388
389 void
390 PrivacyReporter::visit (HIR::StructExprFieldIndexValue &field)
391 {
392 field.get_value ()->accept_vis (*this);
393 }
394
395 void
396 PrivacyReporter::visit (HIR::StructExprStructFields &expr)
397 {
398 for (auto &field : expr.get_fields ())
399 field->accept_vis (*this);
400 }
401
402 void
403 PrivacyReporter::visit (HIR::CallExpr &expr)
404 {
405 expr.get_fnexpr ()->accept_vis (*this);
406
407 for (auto &param : expr.get_arguments ())
408 param->accept_vis (*this);
409 }
410
411 void
412 PrivacyReporter::visit (HIR::MethodCallExpr &expr)
413 {
414 expr.get_receiver ()->accept_vis (*this);
415
416 for (auto &param : expr.get_arguments ())
417 param->accept_vis (*this);
418 }
419
420 void
421 PrivacyReporter::visit (HIR::FieldAccessExpr &expr)
422 {
423 expr.get_receiver_expr ()->accept_vis (*this);
424
425 // FIXME: We should also check if the field is public?
426 }
427
428 void
429 PrivacyReporter::visit (HIR::ClosureExpr &)
430 {
431 // Not handled yet
432 }
433
434 void
435 PrivacyReporter::visit (HIR::BlockExpr &expr)
436 {
437 for (auto &stmt : expr.get_statements ())
438 stmt->accept_vis (*this);
439
440 auto &last_expr = expr.get_final_expr ();
441 if (last_expr)
442 last_expr->accept_vis (*this);
443 }
444
445 void
446 PrivacyReporter::visit (HIR::ContinueExpr &)
447 {}
448
449 void
450 PrivacyReporter::visit (HIR::BreakExpr &expr)
451 {
452 auto &break_expr = expr.get_expr ();
453 if (break_expr)
454 break_expr->accept_vis (*this);
455 }
456
457 void
458 PrivacyReporter::visit (HIR::RangeFromToExpr &expr)
459 {
460 expr.get_from_expr ()->accept_vis (*this);
461 expr.get_to_expr ()->accept_vis (*this);
462 }
463
464 void
465 PrivacyReporter::visit (HIR::RangeFromExpr &expr)
466 {
467 expr.get_from_expr ()->accept_vis (*this);
468 }
469
470 void
471 PrivacyReporter::visit (HIR::RangeToExpr &expr)
472 {
473 expr.get_to_expr ()->accept_vis (*this);
474 }
475
476 void
477 PrivacyReporter::visit (HIR::RangeFullExpr &)
478 {}
479
480 void
481 PrivacyReporter::visit (HIR::RangeFromToInclExpr &expr)
482 {
483 expr.get_from_expr ()->accept_vis (*this);
484 expr.get_to_expr ()->accept_vis (*this);
485 }
486
487 void
488 PrivacyReporter::visit (HIR::RangeToInclExpr &)
489 {
490 // Not handled yet
491 }
492
493 void
494 PrivacyReporter::visit (HIR::ReturnExpr &expr)
495 {
496 auto return_expr = expr.get_expr ();
497 if (return_expr)
498 return_expr->accept_vis (*this);
499 }
500
501 void
502 PrivacyReporter::visit (HIR::UnsafeBlockExpr &expr)
503 {
504 expr.get_block_expr ()->accept_vis (*this);
505 }
506
507 void
508 PrivacyReporter::visit (HIR::LoopExpr &expr)
509 {
510 expr.get_loop_block ()->accept_vis (*this);
511 }
512
513 void
514 PrivacyReporter::visit (HIR::WhileLoopExpr &expr)
515 {
516 expr.get_predicate_expr ()->accept_vis (*this);
517 expr.get_loop_block ()->accept_vis (*this);
518 }
519
520 void
521 PrivacyReporter::visit (HIR::WhileLetLoopExpr &expr)
522 {
523 expr.get_cond ()->accept_vis (*this);
524 expr.get_loop_block ()->accept_vis (*this);
525 }
526
527 void
528 PrivacyReporter::visit (HIR::ForLoopExpr &expr)
529 {
530 expr.get_iterator_expr ()->accept_vis (*this);
531 expr.get_loop_block ()->accept_vis (*this);
532 }
533
534 void
535 PrivacyReporter::visit (HIR::IfExpr &expr)
536 {
537 expr.get_if_condition ()->accept_vis (*this);
538 expr.get_if_block ()->accept_vis (*this);
539 }
540
541 void
542 PrivacyReporter::visit (HIR::IfExprConseqElse &expr)
543 {
544 expr.get_if_condition ()->accept_vis (*this);
545 expr.get_if_block ()->accept_vis (*this);
546 expr.get_else_block ()->accept_vis (*this);
547 }
548
549 void
550 PrivacyReporter::visit (HIR::IfExprConseqIf &expr)
551 {
552 expr.get_if_condition ()->accept_vis (*this);
553 expr.get_if_block ()->accept_vis (*this);
554 expr.get_conseq_if_expr ()->accept_vis (*this);
555 }
556
557 void
558 PrivacyReporter::visit (HIR::IfExprConseqIfLet &expr)
559 {
560 expr.get_if_condition ()->accept_vis (*this);
561 expr.get_if_block ()->accept_vis (*this);
562
563 // TODO: We need to visit the if_let_expr as well
564 }
565
566 void
567 PrivacyReporter::visit (HIR::IfLetExpr &)
568 {
569 // TODO: We need to visit the if_let_expr
570 // TODO: We need to visit the block as well
571 }
572
573 void
574 PrivacyReporter::visit (HIR::IfLetExprConseqElse &)
575 {
576 // TODO: We need to visit the if_let_expr
577 // TODO: We need to visit the if_block as well
578 // TODO: We need to visit the else_block as well
579 }
580
581 void
582 PrivacyReporter::visit (HIR::IfLetExprConseqIf &)
583 {
584 // TODO: We need to visit the if_let_expr
585 // TODO: We need to visit the if_block as well
586 // TODO: We need to visit the else_block as well
587 }
588
589 void
590 PrivacyReporter::visit (HIR::IfLetExprConseqIfLet &)
591 {
592 // TODO: We need to visit the if_let_expr
593 // TODO: We need to visit the if_block as well
594 // TODO: We need to visit the else_block as well
595 }
596
597 void
598 PrivacyReporter::visit (HIR::MatchExpr &expr)
599 {
600 expr.get_scrutinee_expr ()->accept_vis (*this);
601 }
602
603 void
604 PrivacyReporter::visit (HIR::AwaitExpr &)
605 {
606 // Not handled yet
607 }
608
609 void
610 PrivacyReporter::visit (HIR::AsyncBlockExpr &)
611 {
612 // Not handled yet
613 }
614
615 void
616 PrivacyReporter::visit (HIR::Module &module)
617 {
618 // FIXME: We also need to think about module privacy
619
620 auto old_module = current_module;
621 current_module
622 = Optional<NodeId>::some (module.get_mappings ().get_nodeid ());
623
624 for (auto &item : module.get_items ())
625 item->accept_vis (*this);
626
627 current_module = old_module;
628 }
629
630 void
631 PrivacyReporter::visit (HIR::ExternCrate &)
632 {}
633
634 void
635 PrivacyReporter::visit (HIR::UseDeclaration &)
636 {
637 // FIXME: Is there anything we need to do here?
638 }
639
640 void
641 PrivacyReporter::visit (HIR::Function &function)
642 {
643 for (auto &param : function.get_function_params ())
644 check_type_privacy (param.get_type ());
645
646 function.get_definition ()->accept_vis (*this);
647 }
648
649 void
650 PrivacyReporter::visit (HIR::TypeAlias &)
651 {
652 // TODO: Check the type here
653 }
654
655 void
656 PrivacyReporter::visit (HIR::StructStruct &)
657 {
658 // TODO: Check the type of all fields
659 }
660
661 void
662 PrivacyReporter::visit (HIR::TupleStruct &)
663 {
664 // TODO: Check the type of all fields
665 }
666
667 void
668 PrivacyReporter::visit (HIR::EnumItem &)
669 {
670 // TODO: Check the type of all variants
671 }
672
673 void
674 PrivacyReporter::visit (HIR::EnumItemTuple &)
675 {
676 // TODO: Check the type
677 }
678
679 void
680 PrivacyReporter::visit (HIR::EnumItemStruct &)
681 {
682 // TODO: Check the type
683 }
684
685 void
686 PrivacyReporter::visit (HIR::EnumItemDiscriminant &)
687 {}
688
689 void
690 PrivacyReporter::visit (HIR::Enum &)
691 {}
692
693 void
694 PrivacyReporter::visit (HIR::Union &)
695 {
696 // TODO: Check the type
697 }
698
699 void
700 PrivacyReporter::visit (HIR::ConstantItem &const_item)
701 {
702 // TODO: We need to visit the type
703 const_item.get_expr ()->accept_vis (*this);
704 }
705
706 void
707 PrivacyReporter::visit (HIR::StaticItem &static_item)
708 {
709 // TODO: We need to visit the type
710 static_item.get_expr ()->accept_vis (*this);
711 }
712
713 void
714 PrivacyReporter::visit (HIR::Trait &)
715 {
716 // FIXME: We need to be an ItemVisitor as well
717 // for (auto &item : trait.get_trait_items ())
718 // item->accept_vis (*this);
719 }
720
721 void
722 PrivacyReporter::visit (HIR::ImplBlock &impl)
723 {
724 for (auto &item : impl.get_impl_items ())
725 item->accept_vis (*this);
726 }
727
728 void
729 PrivacyReporter::visit (HIR::ExternBlock &)
730 {
731 // FIXME: We need to be an ItemVisitor as well
732 // for (auto &block: block.get_extern_items ())
733 // item->accept_vis (*this);
734 }
735
736 void
737 PrivacyReporter::visit (HIR::EmptyStmt &)
738 {}
739
740 void
741 PrivacyReporter::visit (HIR::LetStmt &stmt)
742 {
743 auto type = stmt.get_type ();
744 if (type)
745 check_type_privacy (type);
746
747 auto init_expr = stmt.get_init_expr ();
748 if (init_expr)
749 init_expr->accept_vis (*this);
750 }
751
752 void
753 PrivacyReporter::visit (HIR::ExprStmtWithoutBlock &stmt)
754 {
755 stmt.get_expr ()->accept_vis (*this);
756 }
757
758 void
759 PrivacyReporter::visit (HIR::ExprStmtWithBlock &stmt)
760 {
761 stmt.get_expr ()->accept_vis (*this);
762 }
763
764 } // namespace Privacy
765 } // namespace Rust