Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update snapshots to latest cargo-insta version #52

Merged
merged 3 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ mod tests;

mod error;
mod parse;
mod parse_extern;
mod parse_fn;
mod parse_impl;
mod parse_mod;
Expand Down
10 changes: 7 additions & 3 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,21 +202,25 @@ pub fn consume_declaration(tokens: &mut Peekable<IntoIter>) -> Result<Declaratio
let static_decl = parse_const_or_static(tokens, attributes, vis_marker);
Declaration::Constant(static_decl)
}
// Note: fn qualifiers appear always in this order in Rust: default const async unsafe extern fn
Some(TokenTree::Ident(keyword)) if keyword == "use" => {
let use_decl = parse_use_declaration(tokens, attributes, vis_marker);

Declaration::Use(use_decl)
}
// Note: fn qualifiers appear always in this order in Rust
// Note: fn qualifiers appear always in this order in Rust: default const async unsafe extern fn
Some(TokenTree::Ident(keyword))
if matches!(
keyword.to_string().as_str(),
"default" | "const" | "async" | "unsafe" | "extern" | "fn" | "type"
) =>
{
// Reuse impl parsing
consume_either_fn_type_const_static_impl(tokens, attributes, vis_marker, "declaration")
consume_either_fn_type_const_static_impl(
tokens,
attributes,
vis_marker,
"fn/type/const/static/extern/extern crate",
)
}
Some(token) => {
if let Some(macro_) = consume_macro(tokens, attributes) {
Expand Down
99 changes: 99 additions & 0 deletions src/parse_extern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use crate::parse_impl::parse_impl_body;
use crate::parse_utils::{consume_ident, parse_any_ident, parse_ident, parse_punct, TokenIter};
use crate::{Attribute, ExternBlock, ExternCrate, VisMarker};
use proc_macro2::{Delimiter, TokenTree};

pub(crate) fn parse_extern_crate(
tokens: &mut TokenIter,
attributes: Vec<Attribute>,
vis_marker: Option<VisMarker>,
) -> ExternCrate {
consume_extern_crate(tokens, attributes, vis_marker).expect("cannot parse extern crate")
}

fn consume_extern_crate(
tokens: &mut TokenIter,
attributes: Vec<Attribute>,
vis_marker: Option<VisMarker>,
) -> Option<ExternCrate> {
let tk_extern = consume_ident(tokens, "extern")?;
let tk_crate = consume_ident(tokens, "crate")?;

let name = parse_any_ident(tokens, "extern crate");
let tk_as = consume_ident(tokens, "as");

let alias;
let tk_underscore;
if tk_as.is_some() {
alias = Some(parse_any_ident(tokens, "extern crate: alias"));
if alias.is_none() {
tk_underscore = Some(parse_ident(tokens, "_", "extern crate"));
} else {
tk_underscore = None;
}
} else {
alias = None;
tk_underscore = None;
}

let tk_semicolon = parse_punct(tokens, ';', "extern crate");

Some(ExternCrate {
attributes,
vis_marker,
tk_extern,
tk_crate,
name,
tk_as,
alias,
tk_underscore,
tk_semicolon,
})
}

pub(crate) fn parse_extern_block(
tokens: &mut TokenIter,
attributes: Vec<Attribute>,
vis_marker: Option<VisMarker>,
) -> ExternBlock {
consume_extern_block(tokens, attributes, vis_marker).expect("cannot parse extern block")
}

fn consume_extern_block(
tokens: &mut TokenIter,
attributes: Vec<Attribute>,
vis_marker: Option<VisMarker>,
) -> Option<ExternBlock> {
let tk_unsafe = consume_ident(tokens, "unsafe");
let tk_extern = consume_ident(tokens, "extern")?;

let extern_abi = match tokens.peek() {
Some(TokenTree::Literal(lit)) => {
let lit = Some(lit.clone());
tokens.next();
lit
}
_ => None,
};

let (tk_braces, inner_attributes, body_items) = match tokens.next() {
Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => {
parse_impl_body(group, true)
}
_ => {
// Only here we know that it's not an extern crate or extern block, so try other options on call-site (fn).
return None;
}
};

Some(ExternBlock {
attributes,
vis_marker,
tk_unsafe,
tk_extern,
extern_abi,
tk_braces,
inner_attributes,
body_items,
})
}
84 changes: 57 additions & 27 deletions src/parse_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ type TokenIter = Peekable<proc_macro2::token_stream::IntoIter>;

/// If venial fails to parse the declaration as a function, it can detect that it
/// is either a constant (`const` ambiguity), an impl or a module (`unsafe` ambiguity).

#[derive(Debug)]
pub(crate) enum NotFunction {
Const,
Static,
Trait,
Impl,
Mod,
ExternCrate,
ExternBlock,
}

pub(crate) fn consume_fn_qualifiers(tokens: &mut TokenIter) -> FnQualifiers {
Expand Down Expand Up @@ -148,36 +153,61 @@ pub(crate) fn consume_fn(

// fn keyword, or const fallback
let next_token = tokens.next();
let tk_fn_keyword = if let Some(TokenTree::Ident(ident)) = &next_token {
if ident == "fn" {
ident.clone()
} else if qualifiers.has_only_const_xor_unsafe() {
// This is not a function, detect what else it is
// Note: detection already done here, because then we only need the lookahead/rollback once
let declaration_type = if qualifiers.tk_const.is_some() {
NotFunction::Const
} else if qualifiers.tk_unsafe.is_some() {
match &next_token {
Some(TokenTree::Ident(ident)) if ident == "trait" => NotFunction::Trait,
Some(TokenTree::Ident(ident)) if ident == "impl" => NotFunction::Impl,
Some(TokenTree::Ident(ident)) if ident == "mod" => NotFunction::Mod,
token => panic!(
"expected one of 'fn|trait|impl|mod' after 'unsafe', got {:?}",
token
),
}
let tk_fn_keyword = match &next_token {
Some(TokenTree::Ident(ident)) => {
if ident == "fn" {
ident.clone()
} else if qualifiers.tk_extern.is_some() && ident == "crate" {
*tokens = before_start; // rollback
return Err(NotFunction::ExternCrate);
} else if ident == "static" {
// rollback iterator, could be start of const declaration
*tokens = before_start;
return Err(NotFunction::Static);
} else if qualifiers.has_only_const_xor_unsafe() {
// This is not a function, detect what else it is.
// Note: detection already done here, because then we only need the lookahead/rollback once.
let declaration_type = if qualifiers.tk_const.is_some() {
NotFunction::Const
} else if qualifiers.tk_unsafe.is_some() {
if ident == "trait" {
NotFunction::Trait
} else if ident == "impl" {
NotFunction::Impl
} else if ident == "mod" {
NotFunction::Mod
} else {
panic!("expected one of 'fn|trait|impl|mod' after 'unsafe', got {ident:?}")
}
} else {
unreachable!()
};

// rollback iterator, could be start of const declaration
*tokens = before_start;
return Err(declaration_type);
} else {
unreachable!()
};
panic!("expected 'fn' keyword, got ident '{}'", ident)
}
}

// rollback iterator, could be start of const declaration
*tokens = before_start;
return Err(declaration_type);
} else {
panic!("expected 'fn' keyword, got ident '{}'", ident)
// extern "C" { ...
Some(TokenTree::Literal(_)) if qualifiers.tk_extern.is_some() => {
*tokens = before_start; // rollback
return Err(NotFunction::ExternBlock);
}

// extern { ...
Some(TokenTree::Group(group))
if qualifiers.tk_extern.is_some() && group.delimiter() == Delimiter::Brace =>
{
*tokens = before_start; // rollback
return Err(NotFunction::ExternBlock);
}

_ => {
panic!("expected 'fn' keyword")
}
} else {
panic!("expected 'fn' keyword")
};

let fn_name = consume_declaration_name(tokens);
Expand Down
40 changes: 35 additions & 5 deletions src/parse_impl.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::parse_extern::{parse_extern_block, parse_extern_crate};
use crate::parse_fn::{consume_fn, consume_macro, NotFunction};
use crate::parse_mod::parse_mod;
use crate::parse_type::{consume_bound, consume_generic_params, consume_where_clause};
Expand Down Expand Up @@ -116,6 +117,7 @@ pub(crate) fn consume_ty_definition(
})
}

// TODO could accept a mask, allowing only certain sub-items. This could be made to reject e.g. extern crate in impl blocks.
pub(crate) fn consume_either_fn_type_const_static_impl(
tokens: &mut TokenIter,
attributes: Vec<Attribute>,
Expand All @@ -129,13 +131,19 @@ pub(crate) fn consume_either_fn_type_const_static_impl(
let assoc_ty = consume_ty_definition(tokens, attributes, vis_marker);
Declaration::TyDefinition(assoc_ty.unwrap())
}
"default" | "const" | "async" | "unsafe" | "extern" | "fn" => {

// Note: `static` is only used for extern "abi" {} blocks. Checked in call site.
"default" | "const" | "static" | "async" | "unsafe" | "extern" | "fn" => {
match consume_fn(tokens, attributes.clone(), vis_marker.clone()) {
Ok(method) => Declaration::Function(method),
Err(NotFunction::Const) => {
let constant = parse_const_or_static(tokens, attributes, vis_marker);
Declaration::Constant(constant)
}
Err(NotFunction::Static) => {
let static_decl = parse_const_or_static(tokens, attributes, vis_marker);
Declaration::Constant(static_decl)
}
Err(NotFunction::Trait) => {
let trait_decl = parse_trait(tokens, attributes, vis_marker);
Declaration::Trait(trait_decl)
Expand All @@ -148,6 +156,14 @@ pub(crate) fn consume_either_fn_type_const_static_impl(
let mod_decl = parse_mod(tokens, attributes, vis_marker);
Declaration::Module(mod_decl)
}
Err(NotFunction::ExternBlock) => {
let extern_decl = parse_extern_block(tokens, attributes, vis_marker);
Declaration::ExternBlock(extern_decl)
}
Err(NotFunction::ExternCrate) => {
let crate_decl = parse_extern_crate(tokens, attributes, vis_marker);
Declaration::ExternCrate(crate_decl)
}
}
}
ident => {
Expand All @@ -168,7 +184,10 @@ pub(crate) fn consume_either_fn_type_const_static_impl(
}
}

pub(crate) fn parse_impl_body(token_group: Group) -> (GroupSpan, Vec<Attribute>, Vec<ImplMember>) {
pub(crate) fn parse_impl_body(
token_group: Group,
allow_static: bool,
) -> (GroupSpan, Vec<Attribute>, Vec<ImplMember>) {
let mut body_items = vec![];

let mut tokens = token_group.stream().into_iter().peekable();
Expand All @@ -187,7 +206,14 @@ pub(crate) fn parse_impl_body(token_group: Group) -> (GroupSpan, Vec<Attribute>,
"impl",
) {
Declaration::Function(function) => ImplMember::Method(function),
Declaration::Constant(constant) => ImplMember::Constant(constant),
Declaration::Constant(const_) if const_.tk_const_or_static == "const" => {
// `const` can appear in impl/trait blocks.
ImplMember::Constant(const_)
}
Declaration::Constant(static_) if allow_static => {
// `static` can appear in `extern "abi" {}` blocks.
ImplMember::Constant(static_)
}
Declaration::TyDefinition(ty_def) => ImplMember::AssocTy(ty_def),
Declaration::Macro(macro_) => ImplMember::Macro(macro_),
_ => panic!("unsupported impl item `{:?}`", tokens.peek()),
Expand Down Expand Up @@ -245,7 +271,9 @@ pub(crate) fn parse_impl(tokens: &mut TokenIter, attributes: Vec<Attribute>) ->
let where_clause = consume_where_clause(tokens);

let (tk_braces, inner_attributes, body_items) = match tokens.next().unwrap() {
TokenTree::Group(group) if group.delimiter() == Delimiter::Brace => parse_impl_body(group),
TokenTree::Group(group) if group.delimiter() == Delimiter::Brace => {
parse_impl_body(group, false)
}
token => panic!("cannot parse impl: unexpected token {:?}", token),
};

Expand Down Expand Up @@ -282,7 +310,9 @@ pub(crate) fn parse_trait(

// For trait body, at the moment reuse impl parsing
let (tk_braces, inner_attributes, body_items) = match tokens.next().unwrap() {
TokenTree::Group(group) if group.delimiter() == Delimiter::Brace => parse_impl_body(group),
TokenTree::Group(group) if group.delimiter() == Delimiter::Brace => {
parse_impl_body(group, false)
}
token => panic!("cannot parse trait: unexpected token {:?}", token),
};

Expand Down
2 changes: 0 additions & 2 deletions src/parse_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ pub(crate) fn parse_mod(
attributes: Vec<Attribute>,
vis_marker: Option<VisMarker>,
) -> Module {
// TODO some items currently unsupported: decl-macros, extern crate

let tk_unsafe = consume_ident(tokens, "unsafe");
let tk_mod = parse_ident(tokens, "mod", "module declaration");
let module_name = consume_declaration_name(tokens);
Expand Down
1 change: 0 additions & 1 deletion src/snapshots/venial__tests__add_bounded_lifetime.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: src/tests.rs
assertion_line: 846
expression: tokens
---
struct Hello < ' b : c + d > { a : A , b : B , }
1 change: 0 additions & 1 deletion src/snapshots/venial__tests__add_bounded_ty_param.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: src/tests.rs
assertion_line: 885
expression: tokens
---
struct Hello < T : Clone > { a : A , b : B , }
1 change: 0 additions & 1 deletion src/snapshots/venial__tests__add_const_param-2.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: src/tests.rs
assertion_line: 913
expression: tokens
---
struct Hello < A , B , const N : u32 > { a : A , b : B , }
1 change: 0 additions & 1 deletion src/snapshots/venial__tests__add_const_param.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: src/tests.rs
assertion_line: 912
expression: tokens
---
struct Hello < const N : u32 > { a : A , b : B , }
1 change: 0 additions & 1 deletion src/snapshots/venial__tests__add_lifetime-2.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: src/tests.rs
assertion_line: 828
expression: tokens
---
struct Hello < 'b , A , B > { a : A , b : B , }
1 change: 0 additions & 1 deletion src/snapshots/venial__tests__add_lifetime-3.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: src/tests.rs
assertion_line: 829
expression: tokens
---
struct Hello < 'b , 'a , A , B > { a : & 'a A , b : B , }
1 change: 0 additions & 1 deletion src/snapshots/venial__tests__add_lifetime.snap
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: src/tests.rs
assertion_line: 827
expression: tokens
---
struct Hello < 'b > { a : A , b : B , }
Loading
Loading