@@ -16,6 +16,7 @@ use std::mem::replace;
16
16
use collections:: { HashSet , HashMap } ;
17
17
18
18
use metadata:: csearch;
19
+ use middle:: lint;
19
20
use middle:: resolve;
20
21
use middle:: ty;
21
22
use middle:: typeck:: { MethodMap , MethodOrigin , MethodParam } ;
@@ -1169,6 +1170,251 @@ impl SanePrivacyVisitor {
1169
1170
}
1170
1171
}
1171
1172
1173
+ struct VisiblePrivateTypesVisitor < ' a > {
1174
+ tcx : ty:: ctxt ,
1175
+ exported_items : & ' a ExportedItems ,
1176
+ public_items : & ' a PublicItems ,
1177
+ }
1178
+
1179
+ struct CheckTypeForPrivatenessVisitor < ' a , ' b > {
1180
+ inner : & ' b VisiblePrivateTypesVisitor < ' a > ,
1181
+ /// whether the type refers to private types.
1182
+ contains_private : bool ,
1183
+ /// whether we've recurred at all (i.e. if we're pointing at the
1184
+ /// first type on which visit_ty was called).
1185
+ at_outer_type : bool ,
1186
+ // whether that first type is a public path.
1187
+ outer_type_is_public_path : bool ,
1188
+ }
1189
+
1190
+ impl < ' a > VisiblePrivateTypesVisitor < ' a > {
1191
+ fn path_is_private_type ( & self , path_id : ast:: NodeId ) -> bool {
1192
+ let did = match self . tcx . def_map . borrow ( ) . get ( ) . find_copy ( & path_id) {
1193
+ // `int` etc. (None doesn't seem to occur.)
1194
+ None | Some ( ast:: DefPrimTy ( ..) ) => return false ,
1195
+ Some ( def) => def_id_of_def ( def)
1196
+ } ;
1197
+ // A path can only be private if:
1198
+ // it's in this crate...
1199
+ is_local ( did) &&
1200
+ // ... it's not exported (obviously) ...
1201
+ !self . exported_items . contains ( & did. node ) &&
1202
+ // .. and it corresponds to a type in the AST (this returns None for
1203
+ // type parameters)
1204
+ self . tcx . map . find ( did. node ) . is_some ( )
1205
+ }
1206
+
1207
+ fn trait_is_public ( & self , trait_id : ast:: NodeId ) -> bool {
1208
+ // FIXME: this would preferably be using `exported_items`, but all
1209
+ // traits are exported currently (see `EmbargoVisitor.exported_trait`)
1210
+ self . public_items . contains ( & trait_id)
1211
+ }
1212
+ }
1213
+
1214
+ impl < ' a , ' b > Visitor < ( ) > for CheckTypeForPrivatenessVisitor < ' a , ' b > {
1215
+ fn visit_ty ( & mut self , ty : & ast:: Ty , _: ( ) ) {
1216
+ match ty. node {
1217
+ ast:: TyPath ( _, _, path_id) => {
1218
+ if self . inner . path_is_private_type ( path_id) {
1219
+ self . contains_private = true ;
1220
+ // found what we're looking for so let's stop
1221
+ // working.
1222
+ return
1223
+ } else if self . at_outer_type {
1224
+ self . outer_type_is_public_path = true ;
1225
+ }
1226
+ }
1227
+ _ => { }
1228
+ }
1229
+ self . at_outer_type = false ;
1230
+ visit:: walk_ty ( self , ty, ( ) )
1231
+ }
1232
+
1233
+ // don't want to recurse into [, .. expr]
1234
+ fn visit_expr ( & mut self , _: & ast:: Expr , _: ( ) ) { }
1235
+ }
1236
+
1237
+ impl < ' a > Visitor < ( ) > for VisiblePrivateTypesVisitor < ' a > {
1238
+ fn visit_item ( & mut self , item : & ast:: Item , _: ( ) ) {
1239
+ match item. node {
1240
+ // contents of a private mod can be reexported, so we need
1241
+ // to check internals.
1242
+ ast:: ItemMod ( _) => { }
1243
+
1244
+ // An `extern {}` doesn't introduce a new privacy
1245
+ // namespace (the contents have their own privacies).
1246
+ ast:: ItemForeignMod ( _) => { }
1247
+
1248
+ ast:: ItemTrait ( ..) if !self . trait_is_public ( item. id ) => return ,
1249
+
1250
+ // impls need some special handling to try to offer useful
1251
+ // error messages without (too many) false positives
1252
+ // (i.e. we could just return here to not check them at
1253
+ // all, or some worse estimation of whether an impl is
1254
+ // publically visible.
1255
+ ast:: ItemImpl ( ref g, ref trait_ref, self_, ref methods) => {
1256
+ // `impl [... for] Private` is never visible.
1257
+ let self_contains_private;
1258
+ // impl [... for] Public<...>, but not `impl [... for]
1259
+ // ~[Public]` or `(Public,)` etc.
1260
+ let self_is_public_path;
1261
+
1262
+ // check the properties of the Self type:
1263
+ {
1264
+ let mut visitor = CheckTypeForPrivatenessVisitor {
1265
+ inner : self ,
1266
+ contains_private : false ,
1267
+ at_outer_type : true ,
1268
+ outer_type_is_public_path : false ,
1269
+ } ;
1270
+ visitor. visit_ty ( self_, ( ) ) ;
1271
+ self_contains_private = visitor. contains_private ;
1272
+ self_is_public_path = visitor. outer_type_is_public_path ;
1273
+ }
1274
+
1275
+ // miscellanous info about the impl
1276
+
1277
+ // `true` iff this is `impl Private for ...`.
1278
+ let not_private_trait =
1279
+ trait_ref. as_ref ( ) . map_or ( true , // no trait counts as public trait
1280
+ |tr| {
1281
+ let did = ty:: trait_ref_to_def_id ( self . tcx , tr) ;
1282
+
1283
+ !is_local ( did) || self . trait_is_public ( did. node )
1284
+ } ) ;
1285
+
1286
+ // `true` iff this is a trait impl or at least one method is public.
1287
+ //
1288
+ // `impl Public { $( fn ...() {} )* }` is not visible.
1289
+ //
1290
+ // This is required over just using the methods' privacy
1291
+ // directly because we might have `impl<T: Foo<Private>> ...`,
1292
+ // and we shouldn't warn about the generics if all the methods
1293
+ // are private (because `T` won't be visible externally).
1294
+ let trait_or_some_public_method =
1295
+ trait_ref. is_some ( ) ||
1296
+ methods. iter ( ) . any ( |m| self . exported_items . contains ( & m. id ) ) ;
1297
+
1298
+ if !self_contains_private &&
1299
+ not_private_trait &&
1300
+ trait_or_some_public_method {
1301
+
1302
+ visit:: walk_generics ( self , g, ( ) ) ;
1303
+
1304
+ match * trait_ref {
1305
+ None => {
1306
+ for method in methods. iter ( ) {
1307
+ visit:: walk_method_helper ( self , * method, ( ) )
1308
+ }
1309
+ }
1310
+ Some ( ref tr) => {
1311
+ // Any private types in a trait impl fall into two
1312
+ // categories.
1313
+ // 1. mentioned in the trait definition
1314
+ // 2. mentioned in the type params/generics
1315
+ //
1316
+ // Those in 1. can only occur if the trait is in
1317
+ // this crate and will've been warned about on the
1318
+ // trait definition (there's no need to warn twice
1319
+ // so we don't check the methods).
1320
+ //
1321
+ // Those in 2. are warned via walk_generics and this
1322
+ // call here.
1323
+ visit:: walk_trait_ref_helper ( self , tr, ( ) )
1324
+ }
1325
+ }
1326
+ } else if trait_ref. is_none ( ) && self_is_public_path {
1327
+ // impl Public<Private> { ... }. Any public static
1328
+ // methods will be visible as `Public::foo`.
1329
+ let mut found_pub_static = false ;
1330
+ for method in methods. iter ( ) {
1331
+ if method. explicit_self . node == ast:: SelfStatic &&
1332
+ self . exported_items . contains ( & method. id ) {
1333
+ found_pub_static = true ;
1334
+ visit:: walk_method_helper ( self , * method, ( ) ) ;
1335
+ }
1336
+ }
1337
+ if found_pub_static {
1338
+ visit:: walk_generics ( self , g, ( ) )
1339
+ }
1340
+ }
1341
+ return
1342
+ }
1343
+
1344
+ // `type ... = ...;` can contain private types, because
1345
+ // we're introducing a new name.
1346
+ ast:: ItemTy ( ..) => return ,
1347
+
1348
+ // not at all public, so we don't care
1349
+ _ if !self . exported_items . contains ( & item. id ) => return ,
1350
+
1351
+ _ => { }
1352
+ }
1353
+
1354
+ // we've carefully constructed it so that if we're here, then
1355
+ // any `visit_ty`'s will be called on things that are in
1356
+ // public signatures, i.e. things that we're interested in for
1357
+ // this visitor.
1358
+ visit:: walk_item ( self , item, ( ) ) ;
1359
+ }
1360
+
1361
+ fn visit_foreign_item ( & mut self , item : & ast:: ForeignItem , _: ( ) ) {
1362
+ if self . exported_items . contains ( & item. id ) {
1363
+ visit:: walk_foreign_item ( self , item, ( ) )
1364
+ }
1365
+ }
1366
+
1367
+ fn visit_fn ( & mut self ,
1368
+ fk : & visit:: FnKind , fd : & ast:: FnDecl , b : & ast:: Block , s : Span , id : ast:: NodeId ,
1369
+ _: ( ) ) {
1370
+ // needs special handling for methods.
1371
+ if self . exported_items . contains ( & id) {
1372
+ visit:: walk_fn ( self , fk, fd, b, s, id, ( ) ) ;
1373
+ }
1374
+ }
1375
+
1376
+ fn visit_ty ( & mut self , t : & ast:: Ty , _: ( ) ) {
1377
+ match t. node {
1378
+ ast:: TyPath ( ref p, _, path_id) => {
1379
+ if self . path_is_private_type ( path_id) {
1380
+ self . tcx . sess . add_lint ( lint:: VisiblePrivateTypes ,
1381
+ path_id, p. span ,
1382
+ ~"private type in exported type signature") ;
1383
+ }
1384
+ }
1385
+ _ => { }
1386
+ }
1387
+ visit:: walk_ty ( self , t, ( ) )
1388
+ }
1389
+
1390
+ fn visit_variant ( & mut self , v : & ast:: Variant , g : & ast:: Generics , _: ( ) ) {
1391
+ if self . exported_items . contains ( & v. node . id ) {
1392
+ visit:: walk_variant ( self , v, g, ( ) ) ;
1393
+ }
1394
+ }
1395
+
1396
+ fn visit_struct_field ( & mut self , s : & ast:: StructField , _: ( ) ) {
1397
+ match s. node . kind {
1398
+ // the only way to get here is by being inside a public
1399
+ // struct/enum variant, so the only way to have a private
1400
+ // field is with an explicit `priv`.
1401
+ ast:: NamedField ( _, ast:: Private ) => { }
1402
+
1403
+ _ => visit:: walk_struct_field ( self , s, ( ) )
1404
+ }
1405
+ }
1406
+
1407
+
1408
+ // we don't need to introspect into these at all: an
1409
+ // expression/block context can't possibly contain exported
1410
+ // things, and neither do view_items. (Making them no-ops stops us
1411
+ // from traversing the whole AST without having to be super
1412
+ // careful about our `walk_...` calls above.)
1413
+ fn visit_view_item ( & mut self , _: & ast:: ViewItem , _: ( ) ) { }
1414
+ fn visit_block ( & mut self , _: & ast:: Block , _: ( ) ) { }
1415
+ fn visit_expr ( & mut self , _: & ast:: Expr , _: ( ) ) { }
1416
+ }
1417
+
1172
1418
pub fn check_crate ( tcx : ty:: ctxt ,
1173
1419
method_map : & MethodMap ,
1174
1420
exp_map2 : & resolve:: ExportMap2 ,
@@ -1225,5 +1471,14 @@ pub fn check_crate(tcx: ty::ctxt,
1225
1471
}
1226
1472
1227
1473
let EmbargoVisitor { exported_items, public_items, .. } = visitor;
1474
+
1475
+ {
1476
+ let mut visitor = VisiblePrivateTypesVisitor {
1477
+ tcx : tcx,
1478
+ exported_items : & exported_items,
1479
+ public_items : & public_items
1480
+ } ;
1481
+ visit:: walk_crate ( & mut visitor, krate, ( ) ) ;
1482
+ }
1228
1483
return ( exported_items, public_items) ;
1229
1484
}
0 commit comments