rubocop-ast 0.0.1 → 0.3.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -4
  3. data/lib/rubocop/ast.rb +10 -7
  4. data/lib/rubocop/ast/builder.rb +6 -1
  5. data/lib/rubocop/ast/ext/range.rb +28 -0
  6. data/lib/rubocop/ast/node.rb +41 -8
  7. data/lib/rubocop/ast/node/array_node.rb +2 -8
  8. data/lib/rubocop/ast/node/break_node.rb +1 -6
  9. data/lib/rubocop/ast/node/case_match_node.rb +3 -9
  10. data/lib/rubocop/ast/node/case_node.rb +13 -9
  11. data/lib/rubocop/ast/node/def_node.rb +5 -24
  12. data/lib/rubocop/ast/node/defined_node.rb +2 -0
  13. data/lib/rubocop/ast/node/float_node.rb +1 -0
  14. data/lib/rubocop/ast/node/forward_args_node.rb +15 -0
  15. data/lib/rubocop/ast/node/hash_node.rb +21 -8
  16. data/lib/rubocop/ast/node/if_node.rb +7 -14
  17. data/lib/rubocop/ast/node/index_node.rb +48 -0
  18. data/lib/rubocop/ast/node/indexasgn_node.rb +50 -0
  19. data/lib/rubocop/ast/node/int_node.rb +1 -0
  20. data/lib/rubocop/ast/node/lambda_node.rb +65 -0
  21. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +2 -8
  22. data/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb +99 -3
  23. data/lib/rubocop/ast/node/mixin/parameterized_node.rb +56 -0
  24. data/lib/rubocop/ast/node/next_node.rb +12 -0
  25. data/lib/rubocop/ast/node/pair_node.rb +2 -2
  26. data/lib/rubocop/ast/node/regexp_node.rb +61 -2
  27. data/lib/rubocop/ast/node/return_node.rb +1 -13
  28. data/lib/rubocop/ast/node/send_node.rb +9 -2
  29. data/lib/rubocop/ast/node/super_node.rb +2 -0
  30. data/lib/rubocop/ast/node/when_node.rb +3 -9
  31. data/lib/rubocop/ast/node/yield_node.rb +2 -0
  32. data/lib/rubocop/ast/node_pattern.rb +952 -0
  33. data/lib/rubocop/ast/processed_source.rb +246 -0
  34. data/lib/rubocop/ast/token.rb +116 -0
  35. data/lib/rubocop/ast/traversal.rb +5 -3
  36. data/lib/rubocop/ast/version.rb +1 -1
  37. metadata +16 -13
  38. data/lib/rubocop/ast/node/retry_node.rb +0 -17
  39. data/lib/rubocop/error.rb +0 -34
  40. data/lib/rubocop/node_pattern.rb +0 -881
  41. data/lib/rubocop/processed_source.rb +0 -211
  42. data/lib/rubocop/token.rb +0 -114
