34
34
//! Context itself, span_lint should be used instead of add_lint.
35
35
36
36
use driver:: session;
37
- use middle:: privacy;
38
37
use middle:: trans:: adt; // for `adt::is_ffi_safe`
39
38
use middle:: ty;
40
39
use middle:: pat_util;
@@ -310,28 +309,21 @@ pub fn get_lint_dict() -> LintDict {
310
309
return map;
311
310
}
312
311
313
- struct Context < ' self > {
312
+ struct Context {
314
313
// All known lint modes (string versions)
315
314
dict : @LintDict ,
316
315
// Current levels of each lint warning
317
316
cur : SmallIntMap < ( level , LintSource ) > ,
318
317
// context we're checking in (used to access fields like sess)
319
318
tcx : ty:: ctxt ,
320
- // Items exported by the crate; used by the missing_doc lint.
321
- exported_items : & ' self privacy:: ExportedItems ,
322
- // The id of the current `ast::struct_def` being walked.
323
- cur_struct_def_id : ast:: NodeId ,
324
- // Whether some ancestor of the current node was marked
325
- // #[doc(hidden)].
326
- is_doc_hidden : bool ,
327
319
328
320
// When recursing into an attributed node of the ast which modifies lint
329
321
// levels, this stack keeps track of the previous lint levels of whatever
330
322
// was modified.
331
323
lint_stack : ~[ ( lint , level , LintSource ) ] ,
332
324
}
333
325
334
- impl < ' self > Context < ' self > {
326
+ impl Context {
335
327
fn get_level ( & self , lint : lint ) -> level {
336
328
match self . cur . find ( & ( lint as uint ) ) {
337
329
Some ( & ( lvl, _) ) => lvl,
@@ -440,16 +432,9 @@ impl<'self> Context<'self> {
440
432
true
441
433
} ;
442
434
443
- let old_is_doc_hidden = self . is_doc_hidden ;
444
- self . is_doc_hidden = self . is_doc_hidden ||
445
- attrs. iter ( ) . any ( |attr| ( "doc" == attr. name ( ) && match attr. meta_item_list ( )
446
- { None => false ,
447
- Some ( l) => attr:: contains_name ( l, "hidden" ) } ) ) ;
448
-
449
435
f ( self ) ;
450
436
451
437
// rollback
452
- self . is_doc_hidden = old_is_doc_hidden;
453
438
do pushed. times {
454
439
let ( lint, lvl, src) = self . lint_stack . pop ( ) ;
455
440
self . set_level ( lint, lvl, src) ;
@@ -877,81 +862,123 @@ fn check_unnecessary_allocation(cx: &Context, e: &ast::Expr) {
877
862
}
878
863
}
879
864
880
- fn check_missing_doc_attrs ( cx : & Context ,
881
- id : ast:: NodeId ,
882
- attrs : & [ ast:: Attribute ] ,
883
- sp : Span ,
884
- desc : & ' static str ) {
885
- // If we're building a test harness, then warning about
886
- // documentation is probably not really relevant right now.
887
- if cx. tcx . sess . opts . test { return }
888
-
889
- // `#[doc(hidden)]` disables missing_doc check.
890
- if cx. is_doc_hidden { return }
891
-
892
- // Only check publicly-visible items, using the result from the
893
- // privacy pass.
894
- if !cx. exported_items . contains ( & id) { return }
895
-
896
- if !attrs. iter ( ) . any ( |a| a. node . is_sugared_doc ) {
897
- cx. span_lint ( missing_doc, sp,
898
- format ! ( "missing documentation for {}" , desc) ) ;
899
- }
900
- }
865
+ struct MissingDocLintVisitor ( ty:: ctxt ) ;
901
866
902
- fn check_missing_doc_item ( cx : & mut Context , it : & ast:: item ) { // XXX doesn't need to be mut
903
- let desc = match it. node {
904
- ast:: item_fn( * ) => "a function" ,
905
- ast:: item_mod( * ) => "a module" ,
906
- ast:: item_enum( * ) => "an enum" ,
907
- ast:: item_struct( * ) => "a struct" ,
908
- ast:: item_trait( * ) => "a trait" ,
909
- _ => return
910
- } ;
911
- check_missing_doc_attrs ( cx, it. id , it. attrs , it. span , desc) ;
912
- }
867
+ impl MissingDocLintVisitor {
868
+ fn check_attrs ( & self , attrs : & [ ast:: Attribute ] , id : ast:: NodeId ,
869
+ sp : Span , msg : ~str ) {
870
+ if !attrs. iter ( ) . any ( |a| a. node . is_sugared_doc ) {
871
+ self . sess . add_lint ( missing_doc, id, sp, msg) ;
872
+ }
873
+ }
913
874
914
- fn check_missing_doc_method ( cx : & Context , m : & ast:: method ) {
915
- let did = ast:: DefId {
916
- crate : ast:: LOCAL_CRATE ,
917
- node : m. id
918
- } ;
919
- match cx. tcx . methods . find ( & did) {
920
- None => cx. tcx . sess . span_bug ( m. span , "missing method descriptor?!" ) ,
921
- Some ( md) => {
922
- match md. container {
923
- // Always check default methods defined on traits.
924
- ty:: TraitContainer ( * ) => { }
925
- // For methods defined on impls, it depends on whether
926
- // it is an implementation for a trait or is a plain
927
- // impl.
928
- ty:: ImplContainer ( cid) => {
929
- match ty:: impl_trait_ref ( cx. tcx , cid) {
930
- Some ( * ) => return , // impl for trait: don't doc
931
- None => { } // plain impl: doc according to privacy
932
- }
875
+ fn check_struct ( & self , sdef : & ast:: struct_def ) {
876
+ for field in sdef. fields . iter ( ) {
877
+ match field. node . kind {
878
+ ast:: named_field( _, vis) if vis != ast:: private => {
879
+ self . check_attrs ( field. node . attrs , field. node . id , field. span ,
880
+ ~"missing documentation for a field") ;
933
881
}
882
+ ast:: unnamed_field | ast:: named_field( * ) => { }
934
883
}
935
884
}
936
885
}
937
- check_missing_doc_attrs ( cx, m. id , m. attrs , m. span , "a method" ) ;
938
- }
939
886
940
- fn check_missing_doc_ty_method ( cx : & Context , tm : & ast:: TypeMethod ) {
941
- check_missing_doc_attrs ( cx, tm. id , tm. attrs , tm. span , "a type method" ) ;
887
+ fn doc_hidden ( & self , attrs : & [ ast:: Attribute ] ) -> bool {
888
+ do attrs. iter ( ) . any |attr| {
889
+ "doc" == attr. name ( ) &&
890
+ match attr. meta_item_list ( ) {
891
+ Some ( l) => attr:: contains_name ( l, "hidden" ) ,
892
+ None => false // not of the form #[doc(...)]
893
+ }
894
+ }
895
+ }
942
896
}
943
897
944
- fn check_missing_doc_struct_field ( cx : & Context , sf : & ast:: struct_field ) {
945
- match sf. node . kind {
946
- ast:: named_field( _, vis) if vis != ast:: private =>
947
- check_missing_doc_attrs ( cx, cx. cur_struct_def_id , sf. node . attrs ,
948
- sf. span , "a struct field" ) ,
949
- _ => { }
898
+ impl Visitor < ( ) > for MissingDocLintVisitor {
899
+ fn visit_ty_method( & mut self , m : & ast:: TypeMethod , _: ( ) ) {
900
+ if self . doc_hidden ( m. attrs ) { return }
901
+
902
+ // All ty_method objects are linted about because they're part of a
903
+ // trait (no visibility)
904
+ self . check_attrs ( m. attrs , m. id , m. span ,
905
+ ~"missing documentation for a method") ;
906
+ visit:: walk_ty_method( self , m, ( ) ) ;
950
907
}
951
- }
952
908
953
- fn check_missing_doc_variant ( cx : & Context , v : & ast:: variant ) {
954
- check_missing_doc_attrs ( cx, v. node . id , v. node . attrs , v. span , "a variant" ) ;
909
+ fn visit_fn( & mut self , fk: & visit:: fn_kind, d: & ast:: fn_decl,
910
+ b: & ast:: Block , sp: Span , id: ast:: NodeId , _: ( ) ) {
911
+ // Only warn about explicitly public methods.
912
+ match * fk {
913
+ visit:: fk_method( _, _, m) => {
914
+ if self . doc_hidden ( m. attrs ) {
915
+ return ;
916
+ }
917
+ // If we're in a trait implementation, no need to duplicate
918
+ // documentation
919
+ if m. vis == ast:: public {
920
+ self . check_attrs ( m. attrs , id, sp,
921
+ ~"missing documentation for a method") ;
922
+ }
923
+ }
924
+ _ => { }
925
+ }
926
+ visit:: walk_fn ( self , fk, d, b, sp, id, ( ) ) ;
927
+ }
928
+
929
+ fn visit_item( & mut self , it : @ast:: item , _: ( ) ) {
930
+ // If we're building a test harness, then warning about documentation is
931
+ // probably not really relevant right now
932
+ if self . sess . opts . test { return }
933
+ if self . doc_hidden ( it. attrs ) { return }
934
+
935
+ match it. node {
936
+ ast:: item_struct( sdef, _) if it. vis == ast:: public => {
937
+ self . check_attrs ( it. attrs , it. id , it. span ,
938
+ ~"missing documentation for a struct") ;
939
+ self . check_struct( sdef) ;
940
+ }
941
+
942
+ // Skip implementations because they inherit documentation from the
943
+ // trait (which was already linted)
944
+ ast:: item_impl( _, Some ( * ) , _, _) => return ,
945
+
946
+ ast:: item_trait( * ) if it. vis != ast:: public => return ,
947
+ ast:: item_trait( * ) => self . check_attrs ( it. attrs , it. id , it. span ,
948
+ ~"missing documentation for a trait") ,
949
+
950
+ ast:: item_fn( * ) if it. vis == ast:: public => {
951
+ self . check_attrs ( it. attrs , it. id , it. span ,
952
+ ~"missing documentation for a function") ;
953
+ }
954
+
955
+ ast:: item_mod( * ) if it. vis == ast:: public => {
956
+ self . check_attrs ( it. attrs , it. id , it. span ,
957
+ ~"missing documentation for a module") ;
958
+ }
959
+
960
+ ast:: item_enum( ref edef, _) if it. vis == ast:: public => {
961
+ self . check_attrs ( it. attrs , it. id , it. span ,
962
+ ~"missing documentation for an enum") ;
963
+ for variant in edef. variants . iter ( ) {
964
+ if variant. node . vis == ast:: private { continue ; }
965
+
966
+ self . check_attrs ( variant. node . attrs , variant. node . id ,
967
+ variant. span ,
968
+ ~"missing documentation for a variant") ;
969
+ match variant. node . kind {
970
+ ast:: struct_variant_kind( sdef) => {
971
+ self . check_struct ( sdef) ;
972
+ }
973
+ _ => ( )
974
+ }
975
+ }
976
+ }
977
+
978
+ _ => { }
979
+ }
980
+ visit:: walk_item ( self , it, ( ) ) ;
981
+ }
955
982
}
956
983
957
984
/// Checks for use of items with #[deprecated], #[experimental] and
@@ -1027,14 +1054,13 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
1027
1054
cx. span_lint ( lint, e. span , msg) ;
1028
1055
}
1029
1056
1030
- impl < ' self > Visitor < ( ) > for Context < ' self > {
1057
+ impl Visitor < ( ) > for Context {
1031
1058
fn visit_item ( & mut self , it : @ast:: item , _: ( ) ) {
1032
1059
do self . with_lint_attrs ( it. attrs ) |cx| {
1033
1060
check_item_ctypes ( cx, it) ;
1034
1061
check_item_non_camel_case_types ( cx, it) ;
1035
1062
check_item_non_uppercase_statics ( cx, it) ;
1036
1063
check_heap_item ( cx, it) ;
1037
- check_missing_doc_item ( cx, it) ;
1038
1064
1039
1065
do cx. visit_ids |v| {
1040
1066
v. visit_item ( it, ( ) ) ;
@@ -1077,8 +1103,6 @@ impl<'self> Visitor<()> for Context<'self> {
1077
1103
match * fk {
1078
1104
visit:: fk_method( _, _, m) => {
1079
1105
do self . with_lint_attrs ( m. attrs ) |cx| {
1080
- check_missing_doc_method ( cx, m) ;
1081
-
1082
1106
do cx. visit_ids |v| {
1083
1107
v. visit_fn ( fk, decl, body, span, id, ( ) ) ;
1084
1108
}
@@ -1088,45 +1112,9 @@ impl<'self> Visitor<()> for Context<'self> {
1088
1112
_ => recurse ( self ) ,
1089
1113
}
1090
1114
}
1091
-
1092
- fn visit_ty_method ( & mut self , t : & ast:: TypeMethod , _: ( ) ) {
1093
- do self . with_lint_attrs ( t. attrs ) |cx| {
1094
- check_missing_doc_ty_method ( cx, t) ;
1095
-
1096
- visit:: walk_ty_method ( cx, t, ( ) ) ;
1097
- }
1098
- }
1099
-
1100
- fn visit_struct_def ( & mut self ,
1101
- s : @ast:: struct_def ,
1102
- i : ast:: Ident ,
1103
- g : & ast:: Generics ,
1104
- id : ast:: NodeId ,
1105
- _: ( ) ) {
1106
- let old_id = self . cur_struct_def_id ;
1107
- self . cur_struct_def_id = id;
1108
- visit:: walk_struct_def ( self , s, i, g, id, ( ) ) ;
1109
- self . cur_struct_def_id = old_id;
1110
- }
1111
-
1112
- fn visit_struct_field ( & mut self , s : @ast:: struct_field , _: ( ) ) {
1113
- do self . with_lint_attrs ( s. node . attrs ) |cx| {
1114
- check_missing_doc_struct_field ( cx, s) ;
1115
-
1116
- visit:: walk_struct_field ( cx, s, ( ) ) ;
1117
- }
1118
- }
1119
-
1120
- fn visit_variant ( & mut self , v : & ast:: variant , g : & ast:: Generics , _: ( ) ) {
1121
- do self . with_lint_attrs ( v. node . attrs ) |cx| {
1122
- check_missing_doc_variant ( cx, v) ;
1123
-
1124
- visit:: walk_variant ( cx, v, g, ( ) ) ;
1125
- }
1126
- }
1127
1115
}
1128
1116
1129
- impl < ' self > ast_util:: IdVisitingOperation for Context < ' self > {
1117
+ impl ast_util:: IdVisitingOperation for Context {
1130
1118
fn visit_id ( & self , id : ast:: NodeId ) {
1131
1119
match self . tcx . sess . lints . pop ( & id) {
1132
1120
None => { }
@@ -1139,16 +1127,17 @@ impl<'self> ast_util::IdVisitingOperation for Context<'self> {
1139
1127
}
1140
1128
}
1141
1129
1142
- pub fn check_crate( tcx : ty:: ctxt ,
1143
- exported_items : & privacy:: ExportedItems ,
1144
- crate : & ast:: Crate ) {
1130
+ pub fn check_crate( tcx : ty:: ctxt , crate : & ast:: Crate ) {
1131
+ // This visitor contains more state than is currently maintained in Context,
1132
+ // and there's no reason for the Context to keep track of this information
1133
+ // really
1134
+ let mut dox = MissingDocLintVisitor ( tcx) ;
1135
+ visit:: walk_crate ( & mut dox, crate , ( ) ) ;
1136
+
1145
1137
let mut cx = Context {
1146
1138
dict : @get_lint_dict ( ) ,
1147
1139
cur : SmallIntMap :: new ( ) ,
1148
1140
tcx : tcx,
1149
- exported_items : exported_items,
1150
- cur_struct_def_id : -1 ,
1151
- is_doc_hidden : false ,
1152
1141
lint_stack : ~[ ] ,
1153
1142
} ;
1154
1143
0 commit comments