1212
1313use core:: prelude:: * ;
1414
15+ use extract;
16+ use syntax:: ast;
17+ use syntax:: ast_map;
1518use astsrv;
1619use doc;
1720use fold:: Fold ;
@@ -28,12 +31,73 @@ pub fn mk_pass() -> Pass {
2831}
2932
3033pub 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
3143 let fold = Fold {
3244 ctxt : srv. clone ( ) ,
3345 fold_mod : fold_mod,
3446 .. fold:: default_any_fold ( srv)
3547 } ;
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+ }
37101}
38102
39103fn fold_mod (
@@ -44,28 +108,40 @@ fn fold_mod(
44108
45109 doc:: ModDoc {
46110 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+ }
48130 } ) ,
49131 .. doc
50132 }
51133}
52134
53135fn is_visible ( srv : astsrv:: Srv , doc : doc:: ItemDoc ) -> bool {
54- use syntax:: ast_map;
55- use syntax:: ast;
56-
57136 let id = doc. id ;
58137
59138 do astsrv:: exec ( srv) |ctxt| {
60139 match ctxt. ast_map . get ( & id) {
61140 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 ! ( )
69145 }
70146 _ => {
71147 // Otherwise just look at the visibility
@@ -85,7 +161,8 @@ fn should_prune_items_without_pub_modifier() {
85161}
86162
87163#[ test]
88- fn unless_they_are_trait_impls ( ) {
164+ fn should_not_prune_trait_impls ( ) {
165+ // Impls are more complicated
89166 let doc = test:: mk_doc(
90167 ~" \
91168 trait Foo { } \
@@ -94,16 +171,87 @@ fn unless_they_are_trait_impls() {
94171 fail_unless!(!doc.cratemod().impls().is_empty());
95172}
96173
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+
97243#[cfg(test)]
98244pub mod test {
99245 use astsrv;
100246 use doc;
101247 use extract;
248+ use tystr_pass;
102249 use prune_private_pass::run;
103250
104251 pub fn mk_doc(source: ~str) -> doc::Doc {
105252 do astsrv::from_str(copy source) |srv| {
106253 let doc = extract::from_srv(srv.clone(), ~" ") ;
254+ let doc = tystr_pass:: run ( srv. clone ( ) , doc) ;
107255 run ( srv. clone ( ) , doc)
108256 }
109257 }
0 commit comments