about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2017-07-16 00:17:35 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2017-07-27 20:38:33 +0200
commit1cebf98e4c2654548e764e937e0b712220ffb600 (patch)
tree08856135fb2d9d42b403b4de5873521f63c6f7d2
parentb68a03bded5380278ae162bacc79d926e41fd76c (diff)
Make a lint instead
-rw-r--r--src/librustc/hir/mod.rs7
-rw-r--r--src/librustc_lint/builtin.rs40
-rw-r--r--src/librustc_lint/lib.rs1
-rw-r--r--src/libsyntax/ast.rs7
-rw-r--r--src/libsyntax/parse/parser.rs32
-rw-r--r--src/test/compile-fail/useless_comment.rs28
-rw-r--r--src/test/compile-fail/useless_comment2.rs25
-rw-r--r--src/test/compile-fail/useless_comment3.rs22
8 files changed, 71 insertions, 91 deletions
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 1b14caad3c8..a3a133daa09 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -892,6 +892,13 @@ impl Decl_ {
             DeclItem(_) => &[]
         }
     }
+
+    pub fn is_local(&self) -> bool {
+        match *self {
+            Decl_::DeclLocal(_) => true,
+            _ => false,
+        }
+    }
 }
 
 /// represents one arm of a 'match'
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 02d68a41b4c..ca30ed4a536 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -723,6 +723,46 @@ impl EarlyLintPass for IllegalFloatLiteralPattern {
 }
 
 declare_lint! {
+    pub UNUSED_DOC_COMMENT,
+    Warn,
+    "detects doc comments that aren't used by rustdoc"
+}
+
+#[derive(Copy, Clone)]
+pub struct UnusedDocComment;
+
+impl LintPass for UnusedDocComment {
+    fn get_lints(&self) -> LintArray {
+        lint_array![UNUSED_DOC_COMMENT]
+    }
+}
+
+impl UnusedDocComment {
+    fn warn_if_doc<'a, 'tcx,
+                   I: Iterator<Item=&'a ast::Attribute>,
+                   C: LintContext<'tcx>>(&self, mut attrs: I, cx: &C) {
+        if let Some(attr) = attrs.find(|a| a.is_value_str() && a.check_name("doc")) {
+            cx.struct_span_lint(UNUSED_DOC_COMMENT, attr.span, "doc comment not used by rustdoc")
+              .emit();
+        }
+    }
+}
+
+impl EarlyLintPass for UnusedDocComment {
+    fn check_local(&mut self, cx: &EarlyContext, decl: &ast::Local) {
+        self.warn_if_doc(decl.attrs.iter(), cx);
+    }
+
+    fn check_arm(&mut self, cx: &EarlyContext, arm: &ast::Arm) {
+        self.warn_if_doc(arm.attrs.iter(), cx);
+    }
+
+    fn check_expr(&mut self, cx: &EarlyContext, expr: &ast::Expr) {
+        self.warn_if_doc(expr.attrs.iter(), cx);
+    }
+}
+
+declare_lint! {
     pub UNCONDITIONAL_RECURSION,
     Warn,
     "functions that cannot return without calling themselves"
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 21dca7f6c61..83c00c178a0 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -111,6 +111,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                        UnusedImportBraces,
                        AnonymousParameters,
                        IllegalFloatLiteralPattern,
+                       UnusedDocComment,
                        );
 
     add_early_builtin_with_new!(sess,
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index f7d9d532062..df3f68fd1c6 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -718,6 +718,13 @@ impl Stmt {
         };
         self
     }
