Skip to content

Commit 6406938

Browse files
authored
Merge pull request #846 from eagr/lint-forbid-as-primitive
forbid `as_u*` method calls in linting
2 parents c47720a + 1e37e68 commit 6406938

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ fn main() {
5959
}
6060
};
6161

62+
track_lint(ForbidAsPrimitiveConversion::lint(&parsed_file));
6263
track_lint(RequireFreezeStruct::lint(&parsed_file));
6364
track_lint(RequireExplicitPalletIndex::lint(&parsed_file));
6465
});
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use super::*;
2+
use syn::{visit::Visit, ExprMethodCall, File, Ident};
3+
4+
pub struct ForbidAsPrimitiveConversion;
5+
6+
impl Lint for ForbidAsPrimitiveConversion {
7+
fn lint(source: &File) -> Result {
8+
let mut visitor = AsPrimitiveVisitor::default();
9+
10+
visitor.visit_file(source);
11+
12+
if !visitor.errors.is_empty() {
13+
return Err(visitor.errors);
14+
}
15+
16+
Ok(())
17+
}
18+
}
19+
20+
#[derive(Default)]
21+
struct AsPrimitiveVisitor {
22+
errors: Vec<syn::Error>,
23+
}
24+
25+
impl<'ast> Visit<'ast> for AsPrimitiveVisitor {
26+
fn visit_expr_method_call(&mut self, node: &'ast ExprMethodCall) {
27+
if is_as_primitive(&node.method) {
28+
self.errors.push(syn::Error::new(
29+
node.method.span(),
30+
"Using 'as_*()' methods is banned to avoid accidental panics. Use `try_into()` instead.",
31+
));
32+
}
33+
34+
syn::visit::visit_expr_method_call(self, node);
35+
}
36+
}
37+
38+
fn is_as_primitive(ident: &Ident) -> bool {
39+
matches!(
40+
ident.to_string().as_str(),
41+
"as_u32" | "as_u64" | "as_u128" | "as_usize"
42+
)
43+
}
44+
45+
#[cfg(test)]
46+
mod tests {
47+
use super::*;
48+
49+
fn lint(input: &str) -> Result {
50+
let expr: ExprMethodCall = syn::parse_str(input).expect("should only use on a method call");
51+
let mut visitor = AsPrimitiveVisitor::default();
52+
visitor.visit_expr_method_call(&expr);
53+
if !visitor.errors.is_empty() {
54+
return Err(visitor.errors);
55+
}
56+
Ok(())
57+
}
58+
59+
#[test]
60+
fn test_as_primitives() {
61+
let input = r#"x.as_u32()"#;
62+
assert!(lint(input).is_err());
63+
let input = r#"x.as_u64()"#;
64+
assert!(lint(input).is_err());
65+
let input = r#"x.as_u128()"#;
66+
assert!(lint(input).is_err());
67+
let input = r#"x.as_usize()"#;
68+
assert!(lint(input).is_err());
69+
}
70+
71+
#[test]
72+
fn test_non_as_primitives() {
73+
let input = r#"x.as_ref()"#;
74+
assert!(lint(input).is_ok());
75+
let input = r#"x.as_slice()"#;
76+
assert!(lint(input).is_ok());
77+
}
78+
}

support/linting/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
pub mod lint;
22
pub use lint::*;
33

4+
mod forbid_as_primitive;
45
mod pallet_index;
56
mod require_freeze_struct;
67

8+
pub use forbid_as_primitive::ForbidAsPrimitiveConversion;
79
pub use pallet_index::RequireExplicitPalletIndex;
810
pub use require_freeze_struct::RequireFreezeStruct;

0 commit comments

Comments
 (0)