1
Fork 0

Auto merge of #33922 - estebank:doc-comment, r=alexcrichton

Specific error message for missplaced doc comments

Identify when documetation comments have been missplaced in the following places:

 * After a struct element:

    ```rust
    // file.rs:
    struct X {
        a: u8 /** document a */,
    }
    ```

    ```bash
    $ rustc file.rs
    file.rs:2:11: 2:28 error: found documentation comment that doesn't
    document anything
    file.rs:2     a: u8 /** document a */,
                        ^~~~~~~~~~~~~~~~~
    file.rs:2:11: 2:28 help: doc comments must come before what they document,
    maybe a comment was intended with `//`?
    ```

 * As the last line of a struct:

    ```rust
    // file.rs:
    struct X {
        a: u8,
        /// incorrect documentation
    }
    ```

    ```bash
    $ rustc file.rs
    file.rs:3:5: 3:27 error: found a documentation comment that doesn't
    document anything
    file.rs:3     /// incorrect documentation
                  ^~~~~~~~~~~~~~~~~~~~~~
    file.rs:3:5: 3:27 help: doc comments must come before what they document,
    maybe a comment was intended with `//`?
    ```

 * As the last line of a `fn`:

    ```rust
    // file.rs:
    fn main() {
        let x = 1;
        /// incorrect documentation
    }
    ```

    ```bash
    $ rustc file.rs
    file.rs:3:5: 3:27 error: found a documentation comment that doesn't
    document anything
    file.rs:3     /// incorrect documentation
                  ^~~~~~~~~~~~~~~~~~~~~~
    file.rs:3:5: 3:27 help: doc comments must come before what they document,
    maybe a comment was intended with `//`?
    ```

Fix #27429, #30322
This commit is contained in:
bors 2016-08-19 18:14:53 -07:00 committed by GitHub
commit 38fa82a314
12 changed files with 169 additions and 20 deletions

View file

@ -564,6 +564,15 @@ impl Handler {
self.bump_err_count(); self.bump_err_count();
self.panic_if_treat_err_as_bug(); self.panic_if_treat_err_as_bug();
} }
pub fn mut_span_err<'a, S: Into<MultiSpan>>(&'a self,
sp: S,
msg: &str)
-> DiagnosticBuilder<'a> {
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
result.set_span(sp);
self.bump_err_count();
result
}
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) { pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
self.emit_with_code(&sp.into(), msg, code, Error); self.emit_with_code(&sp.into(), msg, code, Error);
self.bump_err_count(); self.bump_err_count();

View file

@ -520,12 +520,21 @@ impl<'a> Parser<'a> {
self.bug("ident interpolation not converted to real token"); self.bug("ident interpolation not converted to real token");
} }
_ => { _ => {
let mut err = self.fatal(&format!("expected identifier, found `{}`", let last_token = self.last_token.clone().map(|t| *t);
self.this_token_to_string())); Err(match last_token {
if self.token == token::Underscore { Some(token::DocComment(_)) => self.span_fatal_help(self.last_span,
err.note("`_` is a wildcard pattern, not an identifier"); "found a documentation comment that doesn't document anything",
} "doc comments must come before what they document, maybe a comment was \
Err(err) intended with `//`?"),
_ => {
let mut err = self.fatal(&format!("expected identifier, found `{}`",
self.this_token_to_string()));
if self.token == token::Underscore {
err.note("`_` is a wildcard pattern, not an identifier");
}
err
}
})
} }
} }
} }
@ -927,6 +936,7 @@ impl<'a> Parser<'a> {
// Stash token for error recovery (sometimes; clone is not necessarily cheap). // Stash token for error recovery (sometimes; clone is not necessarily cheap).
self.last_token = if self.token.is_ident() || self.last_token = if self.token.is_ident() ||
self.token.is_path() || self.token.is_path() ||
self.token.is_doc_comment() ||
self.token == token::Comma { self.token == token::Comma {
Some(Box::new(self.token.clone())) Some(Box::new(self.token.clone()))
} else { } else {
@ -1018,6 +1028,11 @@ impl<'a> Parser<'a> {
pub fn span_err(&self, sp: Span, m: &str) { pub fn span_err(&self, sp: Span, m: &str) {
self.sess.span_diagnostic.span_err(sp, m) self.sess.span_diagnostic.span_err(sp, m)
} }
pub fn span_err_help(&self, sp: Span, m: &str, h: &str) {
let mut err = self.sess.span_diagnostic.mut_span_err(sp, m);
err.help(h);
err.emit();
}
pub fn span_bug(&self, sp: Span, m: &str) -> ! { pub fn span_bug(&self, sp: Span, m: &str) -> ! {
self.sess.span_diagnostic.span_bug(sp, m) self.sess.span_diagnostic.span_bug(sp, m)
} }
@ -4021,8 +4036,14 @@ impl<'a> Parser<'a> {
None => { None => {
let unused_attrs = |attrs: &[_], s: &mut Self| { let unused_attrs = |attrs: &[_], s: &mut Self| {
if attrs.len() > 0 { if attrs.len() > 0 {
s.span_err(s.span, let last_token = s.last_token.clone().map(|t| *t);
"expected statement after outer attribute"); match last_token {
Some(token::DocComment(_)) => s.span_err_help(s.last_span,
"found a documentation comment that doesn't document anything",
"doc comments must come before what they document, maybe a \
comment was intended with `//`?"),
_ => s.span_err(s.span, "expected statement after outer attribute"),
}
} }
}; };
@ -5127,14 +5148,13 @@ impl<'a> Parser<'a> {
self.bump(); self.bump();
} }
token::CloseDelim(token::Brace) => {} token::CloseDelim(token::Brace) => {}
_ => { token::DocComment(_) => return Err(self.span_fatal_help(self.span,
let span = self.span; "found a documentation comment that doesn't document anything",
let token_str = self.this_token_to_string(); "doc comments must come before what they document, maybe a comment was \
return Err(self.span_fatal_help(span, intended with `//`?")),
&format!("expected `,`, or `}}`, found `{}`", _ => return Err(self.span_fatal_help(self.span,
token_str), &format!("expected `,`, or `}}`, found `{}`", self.this_token_to_string()),
"struct fields should be separated by commas")) "struct fields should be separated by commas")),
}
} }
Ok(a_var) Ok(a_var)
} }

