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

proc-macros: Support deprecated methods for rpc client #570

Merged
merged 3 commits into from
Nov 21, 2021
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
3 changes: 3 additions & 0 deletions proc-macros/src/render_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,12 @@ impl RpcDescription {
let parameters = self.encode_params(&method.params, &method.param_kind, &method.signature);
// Doc-comment to be associated with the method.
let docs = &method.docs;
// Mark the method as deprecated, if previously declared as so.
let deprecated = &method.deprecated;

let method = quote! {
#docs
#deprecated
async fn #rust_method_name(#rust_method_params) -> #returns {
self.#called_method(#rpc_method_name, #parameters).await
}
Expand Down
20 changes: 18 additions & 2 deletions proc-macros/src/rpc_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub struct RpcMethod {
pub name: String,
pub blocking: bool,
pub docs: TokenStream2,
pub deprecated: TokenStream2,
pub params: Vec<(syn::PatIdent, syn::Type)>,
pub param_kind: ParamKind,
pub returns: Option<syn::Type>,
Expand All @@ -65,6 +66,10 @@ impl RpcMethod {

let sig = method.sig.clone();
let docs = extract_doc_comments(&method.attrs);
let deprecated = match find_attr(&method.attrs, "deprecated") {
Some(attr) => quote!(#attr),
None => quote!(),
};

if blocking && sig.asyncness.is_some() {
return Err(syn::Error::new(sig.span(), "Blocking method must be synchronous"));
Expand All @@ -90,7 +95,18 @@ impl RpcMethod {
// We've analyzed attributes and don't need them anymore.
method.attrs.clear();

Ok(Self { aliases, blocking, name, params, param_kind, returns, signature: method, docs, resources })
Ok(Self {
aliases,
blocking,
name,
params,
param_kind,
returns,
signature: method,
docs,
resources,
deprecated,
})
}
}

Expand Down Expand Up @@ -298,7 +314,7 @@ impl RpcDescription {
/// Based on the namespace, renders the full name of the RPC method/subscription.
/// Examples:
/// For namespace `foo` and method `makeSpam`, result will be `foo_makeSpam`.
/// For no namespace and method `makeSpam` it will be just `makeSpam.
/// For no namespace and method `makeSpam` it will be just `makeSpam`.
pub(crate) fn rpc_identifier<'a>(&self, method: &'a str) -> Cow<'a, str> {
if let Some(ns) = &self.namespace {
format!("{}_{}", ns, method).into()
Expand Down
67 changes: 67 additions & 0 deletions proc-macros/tests/ui/incorrect/rpc/rpc_deprecated_method.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! Test that calling a deprecated method will generate warnings at compile-time.

// Treat warnings as errors to fail the build.
#![deny(warnings)]

use jsonrpsee::{
proc_macros::rpc,
types::{async_trait, RpcResult},
ws_client::*,
ws_server::WsServerBuilder,
};
use std::net::SocketAddr;

#[rpc(client, server)]
pub trait Deprecated {
// Deprecated method that is called by the client.
#[deprecated(since = "0.5.0", note = "please use `new_method` instead")]
#[method(name = "foo")]
async fn async_method(&self) -> RpcResult<u8>;

// Deprecated methods that are not called should not generate warnings.
#[deprecated(since = "0.5.0", note = "please use `new_method` instead")]
#[method(name = "foo_unused")]
async fn async_method_unused(&self) -> RpcResult<u8>;

// If the method is not marked as deprecated, should not generate warnings.
#[method(name = "bar")]
fn sync_method(&self) -> RpcResult<u8>;
}

pub struct DeprecatedServerImpl;

#[async_trait]
impl DeprecatedServer for DeprecatedServerImpl {
async fn async_method(&self) -> RpcResult<u8> {
Ok(16u8)
}

async fn async_method_unused(&self) -> RpcResult<u8> {
Ok(32u8)
}

fn sync_method(&self) -> RpcResult<u8> {
Ok(64u8)
}
}

pub async fn websocket_server() -> SocketAddr {
let server = WsServerBuilder::default().build("127.0.0.1:0").await.unwrap();
let addr = server.local_addr().unwrap();

server.start(DeprecatedServerImpl.into_rpc()).unwrap();

addr
}

#[tokio::main]
async fn main() {
let server_addr = websocket_server().await;
let server_url = format!("ws://{}", server_addr);
let client = WsClientBuilder::default().build(&server_url).await.unwrap();

// Calling this method should generate an warning.
assert_eq!(client.async_method().await.unwrap(), 16);
// Note: `async_method_unused` is not called, and should not generate warnings.
assert_eq!(client.sync_method().await.unwrap(), 64);
}
12 changes: 12 additions & 0 deletions proc-macros/tests/ui/incorrect/rpc/rpc_deprecated_method.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error: use of deprecated associated function `DeprecatedClient::async_method`: please use `new_method` instead
--> $DIR/rpc_deprecated_method.rs:64:20
|
64 | assert_eq!(client.async_method().await.unwrap(), 16);
| ^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/rpc_deprecated_method.rs:4:9
|
4 | #![deny(warnings)]
| ^^^^^^^^
= note: `#[deny(deprecated)]` implied by `#[deny(warnings)]`