@@ -41,6 +41,11 @@ pub type ExportedItems = HashSet<ast::NodeId>;
41
41
/// reexporting a public struct doesn't inline the doc).
42
42
pub type PublicItems = HashSet < ast:: NodeId > ;
43
43
44
+ /// Result of a checking operation - None => no errors were found. Some => an
45
+ /// error and contains the span and message for reporting that error and
46
+ /// optionally the same for a note about the error.
47
+ type CheckResult = Option < ( Span , ~str , Option < ( Span , ~str ) > ) > ;
48
+
44
49
////////////////////////////////////////////////////////////////////////////////
45
50
/// The parent visitor, used to determine what's the parent of what (node-wise)
46
51
////////////////////////////////////////////////////////////////////////////////
@@ -510,40 +515,50 @@ impl<'a> PrivacyVisitor<'a> {
510
515
}
511
516
}
512
517
513
- /// Guarantee that a particular definition is public, possibly emitting an
514
- /// error message if it's not.
518
+ fn report_error ( & self , result : CheckResult ) -> bool {
519
+ match result {
520
+ None => true ,
521
+ Some ( ( span, msg, note) ) => {
522
+ self . tcx . sess . span_err ( span, msg) ;
523
+ match note {
524
+ Some ( ( span, msg) ) => self . tcx . sess . span_note ( span, msg) ,
525
+ None => { } ,
526
+ }
527
+ false
528
+ } ,
529
+ }
530
+ }
531
+
532
+ /// Guarantee that a particular definition is public. Returns a CheckResult
533
+ /// which contains any errors found. These can be reported using `report_error`.
534
+ /// If the result is `None`, no errors were found.
515
535
fn ensure_public ( & self , span : Span , to_check : ast:: DefId ,
516
- source_did : Option < ast:: DefId > , msg : & str ) -> bool {
536
+ source_did : Option < ast:: DefId > , msg : & str ) -> CheckResult {
517
537
match self . def_privacy ( to_check) {
518
- ExternallyDenied => {
519
- self . tcx . sess . span_err ( span, format ! ( "{} is private" , msg) )
520
- }
538
+ ExternallyDenied => Some ( ( span, format ! ( "{} is private" , msg) , None ) ) ,
521
539
DisallowedBy ( id) => {
522
- if id == source_did. unwrap_or ( to_check) . node {
523
- self . tcx . sess . span_err ( span, format ! ( "{} is private" , msg) ) ;
524
- return false ;
540
+ let ( err_span, err_msg) = if id == source_did. unwrap_or ( to_check) . node {
541
+ return Some ( ( span, format ! ( "{} is private" , msg) , None ) ) ;
525
542
} else {
526
- self . tcx . sess . span_err ( span, format ! ( "{} is inaccessible" ,
527
- msg) ) ;
528
- }
543
+ ( span, format ! ( "{} is inaccessible" , msg) )
544
+ } ;
529
545
match self . tcx . map . find ( id) {
530
546
Some ( ast_map:: NodeItem ( item) ) => {
531
547
let desc = match item. node {
532
548
ast:: ItemMod ( ..) => "module" ,
533
549
ast:: ItemTrait ( ..) => "trait" ,
534
- _ => return false ,
550
+ _ => return Some ( ( err_span , err_msg , None ) ) ,
535
551
} ;
536
552
let msg = format ! ( "{} `{}` is private" ,
537
553
desc,
538
554
token:: get_ident( item. ident) ) ;
539
- self . tcx . sess . span_note ( span, msg) ;
540
- }
541
- Some ( .. ) | None => { }
555
+ Some ( ( err_span , err_msg , Some ( ( span, msg) ) ) )
556
+ } ,
557
+ _ => Some ( ( err_span , err_msg , None ) ) ,
542
558
}
543
- }
544
- Allowable => return true
559
+ } ,
560
+ Allowable => None ,
545
561
}
546
- return false ;
547
562
}
548
563
549
564
// Checks that a field is in scope.
@@ -613,34 +628,99 @@ impl<'a> PrivacyVisitor<'a> {
613
628
let method_id = ty:: method ( self . tcx , method_id) . provided_source
614
629
. unwrap_or ( method_id) ;
615
630
616
- self . ensure_public ( span,
617
- method_id,
618
- None ,
619
- format ! ( "method `{}`" , token:: get_ident( name) ) ) ;
631
+ let string = token:: get_ident ( name) ;
632
+ self . report_error ( self . ensure_public ( span,
633
+ method_id,
634
+ None ,
635
+ format ! ( "method `{}`" , string) ) ) ;
620
636
}
621
637
622
638
// Checks that a path is in scope.
623
639
fn check_path ( & mut self , span : Span , path_id : ast:: NodeId , path : & ast:: Path ) {
624
640
debug ! ( "privacy - path {}" , self . nodestr( path_id) ) ;
625
641
let def_map = self . tcx . def_map . borrow ( ) ;
626
- let def = def_map. get ( ) . get_copy ( & path_id) ;
642
+ let orig_def = def_map. get ( ) . get_copy ( & path_id) ;
627
643
let ck = |tyname : & str | {
628
- let origdid = def_id_of_def ( def) ;
644
+ let ck_public = |def : ast:: DefId | {
645
+ let name = token:: get_ident ( path. segments
646
+ . last ( )
647
+ . unwrap ( )
648
+ . identifier ) ;
649
+ let origdid = def_id_of_def ( orig_def) ;
650
+ self . ensure_public ( span,
651
+ def,
652
+ Some ( origdid) ,
653
+ format ! ( "{} `{}`" ,
654
+ tyname,
655
+ name) )
656
+ } ;
657
+
629
658
match * self . last_private_map . get ( & path_id) {
630
- resolve:: AllPublic => { } ,
631
- resolve:: DependsOn ( def) => {
632
- let name = token:: get_ident ( path. segments
633
- . last ( )
634
- . unwrap ( )
635
- . identifier ) ;
636
- self . ensure_public ( span,
637
- def,
638
- Some ( origdid) ,
639
- format ! ( "{} `{}`" ,
640
- tyname, name) ) ;
641
- }
659
+ resolve:: LastMod ( resolve:: AllPublic ) => { } ,
660
+ resolve:: LastMod ( resolve:: DependsOn ( def) ) => {
661
+ self . report_error ( ck_public ( def) ) ;
662
+ } ,
663
+ resolve:: LastImport { value_priv : value_priv,
664
+ value_used : check_value,
665
+ type_priv : type_priv,
666
+ type_used : check_type} => {
667
+ // This dance with found_error is because we don't want to report
668
+ // a privacy error twice for the same directive.
669
+ let found_error = match ( type_priv, check_type) {
670
+ ( Some ( resolve:: DependsOn ( def) ) , resolve:: Used ) => {
671
+ !self . report_error ( ck_public ( def) )
672
+ } ,
673
+ _ => false ,
674
+ } ;
675
+ if !found_error {
676
+ match ( value_priv, check_value) {
677
+ ( Some ( resolve:: DependsOn ( def) ) , resolve:: Used ) => {
678
+ self . report_error ( ck_public ( def) ) ;
679
+ } ,
680
+ _ => { } ,
681
+ }
682
+ }
683
+ // If an import is not used in either namespace, we still want to check
684
+ // that it could be legal. Therefore we check in both namespaces and only
685
+ // report an error if both would be illegal. We only report one error,
686
+ // even if it is illegal to import from both namespaces.
687
+ match ( value_priv, check_value, type_priv, check_type) {
688
+ ( Some ( p) , resolve:: Unused , None , _) |
689
+ ( None , _, Some ( p) , resolve:: Unused ) => {
690
+ let p = match p {
691
+ resolve:: AllPublic => None ,
692
+ resolve:: DependsOn ( def) => ck_public ( def) ,
693
+ } ;
694
+ if p. is_some ( ) {
695
+ self . report_error ( p) ;
696
+ }
697
+ } ,
698
+ ( Some ( v) , resolve:: Unused , Some ( t) , resolve:: Unused ) => {
699
+ let v = match v {
700
+ resolve:: AllPublic => None ,
701
+ resolve:: DependsOn ( def) => ck_public ( def) ,
702
+ } ;
703
+ let t = match t {
704
+ resolve:: AllPublic => None ,
705
+ resolve:: DependsOn ( def) => ck_public ( def) ,
706
+ } ;
707
+ match ( v, t) {
708
+ ( Some ( _) , Some ( t) ) => {
709
+ self . report_error ( Some ( t) ) ;
710
+ } ,
711
+ _ => { } ,
712
+ }
713
+ } ,
714
+ _ => { } ,
715
+ }
716
+ } ,
642
717
}
643
718
} ;
719
+ // FIXME(#12334) Imports can refer to definitions in both the type and
720
+ // value namespaces. The privacy information is aware of this, but the
721
+ // def map is not. Therefore the names we work out below will not always
722
+ // be accurate and we can get slightly wonky error messages (but type
723
+ // checking is always correct).
644
724
let def_map = self . tcx . def_map . borrow ( ) ;
645
725
match def_map. get ( ) . get_copy ( & path_id) {
646
726
ast:: DefStaticMethod ( ..) => ck ( "static method" ) ,
@@ -668,7 +748,7 @@ impl<'a> PrivacyVisitor<'a> {
668
748
// is whether the trait itself is accessible or not.
669
749
method_param( method_param { trait_id : trait_id, .. } ) |
670
750
method_object( method_object { trait_id : trait_id, .. } ) => {
671
- self . ensure_public ( span, trait_id, None , "source trait" ) ;
751
+ self . report_error ( self . ensure_public ( span, trait_id, None , "source trait" ) ) ;
672
752
}
673
753
}
674
754
}
0 commit comments