@@ -0,0 +1,246 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest/sha1'
4
+
5
+ # rubocop:disable Metrics/ClassLength
6
+ module RuboCop
7
+ module AST
8
+ # ProcessedSource contains objects which are generated by Parser
9
+ # and other information such as disabled lines for cops.
10
+ # It also provides a convenient way to access source lines.
11
+ class ProcessedSource
12
+ STRING_SOURCE_NAME = '(string)'
13
+
14
+ attr_reader :path, :buffer, :ast, :comments, :tokens, :diagnostics,
15
+ :parser_error, :raw_source, :ruby_version
16
+
17
+ def self.from_file(path, ruby_version)
18
+ file = File.read(path, mode: 'rb')
19
+ new(file, ruby_version, path)
20
+ end
21
+
22
+ def initialize(source, ruby_version, path = nil)
23
+ # Defaults source encoding to UTF-8, regardless of the encoding it has
24
+ # been read with, which could be non-utf8 depending on the default
25
+ # external encoding.
26
+ source.force_encoding(Encoding::UTF_8) unless source.encoding == Encoding::UTF_8
27
+
28
+ @raw_source = source
29
+ @path = path
30
+ @diagnostics = []
31
+ @ruby_version = ruby_version
32
+ @parser_error = nil
33
+
34
+ parse(source, ruby_version)
35
+ end
36
+
37
+ def ast_with_comments
38
+ return if !ast || !comments
39
+
40
+ @ast_with_comments ||= Parser::Source::Comment.associate(ast, comments)
41
+ end
42
+
43
+ # Returns the source lines, line break characters removed, excluding a
44
+ # possible __END__ and everything that comes after.
45
+ def lines
46
+ @lines ||= begin
47
+ all_lines = @buffer.source_lines
48
+ last_token_line = tokens.any? ? tokens.last.line : all_lines.size
49
+ result = []
50
+ all_lines.each_with_index do |line, ix|
51
+ break if ix >= last_token_line && line == '__END__'
52
+
53
+ result << line
54
+ end
55
+ result
56
+ end
57
+ end
58
+
59
+ def [](*args)
60
+ lines[*args]
61
+ end
62
+
63
+ def valid_syntax?
64
+ return false if @parser_error
65
+
66
+ @diagnostics.none? { |d| %i[error fatal].include?(d.level) }
67
+ end
68
+
69
+ # Raw source checksum for tracking infinite loops.
70
+ def checksum
71
+ Digest::SHA1.hexdigest(@raw_source)
72
+ end
73
+
74
+ # @deprecated Use `comments.each`
75
+ def each_comment(&block)
76
+ comments.each(&block)
77
+ end
78
+
79
+ # @deprecated Use `comment_at_line`, `each_comment_in_lines`, or `comments.find`
80
+ def find_comment(&block)
81
+ comments.find(&block)
82
+ end
83
+
84
+ # @deprecated Use `tokens.each`
85
+ def each_token(&block)
86
+ tokens.each(&block)
87
+ end
88
+
89
+ # @deprecated Use `tokens.find`
90
+ def find_token(&block)
91
+ tokens.find(&block)
92
+ end
93
+
94
+ def file_path
95
+ buffer.name
96
+ end
97
+
98
+ def blank?
99
+ ast.nil?
100
+ end
101
+
102
+ # @return [Comment, nil] the comment at that line, if any.
103
+ def comment_at_line(line)
104
+ comment_index[line]
105
+ end
106
+
107
+ # @return [Boolean] if the given line number has a comment.
108
+ def line_with_comment?(line)
109
+ comment_index.include?(line)
110
+ end
111
+
112
+ # Enumerates on the comments contained with the given `line_range`
113
+ def each_comment_in_lines(line_range)
114
+ return to_enum(:each_comment_in_lines, line_range) unless block_given?
115
+
116
+ line_range.each do |line|
117
+ if (comment = comment_index[line])
118
+ yield comment
119
+ end
120
+ end
121
+ end
122
+
123
+ # @return [Boolean] if any of the lines in the given `source_range` has a comment.
124
+ # Consider using `each_comment_in_lines` instead
125
+ def contains_comment?(source_range)
126
+ each_comment_in_lines(source_range.line..source_range.last_line).any?
127
+ end
128
+ # @deprecated use contains_comment?
129
+ alias commented? contains_comment?
130
+
131
+ # @deprecated Use `each_comment_in_lines`
132
+ # Should have been called `comments_before_or_at_line`. Doubtful it has of any valid use.
133
+ def comments_before_line(line)
134
+ each_comment_in_lines(0..line).to_a
135
+ end
136
+
137
+ def start_with?(string)
138
+ return false if self[0].nil?
139
+
140
+ self[0].start_with?(string)
141
+ end
142
+
143
+ def preceding_line(token)
144
+ lines[token.line - 2]
145
+ end
146
+
147
+ def current_line(token)
148
+ lines[token.line - 1]
149
+ end
150
+
151
+ def following_line(token)
152
+ lines[token.line]
153
+ end
154
+
155
+ def line_indentation(line_number)
156
+ lines[line_number - 1]
157
+ .match(/^(\s*)/)[1]
158
+ .to_s
159
+ .length
160
+ end
161
+
162
+ private
163
+
164
+ def comment_index
165
+ @comment_index ||= {}.tap do |hash|
166
+ comments.each { |c| hash[c.location.line] = c }
167
+ end
168
+ end
169
+
170
+ def parse(source, ruby_version)
171
+ buffer_name = @path || STRING_SOURCE_NAME
172
+ @buffer = Parser::Source::Buffer.new(buffer_name, 1)
173
+
174
+ begin
175
+ @buffer.source = source
176
+ rescue EncodingError => e
177
+ @parser_error = e
178
+ @ast = nil
179
+ @comments = []
180
+ @tokens = []
181
+ return
182
+ end
183
+
184
+ @ast, @comments, @tokens = tokenize(create_parser(ruby_version))
185
+ end
186
+
187
+ def tokenize(parser)
188
+ begin
189
+ ast, comments, tokens = parser.tokenize(@buffer)
190
+ ast ||= nil # force `false` to `nil`, see https://github.com/whitequark/parser/pull/722
191
+ rescue Parser::SyntaxError
192
+ # All errors are in diagnostics. No need to handle exception.
193
+ comments = []
194
+ tokens = []
195
+ end
196
+
197
+ ast&.complete!
198
+ tokens.map! { |t| Token.from_parser_token(t) }
199
+
200
+ [ast, comments, tokens]
201
+ end
202
+
203
+ # rubocop:disable Metrics/MethodLength
204
+ def parser_class(ruby_version)
205
+ case ruby_version
206
+ when 2.4
207
+ require 'parser/ruby24'
208
+ Parser::Ruby24
209
+ when 2.5
210
+ require 'parser/ruby25'
211
+ Parser::Ruby25
212
+ when 2.6
213
+ require 'parser/ruby26'
214
+ Parser::Ruby26
215
+ when 2.7
216
+ require 'parser/ruby27'
217
+ Parser::Ruby27
218
+ when 2.8
219
+ require 'parser/ruby28'
220
+ Parser::Ruby28
221
+ else
222
+ raise ArgumentError,
223
+ "RuboCop found unknown Ruby version: #{ruby_version.inspect}"
224
+ end
225
+ end
226
+ # rubocop:enable Metrics/MethodLength
227
+
228
+ def create_parser(ruby_version)
229
+ builder = RuboCop::AST::Builder.new
230
+
231
+ parser_class(ruby_version).new(builder).tap do |parser|
232
+ # On JRuby there's a risk that we hang in tokenize() if we
233
+ # don't set the all errors as fatal flag. The problem is caused by a bug
234
+ # in Racc that is discussed in issue #93 of the whitequark/parser
235
+ # project on GitHub.
236
+ parser.diagnostics.all_errors_are_fatal = (RUBY_ENGINE != 'ruby')
237
+ parser.diagnostics.ignore_warnings = false
238
+ parser.diagnostics.consumer = lambda do |diagnostic|
239
+ @diagnostics << diagnostic
240
+ end
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end
246
+ # rubocop:enable Metrics/ClassLength
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module AST
5
+ # A basic wrapper around Parser's tokens.
6
+ class Token
7
+ attr_reader :pos, :type, :text
8
+
9
+ def self.from_parser_token(parser_token)
10
+ type, details = parser_token
11
+ text, range = details
12
+ new(range, type, text)
13
+ end
14
+
15
+ def initialize(pos, type, text)
16
+ @pos = pos
17
+ @type = type
18
+ # Parser token "text" may be an Integer
19
+ @text = text.to_s
20
+ end
21
+
22
+ def line
23
+ @pos.line
24
+ end
25
+
26
+ def column
27
+ @pos.column
28
+ end
29
+
30
+ def begin_pos
31
+ @pos.begin_pos
32
+ end
33
+
34
+ def end_pos
35
+ @pos.end_pos
36
+ end
37
+
38
+ def to_s
39
+ "[[#{line}, #{column}], #{type}, #{text.inspect}]"
40
+ end
41
+
42
+ # Checks if there is whitespace after token
43
+ def space_after?
44
+ pos.source_buffer.source.match(/\G\s/, end_pos)
45
+ end
46
+
47
+ # Checks if there is whitespace before token
48
+ def space_before?
49
+ position = begin_pos.zero? ? begin_pos : begin_pos - 1
50
+ pos.source_buffer.source.match(/\G\s/, position)
51
+ end
52
+
53
+ ## Type Predicates
54
+
55
+ def comment?
56
+ type == :tCOMMENT
57
+ end
58
+
59
+ def semicolon?
60
+ type == :tSEMI
61
+ end
62
+
63
+ def left_array_bracket?
64
+ type == :tLBRACK
65
+ end
66
+
67
+ def left_ref_bracket?
68
+ type == :tLBRACK2
69
+ end
70
+
71
+ def left_bracket?
72
+ %i[tLBRACK tLBRACK2].include?(type)
73
+ end
74
+
75
+ def right_bracket?
76
+ type == :tRBRACK
77
+ end
78
+
79
+ def left_brace?
80
+ type == :tLBRACE
81
+ end
82
+
83
+ def left_curly_brace?
84
+ type == :tLCURLY
85
+ end
86
+
87
+ def right_curly_brace?
88
+ type == :tRCURLY
89
+ end
90
+
91
+ def left_parens?
92
+ %i[tLPAREN tLPAREN2].include?(type)
93
+ end
94
+
95
+ def right_parens?
96
+ type == :tRPAREN
97
+ end
98
+
99
+ def comma?
100
+ type == :tCOMMA
101
+ end
102
+
103
+ def rescue_modifier?
104
+ type == :kRESCUE_MOD
105
+ end
106
+
107
+ def end?
108
+ type == :kEND
109
+ end
110
+
111
+ def equal_sign?
112
+ %i[tEQL tOP_ASGN].include?(type)
113
+ end
114
+ end
115
+ end
116
+ end
@@ -19,9 +19,10 @@ module RuboCop
19
19
  rational str sym regopt self lvar
