1
1
use crate :: utils:: span_lint;
2
2
use rustc_lint:: { EarlyLintPass , EarlyContext } ;
3
- use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
4
- // use rustc_span::Span;
3
+ use rustc_session:: { impl_lint_pass, declare_tool_lint} ;
5
4
use rustc_ast:: {
6
5
ast:: { MacCall , PathSegment } ,
6
+ tokenstream:: TokenTree ,
7
+ token:: { Token , TokenKind } ,
7
8
} ;
8
9
9
10
declare_clippy_lint ! {
@@ -23,9 +24,91 @@ declare_clippy_lint! {
23
24
"default lint description"
24
25
}
25
26
26
- declare_lint_pass ! ( HacspecMacros => [ HACSPEC_MACROS ] ) ;
27
+ #[ derive( Default ) ]
28
+ pub struct HacspecMacros {
29
+ added_macros : Vec < Vec < String > > ,
30
+ }
27
31
28
- impl EarlyLintPass for HacspecMacros {
29
- fn check_mac ( & mut self , _cx : & EarlyContext < ' _ > , mac : & MacCall ) {
32
+ impl_lint_pass ! ( HacspecMacros => [ HACSPEC_MACROS ] ) ;
33
+
34
+
35
+
36
+ const ALLOWED_MACRO_TYPE_DECL : & [ & [ & str ] ] = & [
37
+ & [ "array" ] ,
38
+ & [ "bytes" ] ,
39
+ & [ "public_bytes" ] ,
40
+ & [ "public_array" ] ,
41
+ & [ "poly" ] ,
42
+ & [ "field_integer" ] ,
43
+ //soon to be replaced by
44
+ // nat_mod
45
+ ] ;
46
+
47
+ const ALLOWED_MACROS_MISC : & [ & [ & str ] ] = & [
48
+ & [ "concat" ] ,
49
+ & [ "secret_array" ] ,
50
+ & [ "secret_bytes" ] ,
51
+ & [ "assert" ] ,
52
+ & [ "assert_bytes_eq" ] ,
53
+ & [ "assert_eq" ] ,
54
+ ] ;
55
+
56
+ fn allowed_path ( authorized_macros : & [ & [ & str ] ] , queried_use : & [ PathSegment ] ) -> bool {
57
+ authorized_macros. iter ( ) . any ( |& allowed_use| {
58
+ allowed_use
59
+ . iter ( )
60
+ . zip ( queried_use. iter ( ) )
61
+ . filter ( |( & allowed_segment, queried_segment) | * allowed_segment == * queried_segment. ident . name . as_str ( ) )
62
+ . count ( )
63
+ == allowed_use. len ( )
64
+ } )
65
+ }
66
+
67
+ // not really nice for code reuse
68
+ impl HacspecMacros {
69
+ fn check_added_macro ( & self , queried_use : & [ PathSegment ] ) -> bool {
70
+ self . added_macros . iter ( ) . any ( |allowed_use| {
71
+ allowed_use
72
+ . iter ( )
73
+ . zip ( queried_use. iter ( ) )
74
+ . filter ( |( allowed_segment, queried_segment) | * allowed_segment. as_str ( ) == * queried_segment. ident . name . as_str ( ) )
75
+ . count ( )
76
+ == allowed_use. len ( )
77
+ } )
30
78
}
31
79
}
80
+
81
+ impl EarlyLintPass for HacspecMacros {
82
+ fn check_mac ( & mut self , cx : & EarlyContext < ' _ > , mac : & MacCall ) {
83
+ if allowed_path ( ALLOWED_MACRO_TYPE_DECL , & mac. path . segments ) {
84
+ let mut flag = false ;
85
+ & mac. args . inner_tokens ( ) . map_enumerated (
86
+ |i, tk_tr| {
87
+ if i == 0 {
88
+ if let TokenTree :: Token ( Token { kind : TokenKind :: Ident ( name, _b) , span : _ } ) = tk_tr {
89
+ name. with (
90
+ |s| { // if self.added_macros.contains(String::from(s)) {
91
+ // span_lint(cx, HACSPEC_MACROS, mac.span(), &format!("Already declared type {}", type_decl)) }
92
+ // shouldn't be possible, macro expansion would cause an error, identifier already used or something like this
93
+ self . added_macros . push ( vec ! [ String :: from( s) ] ) ;
94
+ flag = true ;
95
+ }
96
+ ) ;
97
+ }
98
+ } ; tk_tr }
99
+ ) ;
100
+ if flag {
101
+ return ;
102
+ } else { span_lint ( cx, HACSPEC_MACROS , mac. span ( ) , "FORBIDDEN MACRO" ) }
103
+ }
104
+ if allowed_path ( ALLOWED_MACROS_MISC , & mac. path . segments )
105
+ || self . check_added_macro ( & mac. path . segments ) { return ; }
106
+
107
+ span_lint (
108
+ cx,
109
+ HACSPEC_MACROS ,
110
+ mac. span ( ) ,
111
+ "FORBIDDEN MACRO" ,
112
+ )
113
+ }
114
+ }
0 commit comments