Skip to content

Commit

Permalink
Merge pull request #1476 from dtolnay/verbatimattrs
Browse files Browse the repository at this point in the history
Preserve attributes on verbatim Item in statement position
  • Loading branch information
dtolnay committed Jun 25, 2023
2 parents 0ca3547 + 56226a5 commit 1316ec6
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 131 deletions.
262 changes: 135 additions & 127 deletions src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -898,166 +898,174 @@ pub(crate) mod parsing {
impl Parse for Item {
fn parse(input: ParseStream) -> Result<Self> {
let begin = input.fork();
let mut attrs = input.call(Attribute::parse_outer)?;
let ahead = input.fork();
let vis: Visibility = ahead.parse()?;
let attrs = input.call(Attribute::parse_outer)?;
parse_rest_of_item(begin, attrs, input)
}
}

pub(crate) fn parse_rest_of_item(
begin: ParseBuffer,
mut attrs: Vec<Attribute>,
input: ParseStream,
) -> Result<Item> {
let ahead = input.fork();
let vis: Visibility = ahead.parse()?;

let lookahead = ahead.lookahead1();
let mut item = if lookahead.peek(Token![fn]) || peek_signature(&ahead) {
let vis: Visibility = input.parse()?;
let sig: Signature = input.parse()?;
if input.peek(Token![;]) {
input.parse::<Token![;]>()?;
Ok(Item::Verbatim(verbatim::between(begin, input)))
} else {
parse_rest_of_fn(input, Vec::new(), vis, sig).map(Item::Fn)
}
} else if lookahead.peek(Token![extern]) {
ahead.parse::<Token![extern]>()?;
let lookahead = ahead.lookahead1();
let mut item = if lookahead.peek(Token![fn]) || peek_signature(&ahead) {
let vis: Visibility = input.parse()?;
let sig: Signature = input.parse()?;
if input.peek(Token![;]) {
input.parse::<Token![;]>()?;
Ok(Item::Verbatim(verbatim::between(begin, input)))
} else {
parse_rest_of_fn(input, Vec::new(), vis, sig).map(Item::Fn)
}
} else if lookahead.peek(Token![extern]) {
ahead.parse::<Token![extern]>()?;
if lookahead.peek(Token![crate]) {
input.parse().map(Item::ExternCrate)
} else if lookahead.peek(token::Brace) {
input.parse().map(Item::ForeignMod)
} else if lookahead.peek(LitStr) {
ahead.parse::<LitStr>()?;
let lookahead = ahead.lookahead1();
if lookahead.peek(Token![crate]) {
input.parse().map(Item::ExternCrate)
} else if lookahead.peek(token::Brace) {
if lookahead.peek(token::Brace) {
input.parse().map(Item::ForeignMod)
} else if lookahead.peek(LitStr) {
ahead.parse::<LitStr>()?;
let lookahead = ahead.lookahead1();
if lookahead.peek(token::Brace) {
input.parse().map(Item::ForeignMod)
} else {
Err(lookahead.error())
}
} else {
Err(lookahead.error())
}
} else if lookahead.peek(Token![use]) {
let allow_crate_root_in_path = true;
match parse_item_use(input, allow_crate_root_in_path)? {
Some(item_use) => Ok(Item::Use(item_use)),
None => Ok(Item::Verbatim(verbatim::between(begin, input))),
}
} else if lookahead.peek(Token![static]) {
let vis = input.parse()?;
let static_token = input.parse()?;
let mutability = input.parse()?;
let ident = input.parse()?;
if input.peek(Token![=]) {
input.parse::<Token![=]>()?;
input.parse::<Expr>()?;
input.parse::<Token![;]>()?;
Ok(Item::Verbatim(verbatim::between(begin, input)))
} else {
let colon_token = input.parse()?;
let ty = input.parse()?;
if input.peek(Token![;]) {
input.parse::<Token![;]>()?;
Ok(Item::Verbatim(verbatim::between(begin, input)))
} else {
Ok(Item::Static(ItemStatic {
attrs: Vec::new(),
vis,
static_token,
mutability,
ident,
colon_token,
ty,
eq_token: input.parse()?,
expr: input.parse()?,
semi_token: input.parse()?,
}))
}
}
} else if lookahead.peek(Token![const]) {
let vis = input.parse()?;
let const_token: Token![const] = input.parse()?;
let lookahead = input.lookahead1();
let ident = if lookahead.peek(Ident) || lookahead.peek(Token![_]) {
input.call(Ident::parse_any)?
} else {
return Err(lookahead.error());
};
} else {
Err(lookahead.error())
}
} else if lookahead.peek(Token![use]) {
let allow_crate_root_in_path = true;
match parse_item_use(input, allow_crate_root_in_path)? {
Some(item_use) => Ok(Item::Use(item_use)),
None => Ok(Item::Verbatim(verbatim::between(begin, input))),
}
} else if lookahead.peek(Token![static]) {
let vis = input.parse()?;
let static_token = input.parse()?;
let mutability = input.parse()?;
let ident = input.parse()?;
if input.peek(Token![=]) {
input.parse::<Token![=]>()?;
input.parse::<Expr>()?;
input.parse::<Token![;]>()?;
Ok(Item::Verbatim(verbatim::between(begin, input)))
} else {
let colon_token = input.parse()?;
let ty = input.parse()?;
if input.peek(Token![;]) {
input.parse::<Token![;]>()?;
Ok(Item::Verbatim(verbatim::between(begin, input)))
} else {
Ok(Item::Const(ItemConst {
Ok(Item::Static(ItemStatic {
attrs: Vec::new(),
vis,
const_token,
static_token,
mutability,
ident,
generics: Generics::default(),
colon_token,
ty,
eq_token: input.parse()?,
expr: input.parse()?,
semi_token: input.parse()?,
}))
}
} else if lookahead.peek(Token![unsafe]) {
ahead.parse::<Token![unsafe]>()?;
let lookahead = ahead.lookahead1();
if lookahead.peek(Token![trait])
|| lookahead.peek(Token![auto]) && ahead.peek2(Token![trait])
{
input.parse().map(Item::Trait)
} else if lookahead.peek(Token![impl]) {
let allow_verbatim_impl = true;
if let Some(item) = parse_impl(input, allow_verbatim_impl)? {
Ok(Item::Impl(item))
} else {
Ok(Item::Verbatim(verbatim::between(begin, input)))
}
} else if lookahead.peek(Token![extern]) {
input.parse().map(Item::ForeignMod)
} else if lookahead.peek(Token![mod]) {
input.parse().map(Item::Mod)
} else {
Err(lookahead.error())
}
} else if lookahead.peek(Token![mod]) {
input.parse().map(Item::Mod)
} else if lookahead.peek(Token![type]) {
parse_item_type(begin, input)
} else if lookahead.peek(Token![struct]) {
input.parse().map(Item::Struct)
} else if lookahead.peek(Token![enum]) {
input.parse().map(Item::Enum)
} else if lookahead.peek(Token![union]) && ahead.peek2(Ident) {
input.parse().map(Item::Union)
} else if lookahead.peek(Token![trait]) {
input.call(parse_trait_or_trait_alias)
} else if lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) {
input.parse().map(Item::Trait)
} else if lookahead.peek(Token![impl])
|| lookahead.peek(Token![default]) && !ahead.peek2(Token![!])
}
} else if lookahead.peek(Token![const]) {
let vis = input.parse()?;
let const_token: Token![const] = input.parse()?;
let lookahead = input.lookahead1();
let ident = if lookahead.peek(Ident) || lookahead.peek(Token![_]) {
input.call(Ident::parse_any)?
} else {
return Err(lookahead.error());
};
let colon_token = input.parse()?;
let ty = input.parse()?;
if input.peek(Token![;]) {
input.parse::<Token![;]>()?;
Ok(Item::Verbatim(verbatim::between(begin, input)))
} else {
Ok(Item::Const(ItemConst {
attrs: Vec::new(),
vis,
const_token,
ident,
generics: Generics::default(),
colon_token,
ty,
eq_token: input.parse()?,
expr: input.parse()?,
semi_token: input.parse()?,
}))
}
} else if lookahead.peek(Token![unsafe]) {
ahead.parse::<Token![unsafe]>()?;
let lookahead = ahead.lookahead1();
if lookahead.peek(Token![trait])
|| lookahead.peek(Token![auto]) && ahead.peek2(Token![trait])
{
input.parse().map(Item::Trait)
} else if lookahead.peek(Token![impl]) {
let allow_verbatim_impl = true;
if let Some(item) = parse_impl(input, allow_verbatim_impl)? {
Ok(Item::Impl(item))
} else {
Ok(Item::Verbatim(verbatim::between(begin, input)))
}
} else if lookahead.peek(Token![macro]) {
input.advance_to(&ahead);
parse_macro2(begin, vis, input)
} else if vis.is_inherited()
&& (lookahead.peek(Ident)
|| lookahead.peek(Token![self])
|| lookahead.peek(Token![super])
|| lookahead.peek(Token![crate])
|| lookahead.peek(Token![::]))
{
input.parse().map(Item::Macro)
} else if lookahead.peek(Token![extern]) {
input.parse().map(Item::ForeignMod)
} else if lookahead.peek(Token![mod]) {
input.parse().map(Item::Mod)
} else {
Err(lookahead.error())
}?;
}
} else if lookahead.peek(Token![mod]) {
input.parse().map(Item::Mod)
} else if lookahead.peek(Token![type]) {
parse_item_type(begin, input)
} else if lookahead.peek(Token![struct]) {
input.parse().map(Item::Struct)
} else if lookahead.peek(Token![enum]) {
input.parse().map(Item::Enum)
} else if lookahead.peek(Token![union]) && ahead.peek2(Ident) {
input.parse().map(Item::Union)
} else if lookahead.peek(Token![trait]) {
input.call(parse_trait_or_trait_alias)
} else if lookahead.peek(Token![auto]) && ahead.peek2(Token![trait]) {
input.parse().map(Item::Trait)
} else if lookahead.peek(Token![impl])
|| lookahead.peek(Token![default]) && !ahead.peek2(Token![!])
{
let allow_verbatim_impl = true;
if let Some(item) = parse_impl(input, allow_verbatim_impl)? {
Ok(Item::Impl(item))
} else {
Ok(Item::Verbatim(verbatim::between(begin, input)))
}
} else if lookahead.peek(Token![macro]) {
input.advance_to(&ahead);
parse_macro2(begin, vis, input)
} else if vis.is_inherited()
&& (lookahead.peek(Ident)
|| lookahead.peek(Token![self])
|| lookahead.peek(Token![super])
|| lookahead.peek(Token![crate])
|| lookahead.peek(Token![::]))
{
input.parse().map(Item::Macro)
} else {
Err(lookahead.error())
}?;

attrs.extend(item.replace_attrs(Vec::new()));
item.replace_attrs(attrs);
Ok(item)
}
attrs.extend(item.replace_attrs(Vec::new()));
item.replace_attrs(attrs);
Ok(item)
}

struct FlexibleItemType {
Expand Down
7 changes: 3 additions & 4 deletions src/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ pub(crate) mod parsing {
}

fn parse_stmt(input: ParseStream, allow_nosemi: AllowNoSemi) -> Result<Stmt> {
let mut attrs = input.call(Attribute::parse_outer)?;
let begin = input.fork();
let attrs = input.call(Attribute::parse_outer)?;

// brace-style macros; paren and bracket macros get parsed as
// expression statements.
Expand Down Expand Up @@ -238,9 +239,7 @@ pub(crate) mod parsing {
|| input.peek(Token![macro])
|| is_item_macro
{
let mut item: Item = input.parse()?;
attrs.extend(item.replace_attrs(Vec::new()));
item.replace_attrs(attrs);
let item = item::parsing::parse_rest_of_item(begin, attrs, input)?;
Ok(Stmt::Item(item))
} else {
stmt_expr(input, allow_nosemi, attrs)
Expand Down

0 comments on commit 1316ec6

Please sign in to comment.