From c8498cc2c27b699436c5f3d3759695926ee0c825 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 27 May 2016 19:05:22 -0700 Subject: 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/libsyntax/parse/parser.rs | 52 ++++++++++++++++++++++++++++++------------- src/libsyntax/parse/token.rs | 10 ++++++++- 2 files changed, 45 insertions(+), 17 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6fa95afd9fb..027b78c17d3 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 8376d28164d..3f78dffd31c 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 { -- cgit 1.4.1-3-g733a5