ruby-lint 0.0.5 → 0.9.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 (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