20
20
  ivar cvar gvar nth_ref back_ref cbase
21
21
  arg restarg blockarg shadowarg
22
- kwrestarg zsuper lambda redo retry
22
+ kwrestarg zsuper redo retry
23
23
  forward_args forwarded_args
24
- match_var match_nil_pattern empty_else].freeze
24
+ match_var match_nil_pattern empty_else
25
+ forward_arg lambda procarg0 __ENCODING__].freeze
25
26
  ONE_CHILD_NODE = %i[splat kwsplat block_pass not break next
26
27
  preexe postexe match_current_line defined?
27
28
  arg_expr pin match_rest if_guard unless_guard
@@ -33,7 +34,8 @@ module RuboCop
33
34
  match_with_lvasgn begin kwbegin return
34
35
  in_match match_alt
35
36
  match_as array_pattern array_pattern_with_tail
36
- hash_pattern const_pattern].freeze
37
+ hash_pattern const_pattern find_pattern
38
+ index indexasgn].freeze
37
39
  SECOND_CHILD_ONLY = %i[lvasgn ivasgn cvasgn gvasgn optarg kwarg
38
40
  kwoptarg].freeze
39
41
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module AST
5
5
  module Version
6
- STRING = '0.0.1'
6
+ STRING = '0.3.0'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-ast
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
8
8
  - Jonas Arvidsson
