rubocop-callbacksystems 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +78 -0
- data/config/default.yml +590 -0
- data/docs/cops.md +111 -0
- data/lib/rubocop/callbacksystems/autocorrection/batch.rb +135 -0
- data/lib/rubocop/callbacksystems/autocorrection/comment_rescue.rb +112 -0
- data/lib/rubocop/callbacksystems/autocorrection/rehearsal.rb +65 -0
- data/lib/rubocop/callbacksystems/autocorrection/rewrite_permit.rb +14 -0
- data/lib/rubocop/callbacksystems/class_structure/builder_assignment.rb +48 -0
- data/lib/rubocop/callbacksystems/class_structure/class_body.rb +50 -0
- data/lib/rubocop/callbacksystems/class_structure/divergence.rb +31 -0
- data/lib/rubocop/callbacksystems/class_structure/node_visibility.rb +82 -0
- data/lib/rubocop/callbacksystems/class_structure/reference_order.rb +36 -0
- data/lib/rubocop/callbacksystems/class_structure/statement_rank.rb +84 -0
- data/lib/rubocop/callbacksystems/class_structure/statement_run.rb +42 -0
- data/lib/rubocop/callbacksystems/class_structure/visibility.rb +84 -0
- data/lib/rubocop/callbacksystems/cops_document.rb +78 -0
- data/lib/rubocop/callbacksystems/execution/deferred_local_variables.rb +138 -0
- data/lib/rubocop/callbacksystems/execution/discarded_expression.rb +45 -0
- data/lib/rubocop/callbacksystems/execution/eager_evaluation_path.rb +73 -0
- data/lib/rubocop/callbacksystems/execution/immediate.rb +71 -0
- data/lib/rubocop/callbacksystems/execution/local_variable_occurrences.rb +112 -0
- data/lib/rubocop/callbacksystems/hashes/key_transform_detection.rb +108 -0
- data/lib/rubocop/callbacksystems/hashes/keyword_options.rb +37 -0
- data/lib/rubocop/callbacksystems/helpers/bodies.rb +150 -0
- data/lib/rubocop/callbacksystems/helpers/builders.rb +103 -0
- data/lib/rubocop/callbacksystems/helpers/comments.rb +56 -0
- data/lib/rubocop/callbacksystems/helpers/corrections.rb +15 -0
- data/lib/rubocop/callbacksystems/helpers/methods.rb +46 -0
- data/lib/rubocop/callbacksystems/helpers/names.rb +65 -0
- data/lib/rubocop/callbacksystems/helpers/node_types.rb +154 -0
- data/lib/rubocop/callbacksystems/helpers/rails.rb +52 -0
- data/lib/rubocop/callbacksystems/helpers/ranges.rb +107 -0
- data/lib/rubocop/callbacksystems/helpers/recursion.rb +29 -0
- data/lib/rubocop/callbacksystems/helpers/variables.rb +44 -0
- data/lib/rubocop/callbacksystems/helpers/visibility.rb +121 -0
- data/lib/rubocop/callbacksystems/helpers.rb +43 -0
- data/lib/rubocop/callbacksystems/methods/calls.rb +38 -0
- data/lib/rubocop/callbacksystems/methods/definitions.rb +218 -0
- data/lib/rubocop/callbacksystems/methods/delegate_macro.rb +144 -0
- data/lib/rubocop/callbacksystems/methods/delegation_target.rb +55 -0
- data/lib/rubocop/callbacksystems/methods/domain.rb +77 -0
- data/lib/rubocop/callbacksystems/methods/implicit_invocations.rb +17 -0
- data/lib/rubocop/callbacksystems/methods/macro_references.rb +238 -0
- data/lib/rubocop/callbacksystems/methods/reference_evidence.rb +74 -0
- data/lib/rubocop/callbacksystems/methods/siblings.rb +24 -0
- data/lib/rubocop/callbacksystems/methods/statement_definitions.rb +68 -0
- data/lib/rubocop/callbacksystems/offense.rb +13 -0
- data/lib/rubocop/callbacksystems/plugin.rb +27 -0
- data/lib/rubocop/callbacksystems/project_index/cache.rb +16 -0
- data/lib/rubocop/callbacksystems/project_index/confinement_cache.rb +40 -0
- data/lib/rubocop/callbacksystems/project_index/constant_references.rb +74 -0
- data/lib/rubocop/callbacksystems/project_index/corrections.rb +35 -0
- data/lib/rubocop/callbacksystems/project_index/coverage.rb +56 -0
- data/lib/rubocop/callbacksystems/project_index/diagnostics.rb +60 -0
- data/lib/rubocop/callbacksystems/project_index/freshness.rb +104 -0
- data/lib/rubocop/callbacksystems/project_index/loader.rb +9 -0
- data/lib/rubocop/callbacksystems/project_index/location.rb +29 -0
- data/lib/rubocop/callbacksystems/project_index/nested_class_confinement.rb +297 -0
- data/lib/rubocop/callbacksystems/project_index/nested_class_method_dispatch.rb +50 -0
- data/lib/rubocop/callbacksystems/project_index/reading.rb +129 -0
- data/lib/rubocop/callbacksystems/project_index/source_file.rb +59 -0
- data/lib/rubocop/callbacksystems/project_index/source_file_match.rb +57 -0
- data/lib/rubocop/callbacksystems/project_index/support.rb +46 -0
- data/lib/rubocop/callbacksystems/source/comment_blocks.rb +43 -0
- data/lib/rubocop/callbacksystems/source/comments.rb +141 -0
- data/lib/rubocop/callbacksystems/source/file_ast.rb +15 -0
- data/lib/rubocop/callbacksystems/source/files_checksum.rb +43 -0
- data/lib/rubocop/callbacksystems/source/single_line_call.rb +181 -0
- data/lib/rubocop/callbacksystems/source/statement_with_comments.rb +131 -0
- data/lib/rubocop/callbacksystems/testing/cop_helpers.rb +42 -0
- data/lib/rubocop/callbacksystems/testing/fixture_call.rb +30 -0
- data/lib/rubocop/callbacksystems/testing/fixture_names.rb +62 -0
- data/lib/rubocop/callbacksystems/testing/path_mapping.rb +104 -0
- data/lib/rubocop/cop/callbacksystems/application_controller_method_definition.rb +44 -0
- data/lib/rubocop/cop/callbacksystems/assert_with_expected_argument.rb +60 -0
- data/lib/rubocop/cop/callbacksystems/base.rb +134 -0
- data/lib/rubocop/cop/callbacksystems/body_order.rb +478 -0
- data/lib/rubocop/cop/callbacksystems/builder_method_parentheses.rb +74 -0
- data/lib/rubocop/cop/callbacksystems/collapse_multiline_expression.rb +140 -0
- data/lib/rubocop/cop/callbacksystems/comment_block_length.rb +137 -0
- data/lib/rubocop/cop/callbacksystems/complex_conditional.rb +75 -0
- data/lib/rubocop/cop/callbacksystems/controller_test_response_assertion.rb +105 -0
- data/lib/rubocop/cop/callbacksystems/controller_test_response_first_assertion.rb +123 -0
- data/lib/rubocop/cop/callbacksystems/data_clump.rb +339 -0
- data/lib/rubocop/cop/callbacksystems/declarative_method_naming.rb +350 -0
- data/lib/rubocop/cop/callbacksystems/delegate_requires_private_option.rb +81 -0
- data/lib/rubocop/cop/callbacksystems/eager_loading_scope_naming.rb +386 -0
- data/lib/rubocop/cop/callbacksystems/early_return.rb +215 -0
- data/lib/rubocop/cop/callbacksystems/empty_line_before_method.rb +168 -0
- data/lib/rubocop/cop/callbacksystems/empty_line_between_sections.rb +169 -0
- data/lib/rubocop/cop/callbacksystems/empty_private_section.rb +107 -0
- data/lib/rubocop/cop/callbacksystems/expanded_empty_class_or_module.rb +71 -0
- data/lib/rubocop/cop/callbacksystems/inline_memoized_computation.rb +110 -0
- data/lib/rubocop/cop/callbacksystems/job_enqueue_methods.rb +93 -0
- data/lib/rubocop/cop/callbacksystems/max_safe_navigation_depth.rb +118 -0
- data/lib/rubocop/cop/callbacksystems/method_invocation_order.rb +261 -0
- data/lib/rubocop/cop/callbacksystems/nested_class_order.rb +255 -0
- data/lib/rubocop/cop/callbacksystems/no_abbreviations.rb +197 -0
- data/lib/rubocop/cop/callbacksystems/no_anemic_delegation.rb +101 -0
- data/lib/rubocop/cop/callbacksystems/no_anemic_record.rb +309 -0
- data/lib/rubocop/cop/callbacksystems/no_assert_select.rb +31 -0
- data/lib/rubocop/cop/callbacksystems/no_bang_method_without_counterpart.rb +451 -0
- data/lib/rubocop/cop/callbacksystems/no_call_method.rb +73 -0
- data/lib/rubocop/cop/callbacksystems/no_comments_in_test_class_body.rb +159 -0
- data/lib/rubocop/cop/callbacksystems/no_consecutive_appends.rb +261 -0
- data/lib/rubocop/cop/callbacksystems/no_custom_route_actions.rb +124 -0
- data/lib/rubocop/cop/callbacksystems/no_direct_eager_loading.rb +90 -0
- data/lib/rubocop/cop/callbacksystems/no_each_with_early_return.rb +58 -0
- data/lib/rubocop/cop/callbacksystems/no_explicit_public_modifier.rb +81 -0
- data/lib/rubocop/cop/callbacksystems/no_hash_with_default_block.rb +68 -0
- data/lib/rubocop/cop/callbacksystems/no_local_variable_return.rb +173 -0
- data/lib/rubocop/cop/callbacksystems/no_manual_accumulation.rb +188 -0
- data/lib/rubocop/cop/callbacksystems/no_mixed_memoization.rb +145 -0
- data/lib/rubocop/cop/callbacksystems/no_nested_modules_in_classes.rb +78 -0
- data/lib/rubocop/cop/callbacksystems/no_nil_at_end_of_method.rb +74 -0
- data/lib/rubocop/cop/callbacksystems/no_redundant_validation_name.rb +37 -0
- data/lib/rubocop/cop/callbacksystems/no_redundant_wrapper_method.rb +161 -0
- data/lib/rubocop/cop/callbacksystems/no_section_divider_comments.rb +105 -0
- data/lib/rubocop/cop/callbacksystems/no_send_in_tests.rb +75 -0
- data/lib/rubocop/cop/callbacksystems/no_service_objects.rb +64 -0
- data/lib/rubocop/cop/callbacksystems/no_single_letter_names.rb +47 -0
- data/lib/rubocop/cop/callbacksystems/no_singleton_class_in_modules.rb +43 -0
- data/lib/rubocop/cop/callbacksystems/no_tap_collection_building.rb +173 -0
- data/lib/rubocop/cop/callbacksystems/no_turbo_stream_in_controllers.rb +52 -0
- data/lib/rubocop/cop/callbacksystems/no_typographic_clutter.rb +159 -0
- data/lib/rubocop/cop/callbacksystems/no_writes_in_get_actions.rb +149 -0
- data/lib/rubocop/cop/callbacksystems/ordered_mixin_arguments.rb +78 -0
- data/lib/rubocop/cop/callbacksystems/plural_controller_names.rb +103 -0
- data/lib/rubocop/cop/callbacksystems/prefer_attr_reader_over_instance_variable.rb +86 -0
- data/lib/rubocop/cop/callbacksystems/prefer_backslash_continuation.rb +478 -0
- data/lib/rubocop/cop/callbacksystems/prefer_class_for_state.rb +532 -0
- data/lib/rubocop/cop/callbacksystems/prefer_class_new_for_empty_nested_class.rb +247 -0
- data/lib/rubocop/cop/callbacksystems/prefer_class_over_builder_block.rb +124 -0
- data/lib/rubocop/cop/callbacksystems/prefer_default_argument.rb +225 -0
- data/lib/rubocop/cop/callbacksystems/prefer_delegate.rb +242 -0
- data/lib/rubocop/cop/callbacksystems/prefer_delegate_over_instance_variable_assignment.rb +175 -0
- data/lib/rubocop/cop/callbacksystems/prefer_excluding.rb +204 -0
- data/lib/rubocop/cop/callbacksystems/prefer_extract_associated.rb +54 -0
- data/lib/rubocop/cop/callbacksystems/prefer_it_block_parameter.rb +156 -0
- data/lib/rubocop/cop/callbacksystems/prefer_many.rb +57 -0
- data/lib/rubocop/cop/callbacksystems/prefer_method_over_lambda.rb +211 -0
- data/lib/rubocop/cop/callbacksystems/prefer_method_over_variable.rb +172 -0
- data/lib/rubocop/cop/callbacksystems/prefer_module_for_static_class.rb +286 -0
- data/lib/rubocop/cop/callbacksystems/prefer_ordinal_array_access.rb +136 -0
- data/lib/rubocop/cop/callbacksystems/prefer_positive_wrap.rb +265 -0
- data/lib/rubocop/cop/callbacksystems/prefer_squish.rb +47 -0
- data/lib/rubocop/cop/callbacksystems/prefer_stringify_keys.rb +24 -0
- data/lib/rubocop/cop/callbacksystems/prefer_symbolize_keys.rb +24 -0
- data/lib/rubocop/cop/callbacksystems/prefer_turbo_page_refresh_broadcasts.rb +40 -0
- data/lib/rubocop/cop/callbacksystems/private_constants_in_private_section.rb +160 -0
- data/lib/rubocop/cop/callbacksystems/private_delegate_placement.rb +342 -0
- data/lib/rubocop/cop/callbacksystems/private_methods_in_private_section.rb +70 -0
- data/lib/rubocop/cop/callbacksystems/private_nested_class_method_visibility.rb +269 -0
- data/lib/rubocop/cop/callbacksystems/private_nested_classes.rb +94 -0
- data/lib/rubocop/cop/callbacksystems/public_methods_must_have_tests.rb +190 -0
- data/lib/rubocop/cop/callbacksystems/redundant_concern_extend.rb +157 -0
- data/lib/rubocop/cop/callbacksystems/redundant_constant_freeze.rb +57 -0
- data/lib/rubocop/cop/callbacksystems/redundant_constant_namespace.rb +134 -0
- data/lib/rubocop/cop/callbacksystems/reflow_comments.rb +133 -0
- data/lib/rubocop/cop/callbacksystems/repeated_fixture_in_tests.rb +106 -0
- data/lib/rubocop/cop/callbacksystems/restricted_controller_actions.rb +85 -0
- data/lib/rubocop/cop/callbacksystems/routes_module_scope.rb +336 -0
- data/lib/rubocop/cop/callbacksystems/single_line_setup_block.rb +107 -0
- data/lib/rubocop/cop/callbacksystems/single_singleton_class.rb +49 -0
- data/lib/rubocop/cop/callbacksystems/single_top_level_class_or_module.rb +160 -0
- data/lib/rubocop/cop/callbacksystems/single_use_fixture_variable.rb +211 -0
- data/lib/rubocop/cop/callbacksystems/single_use_setup_variable.rb +684 -0
- data/lib/rubocop/cop/callbacksystems/singular_scope_names.rb +47 -0
- data/lib/rubocop/cop/callbacksystems/space_inside_percent_literal.rb +73 -0
- data/lib/rubocop/cop/callbacksystems/system_test_browser_driver.rb +30 -0
- data/lib/rubocop/cop/callbacksystems/test_method_definition.rb +86 -0
- data/lib/rubocop/cop/callbacksystems/test_method_order.rb +319 -0
- data/lib/rubocop/cop/callbacksystems/too_many_instance_variables.rb +78 -0
- data/lib/rubocop/cop/callbacksystems/too_many_local_variables.rb +77 -0
- data/lib/rubocop/cop/callbacksystems/too_many_validation_guards.rb +84 -0
- data/lib/rubocop/cop/callbacksystems/unnecessary_local_variable.rb +176 -0
- data/lib/rubocop/cop/callbacksystems/unused_private_method_in_nested_class.rb +203 -0
- data/lib/rubocop-callbacksystems.rb +21 -0
- data/rubocop.yml +685 -0
- metadata +337 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Detects a fixture assigned to a variable the test reads once. The variable
|
|
2
|
+
# spends a line on a name for a record the fixture call already names, so the
|
|
3
|
+
# test reads shorter with the call standing where the variable was.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# # bad - fixture stored in variable but only used once
|
|
7
|
+
# test "validates user" do
|
|
8
|
+
# user = users(:john)
|
|
9
|
+
# assert user.valid?
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
# # good - inline the fixture
|
|
13
|
+
# test "validates user" do
|
|
14
|
+
# assert users(:john).valid?
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# # good - variable used multiple times
|
|
18
|
+
# test "validates user" do
|
|
19
|
+
# user = users(:john)
|
|
20
|
+
# assert user.valid?
|
|
21
|
+
# assert user.name.present?
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
class RuboCop::Cop::Callbacksystems::SingleUseFixtureVariable < RuboCop::Cop::Callbacksystems::Base
|
|
25
|
+
include RuboCop::Callbacksystems::Testing::CopHelpers
|
|
26
|
+
extend RuboCop::Cop::AutoCorrector
|
|
27
|
+
|
|
28
|
+
def external_dependency_checksum
|
|
29
|
+
RuboCop::Callbacksystems::Source::FilesChecksum.for \
|
|
30
|
+
"**/test/fixtures/**/*.yml", root: project_root, include_contents: false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def on_block(node)
|
|
34
|
+
report_each SingleUseFixtures.new(node.body) if test_block?(node)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
alias on_numblock on_block
|
|
38
|
+
alias on_itblock on_block
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
class SingleUseFixtures
|
|
42
|
+
include RuboCop::Callbacksystems::Helpers
|
|
43
|
+
|
|
44
|
+
def initialize(body)
|
|
45
|
+
@body = body
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def each_offense(&block)
|
|
49
|
+
test_variables.assignments.filter_map do |assignment|
|
|
50
|
+
FixtureAssignment.new(assignment, usage: test_variables.usage_of(assignment)).offense
|
|
51
|
+
end.each(&block)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
attr_reader :body
|
|
56
|
+
|
|
57
|
+
def test_variables
|
|
58
|
+
@test_variables ||= TestVariables.new(body)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class FixtureAssignment
|
|
63
|
+
include RuboCop::Callbacksystems::Helpers
|
|
64
|
+
|
|
65
|
+
MESSAGE = "Fixture `%<fixture>s` is assigned to `%<variable>s` but only used once. Inline it instead."
|
|
66
|
+
|
|
67
|
+
def initialize(node, usage:)
|
|
68
|
+
@node = node
|
|
69
|
+
@usage = usage
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def offense
|
|
73
|
+
RuboCop::Callbacksystems::Offense.new(node, message, correcting: inlineable?) { correct(it) } if
|
|
74
|
+
fixture.valid? && sole_read
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
attr_reader :node, :usage
|
|
79
|
+
|
|
80
|
+
def fixture
|
|
81
|
+
@fixture ||= RuboCop::Callbacksystems::Testing::FixtureCall.new(node.expression)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# A read inside a block of the test may run more than once, so the call is not the same as the variable there.
|
|
85
|
+
def sole_read
|
|
86
|
+
defined?(@sole_read) ? @sole_read : @sole_read = usage.sole_read
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def message
|
|
90
|
+
format(MESSAGE, fixture: fixture.signature, variable: node.name)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Running anything between the lookup and its use can make moving that lookup observable, so those cases stay as
|
|
94
|
+
# diagnostics for a human.
|
|
95
|
+
def inlineable?
|
|
96
|
+
usage.direct? && assignment_owns_its_lines? && usage.lookup_order_preserved?
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def assignment_owns_its_lines?
|
|
100
|
+
line_removal_range_for(node).source.strip == node.source
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def correct(corrector)
|
|
104
|
+
corrector.remove(line_removal_range_for(node))
|
|
105
|
+
replace_expression(corrector, sole_read, with: fixture.signature)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Local-variable use, statement position and deferred captures indexed once for one test body.
|
|
110
|
+
class TestVariables
|
|
111
|
+
include RuboCop::Callbacksystems::Helpers
|
|
112
|
+
|
|
113
|
+
def initialize(body)
|
|
114
|
+
@body = body
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def assignments
|
|
118
|
+
@assignments ||= RuboCop::Callbacksystems::Execution::Immediate.new(body).nodes_of_type(:lvasgn)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def usage_of(assignment)
|
|
122
|
+
VariableUsage.new \
|
|
123
|
+
assignment,
|
|
124
|
+
occurrences: occurrences.named(assignment.name, around: assignment),
|
|
125
|
+
deferred_variables:,
|
|
126
|
+
position: position_of(assignment)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
attr_reader :body
|
|
131
|
+
|
|
132
|
+
def occurrences
|
|
133
|
+
@occurrences ||= RuboCop::Callbacksystems::Execution::LocalVariableOccurrences.new(body)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def deferred_variables
|
|
137
|
+
@deferred_variables ||= RuboCop::Callbacksystems::Execution::DeferredLocalVariables.new(body)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def position_of(assignment)
|
|
141
|
+
StatementPosition.new(test_scope, next_statements.fetch(assignment, nil), next_statements.key?(assignment))
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def test_scope
|
|
145
|
+
@test_scope ||= body.each_ancestor(:any_block).first
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def next_statements
|
|
149
|
+
@next_statements ||= {}.compare_by_identity.tap do |index|
|
|
150
|
+
statements = statements_in(body)
|
|
151
|
+
statements.each_with_index { |statement, position| index[statement] = statements[position + 1] }
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# The reads and writes belonging to one fixture assignment in its test's lexical scope.
|
|
157
|
+
class VariableUsage
|
|
158
|
+
delegate :direct?, to: :position
|
|
159
|
+
|
|
160
|
+
def initialize(node, occurrences:, deferred_variables:, position:)
|
|
161
|
+
@node = node
|
|
162
|
+
@occurrences = occurrences
|
|
163
|
+
@deferred_variables = deferred_variables
|
|
164
|
+
@position = position
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def lookup_order_preserved?
|
|
168
|
+
read = sole_read
|
|
169
|
+
|
|
170
|
+
read && next_statement &&
|
|
171
|
+
RuboCop::Callbacksystems::Execution::EagerEvaluationPath.new(read, within: next_statement).preserves_order?
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def sole_read
|
|
175
|
+
reads.first if reads.one? && stable?
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
private
|
|
179
|
+
attr_reader :node, :occurrences, :deferred_variables, :position
|
|
180
|
+
delegate :test_scope, :next_statement, to: :position, private: true
|
|
181
|
+
|
|
182
|
+
def reads
|
|
183
|
+
@reads ||= occurrences.select(&:lvar_type?)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def stable?
|
|
187
|
+
!reassigned_before_read? && !repeated_in_test? && deferred_variables.exclude?(node.name)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def reassigned_before_read?
|
|
191
|
+
occurrences.any? do |occurrence|
|
|
192
|
+
occurrence.type?(:lvasgn, :match_var) && !occurrence.equal?(node) &&
|
|
193
|
+
occurrence.source_range.begin_pos < reads.first.source_range.begin_pos
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def repeated_in_test?
|
|
198
|
+
[ node, reads.first ].any? do |occurrence|
|
|
199
|
+
occurrence.each_ancestor.take_while { !it.equal?(test_scope) }.any? do |ancestor|
|
|
200
|
+
ancestor.type?(:any_block, :while, :while_post, :until, :until_post, :for)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
class StatementPosition < Data.define(:test_scope, :next_statement, :direct)
|
|
207
|
+
def direct?
|
|
208
|
+
direct
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|