rubocop-ast 0.0.2 → 0.4.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 +21 -4
- data/lib/rubocop/ast.rb +12 -7
- data/lib/rubocop/ast/builder.rb +8 -1
- data/lib/rubocop/ast/ext/range.rb +28 -0
- data/lib/rubocop/ast/ext/set.rb +12 -0
- data/lib/rubocop/ast/node.rb +81 -10
- data/lib/rubocop/ast/node/array_node.rb +2 -8
- data/lib/rubocop/ast/node/block_node.rb +1 -1
- 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/const_node.rb +63 -0
- 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 +56 -0
- data/lib/rubocop/ast/node/resbody_node.rb +21 -0
- data/lib/rubocop/ast/node/rescue_node.rb +49 -0
- 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 +285 -0
- data/lib/rubocop/ast/token.rb +116 -0
- data/lib/rubocop/ast/traversal.rb +6 -4
- data/lib/rubocop/ast/version.rb +1 -1
- metadata +19 -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
@@ -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
|
@@ -2,8 +2,11 @@
|
|
2
2
|
|
3
3
|
module RuboCop
|
4
4
|
module AST
|
5
|
+
# Requires implementing `arguments`.
|
6
|
+
#
|
5
7
|
# Common functionality for nodes that are parameterized:
|
6
8
|
# `send`, `super`, `zsuper`, `def`, `defs`
|
9
|
+
# and (modern only): `index`, `indexasgn`, `lambda`
|
7
10
|
module ParameterizedNode
|
8
11
|
# Checks whether this node's arguments are wrapped in parentheses.
|
9
12
|
#
|
@@ -56,6 +59,59 @@ module RuboCop
|
|
56
59
|
arguments? &&
|
57
60
|
(last_argument.block_pass_type? || last_argument.blockarg_type?)
|
58
61
|
end
|
62
|
+
|
63
|
+
# A specialized `ParameterizedNode` for node that have a single child
|
64
|
+
# containing either `nil`, an argument, or a `begin` node with all the
|
65
|
+
# arguments
|
66
|
+
module WrappedArguments
|
67
|
+
include ParameterizedNode
|
68
|
+
# @return [Array] The arguments of the node.
|
69
|
+
def arguments
|
70
|
+
first = children.first
|
71
|
+
if first&.begin_type?
|
72
|
+
first.children
|
73
|
+
else
|
74
|
+
children
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# A specialized `ParameterizedNode`.
|
80
|
+
# Requires implementing `first_argument_index`
|
81
|
+
# Implements `arguments` as `children[first_argument_index..-1]`
|
82
|
+
# and optimizes other calls
|
83
|
+
module RestArguments
|
84
|
+
include ParameterizedNode
|
85
|
+
# @return [Array<Node>] arguments, if any
|
86
|
+
def arguments
|
87
|
+
children[first_argument_index..-1].freeze
|
88
|
+
end
|
89
|
+
|
90
|
+
# A shorthand for getting the first argument of the node.
|
91
|
+
# Equivalent to `arguments.first`.
|
92
|
+
#
|
93
|
+
# @return [Node, nil] the first argument of the node,
|
94
|
+
# or `nil` if there are no arguments
|
95
|
+
def first_argument
|
96
|
+
children[first_argument_index]
|
97
|
+
end
|
98
|
+
|
99
|
+
# A shorthand for getting the last argument of the node.
|
100
|
+
# Equivalent to `arguments.last`.
|
101
|
+
#
|
102
|
+
# @return [Node, nil] the last argument of the node,
|
103
|
+
# or `nil` if there are no arguments
|
104
|
+
def last_argument
|
105
|
+
children[-1] if arguments?
|
106
|
+
end
|
107
|
+
|
108
|
+
# Checks whether this node has any arguments.
|
109
|
+
#
|
110
|
+
# @return [Boolean] whether this node has any arguments
|
111
|
+
def arguments?
|
112
|
+
children.size > first_argument_index
|
113
|
+
end
|
114
|
+
end
|
59
115
|
end
|
60
116
|
end
|
61
117
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
# A node extension for `next` nodes. This will be used in place of a
|
6
|
+
# plain node when the builder constructs the AST, making its methods
|
7
|
+
# available to all `next` nodes within RuboCop.
|
8
|
+
class NextNode < Node
|
9
|
+
include ParameterizedNode::WrappedArguments
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
32
32
|
#
|
33
33
|
# @param [Boolean] with_spacing whether to include spacing
|
34
34
|
# @return [String] the delimiter of the `pair`
|
35
|
-
def delimiter(with_spacing
|
35
|
+
def delimiter(*deprecated, with_spacing: deprecated.first)
|
36
36
|
if with_spacing
|
37
37
|
hash_rocket? ? SPACED_HASH_ROCKET : SPACED_COLON
|
38
38
|
else
|
@@ -44,7 +44,7 @@ module RuboCop
|
|
44
44
|
#
|
45
45
|
# @param [Boolean] with_spacing whether to include spacing
|
46
46
|
# @return [String] the inverse delimiter of the `pair`
|
47
|
-
def inverse_delimiter(with_spacing
|
47
|
+
def inverse_delimiter(*deprecated, with_spacing: deprecated.first)
|
48
48
|
if with_spacing
|
49
49
|
hash_rocket? ? SPACED_COLON : SPACED_HASH_ROCKET
|
50
50
|
else
|
@@ -31,6 +31,62 @@ module RuboCop
|
|
31
31
|
def content
|
32
32
|
children.select(&:str_type?).map(&:str_content).join
|
33
33
|
end
|
34
|
+
|
35
|
+
# @return [Bool] if the regexp is a /.../ literal
|
36
|
+
def slash_literal?
|
37
|
+
loc.begin.source == '/'
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Bool] if the regexp is a %r{...} literal (using any delimiters)
|
41
|
+
def percent_r_literal?
|
42
|
+
!slash_literal?
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [String] the regexp delimiters (without %r)
|
46
|
+
def delimiters
|
47
|
+
[loc.begin.source[-1], loc.end.source[0]]
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Bool] if char is one of the delimiters
|
51
|
+
def delimiter?(char)
|
52
|
+
delimiters.include?(char)
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [Bool] if regexp contains interpolation
|
56
|
+
def interpolation?
|
57
|
+
children.any?(&:begin_type?)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Bool] if regexp uses the multiline regopt
|
61
|
+
def multiline_mode?
|
62
|
+
regopt_include?(:m)
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Bool] if regexp uses the extended regopt
|
66
|
+
def extended?
|
67
|
+
regopt_include?(:x)
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Bool] if regexp uses the ignore-case regopt
|
71
|
+
def ignore_case?
|
72
|
+
regopt_include?(:i)
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [Bool] if regexp uses the single-interpolation regopt
|
76
|
+
def single_interpolation?
|
77
|
+
regopt_include?(:o)
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [Bool] if regexp uses the no-encoding regopt
|
81
|
+
def no_encoding?
|
82
|
+
regopt_include?(:n)
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def regopt_include?(option)
|
88
|
+
regopt.children.include?(option)
|
89
|
+
end
|
34
90
|
end
|
35
91
|
end
|
36
92
|
end
|
@@ -13,12 +13,33 @@ module RuboCop
|
|
13
13
|
node_parts[2]
|
14
14
|
end
|
15
15
|
|
16
|
+
# Returns an array of all the exceptions in the `rescue` clause.
|
17
|
+
#
|
18
|
+
# @return [Array<Node>] an array of exception nodes
|
19
|
+
def exceptions
|
20
|
+
exceptions_node = node_parts[0]
|
21
|
+
if exceptions_node.nil?
|
22
|
+
[]
|
23
|
+
elsif exceptions_node.array_type?
|
24
|
+
exceptions_node.values
|
25
|
+
else
|
26
|
+
[exceptions_node]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
16
30
|
# Returns the exception variable of the `rescue` clause.
|
17
31
|
#
|
18
32
|
# @return [Node, nil] The exception variable of the `resbody`.
|
19
33
|
def exception_variable
|
20
34
|
node_parts[1]
|
21
35
|
end
|
36
|
+
|
37
|
+
# Returns the index of the `resbody` branch within the exception handling statement.
|
38
|
+
#
|
39
|
+
# @return [Integer] the index of the `resbody` branch
|
40
|
+
def branch_index
|
41
|
+
parent.resbody_branches.index(self)
|
42
|
+
end
|
22
43
|
end
|
23
44
|
end
|
24
45
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
# A node extension for `rescue` nodes. This will be used in place of a
|
6
|
+
# plain node when the builder constructs the AST, making its methods
|
7
|
+
# available to all `rescue` nodes within RuboCop.
|
8
|
+
class RescueNode < Node
|
9
|
+
# Returns the body of the rescue node.
|
10
|
+
#
|
11
|
+
# @return [Node, nil] The body of the rescue node.
|
12
|
+
def body
|
13
|
+
node_parts[0]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns an array of all the rescue branches in the exception handling statement.
|
17
|
+
#
|
18
|
+
# @return [Array<ResbodyNode>] an array of `resbody` nodes
|
19
|
+
def resbody_branches
|
20
|
+
node_parts[1...-1]
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns an array of all the rescue branches in the exception handling statement.
|
24
|
+
#
|
25
|
+
# @return [Array<Node, nil>] an array of the bodies of the rescue branches
|
26
|
+
# and the else (if any). Note that these bodies could be nil.
|
27
|
+
def branches
|
28
|
+
bodies = resbody_branches.map(&:body)
|
29
|
+
bodies.push(else_branch) if else?
|
30
|
+
bodies
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the else branch of the exception handling statement, if any.
|
34
|
+
#
|
35
|
+
# @return [Node] the else branch node of the exception handling statement
|
36
|
+
# @return [nil] if the exception handling statement does not have an else branch.
|
37
|
+
def else_branch
|
38
|
+
node_parts[-1]
|
39
|
+
end
|
40
|
+
|
41
|
+
# Checks whether this exception handling statement has an `else` branch.
|
42
|
+
#
|
43
|
+
# @return [Boolean] whether the exception handling statement has an `else` branch
|
44
|
+
def else?
|
45
|
+
loc.else
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -6,19 +6,7 @@ module RuboCop
|
|
6
6
|
# plain node when the builder constructs the AST, making its methods
|
7
7
|
# available to all `return` nodes within RuboCop.
|
8
8
|
class ReturnNode < Node
|
9
|
-
include
|
10
|
-
include ParameterizedNode
|
11
|
-
|
12
|
-
# Returns the arguments of the `return`.
|
13
|
-
#
|
14
|
-
# @return [Array] The arguments of the `return`.
|
15
|
-
def arguments
|
16
|
-
if node_parts.one? && node_parts.first.begin_type?
|
17
|
-
node_parts.first.children
|
18
|
-
else
|
19
|
-
node_parts
|
20
|
-
end
|
21
|
-
end
|
9
|
+
include ParameterizedNode::WrappedArguments
|
22
10
|
end
|
23
11
|
end
|
24
12
|
end
|
@@ -6,12 +6,19 @@ module RuboCop
|
|
6
6
|
# node when the builder constructs the AST, making its methods available
|
7
7
|
# to all `send` nodes within RuboCop.
|
8
8
|
class SendNode < Node
|
9
|
-
include ParameterizedNode
|
9
|
+
include ParameterizedNode::RestArguments
|
10
10
|
include MethodDispatchNode
|
11
11
|
|
12
12
|
def_node_matcher :attribute_accessor?, <<~PATTERN
|
13
|
-
(send nil? ${:attr_reader :attr_writer :attr_accessor :attr} $...)
|
13
|
+
[(send nil? ${:attr_reader :attr_writer :attr_accessor :attr} $...)
|
14
|
+
(_ _ _ _ ...)]
|
14
15
|
PATTERN
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def first_argument_index
|
20
|
+
2
|
21
|
+
end
|
15
22
|
end
|
16
23
|
end
|
17
24
|
end
|