9
9
  - Yuji Nakayama
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2020-05-12 00:00:00.000000000 Z
13
+ date: 2020-08-02 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parser
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 2.7.0.1
21
+ version: 2.7.1.4
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
- version: 2.7.0.1
28
+ version: 2.7.1.4
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: bundler
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -59,6 +59,7 @@ files:
59
59
  - lib/rubocop-ast.rb
60
60
  - lib/rubocop/ast.rb
61
61
  - lib/rubocop/ast/builder.rb
62
+ - lib/rubocop/ast/ext/range.rb
62
63
  - lib/rubocop/ast/node.rb
63
64
  - lib/rubocop/ast/node/alias_node.rb
64
65
  - lib/rubocop/ast/node/and_node.rb
@@ -77,8 +78,11 @@ files:
77
78
  - lib/rubocop/ast/node/forward_args_node.rb
78
79
  - lib/rubocop/ast/node/hash_node.rb
79
80
  - lib/rubocop/ast/node/if_node.rb
81
+ - lib/rubocop/ast/node/index_node.rb
82
+ - lib/rubocop/ast/node/indexasgn_node.rb
80
83
  - lib/rubocop/ast/node/int_node.rb
81
84
  - lib/rubocop/ast/node/keyword_splat_node.rb
85
+ - lib/rubocop/ast/node/lambda_node.rb
82
86
  - lib/rubocop/ast/node/mixin/basic_literal_node.rb
