brakeman-lib 3.3.1

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.
Files changed (159) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +872 -0
  3. data/FEATURES +16 -0
  4. data/README.md +169 -0
  5. data/WARNING_TYPES +95 -0
  6. data/bin/brakeman +89 -0
  7. data/lib/brakeman.rb +495 -0
  8. data/lib/brakeman/app_tree.rb +161 -0
  9. data/lib/brakeman/brakeman.rake +17 -0
  10. data/lib/brakeman/call_index.rb +219 -0
  11. data/lib/brakeman/checks.rb +191 -0
  12. data/lib/brakeman/checks/base_check.rb +518 -0
  13. data/lib/brakeman/checks/check_basic_auth.rb +88 -0
  14. data/lib/brakeman/checks/check_basic_auth_timing_attack.rb +33 -0
  15. data/lib/brakeman/checks/check_content_tag.rb +160 -0
  16. data/lib/brakeman/checks/check_create_with.rb +75 -0
  17. data/lib/brakeman/checks/check_cross_site_scripting.rb +385 -0
  18. data/lib/brakeman/checks/check_default_routes.rb +86 -0
  19. data/lib/brakeman/checks/check_deserialize.rb +57 -0
  20. data/lib/brakeman/checks/check_detailed_exceptions.rb +55 -0
  21. data/lib/brakeman/checks/check_digest_dos.rb +38 -0
  22. data/lib/brakeman/checks/check_dynamic_finders.rb +49 -0
  23. data/lib/brakeman/checks/check_escape_function.rb +21 -0
  24. data/lib/brakeman/checks/check_evaluation.rb +36 -0
  25. data/lib/brakeman/checks/check_execute.rb +167 -0
  26. data/lib/brakeman/checks/check_file_access.rb +63 -0
  27. data/lib/brakeman/checks/check_file_disclosure.rb +35 -0
  28. data/lib/brakeman/checks/check_filter_skipping.rb +31 -0
  29. data/lib/brakeman/checks/check_forgery_setting.rb +74 -0
  30. data/lib/brakeman/checks/check_header_dos.rb +31 -0
  31. data/lib/brakeman/checks/check_i18n_xss.rb +48 -0
  32. data/lib/brakeman/checks/check_jruby_xml.rb +38 -0
  33. data/lib/brakeman/checks/check_json_encoding.rb +47 -0
  34. data/lib/brakeman/checks/check_json_parsing.rb +107 -0
  35. data/lib/brakeman/checks/check_link_to.rb +132 -0
  36. data/lib/brakeman/checks/check_link_to_href.rb +115 -0
  37. data/lib/brakeman/checks/check_mail_to.rb +49 -0
  38. data/lib/brakeman/checks/check_mass_assignment.rb +198 -0
  39. data/lib/brakeman/checks/check_mime_type_dos.rb +39 -0
  40. data/lib/brakeman/checks/check_model_attr_accessible.rb +55 -0
  41. data/lib/brakeman/checks/check_model_attributes.rb +119 -0
  42. data/lib/brakeman/checks/check_model_serialize.rb +67 -0
  43. data/lib/brakeman/checks/check_nested_attributes.rb +38 -0
  44. data/lib/brakeman/checks/check_nested_attributes_bypass.rb +58 -0
  45. data/lib/brakeman/checks/check_number_to_currency.rb +74 -0
  46. data/lib/brakeman/checks/check_quote_table_name.rb +40 -0
  47. data/lib/brakeman/checks/check_redirect.rb +215 -0
  48. data/lib/brakeman/checks/check_regex_dos.rb +69 -0
  49. data/lib/brakeman/checks/check_render.rb +92 -0
  50. data/lib/brakeman/checks/check_render_dos.rb +37 -0
  51. data/lib/brakeman/checks/check_render_inline.rb +54 -0
  52. data/lib/brakeman/checks/check_response_splitting.rb +21 -0
  53. data/lib/brakeman/checks/check_route_dos.rb +42 -0
  54. data/lib/brakeman/checks/check_safe_buffer_manipulation.rb +31 -0
  55. data/lib/brakeman/checks/check_sanitize_methods.rb +79 -0
  56. data/lib/brakeman/checks/check_secrets.rb +40 -0
  57. data/lib/brakeman/checks/check_select_tag.rb +60 -0
  58. data/lib/brakeman/checks/check_select_vulnerability.rb +60 -0
  59. data/lib/brakeman/checks/check_send.rb +48 -0
  60. data/lib/brakeman/checks/check_send_file.rb +19 -0
  61. data/lib/brakeman/checks/check_session_manipulation.rb +36 -0
  62. data/lib/brakeman/checks/check_session_settings.rb +170 -0
  63. data/lib/brakeman/checks/check_simple_format.rb +59 -0
  64. data/lib/brakeman/checks/check_single_quotes.rb +101 -0
  65. data/lib/brakeman/checks/check_skip_before_filter.rb +60 -0
  66. data/lib/brakeman/checks/check_sql.rb +660 -0
  67. data/lib/brakeman/checks/check_sql_cves.rb +101 -0
  68. data/lib/brakeman/checks/check_ssl_verify.rb +49 -0
  69. data/lib/brakeman/checks/check_strip_tags.rb +89 -0
  70. data/lib/brakeman/checks/check_symbol_dos.rb +64 -0
  71. data/lib/brakeman/checks/check_symbol_dos_cve.rb +30 -0
  72. data/lib/brakeman/checks/check_translate_bug.rb +45 -0
  73. data/lib/brakeman/checks/check_unsafe_reflection.rb +51 -0
  74. data/lib/brakeman/checks/check_unscoped_find.rb +41 -0
  75. data/lib/brakeman/checks/check_validation_regex.rb +116 -0
  76. data/lib/brakeman/checks/check_weak_hash.rb +151 -0
  77. data/lib/brakeman/checks/check_without_protection.rb +80 -0
  78. data/lib/brakeman/checks/check_xml_dos.rb +51 -0
  79. data/lib/brakeman/checks/check_yaml_parsing.rb +121 -0
  80. data/lib/brakeman/differ.rb +66 -0
  81. data/lib/brakeman/file_parser.rb +50 -0
  82. data/lib/brakeman/format/style.css +133 -0
  83. data/lib/brakeman/options.rb +301 -0
  84. data/lib/brakeman/parsers/rails2_erubis.rb +6 -0
  85. data/lib/brakeman/parsers/rails2_xss_plugin_erubis.rb +48 -0
  86. data/lib/brakeman/parsers/rails3_erubis.rb +74 -0
  87. data/lib/brakeman/parsers/template_parser.rb +89 -0
  88. data/lib/brakeman/processor.rb +102 -0
  89. data/lib/brakeman/processors/alias_processor.rb +1013 -0
  90. data/lib/brakeman/processors/base_processor.rb +277 -0
  91. data/lib/brakeman/processors/config_processor.rb +14 -0
  92. data/lib/brakeman/processors/controller_alias_processor.rb +273 -0
  93. data/lib/brakeman/processors/controller_processor.rb +326 -0
  94. data/lib/brakeman/processors/erb_template_processor.rb +80 -0
  95. data/lib/brakeman/processors/erubis_template_processor.rb +104 -0
  96. data/lib/brakeman/processors/gem_processor.rb +57 -0
  97. data/lib/brakeman/processors/haml_template_processor.rb +190 -0
  98. data/lib/brakeman/processors/lib/basic_processor.rb +37 -0
  99. data/lib/brakeman/processors/lib/find_all_calls.rb +223 -0
  100. data/lib/brakeman/processors/lib/find_call.rb +183 -0
  101. data/lib/brakeman/processors/lib/find_return_value.rb +134 -0
  102. data/lib/brakeman/processors/lib/processor_helper.rb +75 -0
  103. data/lib/brakeman/processors/lib/rails2_config_processor.rb +145 -0
  104. data/lib/brakeman/processors/lib/rails2_route_processor.rb +313 -0
  105. data/lib/brakeman/processors/lib/rails3_config_processor.rb +132 -0
  106. data/lib/brakeman/processors/lib/rails3_route_processor.rb +308 -0
  107. data/lib/brakeman/processors/lib/render_helper.rb +181 -0
  108. data/lib/brakeman/processors/lib/render_path.rb +107 -0
  109. data/lib/brakeman/processors/lib/route_helper.rb +68 -0
  110. data/lib/brakeman/processors/lib/safe_call_helper.rb +16 -0
  111. data/lib/brakeman/processors/library_processor.rb +119 -0
  112. data/lib/brakeman/processors/model_processor.rb +191 -0
  113. data/lib/brakeman/processors/output_processor.rb +171 -0
  114. data/lib/brakeman/processors/route_processor.rb +17 -0
  115. data/lib/brakeman/processors/slim_template_processor.rb +107 -0
  116. data/lib/brakeman/processors/template_alias_processor.rb +116 -0
  117. data/lib/brakeman/processors/template_processor.rb +74 -0
  118. data/lib/brakeman/report.rb +78 -0
  119. data/lib/brakeman/report/config/remediation.yml +71 -0
  120. data/lib/brakeman/report/ignore/config.rb +135 -0
  121. data/lib/brakeman/report/ignore/interactive.rb +311 -0
  122. data/lib/brakeman/report/renderer.rb +24 -0
  123. data/lib/brakeman/report/report_base.rb +286 -0
  124. data/lib/brakeman/report/report_codeclimate.rb +70 -0
  125. data/lib/brakeman/report/report_csv.rb +55 -0
  126. data/lib/brakeman/report/report_hash.rb +23 -0
  127. data/lib/brakeman/report/report_html.rb +216 -0
  128. data/lib/brakeman/report/report_json.rb +42 -0
  129. data/lib/brakeman/report/report_markdown.rb +156 -0
  130. data/lib/brakeman/report/report_table.rb +107 -0
  131. data/lib/brakeman/report/report_tabs.rb +17 -0
  132. data/lib/brakeman/report/templates/controller_overview.html.erb +22 -0
  133. data/lib/brakeman/report/templates/controller_warnings.html.erb +21 -0
  134. data/lib/brakeman/report/templates/error_overview.html.erb +29 -0
  135. data/lib/brakeman/report/templates/header.html.erb +58 -0
  136. data/lib/brakeman/report/templates/ignored_warnings.html.erb +25 -0
  137. data/lib/brakeman/report/templates/model_warnings.html.erb +21 -0
  138. data/lib/brakeman/report/templates/overview.html.erb +38 -0
  139. data/lib/brakeman/report/templates/security_warnings.html.erb +23 -0
  140. data/lib/brakeman/report/templates/template_overview.html.erb +21 -0
  141. data/lib/brakeman/report/templates/view_warnings.html.erb +34 -0
  142. data/lib/brakeman/report/templates/warning_overview.html.erb +17 -0
  143. data/lib/brakeman/rescanner.rb +483 -0
  144. data/lib/brakeman/scanner.rb +317 -0
  145. data/lib/brakeman/tracker.rb +347 -0
  146. data/lib/brakeman/tracker/collection.rb +93 -0
  147. data/lib/brakeman/tracker/config.rb +101 -0
  148. data/lib/brakeman/tracker/constants.rb +101 -0
  149. data/lib/brakeman/tracker/controller.rb +161 -0
  150. data/lib/brakeman/tracker/library.rb +17 -0
  151. data/lib/brakeman/tracker/model.rb +90 -0
  152. data/lib/brakeman/tracker/template.rb +33 -0
  153. data/lib/brakeman/util.rb +481 -0
  154. data/lib/brakeman/version.rb +3 -0
  155. data/lib/brakeman/warning.rb +255 -0
  156. data/lib/brakeman/warning_codes.rb +111 -0
  157. data/lib/ruby_parser/bm_sexp.rb +610 -0
  158. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  159. metadata +362 -0
