12
12
13
13
use core:: prelude:: * ;
14
14
15
+ use extract;
16
+ use syntax:: ast;
17
+ use syntax:: ast_map;
15
18
use astsrv;
16
19
use doc;
17
20
use fold:: Fold ;
@@ -28,12 +31,73 @@ pub fn mk_pass() -> Pass {
28
31
}
29
32
30
33
pub fn run ( srv : astsrv:: Srv , doc : doc:: Doc ) -> doc:: Doc {
34
+ // First strip private methods out of impls
35
+ let fold = Fold {
36
+ ctxt : srv. clone ( ) ,
37
+ fold_impl : fold_impl,
38
+ .. fold:: default_any_fold ( srv. clone ( ) )
39
+ } ;
40
+ let doc = ( fold. fold_doc ) ( & fold, doc) ;
41
+
42
+ // Then strip private items and empty impls
31
43
let fold = Fold {
32
44
ctxt : srv. clone ( ) ,
33
45
fold_mod : fold_mod,
34
46
.. fold:: default_any_fold ( srv)
35
47
} ;
36
- ( fold. fold_doc ) ( & fold, doc)
48
+ let doc = ( fold. fold_doc ) ( & fold, doc) ;
49
+
50
+ return doc;
51
+ }
52
+
53
+ fn fold_impl (
54
+ fold : & fold:: Fold < astsrv:: Srv > ,
55
+ doc : doc:: ImplDoc
56
+ ) -> doc:: ImplDoc {
57
+ let doc = fold:: default_seq_fold_impl ( fold, doc) ;
58
+
59
+ do astsrv:: exec ( fold. ctxt . clone ( ) ) |ctxt| {
60
+ match ctxt. ast_map . get ( & doc. item . id ) {
61
+ ast_map:: node_item( item, _) => {
62
+ match item. node {
63
+ ast:: item_impl( _, None , _, ref methods) => {
64
+ // Associated impls have complex rules for method visibility
65
+ strip_priv_methods ( copy doc, * methods, item. vis )
66
+ }
67
+ ast:: item_impl( _, Some ( _) , _ , _) => {
68
+ // Trait impls don't
69
+ copy doc
70
+ }
71
+ _ => fail ! ( )
72
+ }
73
+ }
74
+ _ => fail ! ( )
75
+ }
76
+ }
77
+ }
78
+
79
+ fn strip_priv_methods (
80
+ doc : doc:: ImplDoc ,
81
+ methods : & [ @ast:: method ] ,
82
+ item_vis : ast:: visibility
83
+ ) -> doc:: ImplDoc {
84
+ let methods = do ( & doc. methods ) . filtered |method| {
85
+ let ast_method = do methods. find |m| {
86
+ extract:: to_str ( m. ident ) == method. name
87
+ } ;
88
+ fail_unless ! ( ast_method. is_some( ) ) ;
89
+ let ast_method = ast_method. unwrap ( ) ;
90
+ match ast_method. vis {
91
+ ast:: public => true ,
92
+ ast:: private => false ,
93
+ ast:: inherited => item_vis == ast:: public
94
+ }
95
+ } ;
96
+
97
+ doc:: ImplDoc {
98
+ methods : methods,
99
+ .. doc
100
+ }
37
101
}
38
102
39
103
fn fold_mod (
@@ -44,28 +108,40 @@ fn fold_mod(
44
108
45
109
doc:: ModDoc {
46
110
items : doc. items . filtered ( |ItemTag | {
47
- is_visible ( fold. ctxt . clone ( ) , ItemTag . item ( ) )
111
+ match ItemTag {
112
+ & doc:: ImplTag ( ref doc) => {
113
+ if doc. trait_types . is_empty ( ) {
114
+ // This is an associated impl. We have already pruned the
115
+ // non-visible methods. If there are any left then
116
+ // retain the impl, otherwise throw it away
117
+ !doc. methods . is_empty ( )
118
+ } else {
119
+ // This is a trait implementation, make it visible
120
+ // NOTE: This is not quite right since this could be an impl
121
+ // of a private trait. We can't know that without running
122
+ // resolve though.
123
+ true
124
+ }
125
+ }
126
+ _ => {
127
+ is_visible ( fold. ctxt . clone ( ) , ItemTag . item ( ) )
128
+ }
129
+ }
48
130
} ) ,
49
131
.. doc
50
132
}
51
133
}
52
134
53
135
fn is_visible ( srv : astsrv:: Srv , doc : doc:: ItemDoc ) -> bool {
54
- use syntax:: ast_map;
55
- use syntax:: ast;
56
-
57
136
let id = doc. id ;
58
137
59
138
do astsrv:: exec ( srv) |ctxt| {
60
139
match ctxt. ast_map . get ( & id) {
61
140
ast_map:: node_item( item, _) => {
62
- match item. node {
63
- ast:: item_impl( _, Some ( _) , _, _) => {
64
- // This is a trait implementation, make it visible
65
- // NOTE: This is not quite right since this could be an impl
66
- // of a private trait. We can't know that without running
67
- // resolve though.
68
- true
141
+ match & item. node {
142
+ & ast:: item_impl( * ) => {
143
+ // Impls handled elsewhere
144
+ fail ! ( )
69
145
}
70
146
_ => {
71
147
// Otherwise just look at the visibility
@@ -85,7 +161,8 @@ fn should_prune_items_without_pub_modifier() {
85
161
}
86
162
87
163
#[ test]
88
- fn unless_they_are_trait_impls ( ) {
164
+ fn should_not_prune_trait_impls ( ) {
165
+ // Impls are more complicated
89
166
let doc = test:: mk_doc(
90
167
~" \
91
168
trait Foo { } \
@@ -94,16 +171,87 @@ fn unless_they_are_trait_impls() {
94
171
fail_unless!(!doc.cratemod().impls().is_empty());
95
172
}
96
173
174
+ #[test]
175
+ fn should_prune_associated_methods_without_vis_modifier_on_impls_without_vis_modifier() {
176
+ let doc = test::mk_doc(
177
+ ~" impl Foo { \
178
+ pub fn bar ( ) { } \
179
+ fn baz ( ) { } \
180
+ } ");
181
+ fail_unless!(doc.cratemod().impls()[0].methods.len() == 1);
182
+ }
183
+
184
+ #[test]
185
+ fn should_prune_priv_associated_methods_on_impls_without_vis_modifier() {
186
+ let doc = test::mk_doc(
187
+ ~" impl Foo { \
188
+ pub fn bar ( ) { } \
189
+ priv fn baz ( ) { } \
190
+ } ");
191
+ fail_unless!(doc.cratemod().impls()[0].methods.len() == 1);
192
+ }
193
+
194
+ #[test]
195
+ fn should_prune_priv_associated_methods_on_pub_impls() {
196
+ let doc = test::mk_doc(
197
+ ~"pub impl Foo { \
198
+ fn bar() { }\
199
+ priv fn baz() { }\
200
+ }") ;
201
+ fail_unless ! ( doc. cratemod( ) . impls( ) [ 0 ] . methods. len( ) == 1 ) ;
202
+ }
203
+
204
+ #[ test]
205
+ fn should_prune_associated_methods_without_vis_modifier_on_priv_impls ( ) {
206
+ let doc = test:: mk_doc (
207
+ ~"priv impl Foo { \
208
+ pub fn bar( ) { } \
209
+ fn baz ( ) { } \
210
+ } ") ;
211
+ fail_unless ! ( doc. cratemod( ) . impls( ) [ 0 ] . methods. len( ) == 1 ) ;
212
+ }
213
+
214
+ #[ test]
215
+ fn should_prune_priv_associated_methods_on_priv_impls ( ) {
216
+ let doc = test:: mk_doc (
217
+ ~"priv impl Foo { \
218
+ pub fn bar( ) { } \
219
+ priv fn baz ( ) { } \
220
+ } ") ;
221
+ fail_unless ! ( doc. cratemod( ) . impls( ) [ 0 ] . methods. len( ) == 1 ) ;
222
+ }
223
+
224
+ #[ test]
225
+ fn should_prune_associated_impls_with_no_pub_methods ( ) {
226
+ let doc = test:: mk_doc (
227
+ ~"priv impl Foo { \
228
+ fn baz( ) { } \
229
+ } ") ;
230
+ fail_unless ! ( doc. cratemod( ) . impls( ) . is_empty( ) ) ;
231
+ }
232
+
233
+ #[ test]
234
+ fn should_not_prune_associated_impls_with_pub_methods ( ) {
235
+ let doc = test:: mk_doc (
236
+ ~" \
237
+ impl Foo { pub fn bar( ) { } } \
238
+ ");
239
+ fail_unless!(!doc.cratemod().impls().is_empty());
240
+ }
241
+
242
+
97
243
#[cfg(test)]
98
244
pub mod test {
99
245
use astsrv;
100
246
use doc;
101
247
use extract;
248
+ use tystr_pass;
102
249
use prune_private_pass::run;
103
250
104
251
pub fn mk_doc(source: ~str) -> doc::Doc {
105
252
do astsrv::from_str(copy source) |srv| {
106
253
let doc = extract::from_srv(srv.clone(), ~" ") ;
254
+ let doc = tystr_pass:: run ( srv. clone ( ) , doc) ;
107
255
run ( srv. clone ( ) , doc)
108
256
}
109
257
}
0 commit comments