brakeman 1.8.3 → 1.9.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +3 -27
- data/lib/brakeman.rb +36 -38
- data/lib/brakeman/app_tree.rb +90 -0
- data/lib/brakeman/call_index.rb +5 -38
- data/lib/brakeman/checks.rb +11 -11
- data/lib/brakeman/checks/base_check.rb +53 -29
- data/lib/brakeman/checks/check_cross_site_scripting.rb +11 -9
- data/lib/brakeman/checks/check_evaluation.rb +1 -1
- data/lib/brakeman/checks/check_execute.rb +3 -3
- data/lib/brakeman/checks/check_link_to.rb +15 -13
- data/lib/brakeman/checks/check_link_to_href.rb +1 -1
- data/lib/brakeman/checks/check_mail_to.rb +1 -1
- data/lib/brakeman/checks/check_mass_assignment.rb +27 -13
- data/lib/brakeman/checks/check_redirect.rb +4 -4
- data/lib/brakeman/checks/check_select_tag.rb +1 -1
- data/lib/brakeman/checks/check_select_vulnerability.rb +1 -1
- data/lib/brakeman/checks/check_send.rb +2 -2
- data/lib/brakeman/checks/check_session_settings.rb +12 -5
- data/lib/brakeman/checks/check_single_quotes.rb +3 -3
- data/lib/brakeman/checks/check_skip_before_filter.rb +4 -3
- data/lib/brakeman/checks/check_sql.rb +30 -30
- data/lib/brakeman/checks/check_translate_bug.rb +11 -10
- data/lib/brakeman/checks/check_validation_regex.rb +36 -11
- data/lib/brakeman/checks/check_without_protection.rb +1 -1
- data/lib/brakeman/options.rb +6 -2
- data/lib/brakeman/processor.rb +6 -5
- data/lib/brakeman/processors/alias_processor.rb +153 -38
- data/lib/brakeman/processors/base_processor.rb +16 -21
- data/lib/brakeman/processors/controller_alias_processor.rb +24 -11
- data/lib/brakeman/processors/controller_processor.rb +25 -25
- data/lib/brakeman/processors/erb_template_processor.rb +6 -7
- data/lib/brakeman/processors/erubis_template_processor.rb +2 -3
- data/lib/brakeman/processors/gem_processor.rb +5 -4
- data/lib/brakeman/processors/haml_template_processor.rb +4 -6
- data/lib/brakeman/processors/lib/find_all_calls.rb +3 -3
- data/lib/brakeman/processors/lib/find_call.rb +2 -2
- data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
- data/lib/brakeman/processors/lib/processor_helper.rb +24 -2
- data/lib/brakeman/processors/lib/rails2_config_processor.rb +13 -14
- data/lib/brakeman/processors/lib/rails2_route_processor.rb +9 -4
- data/lib/brakeman/processors/lib/rails3_config_processor.rb +8 -8
- data/lib/brakeman/processors/lib/rails3_route_processor.rb +23 -21
- data/lib/brakeman/processors/lib/render_helper.rb +2 -2
- data/lib/brakeman/processors/library_processor.rb +2 -2
- data/lib/brakeman/processors/model_processor.rb +16 -12
- data/lib/brakeman/processors/output_processor.rb +2 -1
- data/lib/brakeman/processors/template_alias_processor.rb +12 -8
- data/lib/brakeman/report.rb +28 -14
- data/lib/brakeman/rescanner.rb +5 -5
- data/lib/brakeman/scanner.rb +56 -94
- data/lib/brakeman/templates/header.html.erb +7 -2
- data/lib/brakeman/tracker.rb +14 -4
- data/lib/brakeman/util.rb +38 -17
- data/lib/brakeman/version.rb +1 -1
- data/lib/brakeman/warning.rb +14 -6
- data/lib/ruby_parser/bm_sexp.rb +157 -57
- data/lib/ruby_parser/bm_sexp_processor.rb +1 -2
- metadata +26 -25
- data/lib/ruby_parser/ruby18_parser.rb +0 -5544
- data/lib/ruby_parser/ruby19_parser.rb +0 -5756
- data/lib/ruby_parser/ruby_lexer.rb +0 -1349
- data/lib/ruby_parser/ruby_parser.rb +0 -5
- data/lib/ruby_parser/ruby_parser_extras.rb +0 -1057
@@ -26,13 +26,18 @@
|
|
26
26
|
<tr>
|
27
27
|
<th>Application Path</th>
|
28
28
|
<th>Rails Version</th>
|
29
|
-
<th>
|
29
|
+
<th>Brakeman Version</th>
|
30
|
+
<th>Report Time</th>
|
30
31
|
<th>Checks Performed</th>
|
31
32
|
</tr>
|
32
33
|
<tr>
|
33
34
|
<td><%= File.expand_path tracker.options[:app_path] %></td>
|
34
35
|
<td><%= rails_version %></td>
|
35
|
-
<td><%=
|
36
|
+
<td><%= Brakeman::Version %>
|
37
|
+
<td>
|
38
|
+
<%= tracker.start_time %><br><br>
|
39
|
+
<%= tracker.duration %> seconds
|
40
|
+
</td>
|
36
41
|
<td><%= checks.checks_run.sort.join(", ") %></td>
|
37
42
|
</tr>
|
38
43
|
</table>
|
data/lib/brakeman/tracker.rb
CHANGED
@@ -9,7 +9,8 @@ require 'brakeman/processors/lib/find_all_calls'
|
|
9
9
|
class Brakeman::Tracker
|
10
10
|
attr_accessor :controllers, :templates, :models, :errors,
|
11
11
|
:checks, :initializers, :config, :routes, :processor, :libs,
|
12
|
-
:template_cache, :options, :filter_cache
|
12
|
+
:template_cache, :options, :filter_cache, :start_time, :end_time,
|
13
|
+
:duration
|
13
14
|
|
14
15
|
#Place holder when there should be a model, but it is not
|
15
16
|
#clear what model it will be.
|
@@ -19,9 +20,11 @@ class Brakeman::Tracker
|
|
19
20
|
#
|
20
21
|
#The Processor argument is only used by other Processors
|
21
22
|
#that might need to access it.
|
22
|
-
def initialize processor = nil, options = {}
|
23
|
+
def initialize(app_tree, processor = nil, options = {})
|
24
|
+
@app_tree = app_tree
|
23
25
|
@processor = processor
|
24
26
|
@options = options
|
27
|
+
|
25
28
|
@config = {}
|
26
29
|
@templates = {}
|
27
30
|
@controllers = {}
|
@@ -44,6 +47,9 @@ class Brakeman::Tracker
|
|
44
47
|
@template_cache = Set.new
|
45
48
|
@filter_cache = {}
|
46
49
|
@call_index = nil
|
50
|
+
@start_time = Time.now
|
51
|
+
@end_time = nil
|
52
|
+
@duration = nil
|
47
53
|
end
|
48
54
|
|
49
55
|
#Add an error to the list. If no backtrace is given,
|
@@ -63,7 +69,11 @@ class Brakeman::Tracker
|
|
63
69
|
#Run a set of checks on the current information. Results will be stored
|
64
70
|
#in Tracker#checks.
|
65
71
|
def run_checks
|
66
|
-
@checks = Brakeman::Checks.run_checks(self)
|
72
|
+
@checks = Brakeman::Checks.run_checks(@app_tree, self)
|
73
|
+
|
74
|
+
@end_time = Time.now
|
75
|
+
@duration = @end_time - @start_time
|
76
|
+
@checks
|
67
77
|
end
|
68
78
|
|
69
79
|
#Iterate over all methods in controllers and models.
|
@@ -139,7 +149,7 @@ class Brakeman::Tracker
|
|
139
149
|
|
140
150
|
#Returns a Report with this Tracker's information
|
141
151
|
def report
|
142
|
-
Brakeman::Report.new(self)
|
152
|
+
Brakeman::Report.new(@app_tree, self)
|
143
153
|
end
|
144
154
|
|
145
155
|
def index_call_sites
|
data/lib/brakeman/util.rb
CHANGED
@@ -4,21 +4,21 @@ require 'active_support/inflector'
|
|
4
4
|
#This is a mixin containing utility methods.
|
5
5
|
module Brakeman::Util
|
6
6
|
|
7
|
-
QUERY_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request
|
7
|
+
QUERY_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request), :query_parameters)
|
8
8
|
|
9
|
-
PATH_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request
|
9
|
+
PATH_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request), :path_parameters)
|
10
10
|
|
11
|
-
REQUEST_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request
|
11
|
+
REQUEST_PARAMETERS = Sexp.new(:call, Sexp.new(:call, nil, :request), :request_parameters)
|
12
12
|
|
13
|
-
REQUEST_PARAMS = Sexp.new(:call, Sexp.new(:call, nil, :request
|
13
|
+
REQUEST_PARAMS = Sexp.new(:call, Sexp.new(:call, nil, :request), :parameters)
|
14
14
|
|
15
|
-
REQUEST_ENV = Sexp.new(:call, Sexp.new(:call, nil, :request
|
15
|
+
REQUEST_ENV = Sexp.new(:call, Sexp.new(:call, nil, :request), :env)
|
16
16
|
|
17
|
-
PARAMETERS = Sexp.new(:call, nil, :params
|
17
|
+
PARAMETERS = Sexp.new(:call, nil, :params)
|
18
18
|
|
19
|
-
COOKIES = Sexp.new(:call, nil, :cookies
|
19
|
+
COOKIES = Sexp.new(:call, nil, :cookies)
|
20
20
|
|
21
|
-
SESSION = Sexp.new(:call, nil, :session
|
21
|
+
SESSION = Sexp.new(:call, nil, :session)
|
22
22
|
|
23
23
|
ALL_PARAMETERS = Set[PARAMETERS, QUERY_PARAMETERS, PATH_PARAMETERS, REQUEST_PARAMETERS, REQUEST_PARAMS]
|
24
24
|
|
@@ -75,7 +75,7 @@ module Brakeman::Util
|
|
75
75
|
end
|
76
76
|
index += 2
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
hash << key << value
|
80
80
|
|
81
81
|
hash
|
@@ -96,19 +96,24 @@ module Brakeman::Util
|
|
96
96
|
nil
|
97
97
|
end
|
98
98
|
|
99
|
+
#These are never modified
|
100
|
+
PARAMS_SEXP = Sexp.new(:params)
|
101
|
+
SESSION_SEXP = Sexp.new(:session)
|
102
|
+
COOKIES_SEXP = Sexp.new(:cookies)
|
103
|
+
|
99
104
|
#Adds params, session, and cookies to environment
|
100
105
|
#so they can be replaced by their respective Sexps.
|
101
106
|
def set_env_defaults
|
102
|
-
@env[PARAMETERS] =
|
103
|
-
@env[SESSION] =
|
104
|
-
@env[COOKIES] =
|
107
|
+
@env[PARAMETERS] = PARAMS_SEXP
|
108
|
+
@env[SESSION] = SESSION_SEXP
|
109
|
+
@env[COOKIES] = COOKIES_SEXP
|
105
110
|
end
|
106
111
|
|
107
112
|
#Check if _exp_ represents a hash: s(:hash, {...})
|
108
113
|
#This also includes pseudo hashes params, session, and cookies.
|
109
114
|
def hash? exp
|
110
|
-
exp.is_a? Sexp and (exp.node_type == :hash or
|
111
|
-
exp.node_type == :params or
|
115
|
+
exp.is_a? Sexp and (exp.node_type == :hash or
|
116
|
+
exp.node_type == :params or
|
112
117
|
exp.node_type == :session or
|
113
118
|
exp.node_type == :cookies)
|
114
119
|
end
|
@@ -239,6 +244,22 @@ module Brakeman::Util
|
|
239
244
|
false
|
240
245
|
end
|
241
246
|
|
247
|
+
def make_call target, method, *args
|
248
|
+
call = Sexp.new(:call, target, method)
|
249
|
+
|
250
|
+
if args.empty? or args.first.empty?
|
251
|
+
#nothing to do
|
252
|
+
elsif node_type? args.first, :arglist
|
253
|
+
call.concat args.first[1..-1]
|
254
|
+
elsif args.first.node_type.is_a? Sexp #just a list of args
|
255
|
+
call.concat args.first
|
256
|
+
else
|
257
|
+
call.concat args
|
258
|
+
end
|
259
|
+
|
260
|
+
call
|
261
|
+
end
|
262
|
+
|
242
263
|
#Return file name related to given warning. Uses +warning.file+ if it exists
|
243
264
|
def file_for warning, tracker = nil
|
244
265
|
if tracker.nil?
|
@@ -315,10 +336,10 @@ module Brakeman::Util
|
|
315
336
|
|
316
337
|
#Return array of lines surrounding the warning location from the original
|
317
338
|
#file.
|
318
|
-
def context_for warning, tracker = nil
|
339
|
+
def context_for app_tree, warning, tracker = nil
|
319
340
|
file = file_for warning, tracker
|
320
341
|
context = []
|
321
|
-
return context unless warning.line and file and
|
342
|
+
return context unless warning.line and file and @app_tree.path_exists? file
|
322
343
|
|
323
344
|
current_line = 0
|
324
345
|
start_line = warning.line - 5
|
@@ -369,5 +390,5 @@ module Brakeman::Util
|
|
369
390
|
output << CSV.generate_line(row.cells.map{|cell| cell.to_s.strip})
|
370
391
|
end
|
371
392
|
output
|
372
|
-
end
|
393
|
+
end
|
373
394
|
end
|
data/lib/brakeman/version.rb
CHANGED
data/lib/brakeman/warning.rb
CHANGED
@@ -76,14 +76,14 @@ class Brakeman::Warning
|
|
76
76
|
|
77
77
|
#Return String of the code output from the OutputProcessor and
|
78
78
|
#stripped of newlines and tabs.
|
79
|
-
def format_code
|
80
|
-
|
79
|
+
def format_code strip = true
|
80
|
+
format_ruby self.code, strip
|
81
81
|
end
|
82
82
|
|
83
83
|
#Return String of the user input formatted and
|
84
84
|
#stripped of newlines and tabs.
|
85
|
-
def format_user_input
|
86
|
-
|
85
|
+
def format_user_input strip = true
|
86
|
+
format_ruby self.user_input, strip
|
87
87
|
end
|
88
88
|
|
89
89
|
#Return formatted warning message
|
@@ -171,9 +171,9 @@ class Brakeman::Warning
|
|
171
171
|
:file => self.file,
|
172
172
|
:line => self.line,
|
173
173
|
:link => self.link,
|
174
|
-
:code => (@code && self.format_code),
|
174
|
+
:code => (@code && self.format_code(false)),
|
175
175
|
:location => location,
|
176
|
-
:user_input => (@user_input && self.format_user_input),
|
176
|
+
:user_input => (@user_input && self.format_user_input(false)),
|
177
177
|
:confidence => TEXT_CONFIDENCE[self.confidence]
|
178
178
|
}
|
179
179
|
end
|
@@ -181,4 +181,12 @@ class Brakeman::Warning
|
|
181
181
|
def to_json
|
182
182
|
MultiJson.dump self.to_hash
|
183
183
|
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def format_ruby code, strip
|
188
|
+
formatted = Brakeman::OutputProcessor.new.format(code)
|
189
|
+
formatted.gsub!(/(\t|\r|\n)+/, " ") if strip
|
190
|
+
formatted
|
191
|
+
end
|
184
192
|
end
|
data/lib/ruby_parser/bm_sexp.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
#of a Sexp.
|
4
4
|
class Sexp
|
5
5
|
attr_reader :paren
|
6
|
-
ASSIGNMENT_BOOL = [:gasgn, :iasgn, :lasgn, :cvdecl, :cdecl, :or, :and]
|
6
|
+
ASSIGNMENT_BOOL = [:gasgn, :iasgn, :lasgn, :cvdecl, :cdecl, :or, :and, :colon2]
|
7
7
|
|
8
8
|
def method_missing name, *args
|
9
9
|
#Brakeman does not use this functionality,
|
@@ -23,6 +23,12 @@ class Sexp
|
|
23
23
|
last
|
24
24
|
end
|
25
25
|
|
26
|
+
def value= exp
|
27
|
+
raise WrongSexpError, "Sexp#value= called on multi-item Sexp", caller[1..-1] if size > 2
|
28
|
+
@my_hash_value = nil
|
29
|
+
self[1] = exp
|
30
|
+
end
|
31
|
+
|
26
32
|
def second
|
27
33
|
self[1]
|
28
34
|
end
|
@@ -35,26 +41,6 @@ class Sexp
|
|
35
41
|
self[0] = type
|
36
42
|
end
|
37
43
|
|
38
|
-
#Don't use this, please.
|
39
|
-
#:nodoc:
|
40
|
-
def resbody delete = false
|
41
|
-
#RubyParser and Ruby2Ruby rely on method_missing for this, but since we
|
42
|
-
#don't want to use method_missing, here's a real method.
|
43
|
-
find_node :resbody, delete
|
44
|
-
end
|
45
|
-
|
46
|
-
#Don't use this, please.
|
47
|
-
#:nodoc:
|
48
|
-
def lasgn delete = false
|
49
|
-
find_node :lasgn, delete
|
50
|
-
end
|
51
|
-
|
52
|
-
#Don't use this, please.
|
53
|
-
#:nodoc:
|
54
|
-
def iasgn delete = false
|
55
|
-
find_node :iasgn, delete
|
56
|
-
end
|
57
|
-
|
58
44
|
alias :node_type :sexp_type
|
59
45
|
alias :values :sexp_body # TODO: retire
|
60
46
|
|
@@ -161,21 +147,34 @@ class Sexp
|
|
161
147
|
#s(:call, s(:call, nil, :x, s(:arglist)), :y, s(:arglist, s(:lit, 1)))
|
162
148
|
# ^- method
|
163
149
|
def method
|
164
|
-
expect :call, :attrasgn, :super, :zsuper
|
150
|
+
expect :call, :attrasgn, :super, :zsuper, :result
|
165
151
|
|
166
152
|
case self.node_type
|
167
153
|
when :call, :attrasgn
|
168
154
|
self[2]
|
169
155
|
when :super, :zsuper
|
170
156
|
:super
|
157
|
+
when :result
|
158
|
+
self.last
|
171
159
|
end
|
172
160
|
end
|
173
161
|
|
174
162
|
#Sets the arglist in a method call.
|
175
163
|
def arglist= exp
|
176
164
|
expect :call, :attrasgn
|
177
|
-
|
178
|
-
|
165
|
+
start_index = 3
|
166
|
+
|
167
|
+
if exp.is_a? Sexp and exp.node_type == :arglist
|
168
|
+
exp = exp[1..-1]
|
169
|
+
end
|
170
|
+
|
171
|
+
exp.each_with_index do |e, i|
|
172
|
+
self[start_index + i] = e
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def set_args *exp
|
177
|
+
self.arglist = exp
|
179
178
|
end
|
180
179
|
|
181
180
|
#Returns arglist for method call. This differs from Sexp#args, as Sexp#args
|
@@ -189,17 +188,14 @@ class Sexp
|
|
189
188
|
|
190
189
|
case self.node_type
|
191
190
|
when :call, :attrasgn
|
192
|
-
self[3]
|
191
|
+
self[3..-1].unshift :arglist
|
193
192
|
when :super, :zsuper
|
194
193
|
if self[1]
|
195
|
-
|
194
|
+
self[1..-1].unshift :arglist
|
196
195
|
else
|
197
196
|
Sexp.new(:arglist)
|
198
197
|
end
|
199
198
|
end
|
200
|
-
|
201
|
-
#For new ruby_parser
|
202
|
-
#Sexp.new(:arglist, *self[3..-1])
|
203
199
|
end
|
204
200
|
|
205
201
|
#Returns arguments of a method call. This will be an 'untyped' Sexp.
|
@@ -208,59 +204,93 @@ class Sexp
|
|
208
204
|
# ^--------args--------^
|
209
205
|
def args
|
210
206
|
expect :call, :attrasgn, :super, :zsuper
|
211
|
-
#For new ruby_parser
|
212
|
-
#if self[3]
|
213
|
-
# self[3..-1]
|
214
|
-
#else
|
215
|
-
# []
|
216
|
-
#end
|
217
207
|
|
218
208
|
case self.node_type
|
219
209
|
when :call, :attrasgn
|
220
|
-
#For old ruby_parser
|
221
210
|
if self[3]
|
222
|
-
self[3
|
211
|
+
self[3..-1]
|
223
212
|
else
|
224
|
-
|
213
|
+
Sexp.new
|
225
214
|
end
|
226
215
|
when :super, :zsuper
|
227
216
|
if self[1]
|
228
217
|
self[1..-1]
|
229
218
|
else
|
230
|
-
|
219
|
+
Sexp.new
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def each_arg replace = false
|
225
|
+
expect :call, :attrasgn, :super, :zsuper
|
226
|
+
range = nil
|
227
|
+
|
228
|
+
case self.node_type
|
229
|
+
when :call, :attrasgn
|
230
|
+
if self[3]
|
231
|
+
range = (3...self.length)
|
232
|
+
end
|
233
|
+
when :super, :zsuper
|
234
|
+
if self[1]
|
235
|
+
range = (1...self.length)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
if range
|
240
|
+
range.each do |i|
|
241
|
+
res = yield self[i]
|
242
|
+
self[i] = res if replace
|
231
243
|
end
|
232
244
|
end
|
245
|
+
|
246
|
+
self
|
247
|
+
end
|
248
|
+
|
249
|
+
def each_arg! &block
|
250
|
+
self.each_arg true, &block
|
233
251
|
end
|
234
252
|
|
235
253
|
#Returns first argument of a method call.
|
236
254
|
def first_arg
|
237
255
|
expect :call, :attrasgn
|
238
|
-
|
239
|
-
self[3][1]
|
240
|
-
end
|
256
|
+
self[3]
|
241
257
|
end
|
242
258
|
|
243
259
|
#Sets first argument of a method call.
|
244
260
|
def first_arg= exp
|
245
261
|
expect :call, :attrasgn
|
246
|
-
|
247
|
-
self[3][1] = exp
|
248
|
-
end
|
262
|
+
self[3] = exp
|
249
263
|
end
|
250
264
|
|
251
265
|
#Returns second argument of a method call.
|
252
266
|
def second_arg
|
253
267
|
expect :call, :attrasgn
|
254
|
-
|
255
|
-
self[3][2]
|
256
|
-
end
|
268
|
+
self[4]
|
257
269
|
end
|
258
270
|
|
259
271
|
#Sets second argument of a method call.
|
260
272
|
def second_arg= exp
|
261
273
|
expect :call, :attrasgn
|
274
|
+
self[4] = exp
|
275
|
+
end
|
276
|
+
|
277
|
+
def third_arg
|
278
|
+
expect :call, :attrasgn
|
279
|
+
self[5]
|
280
|
+
end
|
281
|
+
|
282
|
+
def third_arg= exp
|
283
|
+
expect :call, :attrasgn
|
284
|
+
self[5] = exp
|
285
|
+
end
|
286
|
+
|
287
|
+
def last_arg
|
288
|
+
expect :call, :attrasgn
|
289
|
+
|
262
290
|
if self[3]
|
263
|
-
self[
|
291
|
+
self[-1]
|
292
|
+
else
|
293
|
+
nil
|
264
294
|
end
|
265
295
|
end
|
266
296
|
|
@@ -317,7 +347,11 @@ class Sexp
|
|
317
347
|
# s(:lasgn, :y),
|
318
348
|
# s(:block, s(:lvar, :y), s(:call, nil, :z, s(:arglist))))
|
319
349
|
# ^-------------------- block --------------------------^
|
320
|
-
def block
|
350
|
+
def block delete = nil
|
351
|
+
unless delete.nil? #this is from RubyParser
|
352
|
+
return find_node :block, delete
|
353
|
+
end
|
354
|
+
|
321
355
|
expect :iter, :call_with_block, :scope, :resbody
|
322
356
|
|
323
357
|
case self.node_type
|
@@ -342,6 +376,11 @@ class Sexp
|
|
342
376
|
self[2]
|
343
377
|
end
|
344
378
|
|
379
|
+
def first_param
|
380
|
+
expect :args
|
381
|
+
self[1]
|
382
|
+
end
|
383
|
+
|
345
384
|
#Returns the left hand side of assignment or boolean:
|
346
385
|
#
|
347
386
|
# s(:lasgn, :x, s(:lit, 1))
|
@@ -384,34 +423,61 @@ class Sexp
|
|
384
423
|
end
|
385
424
|
end
|
386
425
|
|
387
|
-
|
426
|
+
def formal_args
|
427
|
+
expect :defn, :defs, :methdef, :selfdef
|
428
|
+
|
429
|
+
case self.node_type
|
430
|
+
when :defn, :methdef
|
431
|
+
self[2]
|
432
|
+
when :defs, :selfdef
|
433
|
+
self[3]
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
#Sets body, which is now a complicated process because the body is no longer
|
438
|
+
#a separate Sexp, but just a list of Sexps.
|
388
439
|
def body= exp
|
389
440
|
expect :defn, :defs, :methdef, :selfdef, :class, :module
|
390
441
|
|
391
442
|
case self.node_type
|
392
443
|
when :defn, :methdef, :class
|
393
|
-
|
444
|
+
index = 3
|
394
445
|
when :defs, :selfdef
|
395
|
-
|
446
|
+
index = 4
|
396
447
|
when :module
|
397
|
-
|
448
|
+
index = 2
|
449
|
+
end
|
450
|
+
|
451
|
+
self.slice!(index..-1) #Remove old body
|
452
|
+
|
453
|
+
#Insert new body
|
454
|
+
exp.each do |e|
|
455
|
+
self[index] = e
|
456
|
+
index += 1
|
398
457
|
end
|
399
458
|
end
|
400
459
|
|
401
460
|
#Returns body of a method definition, class, or module.
|
461
|
+
#This will be an untyped Sexp containing a list of Sexps from the body.
|
402
462
|
def body
|
403
463
|
expect :defn, :defs, :methdef, :selfdef, :class, :module
|
404
464
|
|
405
465
|
case self.node_type
|
406
466
|
when :defn, :methdef, :class
|
407
|
-
self[3]
|
467
|
+
self[3..-1]
|
408
468
|
when :defs, :selfdef
|
409
|
-
self[4]
|
469
|
+
self[4..-1]
|
410
470
|
when :module
|
411
|
-
self[2]
|
471
|
+
self[2..-1]
|
412
472
|
end
|
413
473
|
end
|
414
474
|
|
475
|
+
#Like Sexp#body, except the returned Sexp is of type :rlist
|
476
|
+
#instead of untyped.
|
477
|
+
def body_list
|
478
|
+
self.body.unshift :rlist
|
479
|
+
end
|
480
|
+
|
415
481
|
def render_type
|
416
482
|
expect :render
|
417
483
|
self[1]
|
@@ -428,6 +494,27 @@ class Sexp
|
|
428
494
|
expect :class
|
429
495
|
self[2]
|
430
496
|
end
|
497
|
+
|
498
|
+
#Returns the call Sexp in a result returned from FindCall
|
499
|
+
def call
|
500
|
+
expect :result
|
501
|
+
|
502
|
+
self.last
|
503
|
+
end
|
504
|
+
|
505
|
+
#Returns the module the call is inside
|
506
|
+
def module
|
507
|
+
expect :result
|
508
|
+
|
509
|
+
self[1]
|
510
|
+
end
|
511
|
+
|
512
|
+
#Return the class the call is inside
|
513
|
+
def result_class
|
514
|
+
expect :result
|
515
|
+
|
516
|
+
self[2]
|
517
|
+
end
|
431
518
|
end
|
432
519
|
|
433
520
|
#Invalidate hash cache if the Sexp changes
|
@@ -445,4 +532,17 @@ end
|
|
445
532
|
RUBY
|
446
533
|
end
|
447
534
|
|
535
|
+
#Methods used by RubyParser which would normally go through method_missing but
|
536
|
+
#we don't want that to happen because it hides Brakeman errors
|
537
|
+
[:resbody, :lasgn, :iasgn, :splat].each do |method|
|
538
|
+
Sexp.class_eval <<-RUBY
|
539
|
+
def #{method} delete = false
|
540
|
+
if delete
|
541
|
+
@my_hash_value = false
|
542
|
+
end
|
543
|
+
find_node :#{method}, delete
|
544
|
+
end
|
545
|
+
RUBY
|
546
|
+
end
|
547
|
+
|
448
548
|
class WrongSexpError < RuntimeError; end
|