View file

@ -203,7 +203,7 @@ impl Token {
pub fn is_lit(&self) -> bool { pub fn is_lit(&self) -> bool {
match *self { match *self {
Literal(_, _) => true, Literal(_, _) => true,
_ => false, _ => false,
} }
} }
@ -215,6 +215,14 @@ impl Token {
} }
} }
/// Returns `true` if the token is a documentation comment.
pub fn is_doc_comment(&self) -> bool {
match *self {
DocComment(..) => true,
_ => false,
}
}
/// Returns `true` if the token is interpolated. /// Returns `true` if the token is interpolated.
pub fn is_interpolated(&self) -> bool { pub fn is_interpolated(&self) -> bool {
match *self { match *self {

View file

@ -0,0 +1,20 @@
// Copyright 2015 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.
// compile-flags: -Z continue-parse-after-error
struct X {
a: u8 /** document a */,
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
}
fn main() {
let y = X {a = 1};
}

View file

@ -12,5 +12,5 @@
extern { extern {
/// hi /// hi
//~^ ERROR expected item after doc comment
} }
//~^^ ERROR expected item after doc comment

View file

@ -0,0 +1,16 @@
// Copyright 2015 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.
// compile-flags: -Z continue-parse-after-error
fn main() {
/// document
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
}

View file

@ -0,0 +1,18 @@
// Copyright 2015 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.
// compile-flags: -Z continue-parse-after-error
fn /// document
foo() {}
//~^^ ERROR expected identifier, found `/// document`
fn main() {
foo();
}

View file

@ -0,0 +1,15 @@
// Copyright 2015 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.
// compile-flags: -Z continue-parse-after-error
mod Foo {
/// document
//~^ ERROR expected item after doc comment
}

View file

@ -12,5 +12,6 @@
fn main() { fn main() {
println!("Hi"); /// hi println!("Hi"); /// hi
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
} }
//~^ ERROR expected statement

View file

@ -12,6 +12,7 @@
fn main() { fn main() {
/// hi /// hi
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
; ;
//~^ ERROR expected statement
} }

View file

@ -0,0 +1,21 @@
// Copyright 2015 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.
// compile-flags: -Z continue-parse-after-error
struct X {
a: u8,
/// document
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
}
fn main() {
let y = X {a = 1};
}

View file

@ -0,0 +1,20 @@
// Copyright 2015 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.
// compile-flags: -Z continue-parse-after-error
struct X {
a: u8 /// document
//~^ ERROR found a documentation comment that doesn't document anything
//~| HELP maybe a comment was intended
}
fn main() {
let y = X {a = 1};
}