3
3
4
4
use /*mod*/ syntax:: ast;
5
5
use /*mod*/ syntax:: visit;
6
- use syntax:: ast:: { expr_field, ident, item_class, local_crate, node_id} ;
7
- use syntax:: ast:: { private} ;
6
+ use syntax:: ast:: { expr_field, ident, item_class, item_impl, item_trait} ;
7
+ use syntax:: ast:: { local_crate, node_id, private, provided, required} ;
8
+ use syntax:: ast_map:: { node_item, node_method} ;
8
9
use ty:: ty_class;
10
+ use typeck:: { method_map, method_origin, method_param, method_static} ;
11
+ use typeck:: { method_trait} ;
9
12
10
13
use core:: util:: ignore;
11
14
use dvec:: DVec ;
12
- use send_map:: linear:: LinearMap ;
13
15
14
- fn check_crate ( tcx : ty:: ctxt , crate : @ast:: crate ) {
15
- let privileged_structs = @DVec ( ) ;
16
+ fn check_crate( tcx : ty:: ctxt , method_map : & method_map , crate : @ast:: crate ) {
17
+ let privileged_items = @DVec ( ) ;
16
18
17
- let add_privileged_structs = |items : & [ @ast:: item ] | {
19
+ // Adds structs that are privileged to this scope.
20
+ let add_privileged_items = |items : & [ @ast:: item ] | {
18
21
let mut count = 0 ;
19
22
for items. each |item| {
20
23
match item. node {
21
- item_class( * ) => {
22
- privileged_structs . push ( item. id ) ;
24
+ item_class( * ) | item_trait ( * ) | item_impl ( * ) => {
25
+ privileged_items . push ( item. id ) ;
23
26
count += 1 ;
24
27
}
25
28
_ => { }
@@ -28,36 +31,143 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
28
31
count
29
32
} ;
30
33
34
+ // Checks that a private field is in scope.
35
+ let check_field = |span, id, ident| {
36
+ let fields = ty:: lookup_class_fields ( tcx, id) ;
37
+ for fields. each |field| {
38
+ if field. ident != ident { again; }
39
+ if field. vis == private {
40
+ tcx. sess . span_err ( span, fmt ! ( "field `%s` is private" ,
41
+ * tcx. sess. parse_sess. interner
42
+ . get( ident) ) ) ;
43
+ }
44
+ break ;
45
+ }
46
+ } ;
47
+
48
+ // Checks that a private method is in scope.
49
+ let check_method = |span, origin : & method_origin | {
50
+ match * origin {
51
+ method_static( method_id) => {
52
+ if method_id. crate == local_crate {
53
+ match tcx. items . find ( method_id. node ) {
54
+ Some ( node_method( method, impl_id, _) ) => {
55
+ if method. vis == private &&
56
+ ( impl_id. crate != local_crate ||
57
+ !privileged_items
58
+ . contains ( impl_id. node ) ) {
59
+ tcx. sess . span_err ( span,
60
+ fmt ! ( "method `%s` is \
61
+ private",
62
+ * tcx. sess
63
+ . parse_sess
64
+ . interner
65
+ . get( method
66
+ . ident) ) ) ;
67
+ }
68
+ }
69
+ Some ( _) => {
70
+ tcx. sess . span_bug ( span, ~"method wasn' t \
71
+ actually a method?!");
72
+ }
73
+ None => {
74
+ tcx.sess.span_bug(span, ~" method not found in \
75
+ AST map?!");
76
+ }
77
+ }
78
+ } else {
79
+ // XXX: External crates.
80
+ }
81
+ }
82
+ method_param({trait_id: trait_id, method_num: method_num, _}) |
83
+ method_trait(trait_id, method_num) => {
84
+ if trait_id.crate == local_crate {
85
+ match tcx.items.find(trait_id.node) {
86
+ Some(node_item(item, _)) => {
87
+ match item.node {
88
+ item_trait(_, _, methods) => {
89
+ if method_num >= methods.len() {
90
+ tcx.sess.span_bug(span, ~" method \
91
+ number \
92
+ out of \
93
+ range?!");
94
+ }
95
+ match methods[method_num] {
96
+ provided(method)
97
+ if method.vis == private &&
98
+ !privileged_items
99
+ .contains(trait_id.node) => {
100
+ tcx.sess.span_err(span,
101
+ fmt!(" method
102
+ `%s` \
103
+ is \
104
+ private",
105
+ * tcx
106
+ . sess
107
+ . parse_sess
108
+ . interner
109
+ . get
110
+ ( method
111
+ . ident ) ) ) ;
112
+ }
113
+ provided( _) | required( _) => {
114
+ // Required methods can't be
115
+ // private.
116
+ }
117
+ }
118
+ }
119
+ _ => {
120
+ tcx. sess . span_bug ( span, ~"trait wasn' t \
121
+ actually a \
122
+ trait ?!") ;
123
+ }
124
+ }
125
+ }
126
+ Some ( _) => {
127
+ tcx. sess . span_bug ( span, ~"trait wasn' t an \
128
+ item?!") ;
129
+ }
130
+ None => {
131
+ tcx. sess . span_bug ( span, ~"trait item wasn' t \
132
+ found in the AST \
133
+ map?!");
134
+ }
135
+ }
136
+ } else {
137
+ // XXX: External crates.
138
+ }
139
+ }
140
+ }
141
+ };
142
+
31
143
let visitor = visit::mk_vt(@{
32
- visit_mod: |the_module, span, node_id, env , visitor| {
33
- let n_added = add_privileged_structs ( the_module. items ) ;
144
+ visit_mod: |the_module, span, node_id, method_map , visitor| {
145
+ let n_added = add_privileged_items (the_module.items);
34
146
35
- visit:: visit_mod ( the_module, span, node_id, env , visitor) ;
147
+ visit::visit_mod(the_module, span, node_id, method_map , visitor);
36
148
37
149
for n_added.times {
38
- ignore( privileged_structs . pop( ) ) ;
150
+ ignore(privileged_items .pop());
39
151
}
40
152
},
41
- visit_expr: |expr, env , visitor| {
153
+ visit_expr: |expr, method_map: &method_map , visitor| {
42
154
match expr.node {
43
155
expr_field(base, ident, _) => {
44
156
match ty::get(ty::expr_ty(tcx, base)).struct {
45
157
ty_class(id, _)
46
158
if id.crate != local_crate ||
47
- !privileged_structs. contains ( id. node ) => {
48
- let fields = ty:: lookup_class_fields ( tcx, id) ;
49
- for fields. each |field| {
50
- if field. ident != ident { again; }
51
- if field. vis == private {
52
- tcx. sess . span_err ( expr. span ,
53
- fmt ! ( "field `%s` is \
54
- private",
55
- * tcx. sess
56
- . parse_sess
57
- . interner
58
- . get( ident) ) ) ;
159
+ !privileged_items.contains(id.node) => {
160
+ match method_map.find(expr.id) {
161
+ None => {
162
+ debug!(" ( privacy checking) checking \
163
+ field") ;
164
+ check_field ( expr. span , id, ident) ;
165
+ }
166
+ Some ( entry) => {
167
+ debug ! ( "(privacy checking) checking \
168
+ impl method") ;
169
+ check_method ( expr. span , & entry. origin ) ;
59
170
}
60
- break ;
61
171
}
62
172
}
63
173
_ => { }
@@ -66,10 +176,10 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) {
66
176
_ => { }
67
177
}
68
178
69
- visit:: visit_expr ( expr, env , visitor) ;
179
+ visit:: visit_expr( expr, method_map , visitor) ;
70
180
} ,
71
181
.. * visit:: default_visitor ( )
72
182
} ) ;
73
- visit:: visit_crate ( * crate , ( ) , visitor) ;
183
+ visit:: visit_crate ( * crate , method_map , visitor) ;
74
184
}
75
185
0 commit comments