From c8498cc2c27b699436c5f3d3759695926ee0c825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 27 May 2016 19:05:22 -0700 Subject: [PATCH] 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 --- src/librustc_errors/lib.rs | 9 ++++ src/libsyntax/parse/parser.rs | 52 +++++++++++++------ src/libsyntax/parse/token.rs | 10 +++- src/test/parse-fail/doc-after-struct-field.rs | 20 +++++++ .../parse-fail/doc-before-extern-rbrace.rs | 2 +- src/test/parse-fail/doc-before-fn-rbrace.rs | 16 ++++++ src/test/parse-fail/doc-before-identifier.rs | 18 +++++++ src/test/parse-fail/doc-before-mod-rbrace.rs | 15 ++++++ src/test/parse-fail/doc-before-rbrace.rs | 3 +- src/test/parse-fail/doc-before-semi.rs | 3 +- .../parse-fail/doc-before-struct-rbrace-1.rs | 21 ++++++++ .../parse-fail/doc-before-struct-rbrace-2.rs | 20 +++++++ 12 files changed, 169 insertions(+), 20 deletions(-) create mode 100644 src/test/parse-fail/doc-after-struct-field.rs create mode 100644 src/test/parse-fail/doc-before-fn-rbrace.rs create mode 100644 src/test/parse-fail/doc-before-identifier.rs create mode 100644 src/test/parse-fail/doc-before-mod-rbrace.rs create mode 100644 src/test/parse-fail/doc-before-struct-rbrace-1.rs create mode 100644 src/test/parse-fail/doc-before-struct-rbrace-2.rs diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 18fc826f9aa4b..1d0f185c60ada 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -564,6 +564,15 @@ impl Handler { self.bump_err_count(); self.panic_if_treat_err_as_bug(); } + pub fn mut_span_err<'a, S: Into>(&'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>(&self, sp: S, msg: &str, code: &str) { self.emit_with_code(&sp.into(), msg, code, Error); self.bump_err_count(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6fa95afd9fb22..027b78c17d3d1 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -578,12 +578,21 @@ impl<'a> Parser<'a> { self.bug("ident interpolation not converted to real token"); } _ => { - 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(err) + let last_token = self.last_token.clone().map(|t| *t); + Err(match last_token { + Some(token::DocComment(_)) => self.span_fatal_help(self.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 `//`?"), + _ => { + 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 + } + }) } } } @@ -985,6 +994,7 @@ impl<'a> Parser<'a> { // Stash token for error recovery (sometimes; clone is not necessarily cheap). self.last_token = if self.token.is_ident() || self.token.is_path() || + self.token.is_doc_comment() || self.token == token::Comma { Some(Box::new(self.token.clone())) } else { @@ -1076,6 +1086,11 @@ impl<'a> Parser<'a> { pub fn span_err(&self, sp: Span, m: &str) { 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) -> ! { self.sess.span_diagnostic.span_bug(sp, m) } @@ -4029,8 +4044,14 @@ impl<'a> Parser<'a> { None => { let unused_attrs = |attrs: &[_], s: &mut Self| { if attrs.len() > 0 { - s.span_err(s.span, - "expected statement after outer attribute"); + let last_token = s.last_token.clone().map(|t| *t); + 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"), + } } }; @@ -5198,14 +5219,13 @@ impl<'a> Parser<'a> { self.bump(); } token::CloseDelim(token::Brace) => {} - _ => { - let span = self.span; - let token_str = self.this_token_to_string(); - return Err(self.span_fatal_help(span, - &format!("expected `,`, or `}}`, found `{}`", - token_str), - "struct fields should be separated by commas")) - } + token::DocComment(_) => return Err(self.span_fatal_help(self.span, + "found a documentation comment that doesn't document anything", + "doc comments must come before what they document, maybe a comment was \ + intended with `//`?")), + _ => return Err(self.span_fatal_help(self.span, + &format!("expected `,`, or `}}`, found `{}`", self.this_token_to_string()), + "struct fields should be separated by commas")), } Ok(a_var) } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 8376d28164dee..3f78dffd31c2d 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -202,7 +202,7 @@ impl Token { pub fn is_lit(&self) -> bool { match *self { Literal(_, _) => true, - _ => false, + _ => false, } } @@ -214,6 +214,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. pub fn is_interpolated(&self) -> bool { match *self { diff --git a/src/test/parse-fail/doc-after-struct-field.rs b/src/test/parse-fail/doc-after-struct-field.rs new file mode 100644 index 0000000000000..1aa6af5b78f5b --- /dev/null +++ b/src/test/parse-fail/doc-after-struct-field.rs @@ -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 or the MIT license +// , 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}; +} diff --git a/src/test/parse-fail/doc-before-extern-rbrace.rs b/src/test/parse-fail/doc-before-extern-rbrace.rs index 9e825193dc0d8..70da47ba9b4f0 100644 --- a/src/test/parse-fail/doc-before-extern-rbrace.rs +++ b/src/test/parse-fail/doc-before-extern-rbrace.rs @@ -12,5 +12,5 @@ extern { /// hi + //~^ ERROR expected item after doc comment } -//~^^ ERROR expected item after doc comment diff --git a/src/test/parse-fail/doc-before-fn-rbrace.rs b/src/test/parse-fail/doc-before-fn-rbrace.rs new file mode 100644 index 0000000000000..bcf32612c8f4c --- /dev/null +++ b/src/test/parse-fail/doc-before-fn-rbrace.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/parse-fail/doc-before-identifier.rs b/src/test/parse-fail/doc-before-identifier.rs new file mode 100644 index 0000000000000..8f1fad91b1f99 --- /dev/null +++ b/src/test/parse-fail/doc-before-identifier.rs @@ -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 or the MIT license +// , 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(); +} diff --git a/src/test/parse-fail/doc-before-mod-rbrace.rs b/src/test/parse-fail/doc-before-mod-rbrace.rs new file mode 100644 index 0000000000000..d38d1876384a8 --- /dev/null +++ b/src/test/parse-fail/doc-before-mod-rbrace.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/parse-fail/doc-before-rbrace.rs b/src/test/parse-fail/doc-before-rbrace.rs index 295d5ae432ecb..48ea2b5aea12c 100644 --- a/src/test/parse-fail/doc-before-rbrace.rs +++ b/src/test/parse-fail/doc-before-rbrace.rs @@ -12,5 +12,6 @@ fn main() { println!("Hi"); /// hi + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended } -//~^ ERROR expected statement diff --git a/src/test/parse-fail/doc-before-semi.rs b/src/test/parse-fail/doc-before-semi.rs index 6a8906953be09..71104b8caae19 100644 --- a/src/test/parse-fail/doc-before-semi.rs +++ b/src/test/parse-fail/doc-before-semi.rs @@ -12,6 +12,7 @@ fn main() { /// hi + //~^ ERROR found a documentation comment that doesn't document anything + //~| HELP maybe a comment was intended ; - //~^ ERROR expected statement } diff --git a/src/test/parse-fail/doc-before-struct-rbrace-1.rs b/src/test/parse-fail/doc-before-struct-rbrace-1.rs new file mode 100644 index 0000000000000..5ba83190c8e50 --- /dev/null +++ b/src/test/parse-fail/doc-before-struct-rbrace-1.rs @@ -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 or the MIT license +// , 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}; +} diff --git a/src/test/parse-fail/doc-before-struct-rbrace-2.rs b/src/test/parse-fail/doc-before-struct-rbrace-2.rs new file mode 100644 index 0000000000000..643e4aa17a1ac --- /dev/null +++ b/src/test/parse-fail/doc-before-struct-rbrace-2.rs @@ -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 or the MIT license +// , 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}; +}