rubocop-ast 1.29.0 → 1.46.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 +1 -1
- data/lib/rubocop/ast/builder.rb +33 -15
- data/lib/rubocop/ast/builder_prism.rb +11 -0
- data/lib/rubocop/ast/node/args_node.rb +1 -1
- data/lib/rubocop/ast/node/array_node.rb +9 -5
- data/lib/rubocop/ast/node/asgn_node.rb +2 -0
- data/lib/rubocop/ast/node/block_node.rb +27 -8
- data/lib/rubocop/ast/node/casgn_node.rb +4 -12
- data/lib/rubocop/ast/node/complex_node.rb +13 -0
- data/lib/rubocop/ast/node/const_node.rb +1 -52
- data/lib/rubocop/ast/node/def_node.rb +1 -1
- data/lib/rubocop/ast/node/ensure_node.rb +36 -0
- data/lib/rubocop/ast/node/for_node.rb +1 -1
- data/lib/rubocop/ast/node/hash_node.rb +1 -1
- data/lib/rubocop/ast/node/if_node.rb +11 -4
- data/lib/rubocop/ast/node/in_pattern_node.rb +1 -1
- data/lib/rubocop/ast/node/keyword_begin_node.rb +44 -0
- data/lib/rubocop/ast/node/masgn_node.rb +63 -0
- data/lib/rubocop/ast/node/mixin/basic_literal_node.rb +1 -1
- data/lib/rubocop/ast/node/mixin/collection_node.rb +1 -1
- data/lib/rubocop/ast/node/mixin/constant_node.rb +62 -0
- data/lib/rubocop/ast/node/mixin/descendence.rb +3 -3
- data/lib/rubocop/ast/node/mixin/hash_element_node.rb +2 -0
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +12 -13
- data/lib/rubocop/ast/node/mixin/numeric_node.rb +2 -2
- data/lib/rubocop/ast/node/mixin/parameterized_node.rb +2 -2
- data/lib/rubocop/ast/node/mixin/predicate_operator_node.rb +7 -2
- data/lib/rubocop/ast/node/mlhs_node.rb +29 -0
- data/lib/rubocop/ast/node/op_asgn_node.rb +3 -1
- data/lib/rubocop/ast/node/rational_node.rb +13 -0
- data/lib/rubocop/ast/node/str_node.rb +37 -1
- data/lib/rubocop/ast/node/until_node.rb +1 -1
- data/lib/rubocop/ast/node/var_node.rb +15 -0
- data/lib/rubocop/ast/node/when_node.rb +1 -1
- data/lib/rubocop/ast/node/while_node.rb +1 -1
- data/lib/rubocop/ast/node.rb +124 -45
- data/lib/rubocop/ast/node_pattern/compiler/binding.rb +3 -3
- data/lib/rubocop/ast/node_pattern/compiler/debug.rb +3 -8
- data/lib/rubocop/ast/node_pattern/compiler/sequence_subcompiler.rb +3 -4
- data/lib/rubocop/ast/node_pattern/compiler.rb +1 -1
- data/lib/rubocop/ast/node_pattern/lexer.rex.rb +1 -2
- data/lib/rubocop/ast/node_pattern/node.rb +11 -6
- data/lib/rubocop/ast/node_pattern/parser.racc.rb +4 -2
- data/lib/rubocop/ast/node_pattern/parser.rb +1 -1
- data/lib/rubocop/ast/node_pattern.rb +1 -1
- data/lib/rubocop/ast/processed_source.rb +158 -60
- data/lib/rubocop/ast/token.rb +2 -1
- data/lib/rubocop/ast/traversal.rb +35 -25
- data/lib/rubocop/ast/utilities/simple_forwardable.rb +27 -0
- data/lib/rubocop/ast/version.rb +1 -1
- data/lib/rubocop/ast.rb +10 -1
- metadata +29 -7
- data/lib/rubocop/ast/ext/range_min_max.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b94b9545a7aceaf8b52e8e6b8713df63fe1113c4040fd5f92563438c0307d21
|
4
|
+
data.tar.gz: 6db23c373003f60f0faf0f48ff1a4cb7d086f36820e7f5e732a147eea0d22f98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a0fb03bcb60b82177efefcf2146d1512c50f9791f094769d64ae7c87899e9984ce41eebdb1fc8f6d8c40b287e42621f6d4bd9fdde23fe9884ebc0dd2202b5ae
|
7
|
+
data.tar.gz: 8fd5e39ac28109336a207edfedf5fc6b782ede8da4594cfdd1faf41e8e9df4d59a17716e1ea55121c575514d17fce9e0b3071ab98ecc54b007f66af8f002f560
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# RuboCop AST
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/rubocop-ast)
|
4
|
-
[](https://github.com/rubocop/rubocop-ast/actions/workflows/rubocop.yml)
|
5
5
|
[](https://codeclimate.com/github/rubocop/rubocop-ast/test_coverage)
|
6
6
|
[](https://codeclimate.com/github/rubocop/rubocop-ast/maintainability)
|
7
7
|
|
data/lib/rubocop/ast/builder.rb
CHANGED
@@ -2,20 +2,13 @@
|
|
2
2
|
|
3
3
|
module RuboCop
|
4
4
|
module AST
|
5
|
-
#
|
6
|
-
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# builder = RuboCop::AST::Builder.new
|
13
|
-
# require 'parser/ruby25'
|
14
|
-
# parser = Parser::Ruby25.new(builder)
|
15
|
-
# root_node = parser.parse(buffer)
|
16
|
-
class Builder < Parser::Builders::Default
|
17
|
-
self.emit_forward_arg = true if respond_to?(:emit_forward_arg=)
|
18
|
-
self.emit_match_pattern = true if respond_to?(:emit_match_pattern=)
|
5
|
+
# Common functionality between the parser and prism builder
|
6
|
+
# @api private
|
7
|
+
module BuilderExtensions
|
8
|
+
def self.included(base)
|
9
|
+
base.emit_forward_arg = true
|
10
|
+
base.emit_match_pattern = true
|
11
|
+
end
|
19
12
|
|
20
13
|
# @api private
|
21
14
|
NODE_MAP = {
|
@@ -39,11 +32,13 @@ module RuboCop
|
|
39
32
|
gvasgn: AsgnNode,
|
40
33
|
block: BlockNode,
|
41
34
|
numblock: BlockNode,
|
35
|
+
itblock: BlockNode,
|
42
36
|
break: BreakNode,
|
43
37
|
case_match: CaseMatchNode,
|
44
38
|
casgn: CasgnNode,
|
45
39
|
case: CaseNode,
|
46
40
|
class: ClassNode,
|
41
|
+
complex: ComplexNode,
|
47
42
|
const: ConstNode,
|
48
43
|
def: DefNode,
|
49
44
|
defined?: DefinedNode,
|
@@ -63,8 +58,11 @@ module RuboCop
|
|
63
58
|
irange: RangeNode,
|
64
59
|
erange: RangeNode,
|
65
60
|
kwargs: HashNode,
|
61
|
+
kwbegin: KeywordBeginNode,
|
66
62
|
kwsplat: KeywordSplatNode,
|
67
63
|
lambda: LambdaNode,
|
64
|
+
masgn: MasgnNode,
|
65
|
+
mlhs: MlhsNode,
|
68
66
|
module: ModuleNode,
|
69
67
|
next: NextNode,
|
70
68
|
op_asgn: OpAsgnNode,
|
@@ -72,6 +70,7 @@ module RuboCop
|
|
72
70
|
or: OrNode,
|
73
71
|
pair: PairNode,
|
74
72
|
procarg0: Procarg0Node,
|
73
|
+
rational: RationalNode,
|
75
74
|
regexp: RegexpNode,
|
76
75
|
rescue: RescueNode,
|
77
76
|
resbody: ResbodyNode,
|
@@ -86,6 +85,10 @@ module RuboCop
|
|
86
85
|
sym: SymbolNode,
|
87
86
|
until: UntilNode,
|
88
87
|
until_post: UntilNode,
|
88
|
+
lvar: VarNode,
|
89
|
+
ivar: VarNode,
|
90
|
+
cvar: VarNode,
|
91
|
+
gvar: VarNode,
|
89
92
|
when: WhenNode,
|
90
93
|
while: WhileNode,
|
91
94
|
while_post: WhileNode,
|
@@ -99,7 +102,7 @@ module RuboCop
|
|
99
102
|
node_klass(type).new(type, children, location: source_map)
|
100
103
|
end
|
101
104
|
|
102
|
-
#
|
105
|
+
# Overwrite the base method to allow strings with invalid encoding
|
103
106
|
# More details here https://github.com/whitequark/parser/issues/283
|
104
107
|
def string_value(token)
|
105
108
|
value(token)
|
@@ -111,5 +114,20 @@ module RuboCop
|
|
111
114
|
NODE_MAP[type] || Node
|
112
115
|
end
|
113
116
|
end
|
117
|
+
|
118
|
+
# `RuboCop::AST::Builder` is an AST builder that is utilized to let `Parser`
|
119
|
+
# generate ASTs with {RuboCop::AST::Node}.
|
120
|
+
#
|
121
|
+
# @example
|
122
|
+
# buffer = Parser::Source::Buffer.new('(string)')
|
123
|
+
# buffer.source = 'puts :foo'
|
124
|
+
#
|
125
|
+
# builder = RuboCop::AST::Builder.new
|
126
|
+
# require 'parser/ruby25'
|
127
|
+
# parser = Parser::Ruby25.new(builder)
|
128
|
+
# root_node = parser.parse(buffer)
|
129
|
+
class Builder < Parser::Builders::Default
|
130
|
+
include BuilderExtensions
|
131
|
+
end
|
114
132
|
end
|
115
133
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
# A parser builder, based on the one provided by prism,
|
6
|
+
# which is capable of emitting AST for more recent Rubies.
|
7
|
+
class BuilderPrism < Prism::Translation::Parser::Builder
|
8
|
+
include BuilderExtensions
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -7,8 +7,8 @@ module RuboCop
|
|
7
7
|
# to all `array` nodes within RuboCop.
|
8
8
|
class ArrayNode < Node
|
9
9
|
PERCENT_LITERAL_TYPES = {
|
10
|
-
string:
|
11
|
-
symbol:
|
10
|
+
string: /\A%[wW]/,
|
11
|
+
symbol: /\A%[iI]/
|
12
12
|
}.freeze
|
13
13
|
private_constant :PERCENT_LITERAL_TYPES
|
14
14
|
|
@@ -17,7 +17,11 @@ module RuboCop
|
|
17
17
|
# @return [Array<Node>] an array of value nodes
|
18
18
|
alias values children
|
19
19
|
|
20
|
-
#
|
20
|
+
# Calls the given block for each `value` node in the `array` literal.
|
21
|
+
# If no block is given, an `Enumerator` is returned.
|
22
|
+
#
|
23
|
+
# @return [self] if a block is given
|
24
|
+
# @return [Enumerator] if no block is given
|
21
25
|
def each_value(&block)
|
22
26
|
return to_enum(__method__) unless block
|
23
27
|
|
@@ -30,7 +34,7 @@ module RuboCop
|
|
30
34
|
#
|
31
35
|
# @return [Boolean] whether the array is enclosed in square brackets
|
32
36
|
def square_brackets?
|
33
|
-
|
37
|
+
loc_is?(:begin, '[')
|
34
38
|
end
|
35
39
|
|
36
40
|
# Checks whether the `array` literal is delimited by percent brackets.
|
@@ -46,7 +50,7 @@ module RuboCop
|
|
46
50
|
# @return [Boolean] whether the array is enclosed in percent brackets
|
47
51
|
def percent_literal?(type = nil)
|
48
52
|
if type
|
49
|
-
loc.begin
|
53
|
+
loc.begin&.source&.match?(PERCENT_LITERAL_TYPES.fetch(type))
|
50
54
|
else
|
51
55
|
loc.begin&.source&.start_with?('%')
|
52
56
|
end
|
@@ -12,6 +12,7 @@ module RuboCop
|
|
12
12
|
def name
|
13
13
|
node_parts[0]
|
14
14
|
end
|
15
|
+
alias lhs name
|
15
16
|
|
16
17
|
# The expression being assigned to the variable.
|
17
18
|
#
|
@@ -19,6 +20,7 @@ module RuboCop
|
|
19
20
|
def expression
|
20
21
|
node_parts[1]
|
21
22
|
end
|
23
|
+
alias rhs expression
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
@@ -11,6 +11,8 @@ module RuboCop
|
|
11
11
|
class BlockNode < Node
|
12
12
|
include MethodIdentifierPredicates
|
13
13
|
|
14
|
+
IT_BLOCK_ARGUMENT = [ArgNode.new(:arg, [:it])].freeze
|
15
|
+
private_constant :IT_BLOCK_ARGUMENT
|
14
16
|
VOID_CONTEXT_METHODS = %i[each tap].freeze
|
15
17
|
private_constant :VOID_CONTEXT_METHODS
|
16
18
|
|
@@ -21,6 +23,24 @@ module RuboCop
|
|
21
23
|
node_parts[0]
|
22
24
|
end
|
23
25
|
|
26
|
+
# A shorthand for getting the first argument of this block.
|
27
|
+
# Equivalent to `arguments.first`.
|
28
|
+
#
|
29
|
+
# @return [Node, nil] the first argument of this block,
|
30
|
+
# or `nil` if there are no arguments
|
31
|
+
def first_argument
|
32
|
+
arguments[0]
|
33
|
+
end
|
34
|
+
|
35
|
+
# A shorthand for getting the last argument of this block.
|
36
|
+
# Equivalent to `arguments.last`.
|
37
|
+
#
|
38
|
+
# @return [Node, nil] the last argument of this block,
|
39
|
+
# or `nil` if there are no arguments
|
40
|
+
def last_argument
|
41
|
+
arguments[-1]
|
42
|
+
end
|
43
|
+
|
24
44
|
# The arguments of this block.
|
25
45
|
# Note that if the block has destructured arguments, `arguments` will
|
26
46
|
# return a `mlhs` node, whereas `argument_list` will return only
|
@@ -28,10 +48,10 @@ module RuboCop
|
|
28
48
|
#
|
29
49
|
# @return [Array<Node>]
|
30
50
|
def arguments
|
31
|
-
if
|
32
|
-
[].freeze # Numbered parameters have no block arguments.
|
33
|
-
else
|
51
|
+
if block_type?
|
34
52
|
node_parts[1]
|
53
|
+
else
|
54
|
+
[].freeze # Numblocks and itblocks have no explicit block arguments.
|
35
55
|
end
|
36
56
|
end
|
37
57
|
|
@@ -42,6 +62,8 @@ module RuboCop
|
|
42
62
|
def argument_list
|
43
63
|
if numblock_type?
|
44
64
|
numbered_arguments
|
65
|
+
elsif itblock_type?
|
66
|
+
IT_BLOCK_ARGUMENT
|
45
67
|
else
|
46
68
|
arguments.argument_list
|
47
69
|
end
|
@@ -72,14 +94,14 @@ module RuboCop
|
|
72
94
|
#
|
73
95
|
# @return [Boolean] whether the `block` literal is enclosed in braces
|
74
96
|
def braces?
|
75
|
-
loc.end
|
97
|
+
loc.end.is?('}')
|
76
98
|
end
|
77
99
|
|
78
100
|
# Checks whether the `block` literal is delimited by `do`-`end` keywords.
|
79
101
|
#
|
80
102
|
# @return [Boolean] whether the `block` literal is enclosed in `do`-`end`
|
81
103
|
def keywords?
|
82
|
-
loc.end
|
104
|
+
loc.end.is?('end')
|
83
105
|
end
|
84
106
|
|
85
107
|
# The delimiters for this `block` literal.
|
@@ -135,10 +157,7 @@ module RuboCop
|
|
135
157
|
|
136
158
|
private
|
137
159
|
|
138
|
-
# Numbered arguments of this `numblock`.
|
139
160
|
def numbered_arguments
|
140
|
-
return [].freeze unless numblock_type?
|
141
|
-
|
142
161
|
max_param = children[1]
|
143
162
|
1.upto(max_param).map do |i|
|
144
163
|
ArgNode.new(:arg, [:"_#{i}"])
|
@@ -6,19 +6,10 @@ module RuboCop
|
|
6
6
|
# This will be used in place of a plain node when the builder constructs
|
7
7
|
# the AST, making its methods available to all assignment nodes within RuboCop.
|
8
8
|
class CasgnNode < Node
|
9
|
-
|
10
|
-
#
|
11
|
-
# @return [Node, nil] the node associated with the scope (e.g. cbase, const, ...)
|
12
|
-
def namespace
|
13
|
-
node_parts[0]
|
14
|
-
end
|
9
|
+
include ConstantNode
|
15
10
|
|
16
|
-
|
17
|
-
|
18
|
-
# @return [Symbol] the name of the variable being assigned
|
19
|
-
def name
|
20
|
-
node_parts[1]
|
21
|
-
end
|
11
|
+
alias name short_name
|
12
|
+
alias lhs short_name
|
22
13
|
|
23
14
|
# The expression being assigned to the variable.
|
24
15
|
#
|
@@ -26,6 +17,7 @@ module RuboCop
|
|
26
17
|
def expression
|
27
18
|
node_parts[2]
|
28
19
|
end
|
20
|
+
alias rhs expression
|
29
21
|
end
|
30
22
|
end
|
31
23
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
# A node extension for `complex` nodes. This will be used in place of a plain
|
6
|
+
# node when the builder constructs the AST, making its methods available to
|
7
|
+
# all `complex` nodes within RuboCop.
|
8
|
+
class ComplexNode < Node
|
9
|
+
include BasicLiteralNode
|
10
|
+
include NumericNode
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -4,58 +4,7 @@ module RuboCop
|
|
4
4
|
module AST
|
5
5
|
# A node extension for `const` nodes.
|
6
6
|
class ConstNode < Node
|
7
|
-
|
8
|
-
def namespace
|
9
|
-
children[0]
|
10
|
-
end
|
11
|
-
|
12
|
-
# @return [Symbol] the demodulized name of the constant: "::Foo::Bar" => :Bar
|
13
|
-
def short_name
|
14
|
-
children[1]
|
15
|
-
end
|
16
|
-
|
17
|
-
# @return [Boolean] if the constant is a Module / Class, according to the standard convention.
|
18
|
-
# Note: some classes might have uppercase in which case this method
|
19
|
-
# returns false
|
20
|
-
def module_name?
|
21
|
-
short_name.match?(/[[:lower:]]/)
|
22
|
-
end
|
23
|
-
alias class_name? module_name?
|
24
|
-
|
25
|
-
# @return [Boolean] if the constant starts with `::` (aka s(:cbase))
|
26
|
-
def absolute?
|
27
|
-
return false unless namespace
|
28
|
-
|
29
|
-
each_path.first.cbase_type?
|
30
|
-
end
|
31
|
-
|
32
|
-
# @return [Boolean] if the constant does not start with `::` (aka s(:cbase))
|
33
|
-
def relative?
|
34
|
-
!absolute?
|
35
|
-
end
|
36
|
-
|
37
|
-
# Yield nodes for the namespace
|
38
|
-
#
|
39
|
-
# For `::Foo::Bar::BAZ` => yields:
|
40
|
-
# s(:cbase), then
|
41
|
-
# s(:const, :Foo), then
|
42
|
-
# s(:const, s(:const, :Foo), :Bar)
|
43
|
-
def each_path(&block)
|
44
|
-
return to_enum(__method__) unless block
|
45
|
-
|
46
|
-
descendants = []
|
47
|
-
last = self
|
48
|
-
loop do
|
49
|
-
last = last.children.first
|
50
|
-
break if last.nil?
|
51
|
-
|
52
|
-
descendants << last
|
53
|
-
break unless last.const_type?
|
54
|
-
end
|
55
|
-
descendants.reverse_each(&block)
|
56
|
-
|
57
|
-
self
|
58
|
-
end
|
7
|
+
include ConstantNode
|
59
8
|
end
|
60
9
|
end
|
61
10
|
end
|
@@ -13,7 +13,7 @@ module RuboCop
|
|
13
13
|
#
|
14
14
|
# @return [Boolean] whether the `def` node body is a void context
|
15
15
|
def void_context?
|
16
|
-
method?(:initialize) || assignment_method?
|
16
|
+
(def_type? && method?(:initialize)) || assignment_method?
|
17
17
|
end
|
18
18
|
|
19
19
|
# Checks whether this method definition node forwards its arguments
|
@@ -6,12 +6,48 @@ module RuboCop
|
|
6
6
|
# node when the builder constructs the AST, making its methods available
|
7
7
|
# to all `ensure` nodes within RuboCop.
|
8
8
|
class EnsureNode < Node
|
9
|
+
DEPRECATION_WARNING_LOCATION_CACHE = [] # rubocop:disable Style/MutableConstant
|
10
|
+
private_constant :DEPRECATION_WARNING_LOCATION_CACHE
|
11
|
+
|
9
12
|
# Returns the body of the `ensure` clause.
|
10
13
|
#
|
11
14
|
# @return [Node, nil] The body of the `ensure`.
|
15
|
+
# @deprecated Use `EnsureNode#branch`
|
12
16
|
def body
|
17
|
+
first_caller = caller(1..1).first
|
18
|
+
|
19
|
+
unless DEPRECATION_WARNING_LOCATION_CACHE.include?(first_caller)
|
20
|
+
warn '`EnsureNode#body` is deprecated and will be changed in the next major version of ' \
|
21
|
+
'rubocop-ast. Use `EnsureNode#branch` instead to get the body of the `ensure` branch.'
|
22
|
+
warn "Called from:\n#{caller.join("\n")}\n\n"
|
23
|
+
|
24
|
+
DEPRECATION_WARNING_LOCATION_CACHE << first_caller
|
25
|
+
end
|
26
|
+
|
27
|
+
branch
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns an the ensure branch in the exception handling statement.
|
31
|
+
#
|
32
|
+
# @return [Node, nil] the body of the ensure branch.
|
33
|
+
def branch
|
13
34
|
node_parts[1]
|
14
35
|
end
|
36
|
+
|
37
|
+
# Returns the `rescue` node of the `ensure`, if present.
|
38
|
+
#
|
39
|
+
# @return [Node, nil] The `rescue` node.
|
40
|
+
def rescue_node
|
41
|
+
node_parts[0] if node_parts[0].rescue_type?
|
42
|
+
end
|
43
|
+
|
44
|
+
# Checks whether this node body is a void context.
|
45
|
+
# Always `true` for `ensure`.
|
46
|
+
#
|
47
|
+
# @return [true] whether the `ensure` node body is a void context
|
48
|
+
def void_context?
|
49
|
+
true
|
50
|
+
end
|
15
51
|
end
|
16
52
|
end
|
17
53
|
end
|
@@ -25,6 +25,13 @@ module RuboCop
|
|
25
25
|
keyword == 'unless'
|
26
26
|
end
|
27
27
|
|
28
|
+
# Checks whether the `if` node has an `then` clause.
|
29
|
+
#
|
30
|
+
# @return [Boolean] whether the node has an `then` clause
|
31
|
+
def then?
|
32
|
+
loc_is?(:begin, 'then')
|
33
|
+
end
|
34
|
+
|
28
35
|
# Checks whether the `if` is an `elsif`. Parser handles these by nesting
|
29
36
|
# `if` nodes in the `else` branch.
|
30
37
|
#
|
@@ -40,14 +47,14 @@ module RuboCop
|
|
40
47
|
#
|
41
48
|
# @return [Boolean] whether the node has an `else` clause
|
42
49
|
def else?
|
43
|
-
loc
|
50
|
+
loc?(:else)
|
44
51
|
end
|
45
52
|
|
46
53
|
# Checks whether the `if` node is a ternary operator.
|
47
54
|
#
|
48
55
|
# @return [Boolean] whether the `if` node is a ternary operator
|
49
56
|
def ternary?
|
50
|
-
loc
|
57
|
+
loc?(:question)
|
51
58
|
end
|
52
59
|
|
53
60
|
# Returns the keyword of the `if` statement as a string. Returns an empty
|
@@ -81,7 +88,7 @@ module RuboCop
|
|
81
88
|
(if? || unless?) && super
|
82
89
|
end
|
83
90
|
|
84
|
-
#
|
91
|
+
# Checks whether the `if` node has nested `if` nodes in any of its
|
85
92
|
# branches.
|
86
93
|
#
|
87
94
|
# @note This performs a shallow search.
|
@@ -102,7 +109,7 @@ module RuboCop
|
|
102
109
|
#
|
103
110
|
# @return [Boolean] whether the `if` node has at least one `elsif` branch
|
104
111
|
def elsif_conditional?
|
105
|
-
else_branch&.if_type? && else_branch
|
112
|
+
else_branch&.if_type? && else_branch.elsif?
|
106
113
|
end
|
107
114
|
|
108
115
|
# Returns the branch of the `if` node that gets evaluated when its
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
# A node extension for `kwbegin` nodes. This will be used in place of a plain
|
6
|
+
# node when the builder constructs the AST, making its methods available
|
7
|
+
# to all `kwbegin` nodes within RuboCop.
|
8
|
+
class KeywordBeginNode < Node
|
9
|
+
# Returns the body of the `kwbegin` block. Returns `self` if the `kwbegin` contains
|
10
|
+
# multiple nodes.
|
11
|
+
#
|
12
|
+
# @return [Node, nil] The body of the `kwbegin`.
|
13
|
+
def body
|
14
|
+
return unless node_parts.any?
|
15
|
+
|
16
|
+
if rescue_node
|
17
|
+
rescue_node.body
|
18
|
+
elsif ensure_node
|
19
|
+
ensure_node.node_parts[0]
|
20
|
+
elsif node_parts.one?
|
21
|
+
node_parts[0]
|
22
|
+
else
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the `rescue` node of the `kwbegin` block, if one is present.
|
28
|
+
#
|
29
|
+
# @return [Node, nil] The `rescue` node within `kwbegin`.
|
30
|
+
def ensure_node
|
31
|
+
node_parts[0] if node_parts[0]&.ensure_type?
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the `rescue` node of the `kwbegin` block, if one is present.
|
35
|
+
#
|
36
|
+
# @return [Node, nil] The `rescue` node within `kwbegin`.
|
37
|
+
def rescue_node
|
38
|
+
return ensure_node&.rescue_node if ensure_node&.rescue_node
|
39
|
+
|
40
|
+
node_parts[0] if node_parts[0]&.rescue_type?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module AST
|
5
|
+
# A node extension for `masgn` nodes.
|
6
|
+
# This will be used in place of a plain node when the builder constructs
|
7
|
+
# the AST, making its methods available to all assignment nodes within RuboCop.
|
8
|
+
class MasgnNode < Node
|
9
|
+
# @return [MlhsNode] the `mlhs` node
|
10
|
+
def lhs
|
11
|
+
# The first child is a `mlhs` node
|
12
|
+
node_parts[0]
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Array<Node>] the assignment nodes of the multiple assignment
|
16
|
+
def assignments
|
17
|
+
lhs.assignments
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Array<Symbol>] names of all the variables being assigned
|
21
|
+
def names
|
22
|
+
assignments.map do |assignment|
|
23
|
+
if assignment.type?(:send, :indexasgn)
|
24
|
+
assignment.method_name
|
25
|
+
else
|
26
|
+
assignment.name
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# The RHS (right hand side) of the multiple assignment. This returns
|
32
|
+
# the nodes as parsed: either a single node if the RHS has a single value,
|
33
|
+
# or an `array` node containing multiple nodes.
|
34
|
+
#
|
35
|
+
# NOTE: Due to how parsing works, `expression` will return the same for
|
36
|
+
# `a, b = x, y` and `a, b = [x, y]`.
|
37
|
+
#
|
38
|
+
# @return [Node] the right hand side of a multiple assignment.
|
39
|
+
def expression
|
40
|
+
node_parts[1]
|
41
|
+
end
|
42
|
+
alias rhs expression
|
43
|
+
|
44
|
+
# In contrast to `expression`, `values` always returns a Ruby array
|
45
|
+
# containing all the nodes being assigned on the RHS.
|
46
|
+
#
|
47
|
+
# Literal arrays are considered a singular value; but unlike `expression`,
|
48
|
+
# implied `array` nodes from assigning multiple values on the RHS are treated
|
49
|
+
# as separate.
|
50
|
+
#
|
51
|
+
# @return [Array<Node>] individual values being assigned on the RHS of the multiple assignment
|
52
|
+
def values
|
53
|
+
multiple_rhs? ? expression.children : [expression]
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def multiple_rhs?
|
59
|
+
expression.array_type? && !expression.bracketed?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|