rubycop 0.5.0

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 (38) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/README.md +3 -0
  4. data/Rakefile +1 -0
  5. data/lib/rubycop.rb +6 -0
  6. data/lib/rubycop/analyzer.rb +6 -0
  7. data/lib/rubycop/analyzer/gray_list.rb +28 -0
  8. data/lib/rubycop/analyzer/node_builder.rb +523 -0
  9. data/lib/rubycop/analyzer/policy.rb +354 -0
  10. data/lib/rubycop/analyzer/ruby.rb +24 -0
  11. data/lib/rubycop/analyzer/ruby/args.rb +28 -0
  12. data/lib/rubycop/analyzer/ruby/array.rb +11 -0
  13. data/lib/rubycop/analyzer/ruby/assignment.rb +45 -0
  14. data/lib/rubycop/analyzer/ruby/assoc.rb +15 -0
  15. data/lib/rubycop/analyzer/ruby/blocks.rb +23 -0
  16. data/lib/rubycop/analyzer/ruby/call.rb +33 -0
  17. data/lib/rubycop/analyzer/ruby/case.rb +24 -0
  18. data/lib/rubycop/analyzer/ruby/constants.rb +49 -0
  19. data/lib/rubycop/analyzer/ruby/definitions.rb +27 -0
  20. data/lib/rubycop/analyzer/ruby/for.rb +17 -0
  21. data/lib/rubycop/analyzer/ruby/hash.rb +13 -0
  22. data/lib/rubycop/analyzer/ruby/if.rb +33 -0
  23. data/lib/rubycop/analyzer/ruby/list.rb +17 -0
  24. data/lib/rubycop/analyzer/ruby/node.rb +11 -0
  25. data/lib/rubycop/analyzer/ruby/operators.rb +54 -0
  26. data/lib/rubycop/analyzer/ruby/params.rb +23 -0
  27. data/lib/rubycop/analyzer/ruby/position.rb +15 -0
  28. data/lib/rubycop/analyzer/ruby/range.rb +17 -0
  29. data/lib/rubycop/analyzer/ruby/statements.rb +34 -0
  30. data/lib/rubycop/analyzer/ruby/string.rb +26 -0
  31. data/lib/rubycop/analyzer/ruby/tokens.rb +46 -0
  32. data/lib/rubycop/analyzer/ruby/variables.rb +26 -0
  33. data/lib/rubycop/analyzer/ruby/while.rb +29 -0
  34. data/lib/rubycop/version.rb +3 -0
  35. data/rubycop.gemspec +25 -0
  36. data/spec/node_builder_spec.rb +374 -0
  37. data/spec/policy_spec.rb +405 -0
  38. metadata +97 -0
