ruby-lint 0.0.5 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (207) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.asc +14 -14
  3. data/.gitignore +1 -0
  4. data/.yardopts +1 -1
  5. data/Gemfile +3 -3
  6. data/MANIFEST +16 -3
  7. data/benchmark/virtual_machine.rb +17 -0
  8. data/checksum/ruby-lint-0.0.5.gem.sha512 +1 -0
  9. data/doc/changelog.md +42 -0
  10. data/doc/configuration.md +133 -13
  11. data/lib/ruby-lint/analysis/shadowing_variables.rb +8 -14
  12. data/lib/ruby-lint/analysis/unused_variables.rb +17 -0
  13. data/lib/ruby-lint/ast/node.rb +18 -3
  14. data/lib/ruby-lint/cache.rb +121 -0
  15. data/lib/ruby-lint/cache_entry.rb +44 -0
  16. data/lib/ruby-lint/cli/analyze.rb +37 -18
  17. data/lib/ruby-lint/cli/plot.rb +94 -0
  18. data/lib/ruby-lint/cli.rb +1 -0
  19. data/lib/ruby-lint/configuration.rb +48 -3
  20. data/lib/ruby-lint/definition/ruby_method.rb +28 -1
  21. data/lib/ruby-lint/definition/ruby_object.rb +37 -3
  22. data/lib/ruby-lint/definition_builder/ruby_method.rb +4 -1
  23. data/lib/ruby-lint/definition_builder/ruby_module.rb +4 -1
  24. data/lib/ruby-lint/definition_generator.rb +3 -2
  25. data/lib/ruby-lint/definitions/core/arg0.rb +3 -1
  26. data/lib/ruby-lint/definitions/core/argf.rb +3 -1
  27. data/lib/ruby-lint/definitions/core/argument_error.rb +3 -1
  28. data/lib/ruby-lint/definitions/core/argv.rb +3 -1
  29. data/lib/ruby-lint/definitions/core/array.rb +3 -1
  30. data/lib/ruby-lint/definitions/core/autoload.rb +3 -1
  31. data/lib/ruby-lint/definitions/core/basic_object.rb +2 -0
  32. data/lib/ruby-lint/definitions/core/bignum.rb +3 -1
  33. data/lib/ruby-lint/definitions/core/binding.rb +3 -1
  34. data/lib/ruby-lint/definitions/core/class.rb +2 -0
  35. data/lib/ruby-lint/definitions/core/comparable.rb +3 -1
  36. data/lib/ruby-lint/definitions/core/complex.rb +3 -1
  37. data/lib/ruby-lint/definitions/core/condition_variable.rb +3 -1
  38. data/lib/ruby-lint/definitions/core/continuation.rb +3 -1
  39. data/lib/ruby-lint/definitions/core/data.rb +3 -1
  40. data/lib/ruby-lint/definitions/core/date.rb +3 -1
  41. data/lib/ruby-lint/definitions/core/date_time.rb +3 -1
  42. data/lib/ruby-lint/definitions/core/default_record_separator.rb +3 -1
  43. data/lib/ruby-lint/definitions/core/digest.rb +3 -1
  44. data/lib/ruby-lint/definitions/core/dir.rb +3 -1
  45. data/lib/ruby-lint/definitions/core/encoding.rb +3 -1
  46. data/lib/ruby-lint/definitions/core/encoding_error.rb +3 -1
  47. data/lib/ruby-lint/definitions/core/enumerable.rb +3 -1
  48. data/lib/ruby-lint/definitions/core/enumerator.rb +3 -1
  49. data/lib/ruby-lint/definitions/core/env.rb +4 -1
  50. data/lib/ruby-lint/definitions/core/eoferror.rb +3 -1
  51. data/lib/ruby-lint/definitions/core/erb.rb +2 -0
  52. data/lib/ruby-lint/definitions/core/errno.rb +3 -1
  53. data/lib/ruby-lint/definitions/core/etc.rb +3 -1
  54. data/lib/ruby-lint/definitions/core/exception.rb +3 -1
  55. data/lib/ruby-lint/definitions/core/false.rb +3 -1
  56. data/lib/ruby-lint/definitions/core/false_class.rb +3 -1
  57. data/lib/ruby-lint/definitions/core/fatal_error.rb +3 -1
  58. data/lib/ruby-lint/definitions/core/fiber.rb +3 -1
  59. data/lib/ruby-lint/definitions/core/fiber_error.rb +3 -1
  60. data/lib/ruby-lint/definitions/core/file.rb +3 -1
  61. data/lib/ruby-lint/definitions/core/file_list.rb +3 -1
  62. data/lib/ruby-lint/definitions/core/file_test.rb +3 -1
  63. data/lib/ruby-lint/definitions/core/file_utils.rb +3 -1
  64. data/lib/ruby-lint/definitions/core/fixnum.rb +3 -1
  65. data/lib/ruby-lint/definitions/core/float.rb +3 -1
  66. data/lib/ruby-lint/definitions/core/float_domain_error.rb +3 -1
  67. data/lib/ruby-lint/definitions/core/gc.rb +3 -1
  68. data/lib/ruby-lint/definitions/core/gem.rb +3 -1
  69. data/lib/ruby-lint/definitions/core/hash.rb +3 -1
  70. data/lib/ruby-lint/definitions/core/immediate_value.rb +3 -1
  71. data/lib/ruby-lint/definitions/core/index_error.rb +3 -1
  72. data/lib/ruby-lint/definitions/core/integer.rb +3 -1
  73. data/lib/ruby-lint/definitions/core/interrupt.rb +3 -1
  74. data/lib/ruby-lint/definitions/core/io.rb +3 -1
  75. data/lib/ruby-lint/definitions/core/ioerror.rb +3 -1
  76. data/lib/ruby-lint/definitions/core/kernel.rb +2 -0
  77. data/lib/ruby-lint/definitions/core/key_error.rb +3 -1
  78. data/lib/ruby-lint/definitions/core/load_error.rb +3 -1
  79. data/lib/ruby-lint/definitions/core/local_jump_error.rb +3 -1
  80. data/lib/ruby-lint/definitions/core/marshal.rb +3 -1
  81. data/lib/ruby-lint/definitions/core/match_data.rb +3 -1
  82. data/lib/ruby-lint/definitions/core/math.rb +3 -1
  83. data/lib/ruby-lint/definitions/core/memory_segmention_error.rb +3 -1
  84. data/lib/ruby-lint/definitions/core/method.rb +3 -1
  85. data/lib/ruby-lint/definitions/core/module.rb +2 -0
  86. data/lib/ruby-lint/definitions/core/monitor.rb +3 -1
  87. data/lib/ruby-lint/definitions/core/monitor_mixin.rb +3 -1
  88. data/lib/ruby-lint/definitions/core/mutex.rb +3 -1
  89. data/lib/ruby-lint/definitions/core/name_error.rb +3 -1
  90. data/lib/ruby-lint/definitions/core/nil.rb +3 -1
  91. data/lib/ruby-lint/definitions/core/nil_class.rb +3 -1
  92. data/lib/ruby-lint/definitions/core/no_memory_error.rb +3 -1
  93. data/lib/ruby-lint/definitions/core/no_method_error.rb +3 -1
  94. data/lib/ruby-lint/definitions/core/not_implemented_error.rb +3 -1
  95. data/lib/ruby-lint/definitions/core/numeric.rb +3 -1
  96. data/lib/ruby-lint/definitions/core/object.rb +3 -1
  97. data/lib/ruby-lint/definitions/core/object_space.rb +3 -1
  98. data/lib/ruby-lint/definitions/core/open_struct.rb +3 -1
  99. data/lib/ruby-lint/definitions/core/option_parser.rb +3 -1
  100. data/lib/ruby-lint/definitions/core/precision.rb +3 -1
  101. data/lib/ruby-lint/definitions/core/primitive_failure.rb +3 -1
  102. data/lib/ruby-lint/definitions/core/proc.rb +3 -1
  103. data/lib/ruby-lint/definitions/core/process.rb +3 -1
  104. data/lib/ruby-lint/definitions/core/queue.rb +3 -1
  105. data/lib/ruby-lint/definitions/core/rake.rb +3 -1
  106. data/lib/ruby-lint/definitions/core/rake_file_utils.rb +3 -1
  107. data/lib/ruby-lint/definitions/core/rakeversion.rb +3 -1
  108. data/lib/ruby-lint/definitions/core/random.rb +3 -1
  109. data/lib/ruby-lint/definitions/core/range.rb +3 -1
  110. data/lib/ruby-lint/definitions/core/range_error.rb +3 -1
  111. data/lib/ruby-lint/definitions/core/rational.rb +3 -1
  112. data/lib/ruby-lint/definitions/core/rb_config.rb +3 -1
  113. data/lib/ruby-lint/definitions/core/regexp.rb +3 -1
  114. data/lib/ruby-lint/definitions/core/regexp_error.rb +3 -1
  115. data/lib/ruby-lint/definitions/core/ruby_copyright.rb +3 -1
  116. data/lib/ruby-lint/definitions/core/ruby_description.rb +3 -1
  117. data/lib/ruby-lint/definitions/core/ruby_engine.rb +3 -1
  118. data/lib/ruby-lint/definitions/core/ruby_patchlevel.rb +3 -1
  119. data/lib/ruby-lint/definitions/core/ruby_platform.rb +3 -1
  120. data/lib/ruby-lint/definitions/core/ruby_release_date.rb +3 -1
  121. data/lib/ruby-lint/definitions/core/ruby_version.rb +3 -1
  122. data/lib/ruby-lint/definitions/core/runtime_error.rb +3 -1
  123. data/lib/ruby-lint/definitions/core/scan_error.rb +3 -1
  124. data/lib/ruby-lint/definitions/core/script_error.rb +3 -1
  125. data/lib/ruby-lint/definitions/core/security_error.rb +3 -1
  126. data/lib/ruby-lint/definitions/core/shellwords.rb +3 -1
  127. data/lib/ruby-lint/definitions/core/signal.rb +3 -1
  128. data/lib/ruby-lint/definitions/core/signal_exception.rb +3 -1
  129. data/lib/ruby-lint/definitions/core/singleton.rb +3 -1
  130. data/lib/ruby-lint/definitions/core/sized_queue.rb +3 -1
  131. data/lib/ruby-lint/definitions/core/standard_error.rb +3 -1
  132. data/lib/ruby-lint/definitions/core/stderr.rb +2 -0
  133. data/lib/ruby-lint/definitions/core/stdin.rb +2 -0
  134. data/lib/ruby-lint/definitions/core/stdout.rb +2 -0
  135. data/lib/ruby-lint/definitions/core/stop_iteration.rb +3 -1
  136. data/lib/ruby-lint/definitions/core/string.rb +3 -1
  137. data/lib/ruby-lint/definitions/core/string_io.rb +3 -1
  138. data/lib/ruby-lint/definitions/core/string_scanner.rb +3 -1
  139. data/lib/ruby-lint/definitions/core/struct.rb +3 -1
  140. data/lib/ruby-lint/definitions/core/syck.rb +3 -1
  141. data/lib/ruby-lint/definitions/core/symbol.rb +3 -1
  142. data/lib/ruby-lint/definitions/core/syntax_error.rb +3 -1
  143. data/lib/ruby-lint/definitions/core/system_call_error.rb +3 -1
  144. data/lib/ruby-lint/definitions/core/system_exit.rb +3 -1
  145. data/lib/ruby-lint/definitions/core/system_stack_error.rb +3 -1
  146. data/lib/ruby-lint/definitions/core/thread.rb +3 -1
  147. data/lib/ruby-lint/definitions/core/thread_error.rb +3 -1
  148. data/lib/ruby-lint/definitions/core/thread_group.rb +3 -1
  149. data/lib/ruby-lint/definitions/core/time.rb +3 -1
  150. data/lib/ruby-lint/definitions/core/toplevel_binding.rb +3 -1
  151. data/lib/ruby-lint/definitions/core/true.rb +3 -1
  152. data/lib/ruby-lint/definitions/core/true_class.rb +3 -1
  153. data/lib/ruby-lint/definitions/core/type_error.rb +3 -1
  154. data/lib/ruby-lint/definitions/core/unbound_method.rb +3 -1
  155. data/lib/ruby-lint/definitions/core/unmarshalable.rb +3 -1
  156. data/lib/ruby-lint/definitions/core/unsupported_library_error.rb +3 -1
  157. data/lib/ruby-lint/definitions/core/weak_ref.rb +3 -1
  158. data/lib/ruby-lint/definitions/core/yaml.rb +1 -0
  159. data/lib/ruby-lint/definitions/core/zero_division_error.rb +3 -1
  160. data/lib/ruby-lint/definitions/core/zlib.rb +8840 -0
  161. data/lib/ruby-lint/definitions/rails/abstract_controller.rb +1 -0
  162. data/lib/ruby-lint/definitions/rails/action_controller.rb +1 -0
  163. data/lib/ruby-lint/definitions/rails/action_dispatch.rb +1 -0
  164. data/lib/ruby-lint/definitions/rails/action_mailer.rb +1 -0
  165. data/lib/ruby-lint/definitions/rails/action_pack.rb +1 -0
  166. data/lib/ruby-lint/definitions/rails/action_view.rb +1 -0
  167. data/lib/ruby-lint/definitions/rails/active_model.rb +1 -0
  168. data/lib/ruby-lint/definitions/rails/active_record.rb +1 -0
  169. data/lib/ruby-lint/definitions/rails/active_support.rb +1 -0
  170. data/lib/ruby-lint/definitions/rails/arel.rb +1 -0
  171. data/lib/ruby-lint/definitions/rails/rails.rb +1 -0
  172. data/lib/ruby-lint/definitions/rails/sprockets.rb +1 -0
  173. data/lib/ruby-lint/file_scanner.rb +2 -0
  174. data/lib/ruby-lint/iterator.rb +21 -12
  175. data/lib/ruby-lint/method_call_info.rb +31 -0
  176. data/lib/ruby-lint/node_hash.rb +105 -0
  177. data/lib/ruby-lint/parser.rb +4 -2
  178. data/lib/ruby-lint/runner.rb +62 -6
  179. data/lib/ruby-lint/template/definition.erb +2 -0
  180. data/lib/ruby-lint/version.rb +1 -1
  181. data/lib/ruby-lint/virtual_machine.rb +75 -43
  182. data/lib/ruby-lint.rb +20 -2
  183. data/profiling/virtual_machine.rb +20 -0
  184. data/ruby-lint.gemspec +2 -1
  185. data/spec/fixtures/complex/rcap.rb +29 -0
  186. data/spec/fixtures/complex/slop.rb +21 -0
  187. data/spec/fixtures/file_scanner/lib/ruby-lint/definition/constant_proxy.rb +6 -0
  188. data/spec/fixtures/file_scanner/lib/ruby-lint/global_scope.rb +6 -0
  189. data/spec/ruby-lint/analysis/unused_variables_spec.rb +114 -0
  190. data/spec/ruby-lint/cache_entry_spec.rb +25 -0
  191. data/spec/ruby-lint/cache_spec.rb +53 -0
  192. data/spec/ruby-lint/definition/ruby_method_spec.rb +4 -4
  193. data/spec/ruby-lint/definition/ruby_object_spec.rb +33 -0
  194. data/spec/ruby-lint/iterator_spec.rb +15 -0
  195. data/spec/ruby-lint/node_hash_spec.rb +56 -0
  196. data/spec/ruby-lint/runner_spec.rb +6 -1
  197. data/spec/ruby-lint/virtual_machine/assignments/variables_spec.rb +2 -2
  198. data/spec/ruby-lint/virtual_machine/location_spec.rb +64 -0
  199. data/spec/ruby-lint/virtual_machine/method_call_tracking_spec.rb +64 -0
  200. data/spec/spec_helper.rb +7 -0
  201. data/task/generate.rake +1 -1
  202. data.tar.gz.asc +14 -14
  203. metadata +34 -7
  204. metadata.gz.asc +14 -14
  205. data/debug/memory_usage.rb +0 -14
  206. data/debug/profile.rb +0 -18
  207. data/task/profile.rake +0 -27
