1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 #![crate_name = "rustc_privacy"]
12 #![unstable(feature = "rustc_private", issue = "27812")]
13 #![crate_type = "dylib"]
14 #![crate_type = "rlib"]
15 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
16 html_favicon_url
= "https://doc.rust-lang.org/favicon.ico",
17 html_root_url
= "https://doc.rust-lang.org/nightly/")]
18 #![cfg_attr(not(stage0), deny(warnings))]
20 #![feature(rustc_diagnostic_macros)]
21 #![feature(rustc_private)]
22 #![feature(staged_api)]
24 #[macro_use] extern crate log;
25 #[macro_use] extern crate syntax;
27 #[macro_use] extern crate rustc;
30 use std
::mem
::replace
;
32 use rustc
::hir
::{self, PatKind}
;
33 use rustc
::hir
::intravisit
::{self, Visitor}
;
35 use rustc
::dep_graph
::DepNode
;
37 use rustc
::middle
::cstore
::CrateStore
;
38 use rustc
::hir
::def
::{self, Def}
;
39 use rustc
::hir
::def_id
::DefId
;
40 use rustc
::middle
::privacy
::{AccessLevel, AccessLevels}
;
41 use rustc
::ty
::{self, TyCtxt}
;
42 use rustc
::util
::nodemap
::NodeSet
;
43 use rustc
::hir
::map
as ast_map
;
46 use syntax
::codemap
::Span
;
50 type Context
<'a
, 'tcx
> = (&'a ty
::MethodMap
<'tcx
>, &'a def
::ExportMap
);
52 /// Result of a checking operation - None => no errors were found. Some => an
53 /// error and contains the span and message for reporting that error and
54 /// optionally the same for a note about the error.
55 type CheckResult
= Option
<(Span
, String
, Option
<(Span
, String
)>)>;
57 ////////////////////////////////////////////////////////////////////////////////
58 /// The embargo visitor, used to determine the exports of the ast
59 ////////////////////////////////////////////////////////////////////////////////
61 struct EmbargoVisitor
<'a
, 'tcx
: 'a
> {
62 tcx
: &'a TyCtxt
<'tcx
>,
63 export_map
: &'a def
::ExportMap
,
65 // Accessibility levels for reachable nodes
66 access_levels
: AccessLevels
,
67 // Previous accessibility level, None means unreachable
68 prev_level
: Option
<AccessLevel
>,
69 // Have something changed in the level map?
73 struct ReachEverythingInTheInterfaceVisitor
<'b
, 'a
: 'b
, 'tcx
: 'a
> {
74 ev
: &'b
mut EmbargoVisitor
<'a
, 'tcx
>,
77 impl<'a
, 'tcx
> EmbargoVisitor
<'a
, 'tcx
> {
78 fn ty_level(&self, ty
: &hir
::Ty
) -> Option
<AccessLevel
> {
79 if let hir
::TyPath(..) = ty
.node
{
80 match self.tcx
.def_map
.borrow().get(&ty
.id
).unwrap().full_def() {
81 Def
::PrimTy(..) | Def
::SelfTy(..) | Def
::TyParam(..) => {
82 Some(AccessLevel
::Public
)
85 if let Some(node_id
) = self.tcx
.map
.as_local_node_id(def
.def_id()) {
88 Some(AccessLevel
::Public
)
93 Some(AccessLevel
::Public
)
97 fn trait_level(&self, trait_ref
: &hir
::TraitRef
) -> Option
<AccessLevel
> {
98 let did
= self.tcx
.trait_ref_to_def_id(trait_ref
);
99 if let Some(node_id
) = self.tcx
.map
.as_local_node_id(did
) {
102 Some(AccessLevel
::Public
)
106 fn get(&self, id
: ast
::NodeId
) -> Option
<AccessLevel
> {
107 self.access_levels
.map
.get(&id
).cloned()
110 // Updates node level and returns the updated level
111 fn update(&mut self, id
: ast
::NodeId
, level
: Option
<AccessLevel
>) -> Option
<AccessLevel
> {
112 let old_level
= self.get(id
);
113 // Accessibility levels can only grow
114 if level
> old_level
{
115 self.access_levels
.map
.insert(id
, level
.unwrap());
123 fn reach
<'b
>(&'b
mut self) -> ReachEverythingInTheInterfaceVisitor
<'b
, 'a
, 'tcx
> {
124 ReachEverythingInTheInterfaceVisitor { ev: self }
128 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for EmbargoVisitor
<'a
, 'tcx
> {
129 /// We want to visit items in the context of their containing
130 /// module and so forth, so supply a crate for doing a deep walk.
131 fn visit_nested_item(&mut self, item
: hir
::ItemId
) {
132 self.visit_item(self.tcx
.map
.expect_item(item
.id
))
135 fn visit_item(&mut self, item
: &hir
::Item
) {
136 let inherited_item_level
= match item
.node
{
137 // Impls inherit level from their types and traits
138 hir
::ItemImpl(_
, _
, _
, None
, ref ty
, _
) => {
141 hir
::ItemImpl(_
, _
, _
, Some(ref trait_ref
), ref ty
, _
) => {
142 cmp
::min(self.ty_level(&ty
), self.trait_level(trait_ref
))
144 hir
::ItemDefaultImpl(_
, ref trait_ref
) => {
145 self.trait_level(trait_ref
)
147 // Foreign mods inherit level from parents
148 hir
::ItemForeignMod(..) => {
151 // Other `pub` items inherit levels from parents
153 if item
.vis
== hir
::Public { self.prev_level }
else { None }
157 // Update level of the item itself
158 let item_level
= self.update(item
.id
, inherited_item_level
);
160 // Update levels of nested things
162 hir
::ItemEnum(ref def
, _
) => {
163 for variant
in &def
.variants
{
164 let variant_level
= self.update(variant
.node
.data
.id(), item_level
);
165 for field
in variant
.node
.data
.fields() {
166 self.update(field
.id
, variant_level
);
170 hir
::ItemImpl(_
, _
, _
, None
, _
, ref impl_items
) => {
171 for impl_item
in impl_items
{
172 if impl_item
.vis
== hir
::Public
{
173 self.update(impl_item
.id
, item_level
);
177 hir
::ItemImpl(_
, _
, _
, Some(_
), _
, ref impl_items
) => {
178 for impl_item
in impl_items
{
179 self.update(impl_item
.id
, item_level
);
182 hir
::ItemTrait(_
, _
, _
, ref trait_items
) => {
183 for trait_item
in trait_items
{
184 self.update(trait_item
.id
, item_level
);
187 hir
::ItemStruct(ref def
, _
) => {
188 if !def
.is_struct() {
189 self.update(def
.id(), item_level
);
191 for field
in def
.fields() {
192 if field
.vis
== hir
::Public
{
193 self.update(field
.id
, item_level
);
197 hir
::ItemForeignMod(ref foreign_mod
) => {
198 for foreign_item
in &foreign_mod
.items
{
199 if foreign_item
.vis
== hir
::Public
{
200 self.update(foreign_item
.id
, item_level
);
207 // Mark all items in interfaces of reachable items as reachable
209 // The interface is empty
210 hir
::ItemExternCrate(..) => {}
211 // All nested items are checked by visit_item
212 hir
::ItemMod(..) => {}
213 // Reexports are handled in visit_mod
214 hir
::ItemUse(..) => {}
216 hir
::ItemConst(..) | hir
::ItemStatic(..) | hir
::ItemFn(..) |
217 hir
::ItemTrait(..) | hir
::ItemTy(..) | hir
::ItemImpl(_
, _
, _
, Some(..), _
, _
) => {
218 if item_level
.is_some() {
219 self.reach().visit_item(item
);
222 // Visit everything, but enum variants have their own levels
223 hir
::ItemEnum(ref def
, ref generics
) => {
224 if item_level
.is_some() {
225 self.reach().visit_generics(generics
);
227 for variant
in &def
.variants
{
228 if self.get(variant
.node
.data
.id()).is_some() {
229 for field
in variant
.node
.data
.fields() {
230 self.reach().visit_struct_field(field
);
232 // Corner case: if the variant is reachable, but its
233 // enum is not, make the enum reachable as well.
234 self.update(item
.id
, Some(AccessLevel
::Reachable
));
238 // Visit everything, but foreign items have their own levels
239 hir
::ItemForeignMod(ref foreign_mod
) => {
240 for foreign_item
in &foreign_mod
.items
{
241 if self.get(foreign_item
.id
).is_some() {
242 self.reach().visit_foreign_item(foreign_item
);
246 // Visit everything except for private fields
247 hir
::ItemStruct(ref struct_def
, ref generics
) => {
248 if item_level
.is_some() {
249 self.reach().visit_generics(generics
);
250 for field
in struct_def
.fields() {
251 if self.get(field
.id
).is_some() {
252 self.reach().visit_struct_field(field
);
257 // The interface is empty
258 hir
::ItemDefaultImpl(..) => {}
259 // Visit everything except for private impl items
260 hir
::ItemImpl(_
, _
, ref generics
, None
, _
, ref impl_items
) => {
261 if item_level
.is_some() {
262 self.reach().visit_generics(generics
);
263 for impl_item
in impl_items
{
264 if self.get(impl_item
.id
).is_some() {
265 self.reach().visit_impl_item(impl_item
);
272 let orig_level
= self.prev_level
;
273 self.prev_level
= item_level
;
275 intravisit
::walk_item(self, item
);
277 self.prev_level
= orig_level
;
280 fn visit_block(&mut self, b
: &'v hir
::Block
) {
281 let orig_level
= replace(&mut self.prev_level
, None
);
283 // Blocks can have public items, for example impls, but they always
284 // start as completely private regardless of publicity of a function,
285 // constant, type, field, etc. in which this block resides
286 intravisit
::walk_block(self, b
);
288 self.prev_level
= orig_level
;
291 fn visit_mod(&mut self, m
: &hir
::Mod
, _sp
: Span
, id
: ast
::NodeId
) {
292 // This code is here instead of in visit_item so that the
293 // crate module gets processed as well.
294 if self.prev_level
.is_some() {
295 if let Some(exports
) = self.export_map
.get(&id
) {
296 for export
in exports
{
297 if let Some(node_id
) = self.tcx
.map
.as_local_node_id(export
.def_id
) {
298 self.update(node_id
, Some(AccessLevel
::Exported
));
304 intravisit
::walk_mod(self, m
);
307 fn visit_macro_def(&mut self, md
: &'v hir
::MacroDef
) {
308 self.update(md
.id
, Some(AccessLevel
::Public
));
312 impl<'b
, 'a
, 'tcx
: 'a
> ReachEverythingInTheInterfaceVisitor
<'b
, 'a
, 'tcx
> {
313 // Make the type hidden under a type alias reachable
314 fn reach_aliased_type(&mut self, item
: &hir
::Item
, path
: &hir
::Path
) {
315 if let hir
::ItemTy(ref ty
, ref generics
) = item
.node
{
316 // See `fn is_public_type_alias` for details
318 let provided_params
= path
.segments
.last().unwrap().parameters
.types().len();
319 for ty_param
in &generics
.ty_params
[provided_params
..] {
320 if let Some(ref default_ty
) = ty_param
.default {
321 self.visit_ty(default_ty
);
328 impl<'b
, 'a
, 'tcx
: 'a
, 'v
> Visitor
<'v
> for ReachEverythingInTheInterfaceVisitor
<'b
, 'a
, 'tcx
> {
329 fn visit_ty(&mut self, ty
: &hir
::Ty
) {
330 if let hir
::TyPath(_
, ref path
) = ty
.node
{
331 let def
= self.ev
.tcx
.def_map
.borrow().get(&ty
.id
).unwrap().full_def();
333 Def
::Struct(def_id
) | Def
::Enum(def_id
) | Def
::TyAlias(def_id
) |
334 Def
::Trait(def_id
) | Def
::AssociatedTy(def_id
, _
) => {
335 if let Some(node_id
) = self.ev
.tcx
.map
.as_local_node_id(def_id
) {
336 let item
= self.ev
.tcx
.map
.expect_item(node_id
);
337 if let Def
::TyAlias(..) = def
{
338 // Type aliases are substituted. Associated type aliases are not
339 // substituted yet, but ideally they should be.
340 if self.ev
.get(item
.id
).is_none() {
341 self.reach_aliased_type(item
, path
);
344 self.ev
.update(item
.id
, Some(AccessLevel
::Reachable
));
353 intravisit
::walk_ty(self, ty
);
356 fn visit_trait_ref(&mut self, trait_ref
: &hir
::TraitRef
) {
357 let def_id
= self.ev
.tcx
.trait_ref_to_def_id(trait_ref
);
358 if let Some(node_id
) = self.ev
.tcx
.map
.as_local_node_id(def_id
) {
359 let item
= self.ev
.tcx
.map
.expect_item(node_id
);
360 self.ev
.update(item
.id
, Some(AccessLevel
::Reachable
));
363 intravisit
::walk_trait_ref(self, trait_ref
);
366 // Don't recurse into function bodies
367 fn visit_block(&mut self, _
: &hir
::Block
) {}
368 // Don't recurse into expressions in array sizes or const initializers
369 fn visit_expr(&mut self, _
: &hir
::Expr
) {}
370 // Don't recurse into patterns in function arguments
371 fn visit_pat(&mut self, _
: &hir
::Pat
) {}
374 ////////////////////////////////////////////////////////////////////////////////
375 /// The privacy visitor, where privacy checks take place (violations reported)
376 ////////////////////////////////////////////////////////////////////////////////
378 struct PrivacyVisitor
<'a
, 'tcx
: 'a
> {
379 tcx
: &'a TyCtxt
<'tcx
>,
380 curitem
: ast
::NodeId
,
384 impl<'a
, 'tcx
> PrivacyVisitor
<'a
, 'tcx
> {
385 fn item_is_accessible(&self, did
: DefId
) -> bool
{
386 match self.tcx
.map
.as_local_node_id(did
) {
388 ty
::Visibility
::from_hir(&self.tcx
.map
.expect_item(node_id
).vis
, node_id
, self.tcx
),
389 None
=> self.tcx
.sess
.cstore
.visibility(did
),
390 }.is_accessible_from(self.curitem
, &self.tcx
.map
)
393 // Checks that a field is in scope.
394 fn check_field(&mut self, span
: Span
, def
: ty
::AdtDef
<'tcx
>, field
: ty
::FieldDef
<'tcx
>) {
395 if def
.adt_kind() == ty
::AdtKind
::Struct
&&
396 !field
.vis
.is_accessible_from(self.curitem
, &self.tcx
.map
) {
397 span_err
!(self.tcx
.sess
, span
, E0451
, "field `{}` of struct `{}` is private",
398 field
.name
, self.tcx
.item_path_str(def
.did
));
402 // Checks that a method is in scope.
403 fn check_method(&mut self, span
: Span
, method_def_id
: DefId
) {
404 match self.tcx
.impl_or_trait_item(method_def_id
).container() {
405 // Trait methods are always all public. The only controlling factor
406 // is whether the trait itself is accessible or not.
407 ty
::TraitContainer(trait_def_id
) if !self.item_is_accessible(trait_def_id
) => {
408 let msg
= format
!("source trait `{}` is private",
409 self.tcx
.item_path_str(trait_def_id
));
410 self.tcx
.sess
.span_err(span
, &msg
);
417 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for PrivacyVisitor
<'a
, 'tcx
> {
418 /// We want to visit items in the context of their containing
419 /// module and so forth, so supply a crate for doing a deep walk.
420 fn visit_nested_item(&mut self, item
: hir
::ItemId
) {
421 self.visit_item(self.tcx
.map
.expect_item(item
.id
))
424 fn visit_item(&mut self, item
: &hir
::Item
) {
425 let orig_curitem
= replace(&mut self.curitem
, item
.id
);
426 intravisit
::walk_item(self, item
);
427 self.curitem
= orig_curitem
;
430 fn visit_expr(&mut self, expr
: &hir
::Expr
) {
432 hir
::ExprMethodCall(..) => {
433 let method_call
= ty
::MethodCall
::expr(expr
.id
);
434 let method
= self.tcx
.tables
.borrow().method_map
[&method_call
];
435 debug
!("(privacy checking) checking impl method");
436 self.check_method(expr
.span
, method
.def_id
);
438 hir
::ExprStruct(..) => {
439 let adt
= self.tcx
.expr_ty(expr
).ty_adt_def().unwrap();
440 let variant
= adt
.variant_of_def(self.tcx
.resolve_expr(expr
));
441 // RFC 736: ensure all unmentioned fields are visible.
442 // Rather than computing the set of unmentioned fields
443 // (i.e. `all_fields - fields`), just check them all.
444 for field
in &variant
.fields
{
445 self.check_field(expr
.span
, adt
, field
);
448 hir
::ExprPath(..) => {
450 if let Def
::Struct(..) = self.tcx
.resolve_expr(expr
) {
451 let expr_ty
= self.tcx
.expr_ty(expr
);
452 let def
= match expr_ty
.sty
{
453 ty
::TyFnDef(_
, _
, &ty
::BareFnTy
{ sig
: ty
::Binder(ty
::FnSig
{
454 output
: ty
::FnConverging(ty
), ..
457 }.ty_adt_def().unwrap();
458 let any_priv
= def
.struct_variant().fields
.iter().any(|f
| {
459 !f
.vis
.is_accessible_from(self.curitem
, &self.tcx
.map
)
462 span_err
!(self.tcx
.sess
, expr
.span
, E0450
,
463 "cannot invoke tuple struct constructor with private \
471 intravisit
::walk_expr(self, expr
);
474 fn visit_pat(&mut self, pattern
: &hir
::Pat
) {
475 // Foreign functions do not have their patterns mapped in the def_map,
476 // and there's nothing really relevant there anyway, so don't bother
477 // checking privacy. If you can name the type then you can pass it to an
478 // external C function anyway.
479 if self.in_foreign { return }
482 PatKind
::Struct(_
, ref fields
, _
) => {
483 let adt
= self.tcx
.pat_ty(pattern
).ty_adt_def().unwrap();
484 let def
= self.tcx
.def_map
.borrow().get(&pattern
.id
).unwrap().full_def();
485 let variant
= adt
.variant_of_def(def
);
486 for field
in fields
{
487 self.check_field(pattern
.span
, adt
, variant
.field_named(field
.node
.name
));
491 // Patterns which bind no fields are allowable (the path is check
493 PatKind
::TupleStruct(_
, Some(ref fields
)) => {
494 match self.tcx
.pat_ty(pattern
).sty
{
495 ty
::TyStruct(def
, _
) => {
496 for (i
, field
) in fields
.iter().enumerate() {
497 if let PatKind
::Wild
= field
.node
{
500 self.check_field(field
.span
, def
, &def
.struct_variant().fields
[i
]);
504 // enum fields have no privacy at this time
513 intravisit
::walk_pat(self, pattern
);
516 fn visit_foreign_item(&mut self, fi
: &hir
::ForeignItem
) {
517 self.in_foreign
= true;
518 intravisit
::walk_foreign_item(self, fi
);
519 self.in_foreign
= false;
523 ////////////////////////////////////////////////////////////////////////////////
524 /// The privacy sanity check visitor, ensures unnecessary visibility isn't here
525 ////////////////////////////////////////////////////////////////////////////////
527 struct SanePrivacyVisitor
<'a
, 'tcx
: 'a
> {
528 tcx
: &'a TyCtxt
<'tcx
>,
531 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for SanePrivacyVisitor
<'a
, 'tcx
> {
532 fn visit_item(&mut self, item
: &hir
::Item
) {
533 self.check_sane_privacy(item
);
534 intravisit
::walk_item(self, item
);
538 impl<'a
, 'tcx
> SanePrivacyVisitor
<'a
, 'tcx
> {
539 /// Validate that items that shouldn't have visibility qualifiers don't have them.
540 /// Such qualifiers can be set by syntax extensions even if the parser doesn't allow them,
541 /// so we check things like variant fields too.
542 fn check_sane_privacy(&self, item
: &hir
::Item
) {
543 let check_inherited
= |sp
, vis
: &hir
::Visibility
, note
: &str| {
544 if *vis
!= hir
::Inherited
{
545 let mut err
= struct_span_err
!(self.tcx
.sess
, sp
, E0449
,
546 "unnecessary visibility qualifier");
547 if !note
.is_empty() {
548 err
.span_note(sp
, note
);
555 hir
::ItemImpl(_
, _
, _
, Some(..), _
, ref impl_items
) => {
556 check_inherited(item
.span
, &item
.vis
,
557 "visibility qualifiers have no effect on trait impls");
558 for impl_item
in impl_items
{
559 check_inherited(impl_item
.span
, &impl_item
.vis
,
560 "visibility qualifiers have no effect on trait impl items");
563 hir
::ItemImpl(_
, _
, _
, None
, _
, _
) => {
564 check_inherited(item
.span
, &item
.vis
,
565 "place qualifiers on individual methods instead");
567 hir
::ItemDefaultImpl(..) => {
568 check_inherited(item
.span
, &item
.vis
,
569 "visibility qualifiers have no effect on trait impls");
571 hir
::ItemForeignMod(..) => {
572 check_inherited(item
.span
, &item
.vis
,
573 "place qualifiers on individual functions instead");
575 hir
::ItemEnum(ref def
, _
) => {
576 for variant
in &def
.variants
{
577 for field
in variant
.node
.data
.fields() {
578 check_inherited(field
.span
, &field
.vis
,
579 "visibility qualifiers have no effect on variant fields");
583 hir
::ItemStruct(..) | hir
::ItemTrait(..) |
584 hir
::ItemConst(..) | hir
::ItemStatic(..) | hir
::ItemFn(..) |
585 hir
::ItemMod(..) | hir
::ItemExternCrate(..) |
586 hir
::ItemUse(..) | hir
::ItemTy(..) => {}
591 ///////////////////////////////////////////////////////////////////////////////
592 /// Obsolete visitors for checking for private items in public interfaces.
593 /// These visitors are supposed to be kept in frozen state and produce an
594 /// "old error node set". For backward compatibility the new visitor reports
595 /// warnings instead of hard errors when the erroneous node is not in this old set.
596 ///////////////////////////////////////////////////////////////////////////////
598 struct ObsoleteVisiblePrivateTypesVisitor
<'a
, 'tcx
: 'a
> {
599 tcx
: &'a TyCtxt
<'tcx
>,
600 access_levels
: &'a AccessLevels
,
602 // set of errors produced by this obsolete visitor
603 old_error_set
: NodeSet
,
606 struct ObsoleteCheckTypeForPrivatenessVisitor
<'a
, 'b
: 'a
, 'tcx
: 'b
> {
607 inner
: &'a ObsoleteVisiblePrivateTypesVisitor
<'b
, 'tcx
>,
608 /// whether the type refers to private types.
609 contains_private
: bool
,
610 /// whether we've recurred at all (i.e. if we're pointing at the
611 /// first type on which visit_ty was called).
613 // whether that first type is a public path.
614 outer_type_is_public_path
: bool
,
617 impl<'a
, 'tcx
> ObsoleteVisiblePrivateTypesVisitor
<'a
, 'tcx
> {
618 fn path_is_private_type(&self, path_id
: ast
::NodeId
) -> bool
{
619 let did
= match self.tcx
.def_map
.borrow().get(&path_id
).map(|d
| d
.full_def()) {
620 // `int` etc. (None doesn't seem to occur.)
621 None
| Some(Def
::PrimTy(..)) | Some(Def
::SelfTy(..)) => return false,
622 Some(def
) => def
.def_id(),
625 // A path can only be private if:
626 // it's in this crate...
627 if let Some(node_id
) = self.tcx
.map
.as_local_node_id(did
) {
628 // .. and it corresponds to a private type in the AST (this returns
629 // None for type parameters)
630 match self.tcx
.map
.find(node_id
) {
631 Some(ast_map
::NodeItem(ref item
)) => item
.vis
!= hir
::Public
,
632 Some(_
) | None
=> false,
639 fn trait_is_public(&self, trait_id
: ast
::NodeId
) -> bool
{
640 // FIXME: this would preferably be using `exported_items`, but all
641 // traits are exported currently (see `EmbargoVisitor.exported_trait`)
642 self.access_levels
.is_public(trait_id
)
645 fn check_ty_param_bound(&mut self,
646 ty_param_bound
: &hir
::TyParamBound
) {
647 if let hir
::TraitTyParamBound(ref trait_ref
, _
) = *ty_param_bound
{
648 if self.path_is_private_type(trait_ref
.trait_ref
.ref_id
) {
649 self.old_error_set
.insert(trait_ref
.trait_ref
.ref_id
);
654 fn item_is_public(&self, id
: &ast
::NodeId
, vis
: &hir
::Visibility
) -> bool
{
655 self.access_levels
.is_reachable(*id
) || *vis
== hir
::Public
659 impl<'a
, 'b
, 'tcx
, 'v
> Visitor
<'v
> for ObsoleteCheckTypeForPrivatenessVisitor
<'a
, 'b
, 'tcx
> {
660 fn visit_ty(&mut self, ty
: &hir
::Ty
) {
661 if let hir
::TyPath(..) = ty
.node
{
662 if self.inner
.path_is_private_type(ty
.id
) {
663 self.contains_private
= true;
664 // found what we're looking for so let's stop
667 } else if self.at_outer_type
{
668 self.outer_type_is_public_path
= true;
671 self.at_outer_type
= false;
672 intravisit
::walk_ty(self, ty
)
675 // don't want to recurse into [, .. expr]
676 fn visit_expr(&mut self, _
: &hir
::Expr
) {}
679 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for ObsoleteVisiblePrivateTypesVisitor
<'a
, 'tcx
> {
680 /// We want to visit items in the context of their containing
681 /// module and so forth, so supply a crate for doing a deep walk.
682 fn visit_nested_item(&mut self, item
: hir
::ItemId
) {
683 self.visit_item(self.tcx
.map
.expect_item(item
.id
))
686 fn visit_item(&mut self, item
: &hir
::Item
) {
688 // contents of a private mod can be reexported, so we need
689 // to check internals.
690 hir
::ItemMod(_
) => {}
692 // An `extern {}` doesn't introduce a new privacy
693 // namespace (the contents have their own privacies).
694 hir
::ItemForeignMod(_
) => {}
696 hir
::ItemTrait(_
, _
, ref bounds
, _
) => {
697 if !self.trait_is_public(item
.id
) {
701 for bound
in bounds
.iter() {
702 self.check_ty_param_bound(bound
)
706 // impls need some special handling to try to offer useful
707 // error messages without (too many) false positives
708 // (i.e. we could just return here to not check them at
709 // all, or some worse estimation of whether an impl is
710 // publicly visible).
711 hir
::ItemImpl(_
, _
, ref g
, ref trait_ref
, ref self_
, ref impl_items
) => {
712 // `impl [... for] Private` is never visible.
713 let self_contains_private
;
714 // impl [... for] Public<...>, but not `impl [... for]
715 // Vec<Public>` or `(Public,)` etc.
716 let self_is_public_path
;
718 // check the properties of the Self type:
720 let mut visitor
= ObsoleteCheckTypeForPrivatenessVisitor
{
722 contains_private
: false,
724 outer_type_is_public_path
: false,
726 visitor
.visit_ty(&self_
);
727 self_contains_private
= visitor
.contains_private
;
728 self_is_public_path
= visitor
.outer_type_is_public_path
;
731 // miscellaneous info about the impl
733 // `true` iff this is `impl Private for ...`.
734 let not_private_trait
=
735 trait_ref
.as_ref().map_or(true, // no trait counts as public trait
737 let did
= self.tcx
.trait_ref_to_def_id(tr
);
739 if let Some(node_id
) = self.tcx
.map
.as_local_node_id(did
) {
740 self.trait_is_public(node_id
)
742 true // external traits must be public
746 // `true` iff this is a trait impl or at least one method is public.
748 // `impl Public { $( fn ...() {} )* }` is not visible.
750 // This is required over just using the methods' privacy
751 // directly because we might have `impl<T: Foo<Private>> ...`,
752 // and we shouldn't warn about the generics if all the methods
753 // are private (because `T` won't be visible externally).
754 let trait_or_some_public_method
=
755 trait_ref
.is_some() ||
758 match impl_item
.node
{
759 hir
::ImplItemKind
::Const(..) |
760 hir
::ImplItemKind
::Method(..) => {
761 self.access_levels
.is_reachable(impl_item
.id
)
763 hir
::ImplItemKind
::Type(_
) => false,
767 if !self_contains_private
&&
769 trait_or_some_public_method
{
771 intravisit
::walk_generics(self, g
);
775 for impl_item
in impl_items
{
776 // This is where we choose whether to walk down
777 // further into the impl to check its items. We
778 // should only walk into public items so that we
779 // don't erroneously report errors for private
780 // types in private items.
781 match impl_item
.node
{
782 hir
::ImplItemKind
::Const(..) |
783 hir
::ImplItemKind
::Method(..)
784 if self.item_is_public(&impl_item
.id
, &impl_item
.vis
) =>
786 intravisit
::walk_impl_item(self, impl_item
)
788 hir
::ImplItemKind
::Type(..) => {
789 intravisit
::walk_impl_item(self, impl_item
)
796 // Any private types in a trait impl fall into three
798 // 1. mentioned in the trait definition
799 // 2. mentioned in the type params/generics
800 // 3. mentioned in the associated types of the impl
802 // Those in 1. can only occur if the trait is in
803 // this crate and will've been warned about on the
804 // trait definition (there's no need to warn twice
805 // so we don't check the methods).
807 // Those in 2. are warned via walk_generics and this
809 intravisit
::walk_path(self, &tr
.path
);
811 // Those in 3. are warned with this call.
812 for impl_item
in impl_items
{
813 if let hir
::ImplItemKind
::Type(ref ty
) = impl_item
.node
{
819 } else if trait_ref
.is_none() && self_is_public_path
{
820 // impl Public<Private> { ... }. Any public static
821 // methods will be visible as `Public::foo`.
822 let mut found_pub_static
= false;
823 for impl_item
in impl_items
{
824 match impl_item
.node
{
825 hir
::ImplItemKind
::Const(..) => {
826 if self.item_is_public(&impl_item
.id
, &impl_item
.vis
) {
827 found_pub_static
= true;
828 intravisit
::walk_impl_item(self, impl_item
);
831 hir
::ImplItemKind
::Method(ref sig
, _
) => {
832 if sig
.explicit_self
.node
== hir
::SelfStatic
&&
833 self.item_is_public(&impl_item
.id
, &impl_item
.vis
) {
834 found_pub_static
= true;
835 intravisit
::walk_impl_item(self, impl_item
);
841 if found_pub_static
{
842 intravisit
::walk_generics(self, g
)
848 // `type ... = ...;` can contain private types, because
849 // we're introducing a new name.
850 hir
::ItemTy(..) => return,
852 // not at all public, so we don't care
853 _
if !self.item_is_public(&item
.id
, &item
.vis
) => {
860 // We've carefully constructed it so that if we're here, then
861 // any `visit_ty`'s will be called on things that are in
862 // public signatures, i.e. things that we're interested in for
864 debug
!("VisiblePrivateTypesVisitor entering item {:?}", item
);
865 intravisit
::walk_item(self, item
);
868 fn visit_generics(&mut self, generics
: &hir
::Generics
) {
869 for ty_param
in generics
.ty_params
.iter() {
870 for bound
in ty_param
.bounds
.iter() {
871 self.check_ty_param_bound(bound
)
874 for predicate
in &generics
.where_clause
.predicates
{
876 &hir
::WherePredicate
::BoundPredicate(ref bound_pred
) => {
877 for bound
in bound_pred
.bounds
.iter() {
878 self.check_ty_param_bound(bound
)
881 &hir
::WherePredicate
::RegionPredicate(_
) => {}
882 &hir
::WherePredicate
::EqPredicate(ref eq_pred
) => {
883 self.visit_ty(&eq_pred
.ty
);
889 fn visit_foreign_item(&mut self, item
: &hir
::ForeignItem
) {
890 if self.access_levels
.is_reachable(item
.id
) {
891 intravisit
::walk_foreign_item(self, item
)
895 fn visit_ty(&mut self, t
: &hir
::Ty
) {
896 debug
!("VisiblePrivateTypesVisitor checking ty {:?}", t
);
897 if let hir
::TyPath(..) = t
.node
{
898 if self.path_is_private_type(t
.id
) {
899 self.old_error_set
.insert(t
.id
);
902 intravisit
::walk_ty(self, t
)
905 fn visit_variant(&mut self, v
: &hir
::Variant
, g
: &hir
::Generics
, item_id
: ast
::NodeId
) {
906 if self.access_levels
.is_reachable(v
.node
.data
.id()) {
907 self.in_variant
= true;
908 intravisit
::walk_variant(self, v
, g
, item_id
);
909 self.in_variant
= false;
913 fn visit_struct_field(&mut self, s
: &hir
::StructField
) {
914 if s
.vis
== hir
::Public
|| self.in_variant
{
915 intravisit
::walk_struct_field(self, s
);
919 // we don't need to introspect into these at all: an
920 // expression/block context can't possibly contain exported things.
921 // (Making them no-ops stops us from traversing the whole AST without
922 // having to be super careful about our `walk_...` calls above.)
923 // FIXME(#29524): Unfortunately this ^^^ is not true, blocks can contain
924 // exported items (e.g. impls) and actual code in rustc itself breaks
925 // if we don't traverse blocks in `EmbargoVisitor`
926 fn visit_block(&mut self, _
: &hir
::Block
) {}
927 fn visit_expr(&mut self, _
: &hir
::Expr
) {}
930 ///////////////////////////////////////////////////////////////////////////////
931 /// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and
932 /// finds any private components in it.
933 /// PrivateItemsInPublicInterfacesVisitor ensures there are no private types
934 /// and traits in public interfaces.
935 ///////////////////////////////////////////////////////////////////////////////
937 struct SearchInterfaceForPrivateItemsVisitor
<'a
, 'tcx
: 'a
> {
938 tcx
: &'a TyCtxt
<'tcx
>,
939 /// The visitor checks that each component type is at least this visible
940 required_visibility
: ty
::Visibility
,
941 /// The visibility of the least visible component that has been visited
942 min_visibility
: ty
::Visibility
,
943 old_error_set
: &'a NodeSet
,
946 impl<'a
, 'tcx
: 'a
> SearchInterfaceForPrivateItemsVisitor
<'a
, 'tcx
> {
947 fn new(tcx
: &'a TyCtxt
<'tcx
>, old_error_set
: &'a NodeSet
) -> Self {
948 SearchInterfaceForPrivateItemsVisitor
{
950 min_visibility
: ty
::Visibility
::Public
,
951 required_visibility
: ty
::Visibility
::PrivateExternal
,
952 old_error_set
: old_error_set
,
957 impl<'a
, 'tcx
: 'a
> SearchInterfaceForPrivateItemsVisitor
<'a
, 'tcx
> {
958 // Return the visibility of the type alias's least visible component type when substituted
959 fn substituted_alias_visibility(&self, item
: &hir
::Item
, path
: &hir
::Path
)
960 -> Option
<ty
::Visibility
> {
961 // We substitute type aliases only when determining impl publicity
962 // FIXME: This will probably change and all type aliases will be substituted,
963 // requires an amendment to RFC 136.
964 if self.required_visibility
!= ty
::Visibility
::PrivateExternal
{
967 // Type alias is considered public if the aliased type is
968 // public, even if the type alias itself is private. So, something
969 // like `type A = u8; pub fn f() -> A {...}` doesn't cause an error.
970 if let hir
::ItemTy(ref ty
, ref generics
) = item
.node
{
971 let mut check
= SearchInterfaceForPrivateItemsVisitor
{
972 min_visibility
: ty
::Visibility
::Public
, ..*self
975 // If a private type alias with default type parameters is used in public
976 // interface we must ensure, that the defaults are public if they are actually used.
978 // type Alias<T = Private> = T;
979 // pub fn f() -> Alias {...} // `Private` is implicitly used here, so it must be public
981 let provided_params
= path
.segments
.last().unwrap().parameters
.types().len();
982 for ty_param
in &generics
.ty_params
[provided_params
..] {
983 if let Some(ref default_ty
) = ty_param
.default {
984 check
.visit_ty(default_ty
);
987 Some(check
.min_visibility
)
994 impl<'a
, 'tcx
: 'a
, 'v
> Visitor
<'v
> for SearchInterfaceForPrivateItemsVisitor
<'a
, 'tcx
> {
995 fn visit_ty(&mut self, ty
: &hir
::Ty
) {
996 if let hir
::TyPath(_
, ref path
) = ty
.node
{
997 let def
= self.tcx
.def_map
.borrow().get(&ty
.id
).unwrap().full_def();
999 Def
::PrimTy(..) | Def
::SelfTy(..) | Def
::TyParam(..) => {
1002 Def
::AssociatedTy(..)
1003 if self.required_visibility
== ty
::Visibility
::PrivateExternal
=> {
1004 // Conservatively approximate the whole type alias as public without
1005 // recursing into its components when determining impl publicity.
1006 // For example, `impl <Type as Trait>::Alias {...}` may be a public impl
1007 // even if both `Type` and `Trait` are private.
1008 // Ideally, associated types should be substituted in the same way as
1009 // free type aliases, but this isn't done yet.
1012 Def
::Struct(def_id
) | Def
::Enum(def_id
) | Def
::TyAlias(def_id
) |
1013 Def
::Trait(def_id
) | Def
::AssociatedTy(def_id
, _
) => {
1014 // Non-local means public (private items can't leave their crate, modulo bugs)
1015 if let Some(node_id
) = self.tcx
.map
.as_local_node_id(def_id
) {
1016 let item
= self.tcx
.map
.expect_item(node_id
);
1017 let vis
= match self.substituted_alias_visibility(item
, path
) {
1019 None
=> ty
::Visibility
::from_hir(&item
.vis
, node_id
, &self.tcx
),
1022 if !vis
.is_at_least(self.min_visibility
, &self.tcx
.map
) {
1023 self.min_visibility
= vis
;
1025 if !vis
.is_at_least(self.required_visibility
, &self.tcx
.map
) {
1026 if self.old_error_set
.contains(&ty
.id
) {
1027 span_err
!(self.tcx
.sess
, ty
.span
, E0446
,
1028 "private type in public interface");
1030 self.tcx
.sess
.add_lint(lint
::builtin
::PRIVATE_IN_PUBLIC
,
1033 format
!("private type in public interface"));
1042 intravisit
::walk_ty(self, ty
);
1045 fn visit_trait_ref(&mut self, trait_ref
: &hir
::TraitRef
) {
1046 // Non-local means public (private items can't leave their crate, modulo bugs)
1047 let def_id
= self.tcx
.trait_ref_to_def_id(trait_ref
);
1048 if let Some(node_id
) = self.tcx
.map
.as_local_node_id(def_id
) {
1049 let item
= self.tcx
.map
.expect_item(node_id
);
1050 let vis
= ty
::Visibility
::from_hir(&item
.vis
, node_id
, &self.tcx
);
1052 if !vis
.is_at_least(self.min_visibility
, &self.tcx
.map
) {
1053 self.min_visibility
= vis
;
1055 if !vis
.is_at_least(self.required_visibility
, &self.tcx
.map
) {
1056 if self.old_error_set
.contains(&trait_ref
.ref_id
) {
1057 span_err
!(self.tcx
.sess
, trait_ref
.path
.span
, E0445
,
1058 "private trait in public interface");
1060 self.tcx
.sess
.add_lint(lint
::builtin
::PRIVATE_IN_PUBLIC
,
1062 trait_ref
.path
.span
,
1063 "private trait in public interface (error E0445)"
1069 intravisit
::walk_trait_ref(self, trait_ref
);
1072 // Don't recurse into function bodies
1073 fn visit_block(&mut self, _
: &hir
::Block
) {}
1074 // Don't recurse into expressions in array sizes or const initializers
1075 fn visit_expr(&mut self, _
: &hir
::Expr
) {}
1076 // Don't recurse into patterns in function arguments
1077 fn visit_pat(&mut self, _
: &hir
::Pat
) {}
1080 struct PrivateItemsInPublicInterfacesVisitor
<'a
, 'tcx
: 'a
> {
1081 tcx
: &'a TyCtxt
<'tcx
>,
1082 old_error_set
: &'a NodeSet
,
1085 impl<'a
, 'tcx
> PrivateItemsInPublicInterfacesVisitor
<'a
, 'tcx
> {
1086 // A type is considered public if it doesn't contain any private components
1087 fn ty_visibility(&self, ty
: &hir
::Ty
) -> ty
::Visibility
{
1088 let mut check
= SearchInterfaceForPrivateItemsVisitor
::new(self.tcx
, self.old_error_set
);
1090 check
.min_visibility
1093 // A trait reference is considered public if it doesn't contain any private components
1094 fn trait_ref_visibility(&self, trait_ref
: &hir
::TraitRef
) -> ty
::Visibility
{
1095 let mut check
= SearchInterfaceForPrivateItemsVisitor
::new(self.tcx
, self.old_error_set
);
1096 check
.visit_trait_ref(trait_ref
);
1097 check
.min_visibility
1101 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for PrivateItemsInPublicInterfacesVisitor
<'a
, 'tcx
> {
1102 fn visit_item(&mut self, item
: &hir
::Item
) {
1103 let min
= |vis1
: ty
::Visibility
, vis2
| {
1104 if vis1
.is_at_least(vis2
, &self.tcx
.map
) { vis2 }
else { vis1 }
1107 let mut check
= SearchInterfaceForPrivateItemsVisitor
::new(self.tcx
, self.old_error_set
);
1108 let item_visibility
= ty
::Visibility
::from_hir(&item
.vis
, item
.id
, &self.tcx
);
1111 // Crates are always public
1112 hir
::ItemExternCrate(..) => {}
1113 // All nested items are checked by visit_item
1114 hir
::ItemMod(..) => {}
1115 // Checked in resolve
1116 hir
::ItemUse(..) => {}
1117 // Subitems of these items have inherited publicity
1118 hir
::ItemConst(..) | hir
::ItemStatic(..) | hir
::ItemFn(..) |
1119 hir
::ItemEnum(..) | hir
::ItemTrait(..) | hir
::ItemTy(..) => {
1120 check
.required_visibility
= item_visibility
;
1121 check
.visit_item(item
);
1123 // Subitems of foreign modules have their own publicity
1124 hir
::ItemForeignMod(ref foreign_mod
) => {
1125 for foreign_item
in &foreign_mod
.items
{
1126 check
.required_visibility
=
1127 ty
::Visibility
::from_hir(&foreign_item
.vis
, item
.id
, &self.tcx
);
1128 check
.visit_foreign_item(foreign_item
);
1131 // Subitems of structs have their own publicity
1132 hir
::ItemStruct(ref struct_def
, ref generics
) => {
1133 check
.required_visibility
= item_visibility
;
1134 check
.visit_generics(generics
);
1136 for field
in struct_def
.fields() {
1137 let field_visibility
= ty
::Visibility
::from_hir(&field
.vis
, item
.id
, &self.tcx
);
1138 check
.required_visibility
= min(item_visibility
, field_visibility
);
1139 check
.visit_struct_field(field
);
1142 // The interface is empty
1143 hir
::ItemDefaultImpl(..) => {}
1144 // An inherent impl is public when its type is public
1145 // Subitems of inherent impls have their own publicity
1146 hir
::ItemImpl(_
, _
, ref generics
, None
, ref ty
, ref impl_items
) => {
1147 let ty_vis
= self.ty_visibility(ty
);
1148 check
.required_visibility
= ty_vis
;
1149 check
.visit_generics(generics
);
1151 for impl_item
in impl_items
{
1153 ty
::Visibility
::from_hir(&impl_item
.vis
, item
.id
, &self.tcx
);
1154 check
.required_visibility
= min(impl_item_vis
, ty_vis
);
1155 check
.visit_impl_item(impl_item
);
1158 // A trait impl is public when both its type and its trait are public
1159 // Subitems of trait impls have inherited publicity
1160 hir
::ItemImpl(_
, _
, ref generics
, Some(ref trait_ref
), ref ty
, ref impl_items
) => {
1161 let vis
= min(self.ty_visibility(ty
), self.trait_ref_visibility(trait_ref
));
1162 check
.required_visibility
= vis
;
1163 check
.visit_generics(generics
);
1164 for impl_item
in impl_items
{
1165 check
.visit_impl_item(impl_item
);
1172 pub fn check_crate(tcx
: &TyCtxt
, export_map
: &def
::ExportMap
) -> AccessLevels
{
1173 let _task
= tcx
.dep_graph
.in_task(DepNode
::Privacy
);
1175 let krate
= tcx
.map
.krate();
1177 // Sanity check to make sure that all privacy usage is reasonable.
1178 let mut visitor
= SanePrivacyVisitor { tcx: tcx }
;
1179 krate
.visit_all_items(&mut visitor
);
1181 // Use the parent map to check the privacy of everything
1182 let mut visitor
= PrivacyVisitor
{
1183 curitem
: ast
::DUMMY_NODE_ID
,
1187 intravisit
::walk_crate(&mut visitor
, krate
);
1189 tcx
.sess
.abort_if_errors();
1191 // Build up a set of all exported items in the AST. This is a set of all
1192 // items which are reachable from external crates based on visibility.
1193 let mut visitor
= EmbargoVisitor
{
1195 export_map
: export_map
,
1196 access_levels
: Default
::default(),
1197 prev_level
: Some(AccessLevel
::Public
),
1201 intravisit
::walk_crate(&mut visitor
, krate
);
1202 if visitor
.changed
{
1203 visitor
.changed
= false;
1208 visitor
.update(ast
::CRATE_NODE_ID
, Some(AccessLevel
::Public
));
1211 let mut visitor
= ObsoleteVisiblePrivateTypesVisitor
{
1213 access_levels
: &visitor
.access_levels
,
1215 old_error_set
: NodeSet(),
1217 intravisit
::walk_crate(&mut visitor
, krate
);
1219 // Check for private types and traits in public interfaces
1220 let mut visitor
= PrivateItemsInPublicInterfacesVisitor
{
1222 old_error_set
: &visitor
.old_error_set
,
1224 krate
.visit_all_items(&mut visitor
);
1227 visitor
.access_levels
1230 __build_diagnostic_array
! { librustc_privacy, DIAGNOSTICS }