Skip to content

Commit d3329df

Browse files
committed
rustwasm#2806 bugfix: Added checks for JS keywords in signatures.
1 parent 1ceec1a commit d3329df

File tree

3 files changed

+115
-2
lines changed

3 files changed

+115
-2
lines changed

crates/macro-support/src/parser.rs

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,35 @@ use backend::Diagnostic;
99
use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
1010
use quote::ToTokens;
1111
use shared;
12-
use syn;
1312
use syn::parse::{Parse, ParseStream, Result as SynResult};
1413
use syn::spanned::Spanned;
14+
use syn::{self, FnArg, Pat, Signature};
1515

1616
thread_local!(static ATTRS: AttributeParseState = Default::default());
1717

18+
/// Javascript keywords which are not keywords in Rust.
19+
const JS_KEYWORDS: [&str; 19] = [
20+
"class",
21+
"case",
22+
"catch",
23+
"debugger",
24+
"default",
25+
"delete",
26+
"export",
27+
"extends",
28+
"finally",
29+
"function",
30+
"import",
31+
"instaceof",
32+
"new",
33+
"switch",
34+
"this",
35+
"throw",
36+
"var",
37+
"void",
38+
"with",
39+
];
40+
1841
#[derive(Default)]
1942
struct AttributeParseState {
2043
parsed: Cell<usize>,
@@ -815,6 +838,30 @@ fn function_from_decl(
815838
))
816839
}
817840

841+
/// Checks if `keyword` is keyword in javascript.
842+
pub(crate) fn is_js_keyword<T: ToString>(keyword: T) -> bool {
843+
let keyword = keyword.to_string();
844+
JS_KEYWORDS.contains(&keyword.as_str())
845+
}
846+
847+
/// Maps signatures's arguments to idents.
848+
pub(crate) fn sign_args_to_idents(sig: &Signature) -> Vec<Ident> {
849+
sig.inputs
850+
.to_owned()
851+
.into_iter()
852+
.filter_map(|arg| match arg {
853+
FnArg::Typed(t) => {
854+
if let Pat::Ident(ident) = *t.pat {
855+
Some(ident.ident)
856+
} else {
857+
None
858+
}
859+
}
860+
_ => None,
861+
})
862+
.collect()
863+
}
864+
818865
pub(crate) trait MacroParse<Ctx> {
819866
/// Parse the contents of an object into our AST, with a context if necessary.
820867
///
@@ -854,6 +901,19 @@ impl<'a> MacroParse<(Option<BindgenAttrs>, &'a mut TokenStream)> for syn::Item {
854901
bail_span!(&f.sig.inputs, "the start function cannot have arguments",);
855902
}
856903
}
904+
let fn_name_as_ident = if let Some((js_name, span)) = opts.js_name() {
905+
Ident::new(js_name, span)
906+
} else {
907+
f.sig.ident.clone()
908+
};
909+
if is_js_keyword(fn_name_as_ident) {
910+
bail_span!(&f.sig.ident, "function name cannot be js keyword",);
911+
}
912+
let fn_args = sign_args_to_idents(&f.sig);
913+
if let Some(ident) = fn_args.into_iter().find(|inpt| is_js_keyword(inpt)) {
914+
bail_span!(ident, "function argument name cannot be js keyword",);
915+
}
916+
857917
let method_kind = ast::MethodKind::Operation(ast::Operation {
858918
is_static: true,
859919
kind: operation_kind(&opts),
@@ -978,7 +1038,13 @@ fn prepare_for_impl_recursion(
9781038
impl_opts: &BindgenAttrs,
9791039
) -> Result<(), Diagnostic> {
9801040
let method = match item {
981-
syn::ImplItem::Method(m) => m,
1041+
syn::ImplItem::Method(m) => {
1042+
let fn_args = sign_args_to_idents(&m.sig);
1043+
if let Some(ident) = fn_args.into_iter().find(|inpt| is_js_keyword(inpt)) {
1044+
bail_span!(ident, "method argument name cannot be js keyword",);
1045+
}
1046+
m
1047+
}
9821048
syn::ImplItem::Const(_) => {
9831049
bail_span!(
9841050
&*item,
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen]
4+
pub fn class(arg: u8) {}
5+
6+
#[wasm_bindgen(js_name = class)]
7+
pub fn parsed_to_class(arg: u8) {}
8+
9+
#[wasm_bindgen(js_name = classy)]
10+
pub fn arg_is_class(class: u8) {}
11+
12+
#[wasm_bindgen]
13+
struct Class {
14+
name: String,
15+
}
16+
17+
#[wasm_bindgen]
18+
impl Class {
19+
pub fn class(void: String) -> Self {
20+
Class { name: void }
21+
}
22+
}
23+
24+
fn main() {}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error: function name cannot be js keyword
2+
--> ui-tests/compiles-to-js-keyword.rs:4:8
3+
|
4+
4 | pub fn class(arg: u8) {}
5+
| ^^^^^
6+
7+
error: function name cannot be js keyword
8+
--> ui-tests/compiles-to-js-keyword.rs:7:8
9+
|
10+
7 | pub fn parsed_to_class(arg: u8) {}
11+
| ^^^^^^^^^^^^^^^
12+
13+
error: function argument name cannot be js keyword
14+
--> ui-tests/compiles-to-js-keyword.rs:10:21
15+
|
16+
10 | pub fn arg_is_class(class: u8) {}
17+
| ^^^^^
18+
19+
error: method argument name cannot be js keyword
20+
--> ui-tests/compiles-to-js-keyword.rs:19:18
21+
|
22+
19 | pub fn class(void: String) -> Self {
23+
| ^^^^

0 commit comments

Comments
 (0)