@@ -0,0 +1,57 @@
1
+ require 'brakeman/processors/lib/basic_processor'
2
+
3
+ #Processes Gemfile and Gemfile.lock
4
+ class Brakeman::GemProcessor < Brakeman::BasicProcessor
5
+
6
+ def initialize *args
7
+ super
8
+ @gem_name_version = /^\s*([-_+.A-Za-z0-9]+) \((\w(\.\w+)*)\)/
9
+ end
10
+
11
+ def process_gems gem_files
12
+ @gem_files = gem_files
13
+ @gemfile = gem_files[:gemfile][:file]
14
+ process gem_files[:gemfile][:src]
15
+
16
+ if gem_files[:gemlock]
17
+ process_gem_lock
18
+ end
19
+
20
+ @tracker.config.set_rails_version
21
+ end
22
+
23
+ def process_call exp
24
+ if exp.target == nil and exp.method == :gem
25
+ gem_name = exp.first_arg
26
+ return exp unless string? gem_name
27
+
28
+ gem_version = exp.second_arg
29
+
30
+ version = if string? gem_version
31
+ gem_version.value
32
+ else
33
+ nil
34
+ end
35
+
36
+ @tracker.config.add_gem gem_name.value, version, @gemfile, exp.line
37
+ end
38
+
39
+ exp
40
+ end
41
+
42
+ def process_gem_lock
43
+ line_num = 1
44
+ file = @gem_files[:gemlock][:file]
45
+ @gem_files[:gemlock][:src].each_line do |line|
46
+ set_gem_version_and_file line, file, line_num
47
+ line_num += 1
48
+ end
49
+ end
50
+
51
+ # Supports .rc2 but not ~>, >=, or <=
52
+ def set_gem_version_and_file line, file, line_num
53
+ if line =~ @gem_name_version
54
+ @tracker.config.add_gem $1, $2, file, line_num
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,190 @@
1
+ require 'brakeman/processors/template_processor'
2
+
3
+ #Processes HAML templates.
4
+ class Brakeman::HamlTemplateProcessor < Brakeman::TemplateProcessor
5
+ HAML_FORMAT_METHOD = /format_script_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)_(true|false)/
6
+ HAML_HELPERS = s(:colon2, s(:const, :Haml), :Helpers)
7
+ JAVASCRIPT_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Javascript)
8
+ COFFEE_FILTER = s(:colon2, s(:colon2, s(:const, :Haml), :Filters), :Coffee)
9
+
10
+ #Processes call, looking for template output
11
+ def process_call exp
12
+ target = exp.target
13
+ if sexp? target
14
+ target = process target
15
+ end
16
+
17
+ method = exp.method
18
+
19
+ if (call? target and target.method == :_hamlout)
20
+ res = case method
21
+ when :adjust_tabs, :rstrip!, :attributes #Check attributes, maybe?
22
+ ignore
23
+ when :options, :buffer
24
+ exp
25
+ when :open_tag
26
+ process_call_args exp
27
+ else
28
+ arg = exp.first_arg
29
+
30
+ if arg
31
+ @inside_concat = true
32
+ exp.first_arg = process(arg)
33
+ out = normalize_output(exp.first_arg)
34
+ @inside_concat = false
35
+ else
36
+ raise "Empty _hamlout.#{method}()?"
37
+ end
38
+
39
+ if string? out
40
+ ignore
41
+ else
42
+ r = case method.to_s
43
+ when "push_text"
44
+ build_output_from_push_text(out)
45
+ when HAML_FORMAT_METHOD
46
+ if $4 == "true"
47
+ if string_interp? out
48
+ build_output_from_push_text(out, :escaped_output)
49
+ else
50
+ Sexp.new :format_escaped, out
51
+ end
52
+ else
53
+ if string_interp? out
54
+ build_output_from_push_text(out)
55
+ else
56
+ Sexp.new :format, out
57
+ end
58
+ end
59
+
60
+ else
61
+ raise "Unrecognized action on _hamlout: #{method}"
62
+ end
63
+
64
+ @javascript = false
65
+ r
66
+ end
67
+ end
68
+
69
+ res.line(exp.line)
70
+ res
71
+
72
+ #_hamlout.buffer <<
73
+ #This seems to be used rarely, but directly appends args to output buffer.
74
+ #Has something to do with values of blocks?
75
+ elsif sexp? target and method == :<< and is_buffer_target? target
76
+ @inside_concat = true
77
+ exp.first_arg = process(exp.first_arg)
78
+ out = normalize_output(exp.first_arg)
79
+ @inside_concat = false
80
+
81
+ if out.node_type == :str #ignore plain strings
82
+ ignore
83
+ else
84
+ s = Sexp.new(:output, out)
85
+ @current_template.add_output s
86
+ s.line(exp.line)
87
+ s
88
+ end
89
+ elsif target == nil and method == :render
90
+ #Process call to render()
91
+ exp.arglist = process exp.arglist
92
+ make_render_in_view exp
93
+ elsif target == nil and method == :find_and_preserve and exp.first_arg
94
+ process exp.first_arg
95
+ elsif method == :render_with_options
96
+ if target == JAVASCRIPT_FILTER or target == COFFEE_FILTER
97
+ @javascript = true
98
+ end
99
+
100
+ process exp.first_arg
101
+ else
102
+ exp.target = target
103
+ exp.arglist = process exp.arglist
104
+ exp
105
+ end
106
+ end
107
+
108
+ #If inside an output stream, only return the final expression
109
+ def process_block exp
110
+ exp = exp.dup
111
+ exp.shift
112
+ if @inside_concat
113
+ @inside_concat = false
114
+ exp[0..-2].each do |e|
115
+ process e
116
+ end
117
+ @inside_concat = true
118
+ process exp[-1]
119
+ else
120
+ exp.map! do |e|
121
+ res = process e
122
+ if res.empty?
123
+ nil
124
+ else
125
+ res
126
+ end
127
+ end
128
+ Sexp.new(:rlist).concat(exp).compact
129
+ end
130
+ end
131
+
132
+ #Checks if the buffer is the target in a method call Sexp.
133
+ #TODO: Test this
134
+ def is_buffer_target? exp
135
+ exp.node_type == :call and
136
+ node_type? exp.target, :lvar and
137
+ exp.target.value == :_hamlout and
138
+ exp.method == :buffer
139
+ end
140
+
141
+ #HAML likes to put interpolated values into _hamlout.push_text
142
+ #but we want to handle those individually
143
+ def build_output_from_push_text exp, default = :output
144
+ if string_interp? exp
145
+ exp.map! do |e|
146
+ if sexp? e
147
+ if node_type? e, :evstr and e[1]
148
+ e = e.value
149
+ end
150
+
151
+ get_pushed_value e, default
152
+ else
153
+ e
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ #Gets outputs from values interpolated into _hamlout.push_text
160
+ def get_pushed_value exp, default = :output
161
+ return exp unless sexp? exp
162
+
163
+ case exp.node_type
164
+ when :format
165
+ exp.node_type = :output
166
+ @current_template.add_output exp
167
+ exp
168
+ when :format_escaped
169
+ exp.node_type = :escaped_output
170
+ @current_template.add_output exp
171
+ exp
172
+ when :str, :ignore, :output, :escaped_output
173
+ exp
174
+ when :block, :rlist, :dstr
175
+ exp.map! { |e| get_pushed_value e }
176
+ else
177
+ if call? exp and exp.target == HAML_HELPERS and exp.method == :html_escape
178
+ s = Sexp.new(:escaped_output, exp.first_arg)
179
+ elsif @javascript and call? exp and (exp.method == :j or exp.method == :escape_javascript)
180
+ s = Sexp.new(:escaped_output, exp.first_arg)
181
+ else
182
+ s = Sexp.new(default, exp)
183
+ end
184
+
185
+ s.line(exp.line)
186
+ @current_template.add_output s
187
+ s
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,37 @@
1
+ require 'brakeman/processors/lib/processor_helper'
2
+ require 'brakeman/processors/lib/safe_call_helper'
3
+ require 'brakeman/util'
4
+
5
+ class Brakeman::BasicProcessor < Brakeman::SexpProcessor
6
+ include Brakeman::ProcessorHelper
7
+ include Brakeman::SafeCallHelper
8
+ include Brakeman::Util
9
+
10
+ def initialize tracker
11
+ super()
12
+ @tracker = tracker
13
+ @current_template = @current_module = @current_class = @current_method = nil
14
+ end
15
+
16
+ def process_default exp
17
+ process_all exp
18
+ end
19
+
20
+ def process_if exp
21
+ condition = exp.condition
22
+
23
+ process condition
24
+
25
+ if true? condition
26
+ process exp.then_clause
27
+ elsif false? condition
28
+ process exp.else_clause
29
+ else
30
+ [exp.then_clause, exp.else_clause].compact.map do |e|
31
+ process e
32
+ end
33
+ end
34
+
35
+ exp
36
+ end
37
+ end
@@ -0,0 +1,223 @@
1
+ require 'brakeman/processors/lib/basic_processor'
2
+
3
+ class Brakeman::FindAllCalls < Brakeman::BasicProcessor
4
+ attr_reader :calls
5
+
6
+ def initialize tracker
7
+ super
8
+ @current_class = nil
9
+ @current_method = nil
10
+ @in_target = false
11
+ @calls = []
12
+ @cache = {}
13
+ end
14
+
15
+ #Process the given source. Provide either class and method being searched
16
+ #or the template. These names are used when reporting results.
17
+ def process_source exp, opts
18
+ @current_class = opts[:class]
19
+ @current_method = opts[:method]
20
+ @current_template = opts[:template]
21
+ @current_file = opts[:file]
22
+ process exp
23
+ end
24
+
25
+ #Process body of method
26
+ def process_defn exp
27
+ return exp unless @current_method
28
+ process_all exp.body
29
+ end
30
+
31
+ #Process body of method
32
+ def process_defs exp
33
+ return exp unless @current_method
34
+ process_all exp.body
35
+ end
36
+
37
+ #Process body of block
38
+ def process_rlist exp
39
+ process_all exp
40
+ end
41
+
42
+ def process_call exp
43
+ @calls << create_call_hash(exp)
44
+ exp
45
+ end
46
+
47
+ def process_iter exp
48
+ call = exp.block_call
49
+
50
+ if call.node_type == :call
51
+ call_hash = create_call_hash(call)
52
+
53
+ call_hash[:block] = exp.block
54
+ call_hash[:block_args] = exp.block_args
55
+
56
+ @calls << call_hash
57
+
58
+ process exp.block
59
+ else
60
+ #Probably a :render call with block
61
+ process call
62
+ process exp.block
63
+ end
64
+
65
+ exp
66
+ end
67
+
68
+ #Calls to render() are converted to s(:render, ...) but we would
69
+ #like them in the call cache still for speed
70
+ def process_render exp
71
+ process exp.last if sexp? exp.last
72
+
73
+ @calls << { :target => nil,
74
+ :method => :render,
75
+ :call => exp,
76
+ :nested => false,
77
+ :location => make_location }
78
+
79
+ exp
80
+ end
81
+
82
+ #Technically, `` is call to Kernel#`
83
+ #But we just need them in the call cache for speed
84
+ def process_dxstr exp
85
+ process exp.last if sexp? exp.last
86
+
87
+ @calls << { :target => nil,
88
+ :method => :`,
89
+ :call => exp,
90
+ :nested => false,
91
+ :location => make_location }
92
+
93
+ exp
94
+ end
95
+
96
+ #:"string" is equivalent to "string".to_sym
97
+ def process_dsym exp
98
+ exp.each { |arg| process arg if sexp? arg }
99
+
100
+ @calls << { :target => nil,
101
+ :method => :literal_to_sym,
102
+ :call => exp,
103
+ :nested => false,
104
+ :location => make_location }
105
+
106
+ exp
107
+ end
108
+
109
+ # Process a dynamic regex like a call
110
+ def process_dregx exp
111
+ exp.each { |arg| process arg if sexp? arg }
112
+
113
+ @calls << { :target => nil,
114
+ :method => :brakeman_regex_interp,
115
+ :call => exp,
116
+ :nested => false,
117
+ :location => make_location }
118
+
119
+ exp
120
+ end
121
+
122
+ #Process an assignment like a call
123
+ def process_attrasgn exp
124
+ process_call exp
125
+ end
126
+
127
+ private
128
+
129
+ #Gets the target of a call as a Symbol
130
+ #if possible
131
+ def get_target exp, include_calls = false
132
+ if sexp? exp
133
+ case exp.node_type
134
+ when :ivar, :lvar, :const, :lit
135
+ exp.value
136
+ when :true, :false
137
+ exp[0]
138
+ when :colon2
139
+ class_name exp
140
+ when :self
141
+ @current_class || @current_module || nil
142
+ when :params, :session, :cookies
143
+ exp.node_type
144
+ when :call, :safe_call
145
+ if include_calls
146
+ if exp.target.nil?
147
+ exp.method
148
+ else
149
+ t = get_target(exp.target, :include_calls)
150
+ if t.is_a? Symbol
151
+ :"#{t}.#{exp.method}"
152
+ else
153
+ exp
154
+ end
155
+ end
156
+ else
157
+ exp
158
+ end
159
+ else
160
+ exp
161
+ end
162
+ else
163
+ exp
164
+ end
165
+ end
166
+
167
+ #Returns method chain as an array
168
+ #For example, User.human.alive.all would return [:User, :human, :alive, :all]
169
+ def get_chain call
170
+ if node_type? call, :call, :attrasgn, :safe_call, :safe_attrasgn
171
+ get_chain(call.target) + [call.method]
172
+ elsif call.nil?
173
+ []
174
+ else
175
+ [get_target(call)]
176
+ end
177
+ end
178
+
179
+ def make_location
180
+ if @current_template
181
+ key = [@current_template, @current_file]
182
+ cached = @cache[key]
183
+ return cached if cached
184
+
185
+ @cache[key] = { :type => :template,
186
+ :template => @current_template,
187
+ :file => @current_file }
188
+ else
189
+ key = [@current_class, @current_method, @current_file]
190
+ cached = @cache[key]
191
+ return cached if cached
192
+ @cache[key] = { :type => :class,
193
+ :class => @current_class,
194
+ :method => @current_method,
195
+ :file => @current_file }
196
+ end
197
+
198
+ end
199
+
200
+ #Return info hash for a call Sexp
201
+ def create_call_hash exp
202
+ target = get_target exp.target
203
+
204
+ if call? target
205
+ already_in_target = @in_target
206
+ @in_target = true
207
+ process target
208
+ @in_target = already_in_target
209
+
210
+ target = get_target(target, :include_calls)
211
+ end
212
+
213
+ method = exp.method
214
+ process_call_args exp
215
+
216
+ { :target => target,
217
+ :method => method,
218
+ :call => exp,
219
+ :nested => @in_target,
220
+ :chain => get_chain(exp),
221
+ :location => make_location }
222
+ end
223
+ end