@@ -13,10 +13,10 @@ use rustc_hir::*;
1313use rustc_lint:: { EarlyContext , EarlyLintPass , LateContext , LateLintPass } ;
1414use rustc_session:: declare_tool_lint;
1515use rustc_session:: { declare_lint_pass, impl_lint_pass} ;
16- use rustc_span:: source_map:: Span ;
16+ use rustc_span:: source_map:: { Span , Spanned } ;
1717use rustc_span:: symbol:: SymbolStr ;
1818use syntax:: ast;
19- use syntax:: ast:: { Crate as AstCrate , ItemKind , Name } ;
19+ use syntax:: ast:: { Crate as AstCrate , ItemKind , LitKind , Name } ;
2020use syntax:: visit:: FnKind ;
2121
2222declare_clippy_lint ! {
@@ -121,6 +121,29 @@ declare_clippy_lint! {
121121 "this message should not appear anywhere as we ICE before and don't emit the lint"
122122}
123123
124+ declare_clippy_lint ! {
125+ /// **What it does:** Checks for cases of an auto-generated lint without an updated description,
126+ /// i.e. `default lint description`.
127+ ///
128+ /// **Why is this bad?** Indicates that the lint is not finished.
129+ ///
130+ /// **Known problems:** None
131+ ///
132+ /// **Example:**
133+ /// Bad:
134+ /// ```rust,ignore
135+ /// declare_lint! { pub COOL_LINT, nursery, "default lint description" }
136+ /// ```
137+ ///
138+ /// Good:
139+ /// ```rust,ignore
140+ /// declare_lint! { pub COOL_LINT, nursery, "a great new lint" }
141+ /// ```
142+ pub DEFAULT_LINT ,
143+ internal,
144+ "found 'default lint description' in a lint declaration"
145+ }
146+
124147declare_lint_pass ! ( ClippyLintsInternal => [ CLIPPY_LINTS_INTERNAL ] ) ;
125148
126149impl EarlyLintPass for ClippyLintsInternal {
@@ -163,12 +186,34 @@ pub struct LintWithoutLintPass {
163186 registered_lints : FxHashSet < Name > ,
164187}
165188
166- impl_lint_pass ! ( LintWithoutLintPass => [ LINT_WITHOUT_LINT_PASS ] ) ;
189+ impl_lint_pass ! ( LintWithoutLintPass => [ DEFAULT_LINT , LINT_WITHOUT_LINT_PASS ] ) ;
167190
168191impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for LintWithoutLintPass {
169192 fn check_item ( & mut self , cx : & LateContext < ' a , ' tcx > , item : & ' tcx Item < ' _ > ) {
170- if let hir:: ItemKind :: Static ( ref ty, Mutability :: Not , _ ) = item. kind {
193+ if let hir:: ItemKind :: Static ( ref ty, Mutability :: Not , body_id ) = item. kind {
171194 if is_lint_ref_type ( cx, ty) {
195+ let expr = & cx. tcx . hir ( ) . body ( body_id) . value ;
196+ if_chain ! {
197+ if let ExprKind :: AddrOf ( _, _, ref inner_exp) = expr. kind;
198+ if let ExprKind :: Struct ( _, ref fields, _) = inner_exp. kind;
199+ let field = fields. iter( )
200+ . find( |f| f. ident. as_str( ) == "desc" )
201+ . expect( "lints must have a description field" ) ;
202+ if let ExprKind :: Lit ( Spanned {
203+ node: LitKind :: Str ( ref sym, _) ,
204+ ..
205+ } ) = field. expr. kind;
206+ if sym. as_str( ) == "default lint description" ;
207+
208+ then {
209+ span_lint(
210+ cx,
211+ DEFAULT_LINT ,
212+ item. span,
213+ & format!( "the lint `{}` has the default lint description" , item. ident. name) ,
214+ ) ;
215+ }
216+ }
172217 self . declared_lints . insert ( item. ident . name , item. span ) ;
173218 }
174219 } else if is_expn_of ( item. span , "impl_lint_pass" ) . is_some ( )
0 commit comments