brakeman 1.8.3 → 1.9.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/README.md +3 -27
  2. data/lib/brakeman.rb +36 -38
  3. data/lib/brakeman/app_tree.rb +90 -0
  4. data/lib/brakeman/call_index.rb +5 -38
  5. data/lib/brakeman/checks.rb +11 -11
  6. data/lib/brakeman/checks/base_check.rb +53 -29
  7. data/lib/brakeman/checks/check_cross_site_scripting.rb +11 -9
  8. data/lib/brakeman/checks/check_evaluation.rb +1 -1
  9. data/lib/brakeman/checks/check_execute.rb +3 -3
  10. data/lib/brakeman/checks/check_link_to.rb +15 -13
  11. data/lib/brakeman/checks/check_link_to_href.rb +1 -1
  12. data/lib/brakeman/checks/check_mail_to.rb +1 -1
  13. data/lib/brakeman/checks/check_mass_assignment.rb +27 -13
  14. data/lib/brakeman/checks/check_redirect.rb +4 -4
  15. data/lib/brakeman/checks/check_select_tag.rb +1 -1
  16. data/lib/brakeman/checks/check_select_vulnerability.rb +1 -1
  17. data/lib/brakeman/checks/check_send.rb +2 -2
  18. data/lib/brakeman/checks/check_session_settings.rb +12 -5
  19. data/lib/brakeman/checks/check_single_quotes.rb +3 -3
  20. data/lib/brakeman/checks/check_skip_before_filter.rb +4 -3
  21. data/lib/brakeman/checks/check_sql.rb +30 -30
  22. data/lib/brakeman/checks/check_translate_bug.rb +11 -10
  23. data/lib/brakeman/checks/check_validation_regex.rb +36 -11
  24. data/lib/brakeman/checks/check_without_protection.rb +1 -1
  25. data/lib/brakeman/options.rb +6 -2
  26. data/lib/brakeman/processor.rb +6 -5
  27. data/lib/brakeman/processors/alias_processor.rb +153 -38
  28. data/lib/brakeman/processors/base_processor.rb +16 -21
  29. data/lib/brakeman/processors/controller_alias_processor.rb +24 -11
  30. data/lib/brakeman/processors/controller_processor.rb +25 -25
  31. data/lib/brakeman/processors/erb_template_processor.rb +6 -7
  32. data/lib/brakeman/processors/erubis_template_processor.rb +2 -3
  33. data/lib/brakeman/processors/gem_processor.rb +5 -4
  34. data/lib/brakeman/processors/haml_template_processor.rb +4 -6
  35. data/lib/brakeman/processors/lib/find_all_calls.rb +3 -3
  36. data/lib/brakeman/processors/lib/find_call.rb +2 -2
  37. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  38. data/lib/brakeman/processors/lib/processor_helper.rb +24 -2
  39. data/lib/brakeman/processors/lib/rails2_config_processor.rb +13 -14
  40. data/lib/brakeman/processors/lib/rails2_route_processor.rb +9 -4
  41. data/lib/brakeman/processors/lib/rails3_config_processor.rb +8 -8
  42. data/lib/brakeman/processors/lib/rails3_route_processor.rb +23 -21
  43. data/lib/brakeman/processors/lib/render_helper.rb +2 -2
  44. data/lib/brakeman/processors/library_processor.rb +2 -2
  45. data/lib/brakeman/processors/model_processor.rb +16 -12
  46. data/lib/brakeman/processors/output_processor.rb +2 -1
  47. data/lib/brakeman/processors/template_alias_processor.rb +12 -8
  48. data/lib/brakeman/report.rb +28 -14
  49. data/lib/brakeman/rescanner.rb +5 -5
  50. data/lib/brakeman/scanner.rb +56 -94
  51. data/lib/brakeman/templates/header.html.erb +7 -2
  52. data/lib/brakeman/tracker.rb +14 -4
  53. data/lib/brakeman/util.rb +38 -17
  54. data/lib/brakeman/version.rb +1 -1
  55. data/lib/brakeman/warning.rb +14 -6
  56. data/lib/ruby_parser/bm_sexp.rb +157 -57
  57. data/lib/ruby_parser/bm_sexp_processor.rb +1 -2
  58. metadata +26 -25
  59. data/lib/ruby_parser/ruby18_parser.rb +0 -5544
  60. data/lib/ruby_parser/ruby19_parser.rb +0 -5756
  61. data/lib/ruby_parser/ruby_lexer.rb +0 -1349
  62. data/lib/ruby_parser/ruby_parser.rb +0 -5
  63. 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>Report Generation Time</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><%= Time.now %></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>
@@ -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, Sexp.new(:arglist)), :query_parameters, Sexp.new(:arglist))
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, Sexp.new(:arglist)), :path_parameters, Sexp.new(:arglist))
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, Sexp.new(:arglist)), :request_parameters, Sexp.new(:arglist))
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, Sexp.new(:arglist)), :parameters, Sexp.new(:arglist))
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, Sexp.new(:arglist)), :env, Sexp.new(:arglist))
15
+ REQUEST_ENV = Sexp.new(:call, Sexp.new(:call, nil, :request), :env)
16
16
 
17
- PARAMETERS = Sexp.new(:call, nil, :params, Sexp.new(:arglist))
17
+ PARAMETERS = Sexp.new(:call, nil, :params)
18
18
 
19
- COOKIES = Sexp.new(:call, nil, :cookies, Sexp.new(:arglist))
19
+ COOKIES = Sexp.new(:call, nil, :cookies)
20
20
 
21
- SESSION = Sexp.new(:call, nil, :session, Sexp.new(:arglist))
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] = Sexp.new(:params)
103
- @env[SESSION] = Sexp.new(:session)
104
- @env[COOKIES] = Sexp.new(: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 File.exist? file
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
@@ -1,3 +1,3 @@
1
1
  module Brakeman
2
- Version = "1.8.3"
2
+ Version = "1.9.0.pre1"
3
3
  end
@@ -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
- Brakeman::OutputProcessor.new.format(self.code).gsub(/(\t|\r|\n)+/, " ")
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
- Brakeman::OutputProcessor.new.format(self.user_input).gsub(/(\t|\r|\n)+/, " ")
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
@@ -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
- self[3] = exp
178
- #RP 3 TODO
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
- Sexp.new(:arglist).concat self[1..-1]
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][1..-1]
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
- if self[3]
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
- if self[3]
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
- if self[3]
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[3][2] = exp
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
- #Sets body
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
- self[3] = exp
444
+ index = 3
394
445
  when :defs, :selfdef
395
- self[4] = exp
446
+ index = 4
396
447
  when :module
397
- self[2] = exp
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