83
87
  - lib/rubocop/ast/node/mixin/binary_operator_node.rb
84
88
  - lib/rubocop/ast/node/mixin/collection_node.rb
@@ -91,12 +95,12 @@ files:
91
95
  - lib/rubocop/ast/node/mixin/parameterized_node.rb
92
96
  - lib/rubocop/ast/node/mixin/predicate_operator_node.rb
93
97
  - lib/rubocop/ast/node/module_node.rb
98
+ - lib/rubocop/ast/node/next_node.rb
94
99
  - lib/rubocop/ast/node/or_node.rb
95
100
  - lib/rubocop/ast/node/pair_node.rb
96
101
  - lib/rubocop/ast/node/range_node.rb
97
102
  - lib/rubocop/ast/node/regexp_node.rb
98
103
  - lib/rubocop/ast/node/resbody_node.rb
99
- - lib/rubocop/ast/node/retry_node.rb
100
104
  - lib/rubocop/ast/node/return_node.rb
101
105
  - lib/rubocop/ast/node/self_class_node.rb
102
106
  - lib/rubocop/ast/node/send_node.rb
@@ -107,13 +111,12 @@ files:
107
111
  - lib/rubocop/ast/node/when_node.rb
108
112
  - lib/rubocop/ast/node/while_node.rb
109
113
  - lib/rubocop/ast/node/yield_node.rb
114
+ - lib/rubocop/ast/node_pattern.rb
115
+ - lib/rubocop/ast/processed_source.rb
110
116
  - lib/rubocop/ast/sexp.rb
117
+ - lib/rubocop/ast/token.rb
111
118
  - lib/rubocop/ast/traversal.rb
112
119
  - lib/rubocop/ast/version.rb
113
- - lib/rubocop/error.rb
114
- - lib/rubocop/node_pattern.rb
115
- - lib/rubocop/processed_source.rb
116
- - lib/rubocop/token.rb
117
120
  homepage: https://github.com/rubocop-hq/rubocop-ast
118
121
  licenses:
119
122
  - MIT
@@ -121,9 +124,9 @@ metadata:
121
124
  homepage_uri: https://www.rubocop.org/
122
125
  changelog_uri: https://github.com/rubocop-hq/rubocop-ast/blob/master/CHANGELOG.md
123
126
  source_code_uri: https://github.com/rubocop-hq/rubocop-ast/
124
- documentation_uri: https://docs.rubocop.org/
127
+ documentation_uri: https://docs.rubocop.org/rubocop-ast/
125
128
  bug_tracker_uri: https://github.com/rubocop-hq/rubocop-ast/issues
126
- post_install_message:
129
+ post_install_message:
127
130
  rdoc_options: []
128
131
  require_paths:
129
132
  - lib
@@ -139,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
142
  version: '0'
140
143
  requirements: []
141
144
  rubygems_version: 3.1.2
142
- signing_key:
145
+ signing_key:
143
146
  specification_version: 4
144
147
  summary: RuboCop tools to deal with Ruby code AST.
145
148
  test_files: []