34
34
//! Context itself, span_lint should be used instead of add_lint.
35
35
36
36
use driver:: session;
37
+ use middle:: privacy;
37
38
use middle:: trans:: adt; // for `adt::is_ffi_safe`
38
39
use middle:: ty;
39
40
use middle:: pat_util;
@@ -309,21 +310,28 @@ pub fn get_lint_dict() -> LintDict {
309
310
return map;
310
311
}
311
312
312
- struct Context {
313
+ struct Context < ' self > {
313
314
// All known lint modes (string versions)
314
315
dict : @LintDict ,
315
316
// Current levels of each lint warning
316
317
cur : SmallIntMap < ( level , LintSource ) > ,
317
318
// context we're checking in (used to access fields like sess)
318
319
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 ,
319
327
320
328
// When recursing into an attributed node of the ast which modifies lint
321
329
// levels, this stack keeps track of the previous lint levels of whatever
322
330
// was modified.
323
331
lint_stack : ~[ ( lint , level , LintSource ) ] ,
324
332
}
325
333
326
- impl Context {
334
+ impl < ' self > Context < ' self > {
327
335
fn get_level ( & self , lint : lint ) -> level {
328
336
match self . cur . find ( & ( lint as uint ) ) {
329
337
Some ( & ( lvl, _) ) => lvl,
@@ -432,9 +440,16 @@ impl Context {
432
440
true
433
441
} ;
434
442
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
+
435
449
f ( self ) ;
436
450
437
451
// rollback
452
+ self . is_doc_hidden = old_is_doc_hidden;
438
453
do pushed. times {
439
454
let ( lint, lvl, src) = self . lint_stack . pop ( ) ;
440
455
self . set_level ( lint, lvl, src) ;
@@ -862,125 +877,83 @@ fn check_unnecessary_allocation(cx: &Context, e: &ast::Expr) {
862
877
}
863
878
}
864
879
865
- struct MissingDocLintVisitor ( ty:: ctxt ) ;
866
-
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
- }
874
-
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") ;
881
- }
882
- ast:: unnamed_field | ast:: named_field( * ) => { }
883
- }
884
- }
885
- }
886
-
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
- }
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) ) ;
895
899
}
896
900
}
897
901
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, ( ) ) ;
907
- }
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
+ }
908
913
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") ;
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
+ }
922
933
}
923
934
}
924
- _ => { }
925
935
}
926
- visit:: walk_fn ( self , fk, d, b, sp, id, ( ) ) ;
927
936
}
937
+ check_missing_doc_attrs ( cx, m. id , m. attrs , m. span , "a method" ) ;
938
+ }
928
939
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
- }
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" ) ;
942
+ }
977
943
978
- _ => { }
979
- }
980
- visit:: walk_item ( self , it, ( ) ) ;
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
+ _ => { }
981
950
}
982
951
}
983
952
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" ) ;
955
+ }
956
+
984
957
/// Checks for use of items with #[deprecated], #[experimental] and
985
958
/// #[unstable] (or none of them) attributes.
986
959
fn check_stability ( cx : & Context , e : & ast:: Expr ) {
@@ -1054,13 +1027,14 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
1054
1027
cx. span_lint ( lint, e. span , msg) ;
1055
1028
}
1056
1029
1057
- impl Visitor < ( ) > for Context {
1030
+ impl < ' self > Visitor < ( ) > for Context < ' self > {
1058
1031
fn visit_item ( & mut self , it : @ast:: item , _: ( ) ) {
1059
1032
do self . with_lint_attrs ( it. attrs ) |cx| {
1060
1033
check_item_ctypes ( cx, it) ;
1061
1034
check_item_non_camel_case_types ( cx, it) ;
1062
1035
check_item_non_uppercase_statics ( cx, it) ;
1063
1036
check_heap_item ( cx, it) ;
1037
+ check_missing_doc_item ( cx, it) ;
1064
1038
1065
1039
do cx. visit_ids |v| {
1066
1040
v. visit_item ( it, ( ) ) ;
@@ -1103,6 +1077,8 @@ impl Visitor<()> for Context {
1103
1077
match * fk {
1104
1078
visit:: fk_method( _, _, m) => {
1105
1079
do self . with_lint_attrs ( m. attrs ) |cx| {
1080
+ check_missing_doc_method ( cx, m) ;
1081
+
1106
1082
do cx. visit_ids |v| {
1107
1083
v. visit_fn ( fk, decl, body, span, id, ( ) ) ;
1108
1084
}
@@ -1112,9 +1088,45 @@ impl Visitor<()> for Context {
1112
1088
_ => recurse ( self ) ,
1113
1089
}
1114
1090
}
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
+ }
1115
1127
}
1116
1128
1117
- impl ast_util:: IdVisitingOperation for Context {
1129
+ impl < ' self > ast_util:: IdVisitingOperation for Context < ' self > {
1118
1130
fn visit_id ( & self , id : ast:: NodeId ) {
1119
1131
match self . tcx . sess . lints . pop ( & id) {
1120
1132
None => { }
@@ -1127,17 +1139,16 @@ impl ast_util::IdVisitingOperation for Context {
1127
1139
}
1128
1140
}
1129
1141
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
-
1142
+ pub fn check_crate( tcx : ty:: ctxt ,
1143
+ exported_items : & privacy:: ExportedItems ,
1144
+ crate : & ast:: Crate ) {
1137
1145
let mut cx = Context {
1138
1146
dict : @get_lint_dict ( ) ,
1139
1147
cur : SmallIntMap :: new ( ) ,
1140
1148
tcx : tcx,
1149
+ exported_items : exported_items,
1150
+ cur_struct_def_id : -1 ,
1151
+ is_doc_hidden : false ,
1141
1152
lint_stack : ~[ ] ,
1142
1153
} ;
1143
1154
0 commit comments