+
+    pub fn is_item(&self) -> bool {
+        match self.node {
+            StmtKind::Local(_) => true,
+            _ => false,
+        }
+    }
 }
 
 impl fmt::Debug for Stmt {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 047f4b979d9..582f72e398d 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2420,12 +2420,6 @@ impl<'a> Parser<'a> {
             expr.map(|mut expr| {
                 attrs.extend::<Vec<_>>(expr.attrs.into());
                 expr.attrs = attrs;
-                if if let Some(ref doc) = expr.attrs.iter().find(|x| x.is_sugared_doc) {
-                    self.span_fatal_err(doc.span, Error::UselessDocComment).emit();
-                    true
-                } else { false } {
-                    return expr;
-                }
                 match expr.node {
                     ExprKind::If(..) | ExprKind::IfLet(..) => {
                         if !expr.attrs.is_empty() {
@@ -3110,9 +3104,6 @@ impl<'a> Parser<'a> {
 
     // `else` token already eaten
     pub fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
-        if self.prev_token_kind == PrevTokenKind::DocComment {
-            return Err(self.span_fatal_err(self.span, Error::UselessDocComment));
-        }
         if self.eat_keyword(keywords::If) {
             return self.parse_if_expr(ThinVec::new());
         } else {
@@ -3126,9 +3117,6 @@ impl<'a> Parser<'a> {
                           span_lo: Span,
                           mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         // Parse: `for <src_pat> in <src_expr> <src_loop_block>`
-        if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) {
-            self.span_fatal_err(doc.span, Error::UselessDocComment).emit();
-        }
 
         let pat = self.parse_pat()?;
         self.expect_keyword(keywords::In)?;
@@ -3144,9 +3132,6 @@ impl<'a> Parser<'a> {
     pub fn parse_while_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
                             span_lo: Span,
                             mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
-        if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) {
-            self.span_fatal_err(doc.span, Error::UselessDocComment).emit();
-        }
         if self.token.is_keyword(keywords::Let) {
             return self.parse_while_let_expr(opt_ident, span_lo, attrs);
         }
@@ -3175,9 +3160,6 @@ impl<'a> Parser<'a> {
     pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
                            span_lo: Span,
                            mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
-        if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) {
-            self.span_fatal_err(doc.span, Error::UselessDocComment).emit();
-        }
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         let span = span_lo.to(body.span);
@@ -3188,9 +3170,6 @@ impl<'a> Parser<'a> {
     pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
         -> PResult<'a, P<Expr>>
     {
-        if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) {
-            self.span_fatal_err(doc.span, Error::UselessDocComment).emit();
-        }
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs))
@@ -3198,9 +3177,6 @@ impl<'a> Parser<'a> {
 
     // `match` token already eaten
     fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
-        if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) {
-            self.span_fatal_err(doc.span, Error::UselessDocComment).emit();
-        }
         let match_span = self.prev_span;
         let lo = self.prev_span;
         let discriminant = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL,
@@ -3238,9 +3214,6 @@ impl<'a> Parser<'a> {
         maybe_whole!(self, NtArm, |x| x);
 
         let attrs = self.parse_outer_attributes()?;
-        if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) {
-            self.span_fatal_err(doc.span, Error::UselessDocComment).emit();
-        }
         let pats = self.parse_pats()?;
         let guard = if self.eat_keyword(keywords::If) {
             Some(self.parse_expr()?)
@@ -3695,9 +3668,6 @@ impl<'a> Parser<'a> {
 
     /// Parse a local variable declaration
     fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> {
-        if let Some(doc) = attrs.iter().find(|x| x.is_sugared_doc) {
-            self.span_fatal_err(doc.span, Error::UselessDocComment).emit();
-        }
         let lo = self.span;
         let pat = self.parse_pat()?;
 
@@ -4187,8 +4157,6 @@ impl<'a> Parser<'a> {
                 stmts.push(stmt);
             } else if self.token == token::Eof {
                 break;
-            } else if let token::DocComment(_) = self.token {
-                return Err(self.span_fatal_err(self.span, Error::UselessDocComment));
             } else {
                 // Found only `;` or `}`.
                 continue;
diff --git a/src/test/compile-fail/useless_comment.rs b/src/test/compile-fail/useless_comment.rs
index a32988aff12..bceec186120 100644
--- a/src/test/compile-fail/useless_comment.rs
+++ b/src/test/compile-fail/useless_comment.rs
@@ -8,19 +8,23 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn foo3() -> i32 {
-    let mut x = 12;
-    /// z //~ ERROR E0585
-    while x < 1 {
-        /// x //~ ERROR E0585
-        //~^ ERROR attributes on non-item statements and expressions are experimental
-        x += 1;
+#![deny(unused_doc_comment)]
+
+fn foo() {
+    /// a //~ ERROR unused doc comment
+    let x = 12;
+
+    /// b //~ ERROR unused doc comment
+    match x {
+        /// c //~ ERROR unused doc comment
+        1 => {},
+        _ => {}
     }
-    /// d //~ ERROR E0585
-    return x;
+
+    /// foo //~ ERROR unused doc comment
+    unsafe {}
 }
 
 fn main() {
-    /// e //~ ERROR E0585
-    foo3();
-}
+    foo();
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/useless_comment2.rs b/src/test/compile-fail/useless_comment2.rs
deleted file mode 100644
index 52ac7b6a769..00000000000
--- a/src/test/compile-fail/useless_comment2.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn foo() {
-    /// a //~ ERROR E0585
-    let x = 12;
-
-    /// b //~ ERROR E0585
-    match x {
-        /// c //~ ERROR E0585
-        1 => {},
-        _ => {}
-    }
-}
-
-fn main() {
-    foo();
-}
\ No newline at end of file
diff --git a/src/test/compile-fail/useless_comment3.rs b/src/test/compile-fail/useless_comment3.rs
deleted file mode 100644
index c26031b5eb6..00000000000
--- a/src/test/compile-fail/useless_comment3.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn foo() {
-    let x = 13;
-    /// x //~ ERROR E0585
-    if x == 12 {
-        /// y
-        println!("hello");
-    }
-}
-
-fn main() {
-    foo();
-}