Skip to content

Commit

Permalink
feat: Error on wrong sv::data and sv::payload usage
Browse files Browse the repository at this point in the history
  • Loading branch information
jawoznia committed Nov 19, 2024
1 parent dc1a6e2 commit a7af42b
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 26 deletions.
32 changes: 28 additions & 4 deletions sylvia-derive/src/contract/communication/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,13 @@ impl<'a> ReplyData<'a> {
} else {
payload.collect::<Vec<_>>()
};

if payload.is_empty() {
emit_error!(variant.name().span(), "Missing payload parameter.";
note = "Expected at least one payload parameter at the end of parameter list."

Check warning on line 247 in sylvia-derive/src/contract/communication/reply.rs

View check run for this annotation

Codecov / codecov/patch

sylvia-derive/src/contract/communication/reply.rs#L245-L247

Added lines #L245 - L247 were not covered by tests
)
}

assert_no_redundant_params(&payload);
let method_name = variant.function_name();
let reply_on = variant.msg_attr().reply_on();

Check warning on line 253 in sylvia-derive/src/contract/communication/reply.rs

View check run for this annotation

Codecov / codecov/patch

sylvia-derive/src/contract/communication/reply.rs#L251-L253

Added lines #L251 - L253 were not covered by tests
Expand Down Expand Up @@ -524,14 +531,31 @@ impl<'a> ReplyVariant<'a> for MsgVariant<'a> {
/// Validates attributes and returns `Some(MsgField)` if a field marked with `sv::data` attribute
/// is present and the `reply_on` attribute is set to `ReplyOn::Success`.
fn as_data_field(&'a self) -> Option<&'a MsgField<'a>> {
let data_attrs = self.fields().first().map(|field| {
let data_param = self.fields().iter().enumerate().find(|(_, field)| {
ParsedSylviaAttributes::new(field.attrs().iter())
.data
.is_some()
});
match data_attrs {
Some(attrs) if attrs && self.msg_attr().reply_on() == ReplyOn::Success => {
self.fields().first()
match data_param {

Check warning on line 539 in sylvia-derive/src/contract/communication/reply.rs

View check run for this annotation

Codecov / codecov/patch

sylvia-derive/src/contract/communication/reply.rs#L539

Added line #L539 was not covered by tests
Some((index, field))
if self.msg_attr().reply_on() == ReplyOn::Success && index == 0 =>
{
Some(field)
}
Some((index, field))
if self.msg_attr().reply_on() == ReplyOn::Success && index != 0 =>

Check warning on line 546 in sylvia-derive/src/contract/communication/reply.rs

View check run for this annotation

Codecov / codecov/patch

sylvia-derive/src/contract/communication/reply.rs#L545-L546

Added lines #L545 - L546 were not covered by tests
{
emit_error!(field.name().span(), "Wrong usage of `#[sv::data]` attribute.";
note = "The `#[sv::data]` attribute can only be used on the first parameter after the `ReplyCtx`."

Check warning on line 549 in sylvia-derive/src/contract/communication/reply.rs

View check run for this annotation

Codecov / codecov/patch

sylvia-derive/src/contract/communication/reply.rs#L548-L549

Added lines #L548 - L549 were not covered by tests
);
None

Check warning on line 551 in sylvia-derive/src/contract/communication/reply.rs

View check run for this annotation

Codecov / codecov/patch

sylvia-derive/src/contract/communication/reply.rs#L551

Added line #L551 was not covered by tests
}
Some((_, field)) if self.msg_attr().reply_on() != ReplyOn::Success => {
emit_error!(field.name().span(), "Wrong usage of `#[sv::data]` attribute.";
note = "The `#[sv::data]` attribute can only be used in `success` scenario.";
note = format!("Found usage in `{}` scenario.", self.msg_attr().reply_on())

Check warning on line 556 in sylvia-derive/src/contract/communication/reply.rs

View check run for this annotation

Codecov / codecov/patch

sylvia-derive/src/contract/communication/reply.rs#L553-L556

Added lines #L553 - L556 were not covered by tests
);
None

Check warning on line 558 in sylvia-derive/src/contract/communication/reply.rs

View check run for this annotation

Codecov / codecov/patch

sylvia-derive/src/contract/communication/reply.rs#L558

Added line #L558 was not covered by tests
}
_ => None,
}
Expand Down
63 changes: 63 additions & 0 deletions sylvia/tests/ui/attributes/data/invalid_usage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#![allow(unused_imports, unused_variables)]
use sylvia::ctx::{InstantiateCtx, ReplyCtx};
use sylvia::cw_std::{Addr, Binary, Response, StdResult};

pub mod attributes_swapped {
use super::*;

pub struct Contract {}

#[sylvia::contract]
#[sv::features(replies)]
impl Contract {
pub const fn new() -> Self {
Self {}
}

#[sv::msg(instantiate)]
fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
Ok(Response::new())
}

#[sv::msg(reply, reply_on=success)]
fn reply(
&self,
_ctx: ReplyCtx,
#[sv::payload(raw)] param: Binary,
#[sv::data(opt, raw)] _data: Option<Binary>,
) -> StdResult<Response> {
Ok(Response::new())
}
}
}

pub mod error_handler {
use super::*;

pub struct Contract {}

#[sylvia::contract]
#[sv::features(replies)]
impl Contract {
pub const fn new() -> Self {
Self {}
}

#[sv::msg(instantiate)]
fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
Ok(Response::new())
}

#[sv::msg(reply, reply_on=error)]
fn reply(
&self,
_ctx: ReplyCtx,
#[sv::data(opt, raw)] _data: Option<Binary>,
#[sv::payload(raw)] param: Binary,
) -> StdResult<Response> {
Ok(Response::new())
}
}
}

fn main() {}
27 changes: 27 additions & 0 deletions sylvia/tests/ui/attributes/data/invalid_usage.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error: Wrong usage of `#[sv::data]` attribute.

= note: The `#[sv::data]` attribute can only be used on the first parameter after the `ReplyCtx`.

--> tests/ui/attributes/data/invalid_usage.rs:27:35
|
27 | #[sv::data(opt, raw)] _data: Option<Binary>,
| ^^^^^

error: Redundant payload parameter.

= note: Expected no parameters after the parameter marked with `#[sv::payload(raw)]`.

--> tests/ui/attributes/data/invalid_usage.rs:27:35
|
27 | #[sv::data(opt, raw)] _data: Option<Binary>,
| ^^^^^

error: Wrong usage of `#[sv::data]` attribute.

= note: The `#[sv::data]` attribute can only be used in `success` scenario.
= note: Found usage in `error` scenario.

--> tests/ui/attributes/data/invalid_usage.rs:55:35
|
55 | #[sv::data(opt, raw)] _data: Option<Binary>,
| ^^^^^
23 changes: 19 additions & 4 deletions sylvia/tests/ui/attributes/msg/overlapping_reply_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,41 @@ impl Contract {
}

#[sv::msg(reply, handlers=[handler1])]
fn reply_always(&self, _ctx: ReplyCtx, _reply: Reply) -> StdResult<Response> {
fn reply_always(
&self,
_ctx: ReplyCtx,
_result: SubMsgResult,
#[sv::payload(raw)] payload: Binary,
) -> StdResult<Response> {
Ok(Response::new())
}

#[sv::msg(reply, handlers=[handler1], reply_on=success)]
fn duplicated_success_for_reply_always(
&self,
_ctx: ReplyCtx,
_reply: Reply,
#[sv::payload(raw)] reply: Binary,
) -> StdResult<Response> {
Ok(Response::new())
}

#[sv::msg(reply, handlers=[handler2], reply_on=error)]
fn some_reply(&self, _ctx: ReplyCtx, _reply: Reply) -> StdResult<Response> {
fn some_reply(
&self,
_ctx: ReplyCtx,
error: String,
#[sv::payload(raw)] payload: Binary,
) -> StdResult<Response> {
Ok(Response::new())
}

#[sv::msg(reply, reply_on=error)]
fn handler2(&self, _ctx: ReplyCtx, _reply: Reply) -> StdResult<Response> {
fn handler2(
&self,
_ctx: ReplyCtx,
error: String,
#[sv::payload(raw)] payload: Binary,
) -> StdResult<Response> {
Ok(Response::new())
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ error: Duplicated reply handler.

= note: Previous definition of handler=`HANDLER_1_REPLY_ID` for reply_on=`always` defined on `fn reply_always()`

--> tests/ui/attributes/msg/overlapping_reply_handlers.rs:26:32
--> tests/ui/attributes/msg/overlapping_reply_handlers.rs:31:32
|
26 | #[sv::msg(reply, handlers=[handler1], reply_on=success)]
31 | #[sv::msg(reply, handlers=[handler1], reply_on=success)]
| ^^^^^^^^

error: Duplicated reply handler.

= note: Previous definition of handler=`HANDLER_2_REPLY_ID` for reply_on=`error` defined on `fn some_reply()`

--> tests/ui/attributes/msg/overlapping_reply_handlers.rs:41:8
--> tests/ui/attributes/msg/overlapping_reply_handlers.rs:51:8
|
41 | fn handler2(&self, _ctx: ReplyCtx, _reply: Reply) -> StdResult<Response> {
51 | fn handler2(
| ^^^^^^^^
29 changes: 29 additions & 0 deletions sylvia/tests/ui/attributes/payload/invalid_usage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#![allow(unused_imports, unused_variables)]
use sylvia::ctx::{InstantiateCtx, ReplyCtx};
use sylvia::cw_std::{Addr, Binary, Response, StdResult};

pub mod used_on_context {
use super::*;

pub struct Contract {}

#[sylvia::contract]
#[sv::features(replies)]
impl Contract {
pub const fn new() -> Self {
Self {}
}

#[sv::msg(instantiate)]
fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
Ok(Response::new())
}

#[sv::msg(reply, reply_on=success)]
fn reply(&self, #[sv::payload(raw)] _ctx: ReplyCtx) -> StdResult<Response> {
Ok(Response::new())
}
}
}

fn main() {}
8 changes: 8 additions & 0 deletions sylvia/tests/ui/attributes/payload/invalid_usage.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: Missing payload parameter.

= note: Expected at least one payload parameter at the end of parameter list.

--> tests/ui/attributes/payload/invalid_usage.rs:23:12
|
23 | fn reply(&self, #[sv::payload(raw)] _ctx: ReplyCtx) -> StdResult<Response> {
| ^^^^^
23 changes: 15 additions & 8 deletions sylvia/tests/ui/method_signature/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,7 @@ pub mod mismatched_params {
}

#[sv::msg(reply, handlers=[on_instantiated], reply_on=error)]
fn second_reply(
&self,
_ctx: ReplyCtx,
#[sv::data(opt, raw)] _data: Option<Binary>,
param: u32,
) -> StdResult<Response> {
fn second_reply(&self, _ctx: ReplyCtx, error: String, param: u32) -> StdResult<Response> {
Ok(Response::new())
}
}
Expand Down Expand Up @@ -72,7 +67,7 @@ pub mod mismatched_param_arity {
fn second_reply(
&self,
_ctx: ReplyCtx,
#[sv::data(opt, raw)] _data: Option<Binary>,
error: String,
param: String,
param: u32,
) -> StdResult<Response> {
Expand Down Expand Up @@ -100,6 +95,18 @@ pub mod redundant_params {

#[sv::msg(reply, reply_on=success)]
fn first_reply(
&self,
_ctx: ReplyCtx,
redundant_before1: u32,
redundant_before2: String,
#[sv::data(opt, raw)] _data: Option<Binary>,
#[sv::payload(raw)] param: String,
) -> StdResult<Response> {
Ok(Response::new())
}

#[sv::msg(reply, reply_on=success)]
fn second_reply(
&self,
_ctx: ReplyCtx,
#[sv::data(opt, raw)] _data: Option<Binary>,
Expand All @@ -113,7 +120,7 @@ pub mod redundant_params {
}

#[sv::msg(reply, reply_on=success)]
fn second_reply(
fn third_reply(
&self,
_ctx: ReplyCtx,
#[sv::data(opt, raw)] _data: Option<Binary>,
Expand Down
30 changes: 24 additions & 6 deletions sylvia/tests/ui/method_signature/reply.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,43 @@ error: Mismatched quantity of method parameters.
= note: Both `on_instantiated` handlers should have the same number of parameters.
= note: Previous definition of on_instantiated handler.

--> tests/ui/method_signature/reply.rs:62:12
--> tests/ui/method_signature/reply.rs:57:12
|
62 | fn first_reply(
57 | fn first_reply(
| ^^^^^^^^^^^

error: Wrong usage of `#[sv::data]` attribute.

= note: The `#[sv::data]` attribute can only be used on the first parameter after the `ReplyCtx`.

--> tests/ui/method_signature/reply.rs:102:35
|
102 | #[sv::data(opt, raw)] _data: Option<Binary>,
| ^^^^^

error: Redundant payload parameter.

= note: Expected no parameters between the parameter marked with `#[sv::data]` and `#[sv::payload(raw)]`.

--> tests/ui/method_signature/reply.rs:100:13
|
100 | redundant_before1: u32,
| ^^^^^^^^^^^^^^^^^

error: Redundant payload parameter.

= note: Expected no parameters between the parameter marked with `#[sv::data]` and `#[sv::payload(raw)]`.

--> tests/ui/method_signature/reply.rs:106:13
--> tests/ui/method_signature/reply.rs:113:13
|
106 | redundant_between1: u32,
113 | redundant_between1: u32,
| ^^^^^^^^^^^^^^^^^^

error: Redundant payload parameter.

= note: Expected no parameters after the parameter marked with `#[sv::payload(raw)]`.

--> tests/ui/method_signature/reply.rs:121:13
--> tests/ui/method_signature/reply.rs:128:13
|
121 | redundant: Binary,
128 | redundant: Binary,
| ^^^^^^^^^

0 comments on commit a7af42b

Please sign in to comment.