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.
- checksums.yaml +4 -4
- data/README.md +23 -4
- data/lib/rubocop/ast.rb +10 -7
- data/lib/rubocop/ast/builder.rb +6 -1
- data/lib/rubocop/ast/ext/range.rb +28 -0
- data/lib/rubocop/ast/node.rb +41 -8
- data/lib/rubocop/ast/node/array_node.rb +2 -8
- data/lib/rubocop/ast/node/break_node.rb +1 -6
- data/lib/rubocop/ast/node/case_match_node.rb +3 -9
- data/lib/rubocop/ast/node/case_node.rb +13 -9
- data/lib/rubocop/ast/node/def_node.rb +5 -24
- data/lib/rubocop/ast/node/defined_node.rb +2 -0
- data/lib/rubocop/ast/node/float_node.rb +1 -0
- data/lib/rubocop/ast/node/forward_args_node.rb +15 -0
- data/lib/rubocop/ast/node/hash_node.rb +21 -8
- data/lib/rubocop/ast/node/if_node.rb +7 -14
- data/lib/rubocop/ast/node/index_node.rb +48 -0
- data/lib/rubocop/ast/node/indexasgn_node.rb +50 -0
- data/lib/rubocop/ast/node/int_node.rb +1 -0
- data/lib/rubocop/ast/node/lambda_node.rb +65 -0
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +2 -8
- data/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb +99 -3
- data/lib/rubocop/ast/node/mixin/parameterized_node.rb +56 -0
- data/lib/rubocop/ast/node/next_node.rb +12 -0
- data/lib/rubocop/ast/node/pair_node.rb +2 -2
- data/lib/rubocop/ast/node/regexp_node.rb +61 -2
- data/lib/rubocop/ast/node/return_node.rb +1 -13
- data/lib/rubocop/ast/node/send_node.rb +9 -2
- data/lib/rubocop/ast/node/super_node.rb +2 -0
- data/lib/rubocop/ast/node/when_node.rb +3 -9
- data/lib/rubocop/ast/node/yield_node.rb +2 -0
- data/lib/rubocop/ast/node_pattern.rb +952 -0
- data/lib/rubocop/ast/processed_source.rb +246 -0
- data/lib/rubocop/ast/token.rb +116 -0
- data/lib/rubocop/ast/traversal.rb +5 -3
- data/lib/rubocop/ast/version.rb +1 -1
- metadata +16 -13
- data/lib/rubocop/ast/node/retry_node.rb +0 -17
- data/lib/rubocop/error.rb +0 -34
- data/lib/rubocop/node_pattern.rb +0 -881
- data/lib/rubocop/processed_source.rb +0 -211
- data/lib/rubocop/token.rb +0 -114
@@ -8,6 +8,9 @@ module RuboCop
|
|
8
8
|
class HashNode < Node
|
9
9
|
# Returns an array of all the key value pairs in the `hash` literal.
|
10
10
|
#
|
11
|
+
# @note this may be different from children as `kwsplat` nodes are
|
12
|
+
# ignored.
|
13
|
+
#
|
11
14
|
# @return [Array<PairNode>] an array of `pair` nodes
|
12
15
|
def pairs
|
13
16
|
each_pair.to_a
|
@@ -23,6 +26,8 @@ module RuboCop
|
|
23
26
|
# Calls the given block for each `pair` node in the `hash` literal.
|
24
27
|
# If no block is given, an `Enumerator` is returned.
|
25
28
|
#
|
29
|
+
# @note `kwsplat` nodes are ignored.
|
30
|
+
#
|
26
31
|
# @return [self] if a block is given
|
27
32
|
# @return [Enumerator] if no block is given
|
28
33
|
def each_pair
|
@@ -37,6 +42,8 @@ module RuboCop
|
|
37
42
|
|
38
43
|
# Returns an array of all the keys in the `hash` literal.
|
39
44
|
#
|
45
|
+
# @note `kwsplat` nodes are ignored.
|
46
|
+
#
|
40
47
|
# @return [Array<Node>] an array of keys in the `hash` literal
|
41
48
|
def keys
|
42
49
|
each_key.to_a
|
@@ -45,20 +52,22 @@ module RuboCop
|
|
45
52
|
# Calls the given block for each `key` node in the `hash` literal.
|
46
53
|
# If no block is given, an `Enumerator` is returned.
|
47
54
|
#
|
55
|
+
# @note `kwsplat` nodes are ignored.
|
56
|
+
#
|
48
57
|
# @return [self] if a block is given
|
49
58
|
# @return [Enumerator] if no block is given
|
50
|
-
def each_key
|
59
|
+
def each_key(&block)
|
51
60
|
return pairs.map(&:key).to_enum unless block_given?
|
52
61
|
|
53
|
-
pairs.map(&:key).each
|
54
|
-
yield key
|
55
|
-
end
|
62
|
+
pairs.map(&:key).each(&block)
|
56
63
|
|
57
64
|
self
|
58
65
|
end
|
59
66
|
|
60
67
|
# Returns an array of all the values in the `hash` literal.
|
61
68
|
#
|
69
|
+
# @note `kwsplat` nodes are ignored.
|
70
|
+
#
|
62
71
|
# @return [Array<Node>] an array of values in the `hash` literal
|
63
72
|
def values
|
64
73
|
each_pair.map(&:value)
|
@@ -67,14 +76,14 @@ module RuboCop
|
|
67
76
|
# Calls the given block for each `value` node in the `hash` literal.
|
68
77
|
# If no block is given, an `Enumerator` is returned.
|
69
78
|
#
|
79
|
+
# @note `kwsplat` nodes are ignored.
|
80
|
+
#
|
70
81
|
# @return [self] if a block is given
|
71
82
|
# @return [Enumerator] if no block is given
|
72
|
-
def each_value
|
83
|
+
def each_value(&block)
|
73
84
|
return pairs.map(&:value).to_enum unless block_given?
|
74
85
|
|
75
|
-
pairs.map(&:value).each
|
76
|
-
yield value
|
77
|
-
end
|
86
|
+
pairs.map(&:value).each(&block)
|
78
87
|
|
79
88
|
self
|
80
89
|
end
|
@@ -85,6 +94,8 @@ module RuboCop
|
|
85
94
|
# @note A multiline `pair` is considered to be on the same line if it
|
86
95
|
# shares any of its lines with another `pair`
|
87
96
|
#
|
97
|
+
# @note `kwsplat` nodes are ignored.
|
98
|
+
#
|
88
99
|
# @return [Boolean] whether any `pair` nodes are on the same line
|
89
100
|
def pairs_on_same_line?
|
90
101
|
pairs.each_cons(2).any? { |first, second| first.same_line?(second) }
|
@@ -93,6 +104,8 @@ module RuboCop
|
|
93
104
|
# Checks whether this `hash` uses a mix of hash rocket and colon
|
94
105
|
# delimiters for its pairs.
|
95
106
|
#
|
107
|
+
# @note `kwsplat` nodes are ignored.
|
108
|
+
#
|
96
109
|
# @return [Boolean] whether the `hash` uses mixed delimiters
|
97
110
|
def mixed_delimiters?
|
98
111
|
pairs.map(&:delimiter).uniq.size > 1
|
@@ -64,10 +64,9 @@ module RuboCop
|
|
64
64
|
#
|
65
65
|
# @return [String] the inverse keyword of the `if` statement
|
66
66
|
def inverse_keyword
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
'if'
|
67
|
+
case keyword
|
68
|
+
when 'if' then 'unless'
|
69
|
+
when 'unless' then 'if'
|
71
70
|
else
|
72
71
|
''
|
73
72
|
end
|
@@ -148,7 +147,7 @@ module RuboCop
|
|
148
147
|
def branches
|
149
148
|
branches = [if_branch]
|
150
149
|
|
151
|
-
return branches unless
|
150
|
+
return branches unless else?
|
152
151
|
|
153
152
|
other_branches = if elsif_conditional?
|
154
153
|
else_branch.branches
|
@@ -158,17 +157,11 @@ module RuboCop
|
|
158
157
|
branches.concat(other_branches)
|
159
158
|
end
|
160
159
|
|
161
|
-
#
|
162
|
-
|
163
|
-
#
|
164
|
-
# @return [self] if a block is given
|
165
|
-
# @return [Enumerator] if no block is given
|
166
|
-
def each_branch
|
160
|
+
# @deprecated Use `branches.each`
|
161
|
+
def each_branch(&block)
|
167
162
|
return branches.to_enum(__method__) unless block_given?
|
168
163
|
|
169
|
-
branches.each
|
170
|
-
yield branch
|
171
|
-
end
|
164
|
+
branches.each(&block)
|
172
165
|
end
|
173
166
|
end
|
174
167
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
# Used for modern support only!
|
6
|
+
# Not as thoroughly tested as legacy equivalent
|
7
|
+
#
|
8
|
+
# $ ruby-parse -e "foo[:bar]"
|
9
|
+
# (index
|
10
|
+
# (send nil :foo)
|
11
|
+
# (sym :bar))
|
12
|
+
# $ ruby-parse --legacy -e "foo[:bar]"
|
13
|
+
# (send
|
14
|
+
# (send nil :foo) :[]
|
15
|
+
# (sym :bar))
|
16
|
+
#
|
17
|
+
# The main RuboCop runs in legacy mode; this node is only used
|
18
|
+
# if user `AST::Builder.modernize` or `AST::Builder.emit_index=true`
|
19
|
+
class IndexNode < Node
|
20
|
+
include ParameterizedNode::RestArguments
|
21
|
+
include MethodDispatchNode
|
22
|
+
|
23
|
+
# For similarity with legacy mode
|
24
|
+
def attribute_accessor?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
# For similarity with legacy mode
|
29
|
+
def assignment_method?
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
# For similarity with legacy mode
|
34
|
+
def method_name
|
35
|
+
:[]
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# An array containing the arguments of the dispatched method.
|
41
|
+
#
|
42
|
+
# @return [Array<Node>] the arguments of the dispatched method
|
43
|
+
def first_argument_index
|
44
|
+
1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
# Used for modern support only!
|
6
|
+
# Not as thoroughly tested as legacy equivalent
|
7
|
+
#
|
8
|
+
# $ ruby-parse -e "foo[:bar] = :baz"
|
9
|
+
# (indexasgn
|
10
|
+
# (send nil :foo)
|
11
|
+
# (sym :bar)
|
12
|
+
# (sym :baz))
|
13
|
+
# $ ruby-parse --legacy -e "foo[:bar] = :baz"
|
14
|
+
# (send
|
15
|
+
# (send nil :foo) :[]=
|
16
|
+
# (sym :bar)
|
17
|
+
# (sym :baz))
|
18
|
+
#
|
19
|
+
# The main RuboCop runs in legacy mode; this node is only used
|
20
|
+
# if user `AST::Builder.modernize` or `AST::Builder.emit_index=true`
|
21
|
+
class IndexasgnNode < Node
|
22
|
+
include ParameterizedNode::RestArguments
|
23
|
+
include MethodDispatchNode
|
24
|
+
|
25
|
+
# For similarity with legacy mode
|
26
|
+
def attribute_accessor?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
# For similarity with legacy mode
|
31
|
+
def assignment_method?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
# For similarity with legacy mode
|
36
|
+
def method_name
|
37
|
+
:[]=
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# An array containing the arguments of the dispatched method.
|
43
|
+
#
|
44
|
+
# @return [Array<Node>] the arguments of the dispatched method
|
45
|
+
def first_argument_index
|
46
|
+
1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
# Used for modern support only:
|
6
|
+
# Not as thoroughly tested as legacy equivalent
|
7
|
+
#
|
8
|
+
# $ ruby-parse -e "->(foo) { bar }"
|
9
|
+
# (block
|
10
|
+
# (lambda)
|
11
|
+
# (args
|
12
|
+
# (arg :foo))
|
13
|
+
# (send nil :bar))
|
14
|
+
# $ ruby-parse --legacy -e "->(foo) { bar }"
|
15
|
+
# (block
|
16
|
+
# (send nil :lambda)
|
17
|
+
# (args
|
18
|
+
# (arg :foo))
|
19
|
+
# (send nil :bar))
|
20
|
+
#
|
21
|
+
# The main RuboCop runs in legacy mode; this node is only used
|
22
|
+
# if user `AST::Builder.modernize` or `AST::Builder.emit_lambda=true`
|
23
|
+
class LambdaNode < Node
|
24
|
+
include ParameterizedNode::RestArguments
|
25
|
+
include MethodDispatchNode
|
26
|
+
|
27
|
+
# For similarity with legacy mode
|
28
|
+
def lambda?
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
# For similarity with legacy mode
|
33
|
+
def lambda_literal?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
# For similarity with legacy mode
|
38
|
+
def attribute_accessor?
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
# For similarity with legacy mode
|
43
|
+
def assignment_method?
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
# For similarity with legacy mode
|
48
|
+
def receiver
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
# For similarity with legacy mode
|
53
|
+
def method_name
|
54
|
+
:lambda
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# For similarity with legacy mode
|
60
|
+
def first_argument_index
|
61
|
+
2
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -3,7 +3,8 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module AST
|
5
5
|
# Common functionality for nodes that are a kind of method dispatch:
|
6
|
-
# `send`, `csend`, `super`, `zsuper`, `yield`, `defined
|
6
|
+
# `send`, `csend`, `super`, `zsuper`, `yield`, `defined?`,
|
7
|
+
# and (modern only): `index`, `indexasgn`, `lambda`
|
7
8
|
module MethodDispatchNode
|
8
9
|
extend NodePattern::Macros
|
9
10
|
include MethodIdentifierPredicates
|
@@ -25,13 +26,6 @@ module RuboCop
|
|
25
26
|
node_parts[1]
|
26
27
|
end
|
27
28
|
|
28
|
-
# An array containing the arguments of the dispatched method.
|
29
|
-
#
|
30
|
-
# @return [Array<Node>] the arguments of the dispatched method
|
31
|
-
def arguments
|
32
|
-
node_parts[2..-1]
|
33
|
-
end
|
34
|
-
|
35
29
|
# The `block` node associated with this method dispatch, if any.
|
36
30
|
#
|
37
31
|
# @return [BlockNode, nil] the `block` node associated with this method
|
@@ -6,15 +6,62 @@ module RuboCop
|
|
6
6
|
# `send`, `csend`, `def`, `defs`, `super`, `zsuper`
|
7
7
|
#
|
8
8
|
# @note this mixin expects `#method_name` and `#receiver` to be implemented
|
9
|
-
module MethodIdentifierPredicates
|
9
|
+
module MethodIdentifierPredicates # rubocop:disable Metrics/ModuleLength
|
10
10
|
ENUMERATOR_METHODS = %i[collect collect_concat detect downto each
|
11
11
|
find find_all find_index inject loop map!
|
12
12
|
map reduce reject reject! reverse_each select
|
13
|
-
select! times upto].freeze
|
13
|
+
select! times upto].to_set.freeze
|
14
|
+
|
15
|
+
ENUMERABLE_METHODS = (Enumerable.instance_methods + [:each]).to_set.freeze
|
14
16
|
|
15
17
|
# http://phrogz.net/programmingruby/language.html#table_18.4
|
16
18
|
OPERATOR_METHODS = %i[| ^ & <=> == === =~ > >= < <= << >> + - * /
|
17
|
-
% ** ~ +@ -@ !@ ~@ [] []= ! != !~ `].freeze
|
19
|
+
% ** ~ +@ -@ !@ ~@ [] []= ! != !~ `].to_set.freeze
|
20
|
+
|
21
|
+
NONMUTATING_BINARY_OPERATOR_METHODS = %i[* / % + - == === != < > <= >= <=>].to_set.freeze
|
22
|
+
NONMUTATING_UNARY_OPERATOR_METHODS = %i[+@ -@ ~ !].to_set.freeze
|
23
|
+
NONMUTATING_OPERATOR_METHODS = (NONMUTATING_BINARY_OPERATOR_METHODS +
|
24
|
+
NONMUTATING_UNARY_OPERATOR_METHODS).freeze
|
25
|
+
|
26
|
+
NONMUTATING_ARRAY_METHODS = %i[
|
27
|
+
all? any? assoc at bsearch bsearch_index collect
|
28
|
+
combination compact count cycle deconstruct difference
|
29
|
+
dig drop drop_while each each_index empty? eql?
|
30
|
+
fetch filter find_index first flatten hash
|
31
|
+
include? index inspect intersection join
|
32
|
+
last length map max min minmax none? one? pack
|
33
|
+
permutation product rassoc reject
|
34
|
+
repeated_combination repeated_permutation reverse
|
35
|
+
reverse_each rindex rotate sample select shuffle
|
36
|
+
size slice sort sum take take_while
|
37
|
+
to_a to_ary to_h to_s transpose union uniq
|
38
|
+
values_at zip |
|
39
|
+
].to_set.freeze
|
40
|
+
|
41
|
+
NONMUTATING_HASH_METHODS = %i[
|
42
|
+
any? assoc compact dig each each_key each_pair
|
43
|
+
each_value empty? eql? fetch fetch_values filter
|
44
|
+
flatten has_key? has_value? hash include? inspect
|
45
|
+
invert key key? keys? length member? merge rassoc
|
46
|
+
rehash reject select size slice to_a to_h to_hash
|
47
|
+
to_proc to_s transform_keys transform_values value?
|
48
|
+
values values_at
|
49
|
+
].to_set.freeze
|
50
|
+
|
51
|
+
NONMUTATING_STRING_METHODS = %i[
|
52
|
+
ascii_only? b bytes bytesize byteslice capitalize
|
53
|
+
casecmp casecmp? center chars chomp chop chr codepoints
|
54
|
+
count crypt delete delete_prefix delete_suffix
|
55
|
+
downcase dump each_byte each_char each_codepoint
|
56
|
+
each_grapheme_cluster each_line empty? encode encoding
|
57
|
+
end_with? eql? getbyte grapheme_clusters gsub hash
|
58
|
+
hex include index inspect intern length lines ljust lstrip
|
59
|
+
match match? next oct ord partition reverse rindex rjust
|
60
|
+
rpartition rstrip scan scrub size slice squeeze start_with?
|
61
|
+
strip sub succ sum swapcase to_a to_c to_f to_i to_r to_s
|
62
|
+
to_str to_sym tr tr_s unicode_normalize unicode_normalized?
|
63
|
+
unpack unpack1 upcase upto valid_encoding?
|
64
|
+
].to_set.freeze
|
18
65
|
|
19
66
|
# Checks whether the method name matches the argument.
|
20
67
|
#
|
@@ -31,6 +78,48 @@ module RuboCop
|
|
31
78
|
OPERATOR_METHODS.include?(method_name)
|
32
79
|
end
|
33
80
|
|
81
|
+
# Checks whether the method is a nonmutating binary operator method.
|
82
|
+
#
|
83
|
+
# @return [Boolean] whether the method is a nonmutating binary operator method
|
84
|
+
def nonmutating_binary_operator_method?
|
85
|
+
NONMUTATING_BINARY_OPERATOR_METHODS.include?(method_name)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Checks whether the method is a nonmutating unary operator method.
|
89
|
+
#
|
90
|
+
# @return [Boolean] whether the method is a nonmutating unary operator method
|
91
|
+
def nonmutating_unary_operator_method?
|
92
|
+
NONMUTATING_UNARY_OPERATOR_METHODS.include?(method_name)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Checks whether the method is a nonmutating operator method.
|
96
|
+
#
|
97
|
+
# @return [Boolean] whether the method is a nonmutating operator method
|
98
|
+
def nonmutating_operator_method?
|
99
|
+
NONMUTATING_OPERATOR_METHODS.include?(method_name)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Checks whether the method is a nonmutating Array method.
|
103
|
+
#
|
104
|
+
# @return [Boolean] whether the method is a nonmutating Array method
|
105
|
+
def nonmutating_array_method?
|
106
|
+
NONMUTATING_ARRAY_METHODS.include?(method_name)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Checks whether the method is a nonmutating Hash method.
|
110
|
+
#
|
111
|
+
# @return [Boolean] whether the method is a nonmutating Hash method
|
112
|
+
def nonmutating_hash_method?
|
113
|
+
NONMUTATING_HASH_METHODS.include?(method_name)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Checks whether the method is a nonmutating String method.
|
117
|
+
#
|
118
|
+
# @return [Boolean] whether the method is a nonmutating String method
|
119
|
+
def nonmutating_string_method?
|
120
|
+
NONMUTATING_STRING_METHODS.include?(method_name)
|
121
|
+
end
|
122
|
+
|
34
123
|
# Checks whether the method is a comparison method.
|
35
124
|
#
|
36
125
|
# @return [Boolean] whether the method is a comparison
|
@@ -53,6 +142,13 @@ module RuboCop
|
|
53
142
|
method_name.to_s.start_with?('each_')
|
54
143
|
end
|
55
144
|
|
145
|
+
# Checks whether the method is an Enumerable method.
|
146
|
+
#
|
147
|
+
# @return [Boolean] whether the method is an Enumerable method
|
148
|
+
def enumerable_method?
|
149
|
+
ENUMERABLE_METHODS.include?(method_name)
|
150
|
+
end
|
151
|
+
|
56
152
|
# Checks whether the method is a predicate method.
|
57
153
|
#
|
58
154
|
# @return [Boolean] whether the method is a predicate method
|