1
1
use crate :: utils:: span_lint;
2
2
use itertools:: Itertools ;
3
3
use pulldown_cmark;
4
- use rustc:: lint:: { EarlyContext , EarlyLintPass , LintArray , LintPass } ;
4
+ use rustc:: hir;
5
+ use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
5
6
use rustc:: { declare_tool_lint, impl_lint_pass} ;
6
7
use rustc_data_structures:: fx:: FxHashSet ;
7
8
use std:: ops:: Range ;
8
- use syntax:: ast;
9
+ use syntax:: ast:: Attribute ;
9
10
use syntax:: source_map:: { BytePos , Span } ;
10
11
use syntax_pos:: Pos ;
11
12
use url:: Url ;
@@ -100,28 +101,78 @@ declare_clippy_lint! {
100
101
#[ derive( Clone ) ]
101
102
pub struct DocMarkdown {
102
103
valid_idents : FxHashSet < String > ,
104
+ in_trait_impl : bool ,
103
105
}
104
106
105
107
impl DocMarkdown {
106
108
pub fn new ( valid_idents : FxHashSet < String > ) -> Self {
107
- Self { valid_idents }
109
+ Self {
110
+ valid_idents,
111
+ in_trait_impl : false ,
112
+ }
108
113
}
109
114
}
110
115
111
116
impl_lint_pass ! ( DocMarkdown => [ DOC_MARKDOWN , MISSING_SAFETY_DOC , NEEDLESS_DOCTEST_MAIN ] ) ;
112
117
113
- impl EarlyLintPass for DocMarkdown {
114
- fn check_crate ( & mut self , cx : & EarlyContext < ' _ > , krate : & ast :: Crate ) {
118
+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for DocMarkdown {
119
+ fn check_crate ( & mut self , cx : & LateContext < ' a , ' tcx > , krate : & ' tcx hir :: Crate ) {
115
120
check_attrs ( cx, & self . valid_idents , & krate. attrs ) ;
116
121
}
117
122
118
- fn check_item ( & mut self , cx : & EarlyContext < ' _ > , item : & ast:: Item ) {
123
+ fn check_item ( & mut self , cx : & LateContext < ' a , ' tcx > , item : & ' tcx hir:: Item ) {
124
+ if check_attrs ( cx, & self . valid_idents , & item. attrs ) {
125
+ return ;
126
+ }
127
+ // no safety header
128
+ match item. kind {
129
+ hir:: ItemKind :: Fn ( _, ref header, ..) => {
130
+ if cx. access_levels . is_exported ( item. hir_id ) && header. unsafety == hir:: Unsafety :: Unsafe {
131
+ span_lint (
132
+ cx,
133
+ MISSING_SAFETY_DOC ,
134
+ item. span ,
135
+ "unsafe function's docs miss `# Safety` section" ,
136
+ ) ;
137
+ }
138
+ } ,
139
+ hir:: ItemKind :: Impl ( _, _, _, _, ref trait_ref, ..) => {
140
+ self . in_trait_impl = trait_ref. is_some ( ) ;
141
+ } ,
142
+ _ => { } ,
143
+ }
144
+ }
145
+
146
+ fn check_item_post ( & mut self , _cx : & LateContext < ' a , ' tcx > , item : & ' tcx hir:: Item ) {
147
+ if let hir:: ItemKind :: Impl ( ..) = item. kind {
148
+ self . in_trait_impl = false ;
149
+ }
150
+ }
151
+
152
+ fn check_trait_item ( & mut self , cx : & LateContext < ' a , ' tcx > , item : & ' tcx hir:: TraitItem ) {
119
153
if check_attrs ( cx, & self . valid_idents , & item. attrs ) {
120
154
return ;
121
155
}
122
156
// no safety header
123
- if let ast:: ItemKind :: Fn ( _, ref header, ..) = item. kind {
124
- if item. vis . node . is_pub ( ) && header. unsafety == ast:: Unsafety :: Unsafe {
157
+ if let hir:: TraitItemKind :: Method ( ref sig, ..) = item. kind {
158
+ if cx. access_levels . is_exported ( item. hir_id ) && sig. header . unsafety == hir:: Unsafety :: Unsafe {
159
+ span_lint (
160
+ cx,
161
+ MISSING_SAFETY_DOC ,
162
+ item. span ,
163
+ "unsafe function's docs miss `# Safety` section" ,
164
+ ) ;
165
+ }
166
+ }
167
+ }
168
+
169
+ fn check_impl_item ( & mut self , cx : & LateContext < ' a , ' tcx > , item : & ' tcx hir:: ImplItem ) {
170
+ if check_attrs ( cx, & self . valid_idents , & item. attrs ) || self . in_trait_impl {
171
+ return ;
172
+ }
173
+ // no safety header
174
+ if let hir:: ImplItemKind :: Method ( ref sig, ..) = item. kind {
175
+ if cx. access_levels . is_exported ( item. hir_id ) && sig. header . unsafety == hir:: Unsafety :: Unsafe {
125
176
span_lint (
126
177
cx,
127
178
MISSING_SAFETY_DOC ,
@@ -190,7 +241,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(
190
241
panic ! ( "not a doc-comment: {}" , comment) ;
191
242
}
192
243
193
- pub fn check_attrs < ' a > ( cx : & EarlyContext < ' _ > , valid_idents : & FxHashSet < String > , attrs : & ' a [ ast :: Attribute ] ) -> bool {
244
+ pub fn check_attrs < ' a > ( cx : & LateContext < ' _ , ' _ > , valid_idents : & FxHashSet < String > , attrs : & ' a [ Attribute ] ) -> bool {
194
245
let mut doc = String :: new ( ) ;
195
246
let mut spans = vec ! [ ] ;
196
247
@@ -240,7 +291,7 @@ pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>,
240
291
}
241
292
242
293
fn check_doc < ' a , Events : Iterator < Item = ( pulldown_cmark:: Event < ' a > , Range < usize > ) > > (
243
- cx : & EarlyContext < ' _ > ,
294
+ cx : & LateContext < ' _ , ' _ > ,
244
295
valid_idents : & FxHashSet < String > ,
245
296
events : Events ,
246
297
spans : & [ ( usize , Span ) ] ,
@@ -283,6 +334,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
283
334
} else {
284
335
// Adjust for the beginning of the current `Event`
285
336
let span = span. with_lo ( span. lo ( ) + BytePos :: from_usize ( range. start - begin) ) ;
337
+
286
338
check_text ( cx, valid_idents, & text, span) ;
287
339
}
288
340
} ,
@@ -291,13 +343,13 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
291
343
safety_header
292
344
}
293
345
294
- fn check_code ( cx : & EarlyContext < ' _ > , text : & str , span : Span ) {
346
+ fn check_code ( cx : & LateContext < ' _ , ' _ > , text : & str , span : Span ) {
295
347
if text. contains ( "fn main() {" ) {
296
348
span_lint ( cx, NEEDLESS_DOCTEST_MAIN , span, "needless `fn main` in doctest" ) ;
297
349
}
298
350
}
299
351
300
- fn check_text ( cx : & EarlyContext < ' _ > , valid_idents : & FxHashSet < String > , text : & str , span : Span ) {
352
+ fn check_text ( cx : & LateContext < ' _ , ' _ > , valid_idents : & FxHashSet < String > , text : & str , span : Span ) {
301
353
for word in text. split ( |c : char | c. is_whitespace ( ) || c == '\'' ) {
302
354
// Trim punctuation as in `some comment (see foo::bar).`
303
355
// ^^
@@ -320,7 +372,7 @@ fn check_text(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, text: &st
320
372
}
321
373
}
322
374
323
- fn check_word ( cx : & EarlyContext < ' _ > , word : & str , span : Span ) {
375
+ fn check_word ( cx : & LateContext < ' _ , ' _ > , word : & str , span : Span ) {
324
376
/// Checks if a string is camel-case, i.e., contains at least two uppercase
325
377
/// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok).
326
378
/// Plurals are also excluded (`IDs` is ok).
0 commit comments