@@ -0,0 +1,354 @@
1
+ require 'set'
2
+
3
+ module Rubycop
4
+ module Analyzer
5
+ class Policy
6
+ def initialize
7
+ @const_list = GrayList.new
8
+ initialize_const_blacklist
9
+ end
10
+
11
+ def inspect
12
+ '#<%s:0x%x>' % [self.class.name, object_id]
13
+ end
14
+
15
+ def blacklist_const(const)
16
+ @const_list.blacklist(const)
17
+ end
18
+
19
+ def const_allowed?(const)
20
+ @const_list.allow?(const)
21
+ end
22
+
23
+ def whitelist_const(const)
24
+ @const_list.whitelist(const)
25
+ end
26
+
27
+ def visit(node)
28
+ klass = node.class.ancestors.detect do |ancestor|
29
+ respond_to?("visit_#{ancestor.name.split('::').last}")
30
+ end
31
+ if klass
32
+ send("visit_#{klass.name.split('::').last}", node)
33
+ else
34
+ warn "unhandled node type: #{node.inspect}:#{node.class.name}"
35
+ true
36
+ end
37
+ end
38
+
39
+ def visit_Alias(node)
40
+ false # never allowed
41
+ end
42
+
43
+ def visit_Args(node)
44
+ node.elements.all? { |e| visit(e) }
45
+ end
46
+
47
+ def visit_Array(node)
48
+ node.elements.all? { |e| visit(e) }
49
+ end
50
+
51
+ def visit_Assoc(node)
52
+ visit(node.key) && visit(node.value)
53
+ end
54
+
55
+ def visit_Binary(node)
56
+ visit(node.lvalue) && visit(node.rvalue)
57
+ end
58
+
59
+ def visit_Block(node)
60
+ (node.params.nil? || visit(node.params)) && node.elements.all? { |e| visit(e) }
61
+ end
62
+
63
+ CALL_BLACKLIST = %w[
64
+ abort
65
+ alias_method
66
+ at_exit
67
+ autoload
68
+ binding
69
+ callcc
70
+ caller
71
+ class_eval
72
+ const_get
73
+ const_set
74
+ eval
75
+ exec
76
+ exit
77
+ fail
78
+ fork
79
+ gets
80
+ global_variables
81
+ instance_eval
82
+ load
83
+ loop
84
+ method
85
+ module_eval
86
+ open
87
+ readline
88
+ readlines
89
+ redo
90
+ remove_const
91
+ require
92
+ send
93
+ set_trace_func
94
+ sleep
95
+ spawn
96
+ srand
97
+ syscall
98
+ system
99
+ trap
100
+ undef
101
+ __callee__
102
+ __method__
103
+ ].to_set.freeze
104
+
105
+ def visit_Call(node)
106
+ !CALL_BLACKLIST.include?(node.identifier.token.to_s) && [node.target, node.arguments, node.block].compact.all? { |e| visit(e) }
107
+ end
108
+
109
+ def visit_Case(node)
110
+ visit(node.expression) && visit(node.block)
111
+ end
112
+
113
+ def visit_ChainedBlock(node)
114
+ node.elements.all? { |e| visit(e) } && node.blocks.all? { |e| visit(e) } && (node.params.nil? || visit(node.params))
115
+ end
116
+
117
+ def visit_Class(node)
118
+ visit(node.const) && (node.superclass.nil? || visit(node.superclass)) && visit(node.body)
119
+ end
120
+
121
+ def visit_ClassVariable(node)
122
+ false # never allowed
123
+ end
124
+
125
+ def visit_ClassVariableAssignment(node)
126
+ false # never allowed
127
+ end
128
+
129
+ def visit_Char(node)
130
+ true
131
+ end
132
+
133
+ def visit_Constant(node)
134
+ const_allowed?(node.token)
135
+ end
136
+
137
+ def visit_ConstantAssignment(node)
138
+ visit(node.lvalue) && visit(node.rvalue)
139
+ end
140
+
141
+ def visit_Defined(node)
142
+ false # never allowed (though it's probably safe)
143
+ end
144
+
145
+ def visit_Else(node)
146
+ node.elements.all? { |e| visit(e) }
147
+ end
148
+
149
+ def visit_ExecutableString(node)
150
+ false # never allowed
151
+ end
152
+
153
+ def visit_Float(node)
154
+ true
155
+ end
156
+
157
+ def visit_For(node)
158
+ visit(node.variable) && visit(node.range) && visit(node.statements)
159
+ end
160
+
161
+ def visit_GlobalVariable(node)
162
+ false # never allowed
163
+ end
164
+
165
+ def visit_GlobalVariableAssignment(node)
166
+ false # never allowed
167
+ end
168
+
169
+ def visit_Hash(node)
170
+ node.assocs.nil? || node.assocs.all? { |e| visit(e) }
171
+ end
172
+
173
+ def visit_Identifier(node)
174
+ !CALL_BLACKLIST.include?(node.token)
175
+ end
176
+
177
+ def visit_If(node)
178
+ visit(node.expression) && node.elements.all? { |e| visit(e) } && node.blocks.all? { |e| visit(e) }
179
+ end
180
+ alias_method :visit_Unless, :visit_If
181
+
182
+ def visit_IfMod(node)
183
+ visit(node.expression) && node.elements.all? { |e| visit(e) }
184
+ end
185
+ alias_method :visit_UnlessMod, :visit_IfMod
186
+
187
+ def visit_IfOp(node)
188
+ visit(node.condition) && visit(node.then_part) && visit(node.else_part)
189
+ end
190
+
191
+ def visit_InstanceVariable(node)
192
+ true
193
+ end
194
+
195
+ def visit_InstanceVariableAssignment(node)
196
+ visit(node.rvalue)
197
+ end
198
+
199
+ def visit_Integer(node)
200
+ true
201
+ end
202
+
203
+ KEYWORD_WHITELIST = %w[
204
+ false
205
+ nil
206
+ self
207
+ true
208
+ ].to_set.freeze
209
+
210
+ def visit_Keyword(node)
211
+ KEYWORD_WHITELIST.include?(node.token)
212
+ end
213
+
214
+ def visit_Label(node)
215
+ true
216
+ end
217
+
218
+ def visit_LocalVariableAssignment(node)
219
+ visit(node.rvalue)
220
+ end
221
+
222
+ def visit_Method(node)
223
+ [node.target, node.params, node.body].compact.all? { |e| visit(e) }
224
+ end
225
+
226
+ def visit_Module(node)
227
+ visit(node.const) && visit(node.body)
228
+ end
229
+
230
+ def visit_MultiAssignment(node)
231
+ visit(node.lvalue) && visit(node.rvalue)
232
+ end
233
+
234
+ def visit_MultiAssignmentList(node)
235
+ node.elements.all? { |e| visit(e) }
236
+ end
237
+
238
+ def visit_Params(node)
239
+ node.elements.all? { |e| visit(e) }
240
+ end
241
+
242
+ def visit_Program(node)
243
+ node.elements.all? { |e| visit(e) }
244
+ end
245
+
246
+ def visit_Range(node)
247
+ visit(node.min) && visit(node.max)
248
+ end
249
+
250
+ def visit_RescueMod(node)
251
+ node.elements.all? { |e| visit(e) } && visit(node.expression)
252
+ end
253
+
254
+ def visit_RescueParams(node)
255
+ node.elements.all? { |e| visit(e) }
256
+ end
257
+
258
+ def visit_SingletonClass(node)
259
+ visit(node.superclass) && visit(node.body)
260
+ end
261
+
262
+ def visit_SplatArg(node)
263
+ visit(node.arg)
264
+ end
265
+
266
+ def visit_Statements(node)
267
+ node.elements.all? { |e| visit(e) }
268
+ end
269
+
270
+ def visit_String(node)
271
+ # embedded strings can have statements in them, so check those
272
+ node.elements.reject { |e| e.is_a?(::String) }.all? { |e| visit(e) }
273
+ end
274
+
275
+ def visit_StringConcat(node)
276
+ node.elements.all? { |e| visit(e) }
277
+ end
278
+
279
+ def visit_Symbol(node)
280
+ true
281
+ end
282
+
283
+ def visit_Unary(node)
284
+ visit(node.operand)
285
+ end
286
+
287
+ def visit_Until(node)
288
+ false # never allowed
289
+ end
290
+ alias_method :visit_UntilMod, :visit_Until
291
+
292
+ def visit_When(node)
293
+ visit(node.expression) && node.elements.all? { |e| visit(e) }
294
+ end
295
+
296
+ def visit_While(node)
297
+ false # never allowed
298
+ end
299
+ alias_method :visit_WhileMod, :visit_While
300
+
301
+ private
302
+
303
+ CONST_BLACKLIST = %w[
304
+ ARGF
305
+ ARGV
306
+ Array
307
+ Base64
308
+ Class
309
+ Dir
310
+ ENV
311
+ Enumerable
312
+ Error
313
+ Exception
314
+ Fiber
315
+ File
316
+ FileUtils
317
+ GC
318
+ Gem
319
+ Hash
320
+ IO
321
+ IRB
322
+ Kernel
323
+ Module
324
+ Net
325
+ Object
326
+ ObjectSpace
327
+ OpenSSL
328
+ OpenURI
329
+ PLATFORM
330
+ Proc
331
+ Process
332
+ RUBY_COPYRIGHT
333
+ RUBY_DESCRIPTION
334
+ RUBY_ENGINE
335
+ RUBY_PATCHLEVEL
336
+ RUBY_PLATFORM
337
+ RUBY_RELEASE_DATE
338
+ RUBY_VERSION
339
+ Rails
340
+ STDERR
341
+ STDIN
342
+ STDOUT
343
+ String
344
+ TOPLEVEL_BINDING
345
+ Thread
346
+ VERSION
347
+ ].freeze
348
+
349
+ def initialize_const_blacklist
350
+ CONST_BLACKLIST.each { |const| blacklist_const(const) }
351
+ end
352
+ end
353
+ end
354
+ end
@@ -0,0 +1,24 @@
1
+ require 'rubycop/analyzer/ruby/node'
2
+
3
+ require 'rubycop/analyzer/ruby/list'
4
+ require 'rubycop/analyzer/ruby/array'
5
+ require 'rubycop/analyzer/ruby/args'
6
+ require 'rubycop/analyzer/ruby/assignment'
7
+ require 'rubycop/analyzer/ruby/assoc'
8
+ require 'rubycop/analyzer/ruby/statements'
9
+ require 'rubycop/analyzer/ruby/blocks'
10
+ require 'rubycop/analyzer/ruby/call'
11
+ require 'rubycop/analyzer/ruby/case'
12
+ require 'rubycop/analyzer/ruby/tokens'
13
+ require 'rubycop/analyzer/ruby/constants'
14
+ require 'rubycop/analyzer/ruby/definitions'
15
+ require 'rubycop/analyzer/ruby/for'
16
+ require 'rubycop/analyzer/ruby/hash'
17
+ require 'rubycop/analyzer/ruby/if'
18
+ require 'rubycop/analyzer/ruby/operators'
19
+ require 'rubycop/analyzer/ruby/params'
20
+ require 'rubycop/analyzer/ruby/position'
21
+ require 'rubycop/analyzer/ruby/range'
22
+ require 'rubycop/analyzer/ruby/string'
23
+ require 'rubycop/analyzer/ruby/variables'
24
+ require 'rubycop/analyzer/ruby/while'
@@ -0,0 +1,28 @@
1
+ module Rubycop
2
+ module Analyzer
3
+ module Ruby
4
+ class Args < List
5
+ attr_reader :block
6
+
7
+ def add_block(block)
8
+ @block = block
9
+ end
10
+
11
+ def to_array
12
+ Array.new(@elements)
13
+ end
14
+ end
15
+
16
+ class Arg < Node
17
+ def initialize(arg)
18
+ @arg = arg
19
+ end
20
+
21
+ attr_reader :arg
22
+ end
23
+
24
+ class SplatArg < Arg
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ module Rubycop
2
+ module Analyzer
3
+ module Ruby
4
+ class Array < List
5
+ # def inspect
6
+ # '[%s]' % @elements.collect { |e| e.inspect }.join(', ')
7
+ # end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ module Rubycop
2
+ module Analyzer
3
+ module Ruby
4
+ class Assignment < Node
5
+ def initialize(lvalue, rvalue, operator)
6
+ @lvalue = lvalue
7
+ @rvalue = rvalue
8
+ @operator = operator
9
+ end
10
+
11
+ attr_reader :lvalue
12
+ attr_reader :rvalue
13
+ attr_reader :operator
14
+
15
+ # def inspect
16
+ # "#{@lvalue.inspect} #{@operator} #{@rvalue.inspect}"
17
+ # end
18
+ end
19
+
20
+ class ClassVariableAssignment < Assignment
21
+ end
22
+
23
+ class ConstantAssignment < Assignment
24
+ end
25
+
26
+ class GlobalVariableAssignment < Assignment
27
+ end
28
+
29
+ class InstanceVariableAssignment < Assignment
30
+ end
31
+
32
+ class LocalVariableAssignment < Assignment
33
+ end
34
+
35
+ class MultiAssignment < Assignment
36
+ end
37
+
38
+ class MultiAssignmentList < List
39
+ def assignment(rvalue, operator)
40
+ MultiAssignment.new(self, rvalue, operator)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end