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 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
12 html_favicon_url
= "https://doc.rust-lang.org/favicon.ico",
13 html_root_url
= "https://doc.rust-lang.org/nightly/")]
16 #![feature(rustc_diagnostic_macros)]
18 #[macro_use] extern crate rustc;
19 #[macro_use] extern crate syntax;
20 extern crate rustc_typeck
;
21 extern crate syntax_pos
;
23 use rustc
::hir
::{self, PatKind}
;
24 use rustc
::hir
::def
::Def
;
25 use rustc
::hir
::def_id
::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId}
;
26 use rustc
::hir
::intravisit
::{self, Visitor, NestedVisitorMap}
;
27 use rustc
::hir
::itemlikevisit
::DeepVisitor
;
29 use rustc
::middle
::privacy
::{AccessLevel, AccessLevels}
;
30 use rustc
::ty
::{self, TyCtxt, Ty, TypeFoldable}
;
31 use rustc
::ty
::fold
::TypeVisitor
;
32 use rustc
::ty
::maps
::Providers
;
33 use rustc
::util
::nodemap
::NodeSet
;
34 use syntax
::ast
::{self, CRATE_NODE_ID, Ident}
;
35 use syntax
::symbol
::keywords
;
39 use std
::mem
::replace
;
44 ////////////////////////////////////////////////////////////////////////////////
45 /// Visitor used to determine if pub(restricted) is used anywhere in the crate.
47 /// This is done so that `private_in_public` warnings can be turned into hard errors
48 /// in crates that have been updated to use pub(restricted).
49 ////////////////////////////////////////////////////////////////////////////////
50 struct PubRestrictedVisitor
<'a
, 'tcx
: 'a
> {
51 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
52 has_pub_restricted
: bool
,
55 impl<'a
, 'tcx
> Visitor
<'tcx
> for PubRestrictedVisitor
<'a
, 'tcx
> {
56 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'tcx
> {
57 NestedVisitorMap
::All(&self.tcx
.hir
)
59 fn visit_vis(&mut self, vis
: &'tcx hir
::Visibility
) {
60 self.has_pub_restricted
= self.has_pub_restricted
|| vis
.is_pub_restricted();
64 ////////////////////////////////////////////////////////////////////////////////
65 /// The embargo visitor, used to determine the exports of the ast
66 ////////////////////////////////////////////////////////////////////////////////
68 struct EmbargoVisitor
<'a
, 'tcx
: 'a
> {
69 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
71 // Accessibility levels for reachable nodes
72 access_levels
: AccessLevels
,
73 // Previous accessibility level, None means unreachable
74 prev_level
: Option
<AccessLevel
>,
75 // Have something changed in the level map?
79 struct ReachEverythingInTheInterfaceVisitor
<'b
, 'a
: 'b
, 'tcx
: 'a
> {
81 ev
: &'b
mut EmbargoVisitor
<'a
, 'tcx
>,
84 impl<'a
, 'tcx
> EmbargoVisitor
<'a
, 'tcx
> {
85 fn item_ty_level(&self, item_def_id
: DefId
) -> Option
<AccessLevel
> {
86 let ty_def_id
= match self.tcx
.type_of(item_def_id
).sty
{
87 ty
::TyAdt(adt
, _
) => adt
.did
,
88 ty
::TyForeign(did
) => did
,
89 ty
::TyDynamic(ref obj
, ..) if obj
.principal().is_some() =>
90 obj
.principal().unwrap().def_id(),
91 ty
::TyProjection(ref proj
) => proj
.trait_ref(self.tcx
).def_id
,
92 _
=> return Some(AccessLevel
::Public
)
94 if let Some(node_id
) = self.tcx
.hir
.as_local_node_id(ty_def_id
) {
97 Some(AccessLevel
::Public
)
101 fn impl_trait_level(&self, impl_def_id
: DefId
) -> Option
<AccessLevel
> {
102 if let Some(trait_ref
) = self.tcx
.impl_trait_ref(impl_def_id
) {
103 if let Some(node_id
) = self.tcx
.hir
.as_local_node_id(trait_ref
.def_id
) {
104 return self.get(node_id
);
107 Some(AccessLevel
::Public
)
110 fn get(&self, id
: ast
::NodeId
) -> Option
<AccessLevel
> {
111 self.access_levels
.map
.get(&id
).cloned()
114 // Updates node level and returns the updated level
115 fn update(&mut self, id
: ast
::NodeId
, level
: Option
<AccessLevel
>) -> Option
<AccessLevel
> {
116 let old_level
= self.get(id
);
117 // Accessibility levels can only grow
118 if level
> old_level
{
119 self.access_levels
.map
.insert(id
, level
.unwrap());
127 fn reach
<'b
>(&'b
mut self, item_id
: ast
::NodeId
)
128 -> ReachEverythingInTheInterfaceVisitor
<'b
, 'a
, 'tcx
> {
129 ReachEverythingInTheInterfaceVisitor
{
130 item_def_id
: self.tcx
.hir
.local_def_id(item_id
),
136 impl<'a
, 'tcx
> Visitor
<'tcx
> for EmbargoVisitor
<'a
, 'tcx
> {
137 /// We want to visit items in the context of their containing
138 /// module and so forth, so supply a crate for doing a deep walk.
139 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'tcx
> {
140 NestedVisitorMap
::All(&self.tcx
.hir
)
143 fn visit_item(&mut self, item
: &'tcx hir
::Item
) {
144 let inherited_item_level
= match item
.node
{
145 // Impls inherit level from their types and traits
146 hir
::ItemImpl(..) => {
147 let def_id
= self.tcx
.hir
.local_def_id(item
.id
);
148 cmp
::min(self.item_ty_level(def_id
), self.impl_trait_level(def_id
))
150 // Foreign mods inherit level from parents
151 hir
::ItemForeignMod(..) => {
154 // Other `pub` items inherit levels from parents
155 hir
::ItemConst(..) | hir
::ItemEnum(..) | hir
::ItemExternCrate(..) |
156 hir
::ItemGlobalAsm(..) | hir
::ItemFn(..) | hir
::ItemMod(..) |
157 hir
::ItemStatic(..) | hir
::ItemStruct(..) |
158 hir
::ItemTrait(..) | hir
::ItemTraitAlias(..) |
159 hir
::ItemTy(..) | hir
::ItemUnion(..) | hir
::ItemUse(..) => {
160 if item
.vis
== hir
::Public { self.prev_level }
else { None }
164 // Update level of the item itself
165 let item_level
= self.update(item
.id
, inherited_item_level
);
167 // Update levels of nested things
169 hir
::ItemEnum(ref def
, _
) => {
170 for variant
in &def
.variants
{
171 let variant_level
= self.update(variant
.node
.data
.id(), item_level
);
172 for field
in variant
.node
.data
.fields() {
173 self.update(field
.id
, variant_level
);
177 hir
::ItemImpl(.., None
, _
, ref impl_item_refs
) => {
178 for impl_item_ref
in impl_item_refs
{
179 if impl_item_ref
.vis
== hir
::Public
{
180 self.update(impl_item_ref
.id
.node_id
, item_level
);
184 hir
::ItemImpl(.., Some(_
), _
, ref impl_item_refs
) => {
185 for impl_item_ref
in impl_item_refs
{
186 self.update(impl_item_ref
.id
.node_id
, item_level
);
189 hir
::ItemTrait(.., ref trait_item_refs
) => {
190 for trait_item_ref
in trait_item_refs
{
191 self.update(trait_item_ref
.id
.node_id
, item_level
);
194 hir
::ItemStruct(ref def
, _
) | hir
::ItemUnion(ref def
, _
) => {
195 if !def
.is_struct() {
196 self.update(def
.id(), item_level
);
198 for field
in def
.fields() {
199 if field
.vis
== hir
::Public
{
200 self.update(field
.id
, item_level
);
204 hir
::ItemForeignMod(ref foreign_mod
) => {
205 for foreign_item
in &foreign_mod
.items
{
206 if foreign_item
.vis
== hir
::Public
{
207 self.update(foreign_item
.id
, item_level
);
211 hir
::ItemUse(..) | hir
::ItemStatic(..) | hir
::ItemConst(..) |
212 hir
::ItemGlobalAsm(..) | hir
::ItemTy(..) | hir
::ItemMod(..) | hir
::ItemTraitAlias(..) |
213 hir
::ItemFn(..) | hir
::ItemExternCrate(..) => {}
216 // Mark all items in interfaces of reachable items as reachable
218 // The interface is empty
219 hir
::ItemExternCrate(..) => {}
220 // All nested items are checked by visit_item
221 hir
::ItemMod(..) => {}
222 // Re-exports are handled in visit_mod
223 hir
::ItemUse(..) => {}
224 // The interface is empty
225 hir
::ItemGlobalAsm(..) => {}
227 hir
::ItemConst(..) | hir
::ItemStatic(..) |
228 hir
::ItemFn(..) | hir
::ItemTy(..) => {
229 if item_level
.is_some() {
230 self.reach(item
.id
).generics().predicates().ty();
233 hir
::ItemTrait(.., ref trait_item_refs
) => {
234 if item_level
.is_some() {
235 self.reach(item
.id
).generics().predicates();
237 for trait_item_ref
in trait_item_refs
{
238 let mut reach
= self.reach(trait_item_ref
.id
.node_id
);
239 reach
.generics().predicates();
241 if trait_item_ref
.kind
== hir
::AssociatedItemKind
::Type
&&
242 !trait_item_ref
.defaultness
.has_value() {
250 hir
::ItemTraitAlias(..) => {
251 if item_level
.is_some() {
252 self.reach(item
.id
).generics().predicates();
255 // Visit everything except for private impl items
256 hir
::ItemImpl(.., ref trait_ref
, _
, ref impl_item_refs
) => {
257 if item_level
.is_some() {
258 self.reach(item
.id
).generics().predicates().impl_trait_ref();
260 for impl_item_ref
in impl_item_refs
{
261 let id
= impl_item_ref
.id
.node_id
;
262 if trait_ref
.is_some() || self.get(id
).is_some() {
263 self.reach(id
).generics().predicates().ty();
269 // Visit everything, but enum variants have their own levels
270 hir
::ItemEnum(ref def
, _
) => {
271 if item_level
.is_some() {
272 self.reach(item
.id
).generics().predicates();
274 for variant
in &def
.variants
{
275 if self.get(variant
.node
.data
.id()).is_some() {
276 for field
in variant
.node
.data
.fields() {
277 self.reach(field
.id
).ty();
279 // Corner case: if the variant is reachable, but its
280 // enum is not, make the enum reachable as well.
281 self.update(item
.id
, Some(AccessLevel
::Reachable
));
285 // Visit everything, but foreign items have their own levels
286 hir
::ItemForeignMod(ref foreign_mod
) => {
287 for foreign_item
in &foreign_mod
.items
{
288 if self.get(foreign_item
.id
).is_some() {
289 self.reach(foreign_item
.id
).generics().predicates().ty();
293 // Visit everything except for private fields
294 hir
::ItemStruct(ref struct_def
, _
) |
295 hir
::ItemUnion(ref struct_def
, _
) => {
296 if item_level
.is_some() {
297 self.reach(item
.id
).generics().predicates();
298 for field
in struct_def
.fields() {
299 if self.get(field
.id
).is_some() {
300 self.reach(field
.id
).ty();
307 let orig_level
= self.prev_level
;
308 self.prev_level
= item_level
;
310 intravisit
::walk_item(self, item
);
312 self.prev_level
= orig_level
;
315 fn visit_block(&mut self, b
: &'tcx hir
::Block
) {
316 let orig_level
= replace(&mut self.prev_level
, None
);
318 // Blocks can have public items, for example impls, but they always
319 // start as completely private regardless of publicity of a function,
320 // constant, type, field, etc. in which this block resides
321 intravisit
::walk_block(self, b
);
323 self.prev_level
= orig_level
;
326 fn visit_mod(&mut self, m
: &'tcx hir
::Mod
, _sp
: Span
, id
: ast
::NodeId
) {
327 // This code is here instead of in visit_item so that the
328 // crate module gets processed as well.
329 if self.prev_level
.is_some() {
330 let def_id
= self.tcx
.hir
.local_def_id(id
);
331 if let Some(exports
) = self.tcx
.module_exports(def_id
) {
332 for export
in exports
.iter() {
333 if let Some(node_id
) = self.tcx
.hir
.as_local_node_id(export
.def
.def_id()) {
334 if export
.vis
== ty
::Visibility
::Public
{
335 self.update(node_id
, Some(AccessLevel
::Exported
));
342 intravisit
::walk_mod(self, m
, id
);
345 fn visit_macro_def(&mut self, md
: &'tcx hir
::MacroDef
) {
347 self.update(md
.id
, Some(AccessLevel
::Public
));
351 let module_did
= ty
::DefIdTree
::parent(self.tcx
, self.tcx
.hir
.local_def_id(md
.id
)).unwrap();
352 let mut module_id
= self.tcx
.hir
.as_local_node_id(module_did
).unwrap();
353 let level
= if md
.vis
== hir
::Public { self.get(module_id) }
else { None }
;
354 let level
= self.update(md
.id
, level
);
360 let module
= if module_id
== ast
::CRATE_NODE_ID
{
361 &self.tcx
.hir
.krate().module
362 } else if let hir
::ItemMod(ref module
) = self.tcx
.hir
.expect_item(module_id
).node
{
367 for id
in &module
.item_ids
{
368 self.update(id
.id
, level
);
370 let def_id
= self.tcx
.hir
.local_def_id(module_id
);
371 if let Some(exports
) = self.tcx
.module_exports(def_id
) {
372 for export
in exports
.iter() {
373 if let Some(node_id
) = self.tcx
.hir
.as_local_node_id(export
.def
.def_id()) {
374 self.update(node_id
, level
);
379 if module_id
== ast
::CRATE_NODE_ID
{
382 module_id
= self.tcx
.hir
.get_parent_node(module_id
);
386 fn visit_ty(&mut self, ty
: &'tcx hir
::Ty
) {
387 if let hir
::TyImplTraitExistential(..) = ty
.node
{
388 if self.get(ty
.id
).is_some() {
389 // Reach the (potentially private) type and the API being exposed.
390 self.reach(ty
.id
).ty().predicates();
394 intravisit
::walk_ty(self, ty
);
398 impl<'b
, 'a
, 'tcx
> ReachEverythingInTheInterfaceVisitor
<'b
, 'a
, 'tcx
> {
399 fn generics(&mut self) -> &mut Self {
400 for def
in &self.ev
.tcx
.generics_of(self.item_def_id
).types
{
402 self.ev
.tcx
.type_of(def
.def_id
).visit_with(self);
408 fn predicates(&mut self) -> &mut Self {
409 let predicates
= self.ev
.tcx
.predicates_of(self.item_def_id
);
410 for predicate
in &predicates
.predicates
{
411 predicate
.visit_with(self);
413 &ty
::Predicate
::Trait(poly_predicate
) => {
414 self.check_trait_ref(poly_predicate
.skip_binder().trait_ref
);
416 &ty
::Predicate
::Projection(poly_predicate
) => {
417 let tcx
= self.ev
.tcx
;
418 self.check_trait_ref(
419 poly_predicate
.skip_binder().projection_ty
.trait_ref(tcx
)
428 fn ty(&mut self) -> &mut Self {
429 let ty
= self.ev
.tcx
.type_of(self.item_def_id
);
431 if let ty
::TyFnDef(def_id
, _
) = ty
.sty
{
432 if def_id
== self.item_def_id
{
433 self.ev
.tcx
.fn_sig(def_id
).visit_with(self);
439 fn impl_trait_ref(&mut self) -> &mut Self {
440 if let Some(impl_trait_ref
) = self.ev
.tcx
.impl_trait_ref(self.item_def_id
) {
441 self.check_trait_ref(impl_trait_ref
);
442 impl_trait_ref
.super_visit_with(self);
447 fn check_trait_ref(&mut self, trait_ref
: ty
::TraitRef
<'tcx
>) {
448 if let Some(node_id
) = self.ev
.tcx
.hir
.as_local_node_id(trait_ref
.def_id
) {
449 let item
= self.ev
.tcx
.hir
.expect_item(node_id
);
450 self.ev
.update(item
.id
, Some(AccessLevel
::Reachable
));
455 impl<'b
, 'a
, 'tcx
> TypeVisitor
<'tcx
> for ReachEverythingInTheInterfaceVisitor
<'b
, 'a
, 'tcx
> {
456 fn visit_ty(&mut self, ty
: Ty
<'tcx
>) -> bool
{
457 let ty_def_id
= match ty
.sty
{
458 ty
::TyAdt(adt
, _
) => Some(adt
.did
),
459 ty
::TyForeign(did
) => Some(did
),
460 ty
::TyDynamic(ref obj
, ..) => obj
.principal().map(|p
| p
.def_id()),
461 ty
::TyProjection(ref proj
) => Some(proj
.item_def_id
),
462 ty
::TyFnDef(def_id
, ..) |
463 ty
::TyClosure(def_id
, ..) |
464 ty
::TyGenerator(def_id
, ..) |
465 ty
::TyAnon(def_id
, _
) => Some(def_id
),
469 if let Some(def_id
) = ty_def_id
{
470 if let Some(node_id
) = self.ev
.tcx
.hir
.as_local_node_id(def_id
) {
471 self.ev
.update(node_id
, Some(AccessLevel
::Reachable
));
475 ty
.super_visit_with(self)
479 //////////////////////////////////////////////////////////////////////////////////////
480 /// Name privacy visitor, checks privacy and reports violations.
481 /// Most of name privacy checks are performed during the main resolution phase,
482 /// or later in type checking when field accesses and associated items are resolved.
483 /// This pass performs remaining checks for fields in struct expressions and patterns.
484 //////////////////////////////////////////////////////////////////////////////////////
486 struct NamePrivacyVisitor
<'a
, 'tcx
: 'a
> {
487 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
488 tables
: &'a ty
::TypeckTables
<'tcx
>,
489 current_item
: ast
::NodeId
,
490 empty_tables
: &'a ty
::TypeckTables
<'tcx
>,
493 impl<'a
, 'tcx
> NamePrivacyVisitor
<'a
, 'tcx
> {
494 // Checks that a field is accessible.
495 fn check_field(&mut self, span
: Span
, def
: &'tcx ty
::AdtDef
, field
: &'tcx ty
::FieldDef
) {
496 let ident
= Ident { ctxt: span.ctxt().modern(), ..keywords::Invalid.ident() }
;
497 let def_id
= self.tcx
.adjust_ident(ident
, def
.did
, self.current_item
).1;
498 if !def
.is_enum() && !field
.vis
.is_accessible_from(def_id
, self.tcx
) {
499 struct_span_err
!(self.tcx
.sess
, span
, E0451
, "field `{}` of {} `{}` is private",
500 field
.name
, def
.variant_descr(), self.tcx
.item_path_str(def
.did
))
501 .span_label(span
, format
!("field `{}` is private", field
.name
))
507 // Set the correct TypeckTables for the given `item_id` (or an empty table if
508 // there is no TypeckTables for the item).
509 fn update_tables
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
510 item_id
: ast
::NodeId
,
511 tables
: &mut &'a ty
::TypeckTables
<'tcx
>,
512 empty_tables
: &'a ty
::TypeckTables
<'tcx
>)
513 -> &'a ty
::TypeckTables
<'tcx
> {
514 let def_id
= tcx
.hir
.local_def_id(item_id
);
516 if tcx
.has_typeck_tables(def_id
) {
517 replace(tables
, tcx
.typeck_tables_of(def_id
))
519 replace(tables
, empty_tables
)
523 impl<'a
, 'tcx
> Visitor
<'tcx
> for NamePrivacyVisitor
<'a
, 'tcx
> {
524 /// We want to visit items in the context of their containing
525 /// module and so forth, so supply a crate for doing a deep walk.
526 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'tcx
> {
527 NestedVisitorMap
::All(&self.tcx
.hir
)
530 fn visit_nested_body(&mut self, body
: hir
::BodyId
) {
531 let orig_tables
= replace(&mut self.tables
, self.tcx
.body_tables(body
));
532 let body
= self.tcx
.hir
.body(body
);
533 self.visit_body(body
);
534 self.tables
= orig_tables
;
537 fn visit_item(&mut self, item
: &'tcx hir
::Item
) {
538 let orig_current_item
= replace(&mut self.current_item
, item
.id
);
539 let orig_tables
= update_tables(self.tcx
, item
.id
, &mut self.tables
, self.empty_tables
);
540 intravisit
::walk_item(self, item
);
541 self.current_item
= orig_current_item
;
542 self.tables
= orig_tables
;
545 fn visit_trait_item(&mut self, ti
: &'tcx hir
::TraitItem
) {
546 let orig_tables
= update_tables(self.tcx
, ti
.id
, &mut self.tables
, self.empty_tables
);
547 intravisit
::walk_trait_item(self, ti
);
548 self.tables
= orig_tables
;
551 fn visit_impl_item(&mut self, ii
: &'tcx hir
::ImplItem
) {
552 let orig_tables
= update_tables(self.tcx
, ii
.id
, &mut self.tables
, self.empty_tables
);
553 intravisit
::walk_impl_item(self, ii
);
554 self.tables
= orig_tables
;
557 fn visit_expr(&mut self, expr
: &'tcx hir
::Expr
) {
559 hir
::ExprStruct(ref qpath
, ref fields
, ref base
) => {
560 let def
= self.tables
.qpath_def(qpath
, expr
.hir_id
);
561 let adt
= self.tables
.expr_ty(expr
).ty_adt_def().unwrap();
562 let variant
= adt
.variant_of_def(def
);
563 if let Some(ref base
) = *base
{
564 // If the expression uses FRU we need to make sure all the unmentioned fields
565 // are checked for privacy (RFC 736). Rather than computing the set of
566 // unmentioned fields, just check them all.
567 for variant_field
in &variant
.fields
{
568 let field
= fields
.iter().find(|f
| f
.name
.node
== variant_field
.name
);
569 let span
= if let Some(f
) = field { f.span }
else { base.span }
;
570 self.check_field(span
, adt
, variant_field
);
573 for field
in fields
{
574 self.check_field(field
.span
, adt
, variant
.field_named(field
.name
.node
));
581 intravisit
::walk_expr(self, expr
);
584 fn visit_pat(&mut self, pat
: &'tcx hir
::Pat
) {
586 PatKind
::Struct(ref qpath
, ref fields
, _
) => {
587 let def
= self.tables
.qpath_def(qpath
, pat
.hir_id
);
588 let adt
= self.tables
.pat_ty(pat
).ty_adt_def().unwrap();
589 let variant
= adt
.variant_of_def(def
);
590 for field
in fields
{
591 self.check_field(field
.span
, adt
, variant
.field_named(field
.node
.name
));
597 intravisit
::walk_pat(self, pat
);
601 ////////////////////////////////////////////////////////////////////////////////////////////
602 /// Type privacy visitor, checks types for privacy and reports violations.
603 /// Both explicitly written types and inferred types of expressions and patters are checked.
604 /// Checks are performed on "semantic" types regardless of names and their hygiene.
605 ////////////////////////////////////////////////////////////////////////////////////////////
607 struct TypePrivacyVisitor
<'a
, 'tcx
: 'a
> {
608 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
609 tables
: &'a ty
::TypeckTables
<'tcx
>,
613 empty_tables
: &'a ty
::TypeckTables
<'tcx
>,
616 impl<'a
, 'tcx
> TypePrivacyVisitor
<'a
, 'tcx
> {
617 fn def_id_visibility(&self, did
: DefId
) -> ty
::Visibility
{
618 match self.tcx
.hir
.as_local_node_id(did
) {
620 let vis
= match self.tcx
.hir
.get(node_id
) {
621 hir
::map
::NodeItem(item
) => &item
.vis
,
622 hir
::map
::NodeForeignItem(foreign_item
) => &foreign_item
.vis
,
623 hir
::map
::NodeImplItem(impl_item
) => &impl_item
.vis
,
624 hir
::map
::NodeTraitItem(..) |
625 hir
::map
::NodeVariant(..) => {
626 return self.def_id_visibility(self.tcx
.hir
.get_parent_did(node_id
));
628 hir
::map
::NodeStructCtor(vdata
) => {
629 let struct_node_id
= self.tcx
.hir
.get_parent(node_id
);
630 let struct_vis
= match self.tcx
.hir
.get(struct_node_id
) {
631 hir
::map
::NodeItem(item
) => &item
.vis
,
632 node
=> bug
!("unexpected node kind: {:?}", node
),
635 = ty
::Visibility
::from_hir(struct_vis
, struct_node_id
, self.tcx
);
636 for field
in vdata
.fields() {
637 let field_vis
= ty
::Visibility
::from_hir(&field
.vis
, node_id
, self.tcx
);
638 if ctor_vis
.is_at_least(field_vis
, self.tcx
) {
639 ctor_vis
= field_vis
;
643 // If the structure is marked as non_exhaustive then lower the
644 // visibility to within the crate.
645 let struct_def_id
= self.tcx
.hir
.get_parent_did(node_id
);
646 let adt_def
= self.tcx
.adt_def(struct_def_id
);
647 if adt_def
.is_non_exhaustive() && ctor_vis
== ty
::Visibility
::Public
{
648 ctor_vis
= ty
::Visibility
::Restricted(
649 DefId
::local(CRATE_DEF_INDEX
));
654 node
=> bug
!("unexpected node kind: {:?}", node
)
656 ty
::Visibility
::from_hir(vis
, node_id
, self.tcx
)
658 None
=> self.tcx
.visibility(did
),
662 fn item_is_accessible(&self, did
: DefId
) -> bool
{
663 self.def_id_visibility(did
).is_accessible_from(self.current_item
, self.tcx
)
666 // Take node ID of an expression or pattern and check its type for privacy.
667 fn check_expr_pat_type(&mut self, id
: hir
::HirId
, span
: Span
) -> bool
{
669 if self.tables
.node_id_to_type(id
).visit_with(self) {
672 if self.tables
.node_substs(id
).visit_with(self) {
675 if let Some(adjustments
) = self.tables
.adjustments().get(id
) {
676 for adjustment
in adjustments
{
677 if adjustment
.target
.visit_with(self) {
685 fn check_trait_ref(&mut self, trait_ref
: ty
::TraitRef
<'tcx
>) -> bool
{
686 if !self.item_is_accessible(trait_ref
.def_id
) {
687 let msg
= format
!("trait `{}` is private", trait_ref
);
688 self.tcx
.sess
.span_err(self.span
, &msg
);
692 trait_ref
.super_visit_with(self)
696 impl<'a
, 'tcx
> Visitor
<'tcx
> for TypePrivacyVisitor
<'a
, 'tcx
> {
697 /// We want to visit items in the context of their containing
698 /// module and so forth, so supply a crate for doing a deep walk.
699 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'tcx
> {
700 NestedVisitorMap
::All(&self.tcx
.hir
)
703 fn visit_nested_body(&mut self, body
: hir
::BodyId
) {
704 let orig_tables
= replace(&mut self.tables
, self.tcx
.body_tables(body
));
705 let orig_in_body
= replace(&mut self.in_body
, true);
706 let body
= self.tcx
.hir
.body(body
);
707 self.visit_body(body
);
708 self.tables
= orig_tables
;
709 self.in_body
= orig_in_body
;
712 fn visit_ty(&mut self, hir_ty
: &'tcx hir
::Ty
) {
713 self.span
= hir_ty
.span
;
716 if self.tables
.node_id_to_type(hir_ty
.hir_id
).visit_with(self) {
720 // Types in signatures.
721 // FIXME: This is very ineffective. Ideally each HIR type should be converted
722 // into a semantic type only once and the result should be cached somehow.
723 if rustc_typeck
::hir_ty_to_ty(self.tcx
, hir_ty
).visit_with(self) {
728 intravisit
::walk_ty(self, hir_ty
);
731 fn visit_trait_ref(&mut self, trait_ref
: &'tcx hir
::TraitRef
) {
732 self.span
= trait_ref
.path
.span
;
734 // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
735 // The traits' privacy in bodies is already checked as a part of trait object types.
736 let (principal
, projections
) =
737 rustc_typeck
::hir_trait_to_predicates(self.tcx
, trait_ref
);
738 if self.check_trait_ref(*principal
.skip_binder()) {
741 for poly_predicate
in projections
{
743 if self.check_trait_ref(poly_predicate
.skip_binder().projection_ty
.trait_ref(tcx
)) {
749 intravisit
::walk_trait_ref(self, trait_ref
);
752 // Check types of expressions
753 fn visit_expr(&mut self, expr
: &'tcx hir
::Expr
) {
754 if self.check_expr_pat_type(expr
.hir_id
, expr
.span
) {
755 // Do not check nested expressions if the error already happened.
759 hir
::ExprAssign(.., ref rhs
) | hir
::ExprMatch(ref rhs
, ..) => {
760 // Do not report duplicate errors for `x = y` and `match x { ... }`.
761 if self.check_expr_pat_type(rhs
.hir_id
, rhs
.span
) {
765 hir
::ExprMethodCall(_
, span
, _
) => {
766 // Method calls have to be checked specially.
767 let def_id
= self.tables
.type_dependent_defs()[expr
.hir_id
].def_id();
769 if self.tcx
.type_of(def_id
).visit_with(self) {
776 intravisit
::walk_expr(self, expr
);
779 // Prohibit access to associated items with insufficient nominal visibility.
781 // Additionally, until better reachability analysis for macros 2.0 is available,
782 // we prohibit access to private statics from other crates, this allows to give
783 // more code internal visibility at link time. (Access to private functions
784 // is already prohibited by type privacy for funciton types.)
785 fn visit_qpath(&mut self, qpath
: &'tcx hir
::QPath
, id
: ast
::NodeId
, span
: Span
) {
786 let def
= match *qpath
{
787 hir
::QPath
::Resolved(_
, ref path
) => match path
.def
{
788 Def
::Method(..) | Def
::AssociatedConst(..) |
789 Def
::AssociatedTy(..) | Def
::Static(..) => Some(path
.def
),
792 hir
::QPath
::TypeRelative(..) => {
793 let hir_id
= self.tcx
.hir
.node_to_hir_id(id
);
794 self.tables
.type_dependent_defs().get(hir_id
).cloned()
797 if let Some(def
) = def
{
798 let def_id
= def
.def_id();
799 let is_local_static
= if let Def
::Static(..) = def { def_id.is_local() }
else { false }
;
800 if !self.item_is_accessible(def_id
) && !is_local_static
{
801 let name
= match *qpath
{
802 hir
::QPath
::Resolved(_
, ref path
) => format
!("{}", path
),
803 hir
::QPath
::TypeRelative(_
, ref segment
) => segment
.name
.to_string(),
805 let msg
= format
!("{} `{}` is private", def
.kind_name(), name
);
806 self.tcx
.sess
.span_err(span
, &msg
);
811 intravisit
::walk_qpath(self, qpath
, id
, span
);
814 // Check types of patterns
815 fn visit_pat(&mut self, pattern
: &'tcx hir
::Pat
) {
816 if self.check_expr_pat_type(pattern
.hir_id
, pattern
.span
) {
817 // Do not check nested patterns if the error already happened.
821 intravisit
::walk_pat(self, pattern
);
824 fn visit_local(&mut self, local
: &'tcx hir
::Local
) {
825 if let Some(ref init
) = local
.init
{
826 if self.check_expr_pat_type(init
.hir_id
, init
.span
) {
827 // Do not report duplicate errors for `let x = y`.
832 intravisit
::walk_local(self, local
);
835 // Check types in item interfaces
836 fn visit_item(&mut self, item
: &'tcx hir
::Item
) {
837 let orig_current_item
= self.current_item
;
838 let orig_tables
= update_tables(self.tcx
,
842 let orig_in_body
= replace(&mut self.in_body
, false);
843 self.current_item
= self.tcx
.hir
.local_def_id(item
.id
);
844 intravisit
::walk_item(self, item
);
845 self.tables
= orig_tables
;
846 self.in_body
= orig_in_body
;
847 self.current_item
= orig_current_item
;
850 fn visit_trait_item(&mut self, ti
: &'tcx hir
::TraitItem
) {
851 let orig_tables
= update_tables(self.tcx
, ti
.id
, &mut self.tables
, self.empty_tables
);
852 intravisit
::walk_trait_item(self, ti
);
853 self.tables
= orig_tables
;
856 fn visit_impl_item(&mut self, ii
: &'tcx hir
::ImplItem
) {
857 let orig_tables
= update_tables(self.tcx
, ii
.id
, &mut self.tables
, self.empty_tables
);
858 intravisit
::walk_impl_item(self, ii
);
859 self.tables
= orig_tables
;
863 impl<'a
, 'tcx
> TypeVisitor
<'tcx
> for TypePrivacyVisitor
<'a
, 'tcx
> {
864 fn visit_ty(&mut self, ty
: Ty
<'tcx
>) -> bool
{
866 ty
::TyAdt(&ty
::AdtDef { did: def_id, .. }
, ..) |
867 ty
::TyFnDef(def_id
, ..) |
868 ty
::TyForeign(def_id
) => {
869 if !self.item_is_accessible(def_id
) {
870 let msg
= format
!("type `{}` is private", ty
);
871 self.tcx
.sess
.span_err(self.span
, &msg
);
874 if let ty
::TyFnDef(..) = ty
.sty
{
875 if self.tcx
.fn_sig(def_id
).visit_with(self) {
879 // Inherent static methods don't have self type in substs,
880 // we have to check it additionally.
881 if let Some(assoc_item
) = self.tcx
.opt_associated_item(def_id
) {
882 if let ty
::ImplContainer(impl_def_id
) = assoc_item
.container
{
883 if self.tcx
.type_of(impl_def_id
).visit_with(self) {
889 ty
::TyDynamic(ref predicates
, ..) => {
890 let is_private
= predicates
.skip_binder().iter().any(|predicate
| {
891 let def_id
= match *predicate
{
892 ty
::ExistentialPredicate
::Trait(trait_ref
) => trait_ref
.def_id
,
893 ty
::ExistentialPredicate
::Projection(proj
) =>
894 proj
.trait_ref(self.tcx
).def_id
,
895 ty
::ExistentialPredicate
::AutoTrait(def_id
) => def_id
,
897 !self.item_is_accessible(def_id
)
900 let msg
= format
!("type `{}` is private", ty
);
901 self.tcx
.sess
.span_err(self.span
, &msg
);
905 ty
::TyProjection(ref proj
) => {
907 if self.check_trait_ref(proj
.trait_ref(tcx
)) {
911 ty
::TyAnon(def_id
, ..) => {
912 for predicate
in &self.tcx
.predicates_of(def_id
).predicates
{
913 let trait_ref
= match *predicate
{
914 ty
::Predicate
::Trait(ref poly_trait_predicate
) => {
915 Some(poly_trait_predicate
.skip_binder().trait_ref
)
917 ty
::Predicate
::Projection(ref poly_projection_predicate
) => {
918 if poly_projection_predicate
.skip_binder().ty
.visit_with(self) {
921 Some(poly_projection_predicate
.skip_binder()
922 .projection_ty
.trait_ref(self.tcx
))
924 ty
::Predicate
::TypeOutlives(..) => None
,
925 _
=> bug
!("unexpected predicate: {:?}", predicate
),
927 if let Some(trait_ref
) = trait_ref
{
928 if !self.item_is_accessible(trait_ref
.def_id
) {
929 let msg
= format
!("trait `{}` is private", trait_ref
);
930 self.tcx
.sess
.span_err(self.span
, &msg
);
933 // `Self` here is the same `TyAnon`, so skip it to avoid infinite recursion
934 for subst
in trait_ref
.substs
.iter().skip(1) {
935 if subst
.visit_with(self) {
945 ty
.super_visit_with(self)
949 ///////////////////////////////////////////////////////////////////////////////
950 /// Obsolete visitors for checking for private items in public interfaces.
951 /// These visitors are supposed to be kept in frozen state and produce an
952 /// "old error node set". For backward compatibility the new visitor reports
953 /// warnings instead of hard errors when the erroneous node is not in this old set.
954 ///////////////////////////////////////////////////////////////////////////////
956 struct ObsoleteVisiblePrivateTypesVisitor
<'a
, 'tcx
: 'a
> {
957 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
958 access_levels
: &'a AccessLevels
,
960 // set of errors produced by this obsolete visitor
961 old_error_set
: NodeSet
,
964 struct ObsoleteCheckTypeForPrivatenessVisitor
<'a
, 'b
: 'a
, 'tcx
: 'b
> {
965 inner
: &'a ObsoleteVisiblePrivateTypesVisitor
<'b
, 'tcx
>,
966 /// whether the type refers to private types.
967 contains_private
: bool
,
968 /// whether we've recurred at all (i.e. if we're pointing at the
969 /// first type on which visit_ty was called).
971 // whether that first type is a public path.
972 outer_type_is_public_path
: bool
,
975 impl<'a
, 'tcx
> ObsoleteVisiblePrivateTypesVisitor
<'a
, 'tcx
> {
976 fn path_is_private_type(&self, path
: &hir
::Path
) -> bool
{
977 let did
= match path
.def
{
978 Def
::PrimTy(..) | Def
::SelfTy(..) => return false,
982 // A path can only be private if:
983 // it's in this crate...
984 if let Some(node_id
) = self.tcx
.hir
.as_local_node_id(did
) {
985 // .. and it corresponds to a private type in the AST (this returns
986 // None for type parameters)
987 match self.tcx
.hir
.find(node_id
) {
988 Some(hir
::map
::NodeItem(ref item
)) => item
.vis
!= hir
::Public
,
989 Some(_
) | None
=> false,
996 fn trait_is_public(&self, trait_id
: ast
::NodeId
) -> bool
{
997 // FIXME: this would preferably be using `exported_items`, but all
998 // traits are exported currently (see `EmbargoVisitor.exported_trait`)
999 self.access_levels
.is_public(trait_id
)
1002 fn check_ty_param_bound(&mut self,
1003 ty_param_bound
: &hir
::TyParamBound
) {
1004 if let hir
::TraitTyParamBound(ref trait_ref
, _
) = *ty_param_bound
{
1005 if self.path_is_private_type(&trait_ref
.trait_ref
.path
) {
1006 self.old_error_set
.insert(trait_ref
.trait_ref
.ref_id
);
1011 fn item_is_public(&self, id
: &ast
::NodeId
, vis
: &hir
::Visibility
) -> bool
{
1012 self.access_levels
.is_reachable(*id
) || *vis
== hir
::Public
1016 impl<'a
, 'b
, 'tcx
, 'v
> Visitor
<'v
> for ObsoleteCheckTypeForPrivatenessVisitor
<'a
, 'b
, 'tcx
> {
1017 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'v
> {
1018 NestedVisitorMap
::None
1021 fn visit_ty(&mut self, ty
: &hir
::Ty
) {
1022 if let hir
::TyPath(hir
::QPath
::Resolved(_
, ref path
)) = ty
.node
{
1023 if self.inner
.path_is_private_type(path
) {
1024 self.contains_private
= true;
1025 // found what we're looking for so let's stop
1030 if let hir
::TyPath(_
) = ty
.node
{
1031 if self.at_outer_type
{
1032 self.outer_type_is_public_path
= true;
1035 self.at_outer_type
= false;
1036 intravisit
::walk_ty(self, ty
)
1039 // don't want to recurse into [, .. expr]
1040 fn visit_expr(&mut self, _
: &hir
::Expr
) {}
1043 impl<'a
, 'tcx
> Visitor
<'tcx
> for ObsoleteVisiblePrivateTypesVisitor
<'a
, 'tcx
> {
1044 /// We want to visit items in the context of their containing
1045 /// module and so forth, so supply a crate for doing a deep walk.
1046 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'tcx
> {
1047 NestedVisitorMap
::All(&self.tcx
.hir
)
1050 fn visit_item(&mut self, item
: &'tcx hir
::Item
) {
1052 // contents of a private mod can be re-exported, so we need
1053 // to check internals.
1054 hir
::ItemMod(_
) => {}
1056 // An `extern {}` doesn't introduce a new privacy
1057 // namespace (the contents have their own privacies).
1058 hir
::ItemForeignMod(_
) => {}
1060 hir
::ItemTrait(.., ref bounds
, _
) => {
1061 if !self.trait_is_public(item
.id
) {
1065 for bound
in bounds
.iter() {
1066 self.check_ty_param_bound(bound
)
1070 // impls need some special handling to try to offer useful
1071 // error messages without (too many) false positives
1072 // (i.e. we could just return here to not check them at
1073 // all, or some worse estimation of whether an impl is
1074 // publicly visible).
1075 hir
::ItemImpl(.., ref g
, ref trait_ref
, ref self_
, ref impl_item_refs
) => {
1076 // `impl [... for] Private` is never visible.
1077 let self_contains_private
;
1078 // impl [... for] Public<...>, but not `impl [... for]
1079 // Vec<Public>` or `(Public,)` etc.
1080 let self_is_public_path
;
1082 // check the properties of the Self type:
1084 let mut visitor
= ObsoleteCheckTypeForPrivatenessVisitor
{
1086 contains_private
: false,
1087 at_outer_type
: true,
1088 outer_type_is_public_path
: false,
1090 visitor
.visit_ty(&self_
);
1091 self_contains_private
= visitor
.contains_private
;
1092 self_is_public_path
= visitor
.outer_type_is_public_path
;
1095 // miscellaneous info about the impl
1097 // `true` iff this is `impl Private for ...`.
1098 let not_private_trait
=
1099 trait_ref
.as_ref().map_or(true, // no trait counts as public trait
1101 let did
= tr
.path
.def
.def_id();
1103 if let Some(node_id
) = self.tcx
.hir
.as_local_node_id(did
) {
1104 self.trait_is_public(node_id
)
1106 true // external traits must be public
1110 // `true` iff this is a trait impl or at least one method is public.
1112 // `impl Public { $( fn ...() {} )* }` is not visible.
1114 // This is required over just using the methods' privacy
1115 // directly because we might have `impl<T: Foo<Private>> ...`,
1116 // and we shouldn't warn about the generics if all the methods
1117 // are private (because `T` won't be visible externally).
1118 let trait_or_some_public_method
=
1119 trait_ref
.is_some() ||
1120 impl_item_refs
.iter()
1121 .any(|impl_item_ref
| {
1122 let impl_item
= self.tcx
.hir
.impl_item(impl_item_ref
.id
);
1123 match impl_item
.node
{
1124 hir
::ImplItemKind
::Const(..) |
1125 hir
::ImplItemKind
::Method(..) => {
1126 self.access_levels
.is_reachable(impl_item
.id
)
1128 hir
::ImplItemKind
::Type(_
) => false,
1132 if !self_contains_private
&&
1133 not_private_trait
&&
1134 trait_or_some_public_method
{
1136 intravisit
::walk_generics(self, g
);
1140 for impl_item_ref
in impl_item_refs
{
1141 // This is where we choose whether to walk down
1142 // further into the impl to check its items. We
1143 // should only walk into public items so that we
1144 // don't erroneously report errors for private
1145 // types in private items.
1146 let impl_item
= self.tcx
.hir
.impl_item(impl_item_ref
.id
);
1147 match impl_item
.node
{
1148 hir
::ImplItemKind
::Const(..) |
1149 hir
::ImplItemKind
::Method(..)
1150 if self.item_is_public(&impl_item
.id
, &impl_item
.vis
) =>
1152 intravisit
::walk_impl_item(self, impl_item
)
1154 hir
::ImplItemKind
::Type(..) => {
1155 intravisit
::walk_impl_item(self, impl_item
)
1162 // Any private types in a trait impl fall into three
1164 // 1. mentioned in the trait definition
1165 // 2. mentioned in the type params/generics
1166 // 3. mentioned in the associated types of the impl
1168 // Those in 1. can only occur if the trait is in
1169 // this crate and will've been warned about on the
1170 // trait definition (there's no need to warn twice
1171 // so we don't check the methods).
1173 // Those in 2. are warned via walk_generics and this
1175 intravisit
::walk_path(self, &tr
.path
);
1177 // Those in 3. are warned with this call.
1178 for impl_item_ref
in impl_item_refs
{
1179 let impl_item
= self.tcx
.hir
.impl_item(impl_item_ref
.id
);
1180 if let hir
::ImplItemKind
::Type(ref ty
) = impl_item
.node
{
1186 } else if trait_ref
.is_none() && self_is_public_path
{
1187 // impl Public<Private> { ... }. Any public static
1188 // methods will be visible as `Public::foo`.
1189 let mut found_pub_static
= false;
1190 for impl_item_ref
in impl_item_refs
{
1191 if self.item_is_public(&impl_item_ref
.id
.node_id
, &impl_item_ref
.vis
) {
1192 let impl_item
= self.tcx
.hir
.impl_item(impl_item_ref
.id
);
1193 match impl_item_ref
.kind
{
1194 hir
::AssociatedItemKind
::Const
=> {
1195 found_pub_static
= true;
1196 intravisit
::walk_impl_item(self, impl_item
);
1198 hir
::AssociatedItemKind
::Method { has_self: false }
=> {
1199 found_pub_static
= true;
1200 intravisit
::walk_impl_item(self, impl_item
);
1206 if found_pub_static
{
1207 intravisit
::walk_generics(self, g
)
1213 // `type ... = ...;` can contain private types, because
1214 // we're introducing a new name.
1215 hir
::ItemTy(..) => return,
1217 // not at all public, so we don't care
1218 _
if !self.item_is_public(&item
.id
, &item
.vis
) => {
1225 // We've carefully constructed it so that if we're here, then
1226 // any `visit_ty`'s will be called on things that are in
1227 // public signatures, i.e. things that we're interested in for
1229 intravisit
::walk_item(self, item
);
1232 fn visit_generics(&mut self, generics
: &'tcx hir
::Generics
) {
1233 for ty_param
in generics
.ty_params() {
1234 for bound
in ty_param
.bounds
.iter() {
1235 self.check_ty_param_bound(bound
)
1238 for predicate
in &generics
.where_clause
.predicates
{
1240 &hir
::WherePredicate
::BoundPredicate(ref bound_pred
) => {
1241 for bound
in bound_pred
.bounds
.iter() {
1242 self.check_ty_param_bound(bound
)
1245 &hir
::WherePredicate
::RegionPredicate(_
) => {}
1246 &hir
::WherePredicate
::EqPredicate(ref eq_pred
) => {
1247 self.visit_ty(&eq_pred
.rhs_ty
);
1253 fn visit_foreign_item(&mut self, item
: &'tcx hir
::ForeignItem
) {
1254 if self.access_levels
.is_reachable(item
.id
) {
1255 intravisit
::walk_foreign_item(self, item
)
1259 fn visit_ty(&mut self, t
: &'tcx hir
::Ty
) {
1260 if let hir
::TyPath(hir
::QPath
::Resolved(_
, ref path
)) = t
.node
{
1261 if self.path_is_private_type(path
) {
1262 self.old_error_set
.insert(t
.id
);
1265 intravisit
::walk_ty(self, t
)
1268 fn visit_variant(&mut self,
1269 v
: &'tcx hir
::Variant
,
1270 g
: &'tcx hir
::Generics
,
1271 item_id
: ast
::NodeId
) {
1272 if self.access_levels
.is_reachable(v
.node
.data
.id()) {
1273 self.in_variant
= true;
1274 intravisit
::walk_variant(self, v
, g
, item_id
);
1275 self.in_variant
= false;
1279 fn visit_struct_field(&mut self, s
: &'tcx hir
::StructField
) {
1280 if s
.vis
== hir
::Public
|| self.in_variant
{
1281 intravisit
::walk_struct_field(self, s
);
1285 // we don't need to introspect into these at all: an
1286 // expression/block context can't possibly contain exported things.
1287 // (Making them no-ops stops us from traversing the whole AST without
1288 // having to be super careful about our `walk_...` calls above.)
1289 fn visit_block(&mut self, _
: &'tcx hir
::Block
) {}
1290 fn visit_expr(&mut self, _
: &'tcx hir
::Expr
) {}
1293 ///////////////////////////////////////////////////////////////////////////////
1294 /// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and
1295 /// finds any private components in it.
1296 /// PrivateItemsInPublicInterfacesVisitor ensures there are no private types
1297 /// and traits in public interfaces.
1298 ///////////////////////////////////////////////////////////////////////////////
1300 struct SearchInterfaceForPrivateItemsVisitor
<'a
, 'tcx
: 'a
> {
1301 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
1304 /// The visitor checks that each component type is at least this visible
1305 required_visibility
: ty
::Visibility
,
1306 /// The visibility of the least visible component that has been visited
1307 min_visibility
: ty
::Visibility
,
1308 has_pub_restricted
: bool
,
1309 has_old_errors
: bool
,
1313 impl<'a
, 'tcx
: 'a
> SearchInterfaceForPrivateItemsVisitor
<'a
, 'tcx
> {
1314 fn generics(&mut self) -> &mut Self {
1315 for def
in &self.tcx
.generics_of(self.item_def_id
).types
{
1316 if def
.has_default
{
1317 self.tcx
.type_of(def
.def_id
).visit_with(self);
1323 fn predicates(&mut self) -> &mut Self {
1324 let predicates
= self.tcx
.predicates_of(self.item_def_id
);
1325 for predicate
in &predicates
.predicates
{
1326 predicate
.visit_with(self);
1328 &ty
::Predicate
::Trait(poly_predicate
) => {
1329 self.check_trait_ref(poly_predicate
.skip_binder().trait_ref
);
1331 &ty
::Predicate
::Projection(poly_predicate
) => {
1333 self.check_trait_ref(
1334 poly_predicate
.skip_binder().projection_ty
.trait_ref(tcx
)
1343 fn ty(&mut self) -> &mut Self {
1344 let ty
= self.tcx
.type_of(self.item_def_id
);
1345 ty
.visit_with(self);
1346 if let ty
::TyFnDef(def_id
, _
) = ty
.sty
{
1347 if def_id
== self.item_def_id
{
1348 self.tcx
.fn_sig(def_id
).visit_with(self);
1354 fn impl_trait_ref(&mut self) -> &mut Self {
1355 if let Some(impl_trait_ref
) = self.tcx
.impl_trait_ref(self.item_def_id
) {
1356 self.check_trait_ref(impl_trait_ref
);
1357 impl_trait_ref
.super_visit_with(self);
1362 fn check_trait_ref(&mut self, trait_ref
: ty
::TraitRef
<'tcx
>) {
1363 // Non-local means public (private items can't leave their crate, modulo bugs)
1364 if let Some(node_id
) = self.tcx
.hir
.as_local_node_id(trait_ref
.def_id
) {
1365 let item
= self.tcx
.hir
.expect_item(node_id
);
1366 let vis
= ty
::Visibility
::from_hir(&item
.vis
, node_id
, self.tcx
);
1367 if !vis
.is_at_least(self.min_visibility
, self.tcx
) {
1368 self.min_visibility
= vis
;
1370 if !vis
.is_at_least(self.required_visibility
, self.tcx
) {
1371 if self.has_pub_restricted
|| self.has_old_errors
|| self.in_assoc_ty
{
1372 struct_span_err
!(self.tcx
.sess
, self.span
, E0445
,
1373 "private trait `{}` in public interface", trait_ref
)
1374 .span_label(self.span
, format
!(
1375 "can't leak private trait"))
1378 self.tcx
.lint_node(lint
::builtin
::PRIVATE_IN_PUBLIC
,
1381 &format
!("private trait `{}` in public \
1382 interface (error E0445)", trait_ref
));
1389 impl<'a
, 'tcx
: 'a
> TypeVisitor
<'tcx
> for SearchInterfaceForPrivateItemsVisitor
<'a
, 'tcx
> {
1390 fn visit_ty(&mut self, ty
: Ty
<'tcx
>) -> bool
{
1391 let ty_def_id
= match ty
.sty
{
1392 ty
::TyAdt(adt
, _
) => Some(adt
.did
),
1393 ty
::TyForeign(did
) => Some(did
),
1394 ty
::TyDynamic(ref obj
, ..) => obj
.principal().map(|p
| p
.def_id()),
1395 ty
::TyProjection(ref proj
) => {
1396 if self.required_visibility
== ty
::Visibility
::Invisible
{
1397 // Conservatively approximate the whole type alias as public without
1398 // recursing into its components when determining impl publicity.
1399 // For example, `impl <Type as Trait>::Alias {...}` may be a public impl
1400 // even if both `Type` and `Trait` are private.
1401 // Ideally, associated types should be substituted in the same way as
1402 // free type aliases, but this isn't done yet.
1405 let trait_ref
= proj
.trait_ref(self.tcx
);
1406 Some(trait_ref
.def_id
)
1411 if let Some(def_id
) = ty_def_id
{
1412 // Non-local means public (private items can't leave their crate, modulo bugs)
1413 if let Some(node_id
) = self.tcx
.hir
.as_local_node_id(def_id
) {
1414 let vis
= match self.tcx
.hir
.find(node_id
) {
1415 Some(hir
::map
::NodeItem(item
)) => &item
.vis
,
1416 Some(hir
::map
::NodeForeignItem(item
)) => &item
.vis
,
1417 _
=> bug
!("expected item of foreign item"),
1420 let vis
= ty
::Visibility
::from_hir(vis
, node_id
, self.tcx
);
1422 if !vis
.is_at_least(self.min_visibility
, self.tcx
) {
1423 self.min_visibility
= vis
;
1425 if !vis
.is_at_least(self.required_visibility
, self.tcx
) {
1426 if self.has_pub_restricted
|| self.has_old_errors
|| self.in_assoc_ty
{
1427 let mut err
= struct_span_err
!(self.tcx
.sess
, self.span
, E0446
,
1428 "private type `{}` in public interface", ty
);
1429 err
.span_label(self.span
, "can't leak private type");
1432 self.tcx
.lint_node(lint
::builtin
::PRIVATE_IN_PUBLIC
,
1435 &format
!("private type `{}` in public \
1436 interface (error E0446)", ty
));
1442 ty
.super_visit_with(self)
1446 struct PrivateItemsInPublicInterfacesVisitor
<'a
, 'tcx
: 'a
> {
1447 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
1448 has_pub_restricted
: bool
,
1449 old_error_set
: &'a NodeSet
,
1450 inner_visibility
: ty
::Visibility
,
1453 impl<'a
, 'tcx
> PrivateItemsInPublicInterfacesVisitor
<'a
, 'tcx
> {
1454 fn check(&self, item_id
: ast
::NodeId
, required_visibility
: ty
::Visibility
)
1455 -> SearchInterfaceForPrivateItemsVisitor
<'a
, 'tcx
> {
1456 let mut has_old_errors
= false;
1458 // Slow path taken only if there any errors in the crate.
1459 for &id
in self.old_error_set
{
1460 // Walk up the nodes until we find `item_id` (or we hit a root).
1464 has_old_errors
= true;
1467 let parent
= self.tcx
.hir
.get_parent_node(id
);
1479 SearchInterfaceForPrivateItemsVisitor
{
1481 item_def_id
: self.tcx
.hir
.local_def_id(item_id
),
1482 span
: self.tcx
.hir
.span(item_id
),
1483 min_visibility
: ty
::Visibility
::Public
,
1484 required_visibility
,
1485 has_pub_restricted
: self.has_pub_restricted
,
1492 impl<'a
, 'tcx
> Visitor
<'tcx
> for PrivateItemsInPublicInterfacesVisitor
<'a
, 'tcx
> {
1493 fn nested_visit_map
<'this
>(&'this
mut self) -> NestedVisitorMap
<'this
, 'tcx
> {
1494 NestedVisitorMap
::OnlyBodies(&self.tcx
.hir
)
1497 fn visit_item(&mut self, item
: &'tcx hir
::Item
) {
1499 let min
= |vis1
: ty
::Visibility
, vis2
| {
1500 if vis1
.is_at_least(vis2
, tcx
) { vis2 }
else { vis1 }
1503 let item_visibility
= ty
::Visibility
::from_hir(&item
.vis
, item
.id
, tcx
);
1506 // Crates are always public
1507 hir
::ItemExternCrate(..) => {}
1508 // All nested items are checked by visit_item
1509 hir
::ItemMod(..) => {}
1510 // Checked in resolve
1511 hir
::ItemUse(..) => {}
1513 hir
::ItemGlobalAsm(..) => {}
1514 // Subitems of these items have inherited publicity
1515 hir
::ItemConst(..) | hir
::ItemStatic(..) | hir
::ItemFn(..) |
1516 hir
::ItemTy(..) => {
1517 self.check(item
.id
, item_visibility
).generics().predicates().ty();
1519 // Recurse for e.g. `impl Trait` (see `visit_ty`).
1520 self.inner_visibility
= item_visibility
;
1521 intravisit
::walk_item(self, item
);
1523 hir
::ItemTrait(.., ref trait_item_refs
) => {
1524 self.check(item
.id
, item_visibility
).generics().predicates();
1526 for trait_item_ref
in trait_item_refs
{
1527 let mut check
= self.check(trait_item_ref
.id
.node_id
, item_visibility
);
1528 check
.in_assoc_ty
= trait_item_ref
.kind
== hir
::AssociatedItemKind
::Type
;
1529 check
.generics().predicates();
1531 if trait_item_ref
.kind
== hir
::AssociatedItemKind
::Type
&&
1532 !trait_item_ref
.defaultness
.has_value() {
1533 // No type to visit.
1539 hir
::ItemTraitAlias(..) => {
1540 self.check(item
.id
, item_visibility
).generics().predicates();
1542 hir
::ItemEnum(ref def
, _
) => {
1543 self.check(item
.id
, item_visibility
).generics().predicates();
1545 for variant
in &def
.variants
{
1546 for field
in variant
.node
.data
.fields() {
1547 self.check(field
.id
, item_visibility
).ty();
1551 // Subitems of foreign modules have their own publicity
1552 hir
::ItemForeignMod(ref foreign_mod
) => {
1553 for foreign_item
in &foreign_mod
.items
{
1554 let vis
= ty
::Visibility
::from_hir(&foreign_item
.vis
, item
.id
, tcx
);
1555 self.check(foreign_item
.id
, vis
).generics().predicates().ty();
1558 // Subitems of structs and unions have their own publicity
1559 hir
::ItemStruct(ref struct_def
, _
) |
1560 hir
::ItemUnion(ref struct_def
, _
) => {
1561 self.check(item
.id
, item_visibility
).generics().predicates();
1563 for field
in struct_def
.fields() {
1564 let field_visibility
= ty
::Visibility
::from_hir(&field
.vis
, item
.id
, tcx
);
1565 self.check(field
.id
, min(item_visibility
, field_visibility
)).ty();
1568 // An inherent impl is public when its type is public
1569 // Subitems of inherent impls have their own publicity
1570 hir
::ItemImpl(.., None
, _
, ref impl_item_refs
) => {
1572 self.check(item
.id
, ty
::Visibility
::Invisible
).ty().min_visibility
;
1573 self.check(item
.id
, ty_vis
).generics().predicates();
1575 for impl_item_ref
in impl_item_refs
{
1576 let impl_item
= self.tcx
.hir
.impl_item(impl_item_ref
.id
);
1577 let impl_item_vis
= ty
::Visibility
::from_hir(&impl_item
.vis
, item
.id
, tcx
);
1578 let mut check
= self.check(impl_item
.id
, min(impl_item_vis
, ty_vis
));
1579 check
.in_assoc_ty
= impl_item_ref
.kind
== hir
::AssociatedItemKind
::Type
;
1580 check
.generics().predicates().ty();
1582 // Recurse for e.g. `impl Trait` (see `visit_ty`).
1583 self.inner_visibility
= impl_item_vis
;
1584 intravisit
::walk_impl_item(self, impl_item
);
1587 // A trait impl is public when both its type and its trait are public
1588 // Subitems of trait impls have inherited publicity
1589 hir
::ItemImpl(.., Some(_
), _
, ref impl_item_refs
) => {
1590 let vis
= self.check(item
.id
, ty
::Visibility
::Invisible
)
1591 .ty().impl_trait_ref().min_visibility
;
1592 self.check(item
.id
, vis
).generics().predicates();
1593 for impl_item_ref
in impl_item_refs
{
1594 let impl_item
= self.tcx
.hir
.impl_item(impl_item_ref
.id
);
1595 let mut check
= self.check(impl_item
.id
, vis
);
1596 check
.in_assoc_ty
= impl_item_ref
.kind
== hir
::AssociatedItemKind
::Type
;
1597 check
.generics().predicates().ty();
1599 // Recurse for e.g. `impl Trait` (see `visit_ty`).
1600 self.inner_visibility
= vis
;
1601 intravisit
::walk_impl_item(self, impl_item
);
1607 fn visit_impl_item(&mut self, _impl_item
: &'tcx hir
::ImplItem
) {
1608 // handled in `visit_item` above
1611 fn visit_ty(&mut self, ty
: &'tcx hir
::Ty
) {
1612 if let hir
::TyImplTraitExistential(..) = ty
.node
{
1613 // Check the traits being exposed, as they're separate,
1614 // e.g. `impl Iterator<Item=T>` has two predicates,
1615 // `X: Iterator` and `<X as Iterator>::Item == T`,
1616 // where `X` is the `impl Iterator<Item=T>` itself,
1617 // stored in `predicates_of`, not in the `Ty` itself.
1618 self.check(ty
.id
, self.inner_visibility
).predicates();
1621 intravisit
::walk_ty(self, ty
);
1624 // Don't recurse into expressions in array sizes or const initializers
1625 fn visit_expr(&mut self, _
: &'tcx hir
::Expr
) {}
1626 // Don't recurse into patterns in function arguments
1627 fn visit_pat(&mut self, _
: &'tcx hir
::Pat
) {}
1630 pub fn provide(providers
: &mut Providers
) {
1631 *providers
= Providers
{
1632 privacy_access_levels
,
1637 pub fn check_crate
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) -> Rc
<AccessLevels
> {
1638 tcx
.privacy_access_levels(LOCAL_CRATE
)
1641 fn privacy_access_levels
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
1643 -> Rc
<AccessLevels
> {
1644 assert_eq
!(krate
, LOCAL_CRATE
);
1646 let krate
= tcx
.hir
.krate();
1647 let empty_tables
= ty
::TypeckTables
::empty(None
);
1649 // Check privacy of names not checked in previous compilation stages.
1650 let mut visitor
= NamePrivacyVisitor
{
1652 tables
: &empty_tables
,
1653 current_item
: CRATE_NODE_ID
,
1654 empty_tables
: &empty_tables
,
1656 intravisit
::walk_crate(&mut visitor
, krate
);
1658 // Check privacy of explicitly written types and traits as well as
1659 // inferred types of expressions and patterns.
1660 let mut visitor
= TypePrivacyVisitor
{
1662 tables
: &empty_tables
,
1663 current_item
: DefId
::local(CRATE_DEF_INDEX
),
1666 empty_tables
: &empty_tables
,
1668 intravisit
::walk_crate(&mut visitor
, krate
);
1670 // Build up a set of all exported items in the AST. This is a set of all
1671 // items which are reachable from external crates based on visibility.
1672 let mut visitor
= EmbargoVisitor
{
1674 access_levels
: Default
::default(),
1675 prev_level
: Some(AccessLevel
::Public
),
1679 intravisit
::walk_crate(&mut visitor
, krate
);
1680 if visitor
.changed
{
1681 visitor
.changed
= false;
1686 visitor
.update(ast
::CRATE_NODE_ID
, Some(AccessLevel
::Public
));
1689 let mut visitor
= ObsoleteVisiblePrivateTypesVisitor
{
1691 access_levels
: &visitor
.access_levels
,
1693 old_error_set
: NodeSet(),
1695 intravisit
::walk_crate(&mut visitor
, krate
);
1698 let has_pub_restricted
= {
1699 let mut pub_restricted_visitor
= PubRestrictedVisitor
{
1701 has_pub_restricted
: false
1703 intravisit
::walk_crate(&mut pub_restricted_visitor
, krate
);
1704 pub_restricted_visitor
.has_pub_restricted
1707 // Check for private types and traits in public interfaces
1708 let mut visitor
= PrivateItemsInPublicInterfacesVisitor
{
1711 old_error_set
: &visitor
.old_error_set
,
1712 inner_visibility
: ty
::Visibility
::Public
,
1714 krate
.visit_all_item_likes(&mut DeepVisitor
::new(&mut visitor
));
1717 Rc
::new(visitor
.access_levels
)
1720 #[cfg(not(stage0))] // remove after the next snapshot
1721 __build_diagnostic_array
! { librustc_privacy, DIAGNOSTICS }