1
Fork 0

Throw errors when doc comments are added where they're unused

This commit is contained in:
Guillaume Gomez 2017-07-02 01:37:47 +02:00
parent 0565653eec
commit 7e70a63e61
6 changed files with 111 additions and 7 deletions

View file

@ -1679,7 +1679,7 @@ pub struct Item {
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Item_ { pub enum Item_ {
/// An`extern crate` item, with optional original crate name, /// An `extern crate` item, with optional original crate name,
/// ///
/// e.g. `extern crate foo` or `extern crate foo_bar as foo` /// e.g. `extern crate foo` or `extern crate foo_bar as foo`
ItemExternCrate(Option<Name>), ItemExternCrate(Option<Name>),

View file

@ -2131,14 +2131,14 @@ impl<'a> Parser<'a> {
} else { } else {
Ok(self.mk_expr(span, ExprKind::Tup(es), attrs)) Ok(self.mk_expr(span, ExprKind::Tup(es), attrs))
} }
}, }
token::OpenDelim(token::Brace) => { token::OpenDelim(token::Brace) => {
return self.parse_block_expr(lo, BlockCheckMode::Default, attrs); return self.parse_block_expr(lo, BlockCheckMode::Default, attrs);
}, }
token::BinOp(token::Or) | token::OrOr => { token::BinOp(token::Or) | token::OrOr => {
let lo = self.span; let lo = self.span;
return self.parse_lambda_expr(lo, CaptureBy::Ref, attrs); return self.parse_lambda_expr(lo, CaptureBy::Ref, attrs);
}, }
token::OpenDelim(token::Bracket) => { token::OpenDelim(token::Bracket) => {
self.bump(); self.bump();
@ -2387,7 +2387,6 @@ impl<'a> Parser<'a> {
pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode, pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode,
outer_attrs: ThinVec<Attribute>) outer_attrs: ThinVec<Attribute>)
-> PResult<'a, P<Expr>> { -> PResult<'a, P<Expr>> {
self.expect(&token::OpenDelim(token::Brace))?; self.expect(&token::OpenDelim(token::Brace))?;
let mut attrs = outer_attrs; let mut attrs = outer_attrs;
@ -2421,6 +2420,12 @@ impl<'a> Parser<'a> {
expr.map(|mut expr| { expr.map(|mut expr| {
attrs.extend::<Vec<_>>(expr.attrs.into()); attrs.extend::<Vec<_>>(expr.attrs.into());
expr.attrs = attrs; 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 { match expr.node {
ExprKind::If(..) | ExprKind::IfLet(..) => { ExprKind::If(..) | ExprKind::IfLet(..) => {
if !expr.attrs.is_empty() { if !expr.attrs.is_empty() {
@ -3105,6 +3110,9 @@ impl<'a> Parser<'a> {
// `else` token already eaten // `else` token already eaten
pub fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> { 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) { if self.eat_keyword(keywords::If) {
return self.parse_if_expr(ThinVec::new()); return self.parse_if_expr(ThinVec::new());
} else { } else {
@ -3118,6 +3126,9 @@ impl<'a> Parser<'a> {
span_lo: Span, span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
// Parse: `for <src_pat> in <src_expr> <src_loop_block>` // 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()?; let pat = self.parse_pat()?;
self.expect_keyword(keywords::In)?; self.expect_keyword(keywords::In)?;
@ -3133,6 +3144,9 @@ impl<'a> Parser<'a> {
pub fn parse_while_expr(&mut self, opt_ident: Option<ast::SpannedIdent>, pub fn parse_while_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
span_lo: Span, span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { 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) { if self.token.is_keyword(keywords::Let) {
return self.parse_while_let_expr(opt_ident, span_lo, attrs); return self.parse_while_let_expr(opt_ident, span_lo, attrs);
} }
@ -3161,6 +3175,9 @@ impl<'a> Parser<'a> {
pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::SpannedIdent>, pub fn parse_loop_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
span_lo: Span, span_lo: Span,
mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { 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()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs); attrs.extend(iattrs);
let span = span_lo.to(body.span); let span = span_lo.to(body.span);
@ -3171,6 +3188,9 @@ impl<'a> Parser<'a> {
pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>) pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
-> PResult<'a, P<Expr>> -> 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()?; let (iattrs, body) = self.parse_inner_attrs_and_block()?;
attrs.extend(iattrs); attrs.extend(iattrs);
Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs)) Ok(self.mk_expr(span_lo.to(body.span), ExprKind::Catch(body), attrs))
@ -3178,6 +3198,9 @@ impl<'a> Parser<'a> {
// `match` token already eaten // `match` token already eaten
fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> { 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 match_span = self.prev_span;
let lo = self.prev_span; let lo = self.prev_span;
let discriminant = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, let discriminant = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL,
@ -3215,6 +3238,9 @@ impl<'a> Parser<'a> {
maybe_whole!(self, NtArm, |x| x); maybe_whole!(self, NtArm, |x| x);
let attrs = self.parse_outer_attributes()?; 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 pats = self.parse_pats()?;
let guard = if self.eat_keyword(keywords::If) { let guard = if self.eat_keyword(keywords::If) {
Some(self.parse_expr()?) Some(self.parse_expr()?)
@ -3669,6 +3695,9 @@ impl<'a> Parser<'a> {
/// Parse a local variable declaration /// Parse a local variable declaration
fn parse_local(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Local>> { 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 lo = self.span;
let pat = self.parse_pat()?; let pat = self.parse_pat()?;
@ -4158,6 +4187,8 @@ impl<'a> Parser<'a> {
stmts.push(stmt); stmts.push(stmt);
} else if self.token == token::Eof { } else if self.token == token::Eof {
break; break;
} else if let token::DocComment(_) = self.token {
return Err(self.span_fatal_err(self.span, Error::UselessDocComment));
} else { } else {
// Found only `;` or `}`. // Found only `;` or `}`.
continue; continue;

View file

@ -13,6 +13,6 @@
#[rustc_error] #[rustc_error]
fn main() { //~ ERROR compilation successful fn main() { //~ ERROR compilation successful
/// crash // crash
let x = 0; let x = 0;
} }

View file

@ -0,0 +1,26 @@
// 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 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;
}
/// d //~ ERROR E0585
return x;
}
fn main() {
/// e //~ ERROR E0585
foo3();
}

View file

@ -0,0 +1,25 @@
// 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();
}

View file

@ -0,0 +1,22 @@
// 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();
}