Skip to content
Merged
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
84 changes: 7 additions & 77 deletions near-plugins-derive/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,89 +1,19 @@
use proc_macro2::Span;
use proc_macro_crate::crate_name;
use std::str::FromStr;
use syn::{FnArg, Ident, ItemFn};
use syn::{Ident, ItemFn};

/// Determines if this block of code was [generated by near_bindgen].
/// Heuristic used is to check for #[no_mangle].
/// TODO: How to make this 100% safe. Discuss with near-sdk team
///
/// [generated by near_bindgen]: https://github.com/near/near-sdk-rs/issues/722
pub(crate) fn is_near_bindgen_wrapped_or_marshall(item: &ItemFn) -> bool {
let condition_1 = {
let pattern1 = "(target_arch = \"wasm32\")";
let pattern2 = "(not(target_arch = \"wasm32\"))";

item.attrs.iter().any(|attr| {
let seq = attr.tokens.to_string();
seq == pattern1 || seq == pattern2
})
};
if condition_1 {
return true;
}

// Assume `#[only(self, owner)]` is used in the following way:
//
// ```
// #[near_bindgen]
// #[derive(Ownable)]
// struct Counter {
// counter: u64,
// }
//
// #[near_bindgen]
// impl Counter {
// #[only(self, owner)]
// fn foo(&self) {}
// }
// ```
//
// Then `near-sdk` will create a struct `CounterExt` and code like this:
//
// ```
// impl CodeExt {
// #[only(self, owner)] // <- the attribute being forwared here is problematic
// fn foo(&self) -> near_sdk::Promise {
// // We don't want `#[only]` to inject code here.
// }
// }
// ```
//
// The code is generated here:
// https://github.com/near/near-sdk-rs/blob/770cbce018a1b6c49d58276a075ace3da96d6dc1/near-sdk-macros/src/core_impl/code_generator/ext.rs#L79-L105
//
// The following heuristic detects if macro expansion is invoked on an
// `ItemFn` inside an implementation of `CounterExt`. It's hacky since it
// relies on debug formatting of `proc_macro2::Span`.
let condition_2 = {
let signature_span = item.sig.ident.span();
let self_token_span = match item.sig.inputs.iter().next() {
Some(FnArg::Receiver(receiver)) => receiver.self_token.span,
_ => panic!("Attribute must be used on a method with self receiver"),
};
// If `item` is in an `impl` block generated by `near_bindgen`, its
// signature should have a different span number than the self token
// referring to an *Ext struct generated by `near_bindgen`.
span_number(&signature_span) != span_number(&self_token_span)
};
condition_2
}

/// Returns the number of the span.
///
/// # Panics
///
/// Panics if the formatted `span` does not correspond to the pattern
/// `"#42 bytes(1124..1142)"`.
fn span_number(span: &Span) -> u64 {
let formatted = format!("{:#?}", span);
let mut number_part = formatted
.split(' ')
.next()
.expect("Formatting a Span yielded an unexpected pattern")
.to_string();
number_part.remove(0); // remove the `#`
u64::from_str(&number_part).expect("Failed to extract number from formatted Span")
let pattern1 = "(target_arch = \"wasm32\")";
let pattern2 = "(not(target_arch = \"wasm32\"))";
item.attrs.iter().any(|attr| {
let seq = attr.tokens.to_string();
seq == pattern1 || seq == pattern2
})
}

pub(crate) fn cratename() -> Ident {
Expand Down