@@ -479,3 +479,4 @@ RubyLint::GlobalScope.definitions.define_constant('AbstractController::ViewPaths
479
479
  end
480
480
  end
481
481
 
482
+ RubyLint::GlobalScope.definitions.lookup(:const, 'AbstractController').deep_freeze
@@ -5651,3 +5651,4 @@ RubyLint::GlobalScope.definitions.define_constant('ActionController::UrlGenerati
5651
5651
  end
5652
5652
  end
5653
5653
 
5654
+ RubyLint::GlobalScope.definitions.lookup(:const, 'ActionController').deep_freeze
@@ -2936,3 +2936,4 @@ RubyLint::GlobalScope.definitions.define_constant('ActionDispatch::TestResponse'
2936
2936
  klass.define_instance_method('unprocessable?')
2937
2937
  end
2938
2938
 
2939
+ RubyLint::GlobalScope.definitions.lookup(:const, 'ActionDispatch').deep_freeze
@@ -1743,3 +1743,4 @@ RubyLint::GlobalScope.definitions.define_constant('ActionMailer::VERSION') do |k
1743
1743
  end
1744
1744
  end
1745
1745
 
1746
+ RubyLint::GlobalScope.definitions.lookup(:const, 'ActionMailer').deep_freeze
@@ -22,3 +22,4 @@ RubyLint::GlobalScope.definitions.define_constant('ActionPack::VERSION') do |kla
22
22
  end
23
23
  end
24
24
 
25
+ RubyLint::GlobalScope.definitions.lookup(:const, 'ActionPack').deep_freeze
@@ -7392,3 +7392,4 @@ RubyLint::GlobalScope.definitions.define_constant('ActionView::WrongEncodingErro
7392
7392
  end
7393
7393
  end
7394
7394
 
7395
+ RubyLint::GlobalScope.definitions.lookup(:const, 'ActionView').deep_freeze
@@ -1578,3 +1578,4 @@ RubyLint::GlobalScope.definitions.define_constant('ActiveModel::Validator') do |
1578
1578
  end
1579
1579
  end
1580
1580
 
1581
+ RubyLint::GlobalScope.definitions.lookup(:const, 'ActiveModel').deep_freeze
@@ -11793,3 +11793,4 @@ RubyLint::GlobalScope.definitions.define_constant('ActiveRecord::WrappedDatabase
11793
11793
  end
11794
11794
  end
11795
11795
 
11796
+ RubyLint::GlobalScope.definitions.lookup(:const, 'ActiveRecord').deep_freeze
@@ -6019,3 +6019,4 @@ RubyLint::GlobalScope.definitions.define_constant('ActiveSupport::XmlMini_REXML'
6019
6019
  end
6020
6020
  end
6021
6021
 
6022
+ RubyLint::GlobalScope.definitions.lookup(:const, 'ActiveSupport').deep_freeze
@@ -3555,3 +3555,4 @@ RubyLint::GlobalScope.definitions.define_constant('Arel::WindowPredications') do
3555
3555
  end
3556
3556
  end
3557
3557
 
3558
+ RubyLint::GlobalScope.definitions.lookup(:const, 'Arel').deep_freeze
@@ -3288,3 +3288,4 @@ RubyLint::GlobalScope.definitions.define_constant('Rails::WelcomeController') do
3288
3288
  end
3289
3289
  end
3290
3290
 
3291
+ RubyLint::GlobalScope.definitions.lookup(:const, 'Rails').deep_freeze
@@ -3737,3 +3737,4 @@ RubyLint::GlobalScope.definitions.define_constant('Sprockets::YUICompressor') do
3737
3737
  end
3738
3738
  end
3739
3739
 
3740
+ RubyLint::GlobalScope.definitions.lookup(:const, 'Sprockets').deep_freeze
@@ -44,6 +44,8 @@ module RubyLint
44
44
  paths = Dir.glob(glob_pattern(segment))
45
45
  end
46
46
 
47
+ paths.map! { |path| File.expand_path(path) }
48
+
47
49
  ignore.each do |pattern|
48
50
  paths.reject! do |path|
49
51
  path.include?(pattern)
@@ -50,7 +50,13 @@ module RubyLint
50
50
  # the specified node (`throw` calls bubble up regardless of `catch` calls,
51
51
  # unlike when using `begin/rescue`).
52
52
  #
53
+ # @!attribute [r] arity_cache Hash containing the amount of arguments for
54
+ # each method.
55
+ # @return [Hash]
56
+ #
53
57
  class Iterator
58
+ attr_reader :arity_cache
59
+
54
60
  ##
55
61
  # @param [Hash] options Hash containing custom options to set for the
56
62
  # iterator.
@@ -61,6 +67,8 @@ module RubyLint
61
67
  end
62
68
 
63
69
  after_initialize if respond_to?(:after_initialize)
70
+
71
+ @arity_cache = {}
64
72
  end
65
73
 
66
74
  ##
@@ -72,8 +80,9 @@ module RubyLint
72
80
  def iterate(node)
73
81
  return unless node.is_a?(AST::Node)
74
82
 
75
- before, after = callback_names(node)
76
- skip_node = catch :skip_child_nodes do
83
+ before = :"on_#{node.type}"
84
+ after = :"after_#{node.type}"
85
+ skip_node = catch :skip_child_nodes do
77
86
  execute_callback(before, node)
78
87
  end
79
88
 
@@ -104,17 +113,17 @@ module RubyLint
104
113
  # @param [Array] args Arguments to pass to the callback method.
105
114
  #
106
115
  def execute_callback(name, *args)
107
- send(name, *args) if respond_to?(name)
108
- end
116
+ return unless respond_to?(name)
109
117
 
110
- ##
111
- # Returns an array containin the callback names for the specified node.
112
- #
113
- # @param [RubyLint::Node] node
114
- # @return [Array]
115
- #
116
- def callback_names(node)
117
- return ["on_#{node.type}", "after_#{node.type}"]
118
+ unless arity_cache.key?(name)
119
+ arity_cache[name] = method(name).arity
120
+ end
121
+
122
+ if arity_cache[name] == 0
123
+ send(name)
124
+ else
125
+ send(name, *args)
126
+ end
118
127
  end
119
128
  end # Iterator
120
129
  end # RubyLint
@@ -0,0 +1,31 @@
1
+ module RubyLint
2
+ ##
3
+ # The MethodCallInfo class stores basic information about method calls such
4
+ # as the definition of the method and location information of the method
5
+ # call.
6
+ #
7
+ # @!attribute [r] definition
8
+ # @return [RubyLint::Definition::RubyMethod]
9
+ #
10
+ # @!attribute [r] line
11
+ # @return [Numeric] The line of the method call.
12
+ #
13
+ # @!attribute [r] column
14
+ # @return [Numeric] The column of the method call.
15
+ #
16
+ # @!attribute [r] file
17
+ # @return [String] The file of the method call.
18
+ #
19
+ class MethodCallInfo
20
+ attr_reader :definition, :line, :column, :file
21
+
22
+ ##
23
+ # @param [Hash] options
24
+ #
25
+ def initialize(options = {})
26
+ options.each do |key, value|
27
+ instance_variable_set("@#{key}", value) if respond_to?(key)
28
+ end
29
+ end
30
+ end # MethodCallInfo
31
+ end # RubyLint
@@ -0,0 +1,105 @@
1
+ module RubyLint
2
+ ##
3
+ # The NodeHash class is used to store information about {RubyLint::AST::Node}
4
+ # instances based on their SHA1 hashes. It's primarily used by
5
+ # {RubyLint::Runner} to store nodes and their associated comments.
6
+ #
7
+ # @!attribute [r] hash
8
+ # @return [Hash]
9
+ #
10
+ class NodeHash
11
+ attr_reader :hash
12
+
13
+ ##
14
+ # Creates a new instance from a regular Hash.
15
+ #
16
+ # @param [Hash] hash
17
+ # @return [RubyLint::NodeHash]
18
+ #
19
+ def self.from_hash(hash)
20
+ converted = {}
21
+
22
+ hash.each do |key, value|
23
+ converted[key.sha1] = value
24
+ end
25
+
26
+ return new(converted)
27
+ end
28
+
29
+ ##
30
+ # @param [Hash] hash
31
+ #
32
+ def initialize(hash = {})
33
+ @hash = hash
34
+ end
35
+
36
+ ##
37
+ # Returns the value associated with the given node.
38
+ #
39
+ # @param [RubyLint::AST::Node] node
40
+ # @return [Mixed]
41
+ #
42
+ def [](node)
43
+ return @hash[node.sha1]
44
+ end
45
+
46
+ ##
47
+ # Checks if there's a value stored for the node.
48
+ #
49
+ # @param [RubyLint::AST::Node] node
50
+ # @return [TrueClass|FalseClass]
51
+ #
52
+ def key?(node)
53
+ return @hash.key?(node.sha1)
54
+ end
55
+
56
+ ##
57
+ # Sets a value for the given node.
58
+ #
59
+ # @param [RubyLint::AST::Node] node
60
+ # @param [Mixed] value
61
+ #
62
+ def []=(node, value)
63
+ return @hash[node.sha1] = value
64
+ end
65
+
66
+ ##
67
+ # @return [Array]
68
+ #
69
+ def keys
70
+ return @hash.keys
71
+ end
72
+
73
+ ##
74
+ # @return [Array]
75
+ #
76
+ def values
77
+ return @hash.values
78
+ end
79
+
80
+ ##
81
+ # @return [Array]
82
+ #
83
+ def to_a
84
+ return @hash.to_a
85
+ end
86
+
87
+ ##
88
+ # Merges the values of another NodeHash into the current one.
89
+ #
90
+ # @param [RubyLint::NodeHash] other
91
+ #
92
+ def merge!(other)
93
+ @hash.merge!(other.hash)
94
+ end
95
+
96
+ ##
97
+ # Merges a regular Hash into the current NodeHash.
98
+ #
99
+ # @param [Hash] hash
100
+ #
101
+ def merge_hash!(hash)
102
+ merge!(self.class.from_hash(hash))
103
+ end
104
+ end # NodeHash
105
+ end # RubyLint
@@ -39,11 +39,13 @@ module RubyLint
39
39
  buffer = ::Parser::Source::Buffer.new(file, line)
40
40
  buffer.source = code
41
41
  ast, comments = internal_parser.parse_with_comments(buffer)
42
- associator = ::Parser::Source::Comment::Associator.new(comments, ast)
42
+ associator = ::Parser::Source::Comment::Associator.new(ast, comments)
43
43
 
44
44
  internal_parser.reset
45
45
 
46
- return AST::Node.new(:root, [ast]), associator.associate
46
+ root = AST::Node.new(:root, [ast], :location => ast.location)
47
+
48
+ return root, associator.associate
47
49
  end
48
50
  end # Parser
49
51
  end # RubyLint
@@ -7,14 +7,20 @@ module RubyLint
7
7
  # @!attribute [r] configuration
8
8
  # @return [RubyLint::Configuration]
9
9
  #
10
+ # @!attribute [r] cache
11
+ # @return [RubyLint::Cache]
12
+ #
10
13
  class Runner
11
- attr_reader :configuration
14
+ attr_reader :configuration, :cache
12
15
 
13
16
  ##
14
17
  # @param [RubyLint::Configuration] configuration
15
18
  #
16
19
  def initialize(configuration)
17
- @configuration = configuration
20
+ @configuration = configuration
21
+ @cache = Cache.new(configuration.cache_directory)
22
+
23
+ @cache.create_directory! if configuration.enable_cache
18
24
  end
19
25
 
20
26
  ##
@@ -77,7 +83,9 @@ module RubyLint
77
83
  # @return [Array]
78
84
  #
79
85
  def parse_file(parser, file)
80
- return parser.parse(File.read(file), file)
86
+ ast, comments = parser.parse(File.read(file), file)
87
+
88
+ return ast, NodeHash.from_hash(comments)
81
89
  end
82
90
 
83
91
  ##
@@ -98,6 +106,10 @@ module RubyLint
98
106
  # @return [Array]
99
107
  #
100
108
  def process_external_files(root_ast)
109
+ if cached_values = get_cache(root_ast)
110
+ return cached_values
111
+ end
112
+
101
113
  loader = FileLoader.new(
102
114
  :directories => configuration.directories,
103
115
  :ignore_paths => configuration.ignore_paths,
@@ -105,16 +117,21 @@ module RubyLint
105
117
  )
106
118
 
107
119
  nodes = []
108
- comments = {}
120
+ mtimes = {}
121
+ comments = NodeHash.new
109
122
 
110
123
  loader.iterate(root_ast)
111
124
 
112
- loader.nodes.each do |(ast, cmts)|
125
+ loader.nodes.each do |(ast, comment_associations)|
113
126
  nodes << ast
114
127
 
115
- comments.merge!(cmts)
128
+ mtimes[ast.file] = File.mtime(ast.file) if configuration.enable_cache
129
+
130
+ comments.merge_hash!(comment_associations)
116
131
  end
117
132
 
133
+ set_cache(root_ast, nodes, comments, mtimes)
134
+
118
135
  return nodes, comments
119
136
  end
120
137
 
@@ -158,5 +175,44 @@ module RubyLint
158
175
  instance.iterate(ast)
159
176
  end
160
177
  end
178
+
179
+ ##
180
+ # Checks if the AST node has a cache file and if so returns the nodes and
181
+ # comments that are cached.
182
+ #
183
+ # @param [RubyLint::AST::Node] node
184
+ # @return [Array]
185
+ #
186
+ def get_cache(node)
187
+ return unless configuration.enable_cache
188
+
189
+ cache_name = node.sha1
190
+
191
+ if cache.exists?(cache_name)
192
+ entry = cache.get(cache_name)
193
+
194
+ if entry.valid?
195
+ return entry.nodes, entry.comments
196
+ else
197
+ cache.delete(cache_name)
198
+ end
199
+ end
200
+
201
+ return
202
+ end
203
+
204
+ ##
205
+ # Caches the values for the given node.
206
+ #
207
+ # @param [RubyLint::AST::Node] node
208
+ # @param [Array] nodes
209
+ # @param [RubyLint::NodeHash] comments
210
+ # @param [Hash] mtimes
211
+ #
212
+ def set_cache(node, nodes, comments, mtimes)
213
+ return unless configuration.enable_cache
214
+
215
+ cache.set(node.sha1, CacheEntry.new(nodes, comments, mtimes))
216
+ end
161
217
  end # Runner
162
218
  end # RubyLint
@@ -26,3 +26,5 @@ RubyLint::GlobalScope.definitions.define_constant('<%= constant.name %>') do |kl
26
26
  <%- end -%>
27
27
  end
28
28
  <% end %>
29
+
30
+ RubyLint::GlobalScope.definitions.lookup(:const, '<%= @constants[0].name %>').deep_freeze
@@ -1,3 +1,3 @@
1
1
  module RubyLint
2
- VERSION = '0.0.5'
2
+ VERSION = '0.9.0'
3
3
  end # RubyLint
@@ -195,7 +195,7 @@ module RubyLint
195
195
  #
196
196
  # @param [RubyLint::AST::Node] node
197
197
  #
198
- def on_assign(node)
198
+ def on_assign
199
199
  reset_assignment_value
200
200
  value_stack.add_stack
201
201
  end
@@ -212,10 +212,10 @@ module RubyLint
212
212
  value = assignment_value
213
213
  end
214
214
 
215
- assign_variable(type, name, value)
215
+ assign_variable(type, name, value, node)
216
216
  end
217
217
 
218
- ASSIGNMENT_TYPES.each do |callback, type|
218
+ ASSIGNMENT_TYPES.each do |callback, _|
219
219
  alias_method :"on_#{callback}", :on_assign
220
220
  alias_method :"after_#{callback}", :after_assign
221
221
  end
@@ -259,7 +259,7 @@ module RubyLint
259
259
  ##
260
260
  # @param [RubyLint::AST::Node] node
261
261
  #
262
- def on_masgn(node)
262
+ def on_masgn
263
263
  add_stacks
264
264
  end
265
265
 
@@ -267,9 +267,7 @@ module RubyLint
267
267
  # Processes a mass variable assignment using the stacks created by
268
268
  # {#on_masgn}.
269
269
  #
270
- # @param [RubyLint::AST::Node] node
271
- #
272
- def after_masgn(node)
270
+ def after_masgn
273
271
  variables = variable_stack.pop
274
272
  values = value_stack.pop.first
275
273
  values = values && values.value ? values.value : []
@@ -284,16 +282,14 @@ module RubyLint
284
282
  ##
285
283
  # @param [RubyLint::AST::Node] node
286
284
  #
287
- def on_or_asgn(node)
285
+ def on_or_asgn
288
286
  add_stacks
289
287
  end
290
288
 
291
289
  ##
292
290
  # Processes an `or` assignment in the form of `variable ||= value`.
293
291
  #
294
- # @param [RubyLint::AST::Node] node
295
- #
296
- def after_or_asgn(node)
292
+ def after_or_asgn
297
293
  variable = variable_stack.pop.first
298
294
  value = value_stack.pop.first
299
295
 
@@ -305,7 +301,7 @@ module RubyLint
305
301
  ##
306
302
  # @param [RubyLint::AST::Node] node
307
303
  #
308
- def on_and_asgn(node)
304
+ def on_and_asgn
309
305
  add_stacks
310
306
  end
311
307
 
@@ -314,7 +310,7 @@ module RubyLint
314
310
  #
315
311
  # @param [RubyLint::AST::Node] node
316
312
  #
317
- def after_and_asgn(node)
313
+ def after_and_asgn
318
314
  variable = variable_stack.pop.first
319
315
  value = value_stack.pop.first
320
316
 
@@ -330,7 +326,7 @@ module RubyLint
330
326
 
331
327
  # Creates the callback methods for various variable types such as local
332
328
  # variables.
333
- ASSIGNMENT_TYPES.each do |asgn_name, type|
329
+ ASSIGNMENT_TYPES.each do |_, type|
334
330
  define_method("on_#{type}") do |node|
335
331
  increment_reference_amount(node)
336
332
  push_variable_value(node)
@@ -361,9 +357,9 @@ module RubyLint
361
357
  end
362
358
 
363
359
  ##
364
- # @param [RubyLint::AST::Node] node
360
+ # Adds a new stack for Array values.
365
361
  #
366
- def on_array(node)
362
+ def on_array
367
363
  value_stack.add_stack
368
364
  end
369
365
 
@@ -383,9 +379,9 @@ module RubyLint
383
379
  end
384
380
 
385
381
  ##
386
- # @param [RubyLint::AST::Node] node
382
+ # Adds a new stack for Hash values.
387
383
  #
388
- def on_hash(node)
384
+ def on_hash
389
385
  value_stack.add_stack
390
386
  end
391
387
 
@@ -405,18 +401,16 @@ module RubyLint
405
401
  end
406
402
 
407
403
  ##
408
- # @param [RubyLint::AST::Node] node
404
+ # Adds a new value stack for key/value pairs.
409
405
  #
410
- def on_pair(node)
406
+ def on_pair
411
407
  value_stack.add_stack
412
408
  end
413
409
 
414
410
  ##
415
- # Processes a key/value pair.
416
- #
417
- # @param [RubyLint::AST::Node] node
411
+ # @see #on_pair
418
412
  #
419
- def after_pair(node)
413
+ def after_pair
420
414
  key, value = value_stack.pop
421
415
 
422
416
  return unless key
@@ -431,9 +425,9 @@ module RubyLint
431
425
  end
432
426
 
433
427
  ##
434
- # @param [RubyLint::AST::Node] node
428
+ # Pushes the value of `self` onto the current stack.
435
429
  #
436
- def on_self(node)
430
+ def on_self
437
431
  push_value(current_scope.lookup(:keyword, 'self'))
438
432
  end
439
433
 
@@ -447,9 +441,9 @@ module RubyLint
447
441
  end
448
442
 
449
443
  ##
450
- # @param [RubyLint::AST::Node] node
444
+ # Pops the scope created by the module.
451
445
  #
452
- def after_module(node)
446
+ def after_module
453
447
  pop_scope
454
448
  end
455
449
 
@@ -474,9 +468,9 @@ module RubyLint
474
468
  end
475
469
 
476
470
  ##
477
- # @param [RubyLint::AST::Node] node
471
+ # Pops the scope created by the class.
478
472
  #
479
- def after_class(node)
473
+ def after_class
480
474
  pop_scope
481
475
  end
482
476
 
@@ -495,9 +489,9 @@ module RubyLint
495
489
  end
496
490
 
497
491
  ##
498
- # @param [RubyLint::AST::Node] node
492
+ # Pops the scope created by the block.
499
493
  #
500
- def after_block(node)
494
+ def after_block
501
495
  pop_scope
502
496
  end
503
497
 
@@ -521,9 +515,10 @@ module RubyLint
521
515
  end
522
516
 
523
517
  ##
524
- # @param [RubyLint::AST::Node] node
518
+ # Pops the scope created by the `sclass` block and resets the method
519
+ # definition/send type.
525
520
  #
526
- def after_sclass(node)
521
+ def after_sclass
527
522
  reset_method_type
528
523
  pop_scope
529
524
  end
@@ -569,9 +564,7 @@ module RubyLint
569
564
  ##
570
565
  # Exports various variables to the outer scope of the method definition.
571
566
  #
572
- # @param [RubyLint::AST::Node] node
573
- #
574
- def after_def(node)
567
+ def after_def
575
568
  previous = pop_scope
576
569
  current = current_scope
577
570
 
@@ -584,7 +577,7 @@ module RubyLint
584
577
 
585
578
  # Creates callbacks for various argument types such as :arg and :optarg.
586
579
  ARGUMENT_TYPES.each do |type|
587
- define_method("on_#{type}") do |node|
580
+ define_method("on_#{type}") do
588
581
  value_stack.add_stack
589
582
  end
590
583
 
@@ -686,21 +679,24 @@ Received: #{arguments.length}
686
679
  retval = context.call_method(name)
687
680
 
688
681
  retval ? push_value(retval) : push_unknown_value
682
+
683
+ # Track the method call
684
+ track_method_call(context, name, node)
689
685
  else
690
686
  push_unknown_value
691
687
  end
692
688
  end
693
689
 
694
690
  VISIBILITIES.each do |vis|
695
- define_method("on_send_#{vis}") do |node|
691
+ define_method("on_send_#{vis}") do
696
692
  @visibility = vis
697
693
  end
698
694
  end
699
695
 
700
696
  ##
701
- # @param [RubyLint::AST::Node] node
697
+ # Adds a new value stack for the values of an alias.
702
698
  #
703
- def on_alias(node)
699
+ def on_alias
704
700
  value_stack.add_stack
705
701
  end
706
702
 
@@ -867,8 +863,9 @@ Received: #{arguments.length}
867
863
  # @param [Symbol] type The type of variable.
868
864
  # @param [String] name The name of the variable
869
865
  # @param [RubyLint::Definition::RubyObject] value
866
+ # @param [RubyLint::AST::Node] node
870
867
  #
871
- def assign_variable(type, name, value)
868
+ def assign_variable(type, name, value, node)
872
869
  existing = current_scope.lookup(type, name)
873
870
  ref_amount = existing ? existing.reference_amount + 1 : 0
874
871
  variable = Definition::RubyObject.new(
@@ -876,7 +873,10 @@ Received: #{arguments.length}
876
873
  :name => name,
877
874
  :value => value,
878
875
  :instance_type => :instance,
879
- :reference_amount => ref_amount
876
+ :reference_amount => ref_amount,
877
+ :line => node.line,
878
+ :column => node.column,
879
+ :file => node.file
880
880
  )
881
881
 
882
882
  buffer_assignment_value(variable.value)
@@ -1117,5 +1117,37 @@ Received: #{arguments.length}
1117
1117
  # first one but there should be a nicer way to do this.
1118
1118
  definition.returns(definitions[0]) if definitions[0]
1119
1119
  end
1120
+
1121
+ ##
1122
+ # Tracks a method call.
1123
+ #
1124
+ # @param [RubyLint::Definition::RubyMethod] definition
1125
+ # @param [String] name
1126
+ # @param [RubyLint::AST::Node] node
1127
+ #
1128
+ def track_method_call(definition, name, node)
1129
+ method = definition.lookup(definition.method_call_type, name)
1130
+ current = current_scope
1131
+ location = {
1132
+ :line => node.line,
1133
+ :column => node.column,
1134
+ :file => node.file
1135
+ }
1136
+
1137
+ # Add the call to the current scope if we're dealing with a writable
1138
+ # method definition.
1139
+ if current.respond_to?(:calls) and !current.frozen?
1140
+ current.calls.push(
1141
+ MethodCallInfo.new(location.merge(:definition => method))
1142
+ )
1143
+ end
1144
+
1145
+ # Add the caller to the called method, this allows for inverse lookups.
1146
+ unless method.frozen?
1147
+ method.callers.push(
1148
+ MethodCallInfo.new(location.merge(:definition => definition))
1149
+ )
1150
+ end
1151
+ end
1120
1152
  end # VirtualMachine
1121
1153
  end # RubyLint