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,60 @@
|
|
|
1
|
+
class RuboCop::Callbacksystems::ProjectIndex::Diagnostics
|
|
2
|
+
extend RuboCop::Callbacksystems::ProjectIndex::Cache
|
|
3
|
+
|
|
4
|
+
def initialize(project_index)
|
|
5
|
+
@by_rule_name = {}
|
|
6
|
+
@by_rule_name_and_uri = {}
|
|
7
|
+
project_index.diagnostics.each { index(it) }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def any_named?(*rule_names)
|
|
11
|
+
diagnostics_named(rule_names).any?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def within_definitions?(definitions, named:)
|
|
15
|
+
definitions.any? do |definition|
|
|
16
|
+
diagnostics_named_in(definition.location.uri, named).any? do |diagnostic|
|
|
17
|
+
LocationContainment.new(definition.location, diagnostic.location).contained?
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
attr_reader :by_rule_name, :by_rule_name_and_uri
|
|
24
|
+
|
|
25
|
+
def index(diagnostic)
|
|
26
|
+
rule_name = diagnostic.rule.rule_name
|
|
27
|
+
(by_rule_name[rule_name] ||= []) << diagnostic
|
|
28
|
+
(by_rule_name_and_uri[[ rule_name, diagnostic.location.uri ]] ||= []) << diagnostic
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def diagnostics_named(rule_names)
|
|
32
|
+
rule_names.flat_map { by_rule_name.fetch(it) { [] } }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def diagnostics_named_in(uri, rule_names)
|
|
36
|
+
rule_names.flat_map { by_rule_name_and_uri.fetch([ it, uri ]) { [] } }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class LocationContainment
|
|
40
|
+
def initialize(outer, inner)
|
|
41
|
+
@outer = outer
|
|
42
|
+
@inner = inner
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def contained?
|
|
46
|
+
outer.uri == inner.uri && starts_before? && ends_after?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
attr_reader :outer, :inner
|
|
51
|
+
|
|
52
|
+
def starts_before?
|
|
53
|
+
([ outer.start_line, outer.start_column ] <=> [ inner.start_line, inner.start_column ]) <= 0
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def ends_after?
|
|
57
|
+
([ outer.end_line, outer.end_column ] <=> [ inner.end_line, inner.end_column ]) >= 0
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
require "digest"
|
|
2
|
+
|
|
3
|
+
# The source revisions held by a project index while RuboCop autocorrects in memory. RuboCop builds one graph before
|
|
4
|
+
# inspecting the project, then may run several corrected versions of a file before writing it. Each accepted revision
|
|
5
|
+
# replaces that document in Rubydex; only revisions descended from the indexed disk source are trusted.
|
|
6
|
+
class RuboCop::Callbacksystems::ProjectIndex::Freshness
|
|
7
|
+
class << self
|
|
8
|
+
def update(project_index, processed_source, new_source)
|
|
9
|
+
mutex.synchronize do
|
|
10
|
+
RevisionChain.new(
|
|
11
|
+
processed_source, state_for(project_index), project_index:, new_source:
|
|
12
|
+
).update
|
|
13
|
+
end
|
|
14
|
+
rescue SystemCallError
|
|
15
|
+
false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def current_source?(project_index, processed_source)
|
|
19
|
+
mutex.synchronize do
|
|
20
|
+
RevisionChain.new(processed_source, state_for(project_index)).current?
|
|
21
|
+
end || false
|
|
22
|
+
rescue SystemCallError
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def reliable?(project_index)
|
|
27
|
+
mutex.synchronize { state_for(project_index).reliable }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def generation(project_index)
|
|
31
|
+
mutex.synchronize { state_for(project_index).generation }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
def mutex
|
|
36
|
+
@mutex ||= Mutex.new
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def state_for(project_index)
|
|
40
|
+
states[project_index] ||= State.new(0, true, {})
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def states
|
|
44
|
+
@states ||= ObjectSpace::WeakKeyMap.new
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
State = Struct.new(:generation, :reliable, :revisions)
|
|
50
|
+
Revision = Data.define(:source, :backing_checksum)
|
|
51
|
+
|
|
52
|
+
class RevisionChain
|
|
53
|
+
def initialize(processed_source, state, project_index: nil, new_source: nil)
|
|
54
|
+
@file = RuboCop::Callbacksystems::ProjectIndex::SourceFile.new(processed_source.file_path)
|
|
55
|
+
@source = processed_source.raw_source.b
|
|
56
|
+
@state = state
|
|
57
|
+
@project_index = project_index
|
|
58
|
+
@new_source = new_source
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def update
|
|
62
|
+
backing_checksum ? update_index : false
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def current?
|
|
66
|
+
current_revision? && revision.backing_checksum == disk_checksum
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
attr_reader :file, :source, :state, :project_index, :new_source
|
|
71
|
+
|
|
72
|
+
def backing_checksum
|
|
73
|
+
@backing_checksum ||= disk_checksum if source_on_disk? || current?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def source_on_disk?
|
|
77
|
+
disk_checksum == Digest::SHA256.hexdigest(source)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def disk_checksum
|
|
81
|
+
@disk_checksum ||= Digest::SHA256.file(file.path).hexdigest
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def update_index
|
|
85
|
+
project_index.index_source(file.uri, new_source, "ruby")
|
|
86
|
+
project_index.resolve
|
|
87
|
+
state.revisions[file.path] = Revision.new(new_source.b.dup.freeze, backing_checksum)
|
|
88
|
+
state.generation += 1
|
|
89
|
+
true
|
|
90
|
+
rescue
|
|
91
|
+
state.reliable = false
|
|
92
|
+
state.generation += 1
|
|
93
|
+
false
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def current_revision?
|
|
97
|
+
revision&.source == source
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def revision
|
|
101
|
+
state.revisions[file.path]
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# One source location expressed in Rubydex's zero-based lines and byte columns, so parser ranges and graph locations can
|
|
2
|
+
# be compared without confusing a character column for a byte column.
|
|
3
|
+
class RuboCop::Callbacksystems::ProjectIndex::Location < Data.define \
|
|
4
|
+
:uri, :start_line, :start_column, :end_line, :end_column
|
|
5
|
+
class << self
|
|
6
|
+
def for_ast(range, uri:)
|
|
7
|
+
new \
|
|
8
|
+
uri:,
|
|
9
|
+
start_line: range.line.pred,
|
|
10
|
+
start_column: byte_column_of(range, line: range.line, at: range.column),
|
|
11
|
+
end_line: range.last_line.pred,
|
|
12
|
+
end_column: byte_column_of(range, line: range.last_line, at: range.last_column)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def for_rubydex(location)
|
|
16
|
+
new \
|
|
17
|
+
uri: location.uri,
|
|
18
|
+
start_line: location.start_line,
|
|
19
|
+
start_column: location.start_column,
|
|
20
|
+
end_line: location.end_line,
|
|
21
|
+
end_column: location.end_column
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
def byte_column_of(range, line:, at:)
|
|
26
|
+
range.source_buffer.source_line(line).slice(0, at).bytesize
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# Whether every visible use of a nested class and every instance it constructs stays within the file.
|
|
2
|
+
class RuboCop::Callbacksystems::ProjectIndex::NestedClassConfinement
|
|
3
|
+
include RuboCop::Callbacksystems::Helpers
|
|
4
|
+
|
|
5
|
+
CONSTRUCTION_METHODS = %i[ allocate new ]
|
|
6
|
+
MIXIN_METHODS = %i[ extend include prepend ]
|
|
7
|
+
CLASS_BODY_PRIMITIVES = %i[
|
|
8
|
+
alias_method attr attr_accessor attr_reader attr_writer deprecate_constant module_function
|
|
9
|
+
private private_class_method private_constant protected public public_class_method public_constant
|
|
10
|
+
remove_method ruby2_keywords undef_method
|
|
11
|
+
]
|
|
12
|
+
VALUE_EXPOSURE_METHODS = %i[
|
|
13
|
+
__send__ binding clone dup enum_for freeze instance_eval instance_exec itself method public_method public_send
|
|
14
|
+
send singleton_class singleton_method tap then to_enum yield_self
|
|
15
|
+
]
|
|
16
|
+
HANDOFF_TYPES = %i[
|
|
17
|
+
array hash pair splat kwsplat block_pass yield return super break next def defs
|
|
18
|
+
and or case when rescue resbody ensure for match_pattern match_pattern_p irange erange
|
|
19
|
+
lvasgn ivasgn cvasgn gvasgn casgn masgn or_asgn and_asgn op_asgn
|
|
20
|
+
].to_set.merge(RuboCop::Callbacksystems::Helpers::NodeTypes::BLOCK_NODE_TYPES)
|
|
21
|
+
|
|
22
|
+
def initialize(nested_class, declaration:, project_index:)
|
|
23
|
+
@nested_class = nested_class
|
|
24
|
+
@declaration = declaration
|
|
25
|
+
@project_index = project_index
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def confined?
|
|
29
|
+
return @confined if defined?(@confined)
|
|
30
|
+
|
|
31
|
+
@confined = definition_confined? && values_confined?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
attr_reader :nested_class, :declaration, :project_index
|
|
36
|
+
|
|
37
|
+
def definition_confined?
|
|
38
|
+
nested_class.parent_class.nil? && !mixin_used? && !singleton_callback_defined? &&
|
|
39
|
+
references_in_definition_file? && all_references_located? && reference_nodes.all? { safe_reference?(it) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def mixin_used?
|
|
43
|
+
sends.any? do |send_node|
|
|
44
|
+
call_on_self?(send_node) && MIXIN_METHODS.include?(send_node.method_name)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def sends
|
|
49
|
+
@sends ||= nodes_in(nested_class.body, :send, :csend)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def singleton_callback_defined?
|
|
53
|
+
direct_method_nodes.any? do |definition|
|
|
54
|
+
RuboCop::Callbacksystems::Methods::ImplicitInvocations::RUNTIME_METHODS.include?(definition.method_name) &&
|
|
55
|
+
singleton_definition?(definition)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def direct_method_nodes
|
|
60
|
+
@direct_method_nodes ||= direct_method_nodes_in(nested_class.body)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def singleton_definition?(definition)
|
|
64
|
+
RuboCop::Callbacksystems::Methods::Domain.new(definition).identity.then do |identity|
|
|
65
|
+
identity.present? && identity.all? { it == :self }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def references_in_definition_file?
|
|
70
|
+
definition_uris.one? && references.all? { definition_uris.include?(it.location.uri) }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def definition_uris
|
|
74
|
+
@definition_uris ||= declaration.definitions.to_set { it.location.uri }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def references
|
|
78
|
+
@references ||= declaration.references.to_a
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def all_references_located?
|
|
82
|
+
reference_nodes.size == references.size
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def reference_nodes
|
|
86
|
+
@reference_nodes ||= references.filter_map { const_node_at(it.location) }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def const_node_at(location)
|
|
90
|
+
SourceConstants.for(source_root, uri: location.uri).at(location)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def source_root
|
|
94
|
+
@source_root ||= nested_class.then do |node|
|
|
95
|
+
node = node.parent while node.parent
|
|
96
|
+
node
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def safe_reference?(node)
|
|
101
|
+
namespace_prefix?(node) || locally_consumed_construction?(node)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def namespace_prefix?(node)
|
|
105
|
+
node.parent.const_type? && node.parent.namespace.equal?(node)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def locally_consumed_construction?(node)
|
|
109
|
+
node.parent.call_type? && node.parent.receiver.equal?(node) && construction?(node.parent) &&
|
|
110
|
+
!handed_off?(node.parent)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def construction?(send_node)
|
|
114
|
+
CONSTRUCTION_METHODS.include?(send_node.method_name)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def handed_off?(candidate)
|
|
118
|
+
CarriedValue.new(candidate).outermost.then do |value|
|
|
119
|
+
value.parent&.type?(*HANDOFF_TYPES) || passed_as_argument?(value)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def passed_as_argument?(value)
|
|
124
|
+
value.parent&.call_type? && !value.parent.receiver.equal?(value)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def values_confined?
|
|
128
|
+
!class_escapes? && !instance_escapes? && method_dispatch_confined? &&
|
|
129
|
+
implicit_constructions.none? { implicit_construction_escapes?(it) }
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def class_escapes?
|
|
133
|
+
class_values.any? { handed_off?(it) } || opaque_class_body_call?
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def class_values
|
|
137
|
+
explicit_class_values + implicit_class_values
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def explicit_class_values
|
|
141
|
+
self_nodes.select do |self_node|
|
|
142
|
+
!structural_self?(self_node) && possible_class_side?(self_node)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def self_nodes
|
|
147
|
+
@self_nodes ||= nodes_in(nested_class.body, :self)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def possible_class_side?(node)
|
|
151
|
+
RuboCop::Callbacksystems::Methods::Domain.new(node).then do |domain|
|
|
152
|
+
if domain.container.equal?(nested_class)
|
|
153
|
+
domain.singleton?
|
|
154
|
+
else
|
|
155
|
+
opaque_block_in_nested_class?(domain.container)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def opaque_block_in_nested_class?(container)
|
|
161
|
+
any_block_type?(container) && enclosing_class_or_module_of(container).equal?(nested_class)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def implicit_class_values
|
|
165
|
+
sends.select do |send_node|
|
|
166
|
+
VALUE_EXPOSURE_METHODS.include?(send_node.method_name) && call_on_self?(send_node) &&
|
|
167
|
+
possible_class_side?(send_node)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def opaque_class_body_call?
|
|
172
|
+
sends.any? do |send_node|
|
|
173
|
+
direct_class_body_call?(send_node) && call_on_self?(send_node) &&
|
|
174
|
+
!trusted_class_body_call?(send_node)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def direct_class_body_call?(send_node)
|
|
179
|
+
enclosing_method_of(send_node).nil? && enclosing_class_or_module_of(send_node).equal?(nested_class)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def trusted_class_body_call?(send_node)
|
|
183
|
+
CLASS_BODY_PRIMITIVES.include?(send_node.method_name) && !class_method_redefined?(send_node.method_name)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def class_method_redefined?(method_name)
|
|
187
|
+
project_index["Class"].find_member("#{method_name}()")&.definitions&.any? || false
|
|
188
|
+
rescue
|
|
189
|
+
true
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def instance_escapes?
|
|
193
|
+
instance_values.any? { handed_off?(it) }
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def instance_values
|
|
197
|
+
explicit_instance_values + implicit_instance_values
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def explicit_instance_values
|
|
201
|
+
self_nodes.select { possible_instance_side?(it) }
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def possible_instance_side?(node)
|
|
205
|
+
RuboCop::Callbacksystems::Methods::Domain.new(node).then do |domain|
|
|
206
|
+
(domain.container.equal?(nested_class) && !domain.singleton?) ||
|
|
207
|
+
opaque_block_in_nested_class?(domain.container)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def implicit_instance_values
|
|
212
|
+
sends.select do |send_node|
|
|
213
|
+
VALUE_EXPOSURE_METHODS.include?(send_node.method_name) && call_on_self?(send_node) &&
|
|
214
|
+
possible_instance_side?(send_node)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def method_dispatch_confined?
|
|
219
|
+
RuboCop::Callbacksystems::ProjectIndex::NestedClassMethodDispatch.new(nested_class, declaration:).confined?
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def implicit_constructions
|
|
223
|
+
sends.select do |send_node|
|
|
224
|
+
construction?(send_node) && call_on_self?(send_node) && possible_class_side?(send_node)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def implicit_construction_escapes?(construction)
|
|
229
|
+
opaque_block_in_nested_class?(RuboCop::Callbacksystems::Methods::Domain.new(construction).container) ||
|
|
230
|
+
handed_off?(construction)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
class SourceConstants
|
|
234
|
+
class << self
|
|
235
|
+
def for(source_root, uri:)
|
|
236
|
+
context = Context.new(source_root, uri)
|
|
237
|
+
|
|
238
|
+
cached.then do |cached_context, constants|
|
|
239
|
+
if cached_context&.same_source?(context)
|
|
240
|
+
constants
|
|
241
|
+
else
|
|
242
|
+
new(context).tap { self.cached = [ context, it ] }
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
private
|
|
248
|
+
attr_accessor :cached
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def initialize(context)
|
|
252
|
+
@by_location = context.source_root.each_node(:const).group_by do |node|
|
|
253
|
+
RuboCop::Callbacksystems::ProjectIndex::Location.for_ast(node.loc.name, uri: context.uri)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def at(location)
|
|
258
|
+
key = RuboCop::Callbacksystems::ProjectIndex::Location.for_rubydex(location)
|
|
259
|
+
by_location.fetch(key) { [] }.then { it.first if it.one? }
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
private
|
|
263
|
+
attr_reader :by_location
|
|
264
|
+
|
|
265
|
+
class Context < Data.define(:source_root, :uri)
|
|
266
|
+
def same_source?(other)
|
|
267
|
+
source_root.equal?(other.source_root) && uri == other.uri
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
class CarriedValue
|
|
273
|
+
def initialize(node)
|
|
274
|
+
@node = node
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def outermost
|
|
278
|
+
node.then do |current|
|
|
279
|
+
current = current.parent while carries_value?(current.parent, child: current)
|
|
280
|
+
current
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
private
|
|
285
|
+
attr_reader :node
|
|
286
|
+
|
|
287
|
+
def carries_value?(parent, child:)
|
|
288
|
+
case parent&.type
|
|
289
|
+
when :begin, :kwbegin then parent.children.last.equal?(child)
|
|
290
|
+
when :if then parent.children.drop(1).any?(child)
|
|
291
|
+
when :send, :csend then parent.receiver.equal?(child)
|
|
292
|
+
when :class, :module, :sclass then parent.body.equal?(child)
|
|
293
|
+
else false
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Whether self-dispatch inside a nested class stays on methods the class itself owns.
|
|
2
|
+
class RuboCop::Callbacksystems::ProjectIndex::NestedClassMethodDispatch
|
|
3
|
+
include RuboCop::Callbacksystems::Helpers
|
|
4
|
+
|
|
5
|
+
def initialize(nested_class, declaration:)
|
|
6
|
+
@nested_class = nested_class
|
|
7
|
+
@declaration = declaration
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def confined?
|
|
11
|
+
self_calls.all? { owned_method_call?(it) } && !super_dispatch?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
attr_reader :nested_class, :declaration
|
|
16
|
+
|
|
17
|
+
def self_calls
|
|
18
|
+
nodes_in(nested_class.body, :send, :csend).select do |send_node|
|
|
19
|
+
call_on_self?(send_node) && enclosing_method_of(send_node) && method_owner_of(send_node)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def method_owner_of(send_node)
|
|
24
|
+
RuboCop::Callbacksystems::Methods::Domain.new(send_node).then do |domain|
|
|
25
|
+
owner_for(domain.identity) if domain.container.equal?(nested_class)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def owner_for(identity)
|
|
30
|
+
if identity.empty?
|
|
31
|
+
declaration
|
|
32
|
+
elsif identity.all? { it == :self }
|
|
33
|
+
declaration.singleton_class
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def owned_method_call?(send_node)
|
|
38
|
+
method_owner_of(send_node).then do |owner|
|
|
39
|
+
owner.member("#{send_node.method_name}()").present?
|
|
40
|
+
end
|
|
41
|
+
rescue
|
|
42
|
+
false
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def super_dispatch?
|
|
46
|
+
nodes_in(nested_class.body, :super, :zsuper).any? do |super_node|
|
|
47
|
+
enclosing_class_or_module_of(super_node).equal?(nested_class)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
require "digest"
|
|
2
|
+
|
|
3
|
+
class RuboCop::Callbacksystems::ProjectIndex::Reading
|
|
4
|
+
extend RuboCop::Callbacksystems::ProjectIndex::Cache
|
|
5
|
+
|
|
6
|
+
INCOMPLETE_DIAGNOSTICS = %w[
|
|
7
|
+
ParseError DynamicConstantReference DynamicAncestor DynamicSingletonDefinition
|
|
8
|
+
]
|
|
9
|
+
OPAQUE_CONSTANT_REFLECTIONS = %w[
|
|
10
|
+
const_get const_set remove_const autoload constantize safe_constantize
|
|
11
|
+
eval class_eval class_exec module_eval module_exec instance_eval instance_exec
|
|
12
|
+
each_object constants descendants subclasses unsafe_load unsafe_load_file
|
|
13
|
+
].to_set
|
|
14
|
+
OPAQUE_DISPATCH_METHODS = %w[ send __send__ public_send method public_method ].to_set
|
|
15
|
+
OPAQUE_RECEIVER_METHODS = { "Marshal" => %w[ load restore ].to_set }
|
|
16
|
+
RECEIVER_SEPARATOR_WIDTHS = [ 1, 2 ]
|
|
17
|
+
|
|
18
|
+
def initialize(project_index)
|
|
19
|
+
@project_index = project_index
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def checksum
|
|
23
|
+
@checksum ||= DocumentsChecksum.new(project_index).to_s
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def reliable?
|
|
27
|
+
return @reliable if defined?(@reliable)
|
|
28
|
+
|
|
29
|
+
@reliable = RuboCop::Callbacksystems::ProjectIndex::Coverage.complete?(project_index) &&
|
|
30
|
+
!diagnostics.any_named?(*INCOMPLETE_DIAGNOSTICS) &&
|
|
31
|
+
!opaque_reflection?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
attr_reader :project_index
|
|
36
|
+
|
|
37
|
+
def diagnostics
|
|
38
|
+
@diagnostics ||= RuboCop::Callbacksystems::ProjectIndex::Diagnostics.for(project_index)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def opaque_reflection?
|
|
42
|
+
return @opaque_reflection if defined?(@opaque_reflection)
|
|
43
|
+
|
|
44
|
+
@opaque_reflection = project_index.method_references.any? do |reference|
|
|
45
|
+
method_name = reference.name.delete_suffix("()")
|
|
46
|
+
OPAQUE_CONSTANT_REFLECTIONS.include?(method_name) ||
|
|
47
|
+
(OPAQUE_DISPATCH_METHODS.include?(method_name) && opaque_dispatch_receiver?(reference.receiver)) ||
|
|
48
|
+
opaque_receiver_method?(reference, method_name:)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def opaque_dispatch_receiver?(receiver)
|
|
53
|
+
receiver.nil? || receiver.is_a?(Rubydex::SingletonClass)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def opaque_receiver_method?(reference, method_name:)
|
|
57
|
+
receiver_names_of(reference).any? do |receiver_name|
|
|
58
|
+
OPAQUE_RECEIVER_METHODS.fetch(receiver_name) { [] }.include?(method_name)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def receiver_names_of(reference)
|
|
63
|
+
direct_receiver_name_of(reference).then do |name|
|
|
64
|
+
name ? Set[name] : constant_receiver_names.fetch(reference_location_key(reference)) { Set.new }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def direct_receiver_name_of(reference)
|
|
69
|
+
receiver = reference.receiver
|
|
70
|
+
receiver.attached_class.name if receiver.is_a?(Rubydex::SingletonClass)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def constant_receiver_names
|
|
74
|
+
@constant_receiver_names ||= project_index.constant_references.each_with_object({}) do |reference, names|
|
|
75
|
+
RECEIVER_SEPARATOR_WIDTHS.each do |separator_width|
|
|
76
|
+
key = location_key(reference.location, column: reference.location.end_column + separator_width)
|
|
77
|
+
(names[key] ||= Set.new) << constant_name_of(reference)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def location_key(location, column:)
|
|
83
|
+
[ location.uri, location.start_line, column ]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def constant_name_of(reference)
|
|
87
|
+
if reference.is_a?(Rubydex::ResolvedConstantReference)
|
|
88
|
+
reference.declaration.name
|
|
89
|
+
else
|
|
90
|
+
reference.name.delete_prefix("<").delete_suffix(">")
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def reference_location_key(reference)
|
|
95
|
+
location_key(reference.location, column: reference.location.start_column)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
class DocumentsChecksum
|
|
99
|
+
def initialize(project_index)
|
|
100
|
+
@project_index = project_index
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def to_s
|
|
104
|
+
Digest::SHA256.new.tap do |digest|
|
|
105
|
+
documents.each do |document|
|
|
106
|
+
digest << document.uri << "\0" << checksum_for(document) << "\0"
|
|
107
|
+
end
|
|
108
|
+
end.hexdigest
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
attr_reader :project_index
|
|
113
|
+
|
|
114
|
+
def documents
|
|
115
|
+
project_index.documents.select { it.uri.start_with?(RuboCop::Cop::ProjectIndexHelp::FILE_URI_PREFIX) }
|
|
116
|
+
.sort_by(&:uri)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def checksum_for(document)
|
|
120
|
+
Digest::SHA256.file(path_for(document)).hexdigest
|
|
121
|
+
rescue SystemCallError => error
|
|
122
|
+
error.class.name
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def path_for(document)
|
|
126
|
+
RuboCop::Callbacksystems::ProjectIndex::SourceFile.for_document(document).path
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|