Account for missing keyword in fn/struct definition

This commit is contained in:
Esteban Küber 2017-11-14 17:49:29 -08:00
parent 1737d69c3b
commit 547873aa54
5 changed files with 106 additions and 1 deletions

View file

@ -6236,7 +6236,58 @@ fn parse_item_(&mut self, attrs: Vec<Attribute>,
return Ok(Some(macro_def));
}
self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility)
// Verify wether we have encountered a struct or method definition where the user forgot to
// add the `struct` or `fn` keyword after writing `pub`: `pub S {}`
if visibility == Visibility::Public && self.check_ident() {
// Keep the current state of the parser to rollback after an unsuccessful attempt to
// parse an entire method or struct body.
let parser_snapshot = self.clone();
// Space between `pub` keyword and the identifier
//
// pub S {}
// ^^^ `sp` points here
let sp = self.prev_span.between(self.span);
if self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) {
// possible public struct definition where `struct` was forgotten
let ident = self.parse_ident().unwrap();
match self.parse_record_struct_body() {
Err(mut err) => {
// couldn't parse a struct body, continue parsing as if it were a macro
err.cancel();
mem::replace(self, parser_snapshot);
}
Ok(_) => {
let msg = format!("add `struct` here to parse `{}` as a public struct",
ident);
let mut err = self.diagnostic()
.struct_span_err(sp, "missing `struct` for struct definition");
err.span_suggestion_short(sp, &msg, " struct ".into());
return Err(err);
}
}
} else if self.look_ahead(1, |t| *t == token::OpenDelim(token::Paren)) {
// possible public method definition where `fn` was forgotten
let ident = self.parse_ident().unwrap();
match self.parse_fn_decl(false)
.and_then(|_| self.parse_where_clause())
.and_then(|_| self.parse_inner_attrs_and_block()) {
Err(mut err) => {
// couldn't parse method arguments or body, continue parsing
err.cancel();
mem::replace(self, parser_snapshot);
}
Ok(_) => {
let msg = format!("add `fn` here to parse `{}` as a public method", ident);
let mut err = self.diagnostic()
.struct_span_err(sp, "missing `fn` for method definition");
err.span_suggestion_short(sp, &msg, " fn ".into());
return Err(err);
}
}
}
}
self.parse_macro_use_or_failure(attrs, macros_allowed, attributes_allowed, lo, visibility)
}
/// Parse a foreign item.

View file

@ -0,0 +1,15 @@
// 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.
pub foo(s: usize) -> bool { true }
fn main() {
foo(2);
}

View file

@ -0,0 +1,13 @@
error: missing `fn` for method definition
--> $DIR/pub-ident-fn.rs:11:4
|
11 | pub foo(s: usize) -> bool { true }
| ^^^
|
help: add `fn` here to parse `foo` as a public method
|
11 | pub fn foo(s: usize) -> bool { true }
| ^^
error: aborting due to previous error

View file

@ -0,0 +1,13 @@
// 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.
pub S {
}
fn main() {}

View file

@ -0,0 +1,13 @@
error: missing `struct` for struct definition
--> $DIR/pub-ident-struct.rs:11:4
|
11 | pub S {
| ^
|
help: add `struct` here to parse `S` as a public struct
|
11 | pub struct S {
| ^^^^^^
error: aborting due to previous error