11use crate :: utils:: span_lint;
22use itertools:: Itertools ;
33use pulldown_cmark;
4- use rustc:: lint:: { EarlyContext , EarlyLintPass , LintArray , LintPass } ;
4+ use rustc:: hir;
5+ use rustc:: lint:: { LateContext , LateLintPass , LintArray , LintPass } ;
56use rustc:: { declare_tool_lint, impl_lint_pass} ;
67use rustc_data_structures:: fx:: FxHashSet ;
78use std:: ops:: Range ;
8- use syntax:: ast;
9+ use syntax:: ast:: Attribute ;
910use syntax:: source_map:: { BytePos , Span } ;
1011use syntax_pos:: Pos ;
1112use url:: Url ;
@@ -100,28 +101,78 @@ declare_clippy_lint! {
100101#[ derive( Clone ) ]
101102pub struct DocMarkdown {
102103 valid_idents : FxHashSet < String > ,
104+ in_trait_impl : bool ,
103105}
104106
105107impl DocMarkdown {
106108 pub fn new ( valid_idents : FxHashSet < String > ) -> Self {
107- Self { valid_idents }
109+ Self {
110+ valid_idents,
111+ in_trait_impl : false ,
112+ }
108113 }
109114}
110115
111116impl_lint_pass ! ( DocMarkdown => [ DOC_MARKDOWN , MISSING_SAFETY_DOC , NEEDLESS_DOCTEST_MAIN ] ) ;
112117
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 ) {
115120 check_attrs ( cx, & self . valid_idents , & krate. attrs ) ;
116121 }
117122
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 ) {
119153 if check_attrs ( cx, & self . valid_idents , & item. attrs ) {
120154 return ;
121155 }
122156 // 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 {
125176 span_lint (
126177 cx,
127178 MISSING_SAFETY_DOC ,
@@ -190,7 +241,7 @@ pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(
190241 panic ! ( "not a doc-comment: {}" , comment) ;
191242}
192243
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 {
194245 let mut doc = String :: new ( ) ;
195246 let mut spans = vec ! [ ] ;
196247
@@ -240,7 +291,7 @@ pub fn check_attrs<'a>(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>,
240291}
241292
242293fn check_doc < ' a , Events : Iterator < Item = ( pulldown_cmark:: Event < ' a > , Range < usize > ) > > (
243- cx : & EarlyContext < ' _ > ,
294+ cx : & LateContext < ' _ , ' _ > ,
244295 valid_idents : & FxHashSet < String > ,
245296 events : Events ,
246297 spans : & [ ( usize , Span ) ] ,
@@ -283,6 +334,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
283334 } else {
284335 // Adjust for the beginning of the current `Event`
285336 let span = span. with_lo ( span. lo ( ) + BytePos :: from_usize ( range. start - begin) ) ;
337+
286338 check_text ( cx, valid_idents, & text, span) ;
287339 }
288340 } ,
@@ -291,13 +343,13 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
291343 safety_header
292344}
293345
294- fn check_code ( cx : & EarlyContext < ' _ > , text : & str , span : Span ) {
346+ fn check_code ( cx : & LateContext < ' _ , ' _ > , text : & str , span : Span ) {
295347 if text. contains ( "fn main() {" ) {
296348 span_lint ( cx, NEEDLESS_DOCTEST_MAIN , span, "needless `fn main` in doctest" ) ;
297349 }
298350}
299351
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 ) {
301353 for word in text. split ( |c : char | c. is_whitespace ( ) || c == '\'' ) {
302354 // Trim punctuation as in `some comment (see foo::bar).`
303355 // ^^
@@ -320,7 +372,7 @@ fn check_text(cx: &EarlyContext<'_>, valid_idents: &FxHashSet<String>, text: &st
320372 }
321373}
322374
323- fn check_word ( cx : & EarlyContext < ' _ > , word : & str , span : Span ) {
375+ fn check_word ( cx : & LateContext < ' _ , ' _ > , word : & str , span : Span ) {
324376 /// Checks if a string is camel-case, i.e., contains at least two uppercase
325377 /// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok).
326378 /// Plurals are also excluded (`IDs` is ok).
0 commit comments