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.
- 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
|