1
1
use once_cell:: sync:: Lazy ;
2
2
use std:: collections:: HashMap ;
3
+ use std:: rc:: Rc ;
4
+ use std:: sync:: Arc ;
3
5
4
6
use crate :: query:: ir:: * ;
5
7
use crate :: query:: val_type:: Type ;
@@ -18,15 +20,17 @@ use crate::plan::interface::{NodeMatcher, TreeInterface};
18
20
/// 3. The typed operands of the method call
19
21
///
20
22
/// The callback returns a node filter that is suitable for evaluating the method call
21
- pub struct Handler ( pub Box < dyn for < ' a > Fn ( & ' a Box < dyn TreeInterface + ' a > , NodeFilter , & ' a Vec < Expr < Typed > > ) -> anyhow:: Result < NodeFilter > + Send + Sync > ) ;
23
+ ///
24
+ /// FIXME: The arguments need to be run-time values
25
+ pub struct Handler ( pub Arc < dyn for < ' a > Fn ( Rc < dyn TreeInterface > , & ' a NodeFilter , & ' a Vec < Expr < Typed > > ) -> anyhow:: Result < NodeFilter > + Send + Sync > ) ;
22
26
23
- fn callable_get_name < ' a > ( ti : & Box < dyn TreeInterface + ' a > , base : NodeFilter , operands : & ' a Vec < Expr < Typed > > ) -> anyhow:: Result < NodeFilter > {
27
+ fn callable_get_name < ' a > ( ti : Rc < dyn TreeInterface > , base : & ' a NodeFilter , operands : & ' a Vec < Expr < Typed > > ) -> anyhow:: Result < NodeFilter > {
24
28
assert ! ( operands. is_empty( ) ) ;
25
29
// This is not necessarily an assertion, as this may not be supported for
26
30
// the current language (which we don't know).
27
31
match base {
28
32
NodeFilter :: CallableComputation ( callable_matcher) => {
29
- let name_matcher = ti. callable_name ( callable_matcher)
33
+ let name_matcher = ti. callable_name ( & callable_matcher)
30
34
. ok_or_else ( || PlanError :: NotSupported ( "getNames" . into ( ) , "callable" . into ( ) ) ) ?;
31
35
Ok ( NodeFilter :: StringComputation ( name_matcher) )
32
36
} ,
@@ -37,11 +41,11 @@ fn callable_get_name<'a>(ti : &Box<dyn TreeInterface + 'a>, base : NodeFilter, o
37
41
}
38
42
39
43
/// This is a relational method that returns a *list* of parameters
40
- fn callable_get_a_parameter < ' a > ( ti : & Box < dyn TreeInterface + ' a > , base : NodeFilter , operands : & ' a Vec < Expr < Typed > > ) -> anyhow:: Result < NodeFilter > {
44
+ fn callable_get_a_parameter < ' a > ( ti : Rc < dyn TreeInterface > , base : & ' a NodeFilter , operands : & ' a Vec < Expr < Typed > > ) -> anyhow:: Result < NodeFilter > {
41
45
assert ! ( operands. is_empty( ) ) ;
42
46
match base {
43
47
NodeFilter :: CallableComputation ( callable_matcher) => {
44
- let arg_matcher = ti. callable_arguments ( callable_matcher)
48
+ let arg_matcher = ti. callable_arguments ( & callable_matcher)
45
49
. ok_or_else ( || PlanError :: NotSupported ( "arguments" . into ( ) , "callable" . into ( ) ) ) ?;
46
50
Ok ( NodeFilter :: ArgumentListComputation ( arg_matcher) )
47
51
} ,
@@ -51,7 +55,7 @@ fn callable_get_a_parameter<'a>(ti : &Box<dyn TreeInterface + 'a>, base : NodeFi
51
55
}
52
56
}
53
57
54
- fn string_regexp_match < ' a > ( _ti : & Box < dyn TreeInterface + ' a > , base : NodeFilter , operands : & ' a Vec < Expr < Typed > > ) -> anyhow:: Result < NodeFilter > {
58
+ fn string_regexp_match < ' a > ( _ti : Rc < dyn TreeInterface > , base : & ' a NodeFilter , operands : & ' a Vec < Expr < Typed > > ) -> anyhow:: Result < NodeFilter > {
55
59
assert ! ( operands. len( ) == 1 ) ;
56
60
// The base must be a string computation (and we require that it was a literal that we were able to already compile)
57
61
let c = match base {
@@ -66,15 +70,34 @@ fn string_regexp_match<'a>(_ti : &Box<dyn TreeInterface + 'a>, base : NodeFilter
66
70
panic ! ( "Invalid regex for `regexpMatch`" )
67
71
}
68
72
} ;
73
+ let x = Rc :: clone ( & c. extract ) ;
69
74
let comp = NodeMatcher {
70
- extract : Box :: new ( move |ctx, source| {
71
- let matched_string = ( c . extract ) ( ctx, source) ;
75
+ extract : Rc :: new ( move |ctx, source| {
76
+ let matched_string = x ( ctx, source) ;
72
77
rx. is_match ( matched_string. as_ref ( ) )
73
78
} )
74
79
} ;
75
80
Ok ( NodeFilter :: Predicate ( comp) )
76
81
}
77
82
83
+ fn parameter_get_name < ' a > ( _ti : Rc < dyn TreeInterface > , base : & ' a NodeFilter , operands : & ' a Vec < Expr < Typed > > ) -> anyhow:: Result < NodeFilter > {
84
+ assert ! ( operands. is_empty( ) ) ;
85
+ match base {
86
+ NodeFilter :: ArgumentComputation ( c) => {
87
+ let x = Rc :: clone ( & c. extract ) ;
88
+ let comp = NodeMatcher {
89
+ extract : Rc :: new ( move |ctx, source| {
90
+ x ( ctx, source) . name . unwrap_or ( "<none>" . into ( ) )
91
+ } )
92
+ } ;
93
+ Ok ( NodeFilter :: StringComputation ( comp) )
94
+ } ,
95
+ _ => {
96
+ panic ! ( "Invalid base value for Parameter.getName" ) ;
97
+ }
98
+ }
99
+ }
100
+
78
101
/// Validate the implementations of method calls against the claims in the
79
102
/// library documentation. The intent is that the library documentation should
80
103
/// always correctly reflect what subset of CodeQL ql-grep supports. Any
@@ -132,21 +155,23 @@ fn validate_library(impls : &HashMap<(Type, String), Handler>) {
132
155
static METHOD_IMPLS : Lazy < HashMap < ( Type , String ) , Handler > > = Lazy :: new ( || {
133
156
let mut impls = HashMap :: new ( ) ;
134
157
135
- impls. insert ( ( Type :: Method , "getName" . into ( ) ) , Handler ( Box :: new ( callable_get_name) ) ) ;
136
- impls. insert ( ( Type :: Function , "getName" . into ( ) ) , Handler ( Box :: new ( callable_get_name) ) ) ;
137
- impls. insert ( ( Type :: Callable , "getName" . into ( ) ) , Handler ( Box :: new ( callable_get_name) ) ) ;
158
+ impls. insert ( ( Type :: Method , "getName" . into ( ) ) , Handler ( Arc :: new ( callable_get_name) ) ) ;
159
+ impls. insert ( ( Type :: Function , "getName" . into ( ) ) , Handler ( Arc :: new ( callable_get_name) ) ) ;
160
+ impls. insert ( ( Type :: Callable , "getName" . into ( ) ) , Handler ( Arc :: new ( callable_get_name) ) ) ;
161
+
162
+ impls. insert ( ( Type :: Method , "getAParameter" . into ( ) ) , Handler ( Arc :: new ( callable_get_a_parameter) ) ) ;
163
+ impls. insert ( ( Type :: Function , "getAParameter" . into ( ) ) , Handler ( Arc :: new ( callable_get_a_parameter) ) ) ;
164
+ impls. insert ( ( Type :: Callable , "getAParameter" . into ( ) ) , Handler ( Arc :: new ( callable_get_a_parameter) ) ) ;
138
165
139
- impls. insert ( ( Type :: Method , "getAParameter" . into ( ) ) , Handler ( Box :: new ( callable_get_a_parameter) ) ) ;
140
- impls. insert ( ( Type :: Function , "getAParameter" . into ( ) ) , Handler ( Box :: new ( callable_get_a_parameter) ) ) ;
141
- impls. insert ( ( Type :: Callable , "getAParameter" . into ( ) ) , Handler ( Box :: new ( callable_get_a_parameter) ) ) ;
166
+ impls. insert ( ( Type :: Parameter , "getName" . into ( ) ) , Handler ( Arc :: new ( parameter_get_name) ) ) ;
142
167
143
- impls. insert ( ( Type :: PrimString , "regexpMatch" . into ( ) ) , Handler ( Box :: new ( string_regexp_match) ) ) ;
168
+ impls. insert ( ( Type :: PrimString , "regexpMatch" . into ( ) ) , Handler ( Arc :: new ( string_regexp_match) ) ) ;
144
169
145
170
validate_library ( & impls) ;
146
171
147
172
impls
148
173
} ) ;
149
174
150
- pub fn method_impl_for ( base_type : Type , method_name : & str ) -> Option < & Handler > {
151
- Lazy :: force ( & METHOD_IMPLS ) . get ( & ( base_type, method_name. into ( ) ) )
175
+ pub fn method_impl_for ( base_type : Type , method_name : String ) -> Option < & ' static Handler > {
176
+ Lazy :: force ( & METHOD_IMPLS ) . get ( & ( base_type, method_name) )
152
177
}
0 commit comments