rubocop 1.89.0 → 1.91.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/config/default.yml +309 -14
- data/config/obsoletion.yml +9 -0
- data/exe/rubocop +1 -1
- data/lib/rubocop/cached_data.rb +7 -2
- data/lib/rubocop/changed_files.rb +112 -0
- data/lib/rubocop/cli/command/execute_runner.rb +52 -1
- data/lib/rubocop/cli.rb +11 -7
- data/lib/rubocop/comment_config/directive_range.rb +34 -0
- data/lib/rubocop/comment_config/disable_next.rb +143 -0
- data/lib/rubocop/comment_config/push_pop.rb +55 -0
- data/lib/rubocop/comment_config.rb +50 -64
- data/lib/rubocop/config.rb +33 -5
- data/lib/rubocop/config_loader.rb +13 -6
- data/lib/rubocop/config_loader_resolver.rb +50 -9
- data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
- data/lib/rubocop/config_obsoletion/removed_cop.rb +8 -0
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/config_validator.rb +19 -5
- data/lib/rubocop/cop/autocorrect_logic.rb +8 -0
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/base.rb +49 -5
- data/lib/rubocop/cop/corrector.rb +3 -3
- data/lib/rubocop/cop/correctors.rb +2 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
- data/lib/rubocop/cop/generator.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -2
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -0
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/class_structure.rb +102 -26
- data/lib/rubocop/cop/layout/comment_indentation.rb +8 -5
- data/lib/rubocop/cop/layout/else_alignment.rb +1 -0
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -2
- data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/extra_spacing.rb +105 -3
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +21 -1
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +17 -4
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +6 -5
- data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -2
- data/lib/rubocop/cop/layout/line_length.rb +20 -3
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -2
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -5
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +14 -3
- data/lib/rubocop/cop/layout/space_around_operators.rb +12 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +2 -4
- data/lib/rubocop/cop/lint/ambiguous_range.rb +1 -2
- data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -0
- data/lib/rubocop/cop/lint/constant_reassignment.rb +17 -11
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +165 -15
- data/lib/rubocop/cop/lint/deprecated_reference.rb +11 -2
- data/lib/rubocop/cop/lint/duplicate_methods.rb +113 -15
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
- data/lib/rubocop/cop/lint/interpolation_check.rb +1 -2
- data/lib/rubocop/cop/lint/literal_as_condition.rb +11 -8
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +3 -6
- data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +185 -0
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +25 -12
- data/lib/rubocop/cop/lint/name_typo.rb +53 -6
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -0
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +17 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +122 -29
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +47 -7
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -2
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +1 -2
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +1 -2
- data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -2
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -2
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +2 -4
- data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
- data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +1 -2
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -2
- data/lib/rubocop/cop/lint/unreachable_code.rb +1 -2
- data/lib/rubocop/cop/lint/unused_private_method.rb +94 -17
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -2
- data/lib/rubocop/cop/lint/useless_assignment.rb +1 -2
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +36 -0
- data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -2
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +61 -7
- data/lib/rubocop/cop/lint/void.rb +1 -2
- data/lib/rubocop/cop/lint.rb +3 -0
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -2
- data/lib/rubocop/cop/migration/department_name.rb +1 -2
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -2
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +11 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +7 -4
- data/lib/rubocop/cop/mixin/hash_subset.rb +1 -2
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +7 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +62 -6
- data/lib/rubocop/cop/mixin/range_help.rb +1 -2
- data/lib/rubocop/cop/mixin/statement_modifier.rb +13 -7
- data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -4
- data/lib/rubocop/cop/mixin.rb +6 -2
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +16 -0
- data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +2 -4
- data/lib/rubocop/cop/naming/method_name.rb +5 -2
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -2
- data/lib/rubocop/cop/offense.rb +27 -4
- data/lib/rubocop/cop/registry.rb +43 -11
- data/lib/rubocop/cop/severity.rb +12 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +1 -2
- data/lib/rubocop/cop/style/arguments_forwarding.rb +5 -8
- data/lib/rubocop/cop/style/array_first_last.rb +1 -2
- data/lib/rubocop/cop/style/bitwise_predicate.rb +1 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +3 -6
- data/lib/rubocop/cop/style/case_like_if.rb +5 -7
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -2
- data/lib/rubocop/cop/style/combinable_loops.rb +1 -2
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -2
- data/lib/rubocop/cop/style/constant_visibility.rb +6 -3
- data/lib/rubocop/cop/style/copyright.rb +1 -2
- data/lib/rubocop/cop/style/data_inheritance.rb +14 -0
- data/lib/rubocop/cop/style/directive_scope.rb +304 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +83 -13
- data/lib/rubocop/cop/style/documentation_method.rb +1 -9
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +1 -2
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +12 -2
- data/lib/rubocop/cop/style/endless_method.rb +31 -12
- data/lib/rubocop/cop/style/file_null.rb +2 -2
- data/lib/rubocop/cop/style/float_division.rb +10 -16
- data/lib/rubocop/cop/style/for.rb +5 -0
- data/lib/rubocop/cop/style/format_string_token.rb +1 -2
- data/lib/rubocop/cop/style/guard_clause.rb +5 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -2
- data/lib/rubocop/cop/style/hash_lookup_method.rb +3 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -2
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +2 -4
- data/lib/rubocop/cop/style/if_inside_else.rb +1 -2
- data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -2
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +1 -2
- data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -2
- data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -2
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -2
- data/lib/rubocop/cop/style/negative_array_index.rb +2 -4
- data/lib/rubocop/cop/style/nested_modifier.rb +9 -4
- data/lib/rubocop/cop/style/nil_comparison.rb +36 -9
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +18 -2
- data/lib/rubocop/cop/style/not.rb +3 -1
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +1 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -2
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
- data/lib/rubocop/cop/style/redundant_assignment.rb +1 -2
- data/lib/rubocop/cop/style/redundant_condition.rb +6 -8
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +11 -3
- data/lib/rubocop/cop/style/redundant_each.rb +1 -2
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +2 -4
- data/lib/rubocop/cop/style/redundant_parentheses.rb +13 -5
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +1 -2
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +6 -6
- data/lib/rubocop/cop/style/redundant_return.rb +1 -2
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -2
- data/lib/rubocop/cop/style/safe_navigation.rb +1 -2
- data/lib/rubocop/cop/style/sample.rb +11 -6
- data/lib/rubocop/cop/style/select_by_regexp.rb +1 -2
- data/lib/rubocop/cop/style/semicolon.rb +2 -4
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -2
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +2 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +18 -5
- data/lib/rubocop/cop/style/struct_inheritance.rb +14 -0
- data/lib/rubocop/cop/style/super_arguments.rb +1 -2
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -2
- data/lib/rubocop/cop/style/time_now.rb +41 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +1 -2
- data/lib/rubocop/cop/style.rb +2 -1
- data/lib/rubocop/cop/team.rb +11 -3
- data/lib/rubocop/cop/util.rb +3 -5
- data/lib/rubocop/cop/variable_force/variable.rb +1 -2
- data/lib/rubocop/cops_documentation_generator.rb +26 -8
- data/lib/rubocop/directive_comment.rb +73 -10
- data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -1
- data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
- data/lib/rubocop/formatter/formatter_set.rb +2 -1
- data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
- data/lib/rubocop/formatter/html_formatter.rb +2 -4
- data/lib/rubocop/formatter/json_formatter.rb +11 -6
- data/lib/rubocop/formatter/junit_formatter.rb +26 -9
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -2
- data/lib/rubocop/formatter/sarif_formatter.rb +181 -0
- data/lib/rubocop/formatter/simple_text_formatter.rb +4 -3
- data/lib/rubocop/formatter/tap_formatter.rb +3 -1
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -2
- data/lib/rubocop/formatter.rb +1 -0
- data/lib/rubocop/lockfile.rb +18 -0
- data/lib/rubocop/lsp/diagnostic.rb +4 -8
- data/lib/rubocop/lsp/routes.rb +48 -19
- data/lib/rubocop/magic_comment.rb +27 -0
- data/lib/rubocop/mcp/server.rb +1 -2
- data/lib/rubocop/options.rb +69 -7
- data/lib/rubocop/path_util.rb +2 -3
- data/lib/rubocop/plugin/configuration_integrator.rb +6 -3
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/rake_task.rb +1 -2
- data/lib/rubocop/remote_config.rb +4 -4
- data/lib/rubocop/result_cache.rb +16 -5
- data/lib/rubocop/rspec/expect_offense.rb +2 -4
- data/lib/rubocop/rspec/shared_contexts.rb +4 -2
- data/lib/rubocop/runner.rb +90 -44
- data/lib/rubocop/server/cache.rb +1 -2
- data/lib/rubocop/server/cli.rb +2 -4
- data/lib/rubocop/server.rb +14 -0
- data/lib/rubocop/target_finder.rb +4 -1
- data/lib/rubocop/todo_audit.rb +111 -0
- data/lib/rubocop/unified_diff.rb +257 -0
- data/lib/rubocop/version.rb +3 -5
- data/lib/rubocop.rb +7 -1
- data/lib/ruby_lsp/rubocop/addon.rb +1 -2
- metadata +18 -6
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
|
@@ -25,21 +25,21 @@ module RuboCop
|
|
|
25
25
|
super
|
|
26
26
|
|
|
27
27
|
@test_case_elements = []
|
|
28
|
+
@config_store = nil
|
|
28
29
|
|
|
29
30
|
reset_count
|
|
30
31
|
end
|
|
31
32
|
|
|
33
|
+
def file_started(_file, options)
|
|
34
|
+
@config_store = options[:config_store]
|
|
35
|
+
end
|
|
36
|
+
|
|
32
37
|
def file_finished(file, offenses)
|
|
33
38
|
@inspected_file_count += 1
|
|
39
|
+
@offense_count += offenses.count
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
# the original rubocop-junit-formatter.
|
|
37
|
-
# https://github.com/mikian/rubocop-junit-formatter/blob/v0.1.4/lib/rubocop/formatter/junit_formatter.rb#L9
|
|
38
|
-
#
|
|
39
|
-
# In the future, it would be preferable to return only enabled cops.
|
|
40
|
-
Cop::Registry.all.each do |cop|
|
|
41
|
+
cops_for(file).each do |cop|
|
|
41
42
|
target_offenses = offenses_for_cop(offenses, cop)
|
|
42
|
-
@offense_count += target_offenses.count
|
|
43
43
|
|
|
44
44
|
next unless relevant_for_output?(options, target_offenses)
|
|
45
45
|
|
|
@@ -47,7 +47,7 @@ module RuboCop
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
# rubocop:disable Layout/LineLength,Metrics/AbcSize,Metrics/MethodLength
|
|
50
|
+
# rubocop:disable-next Layout/LineLength,Metrics/AbcSize,Metrics/MethodLength -- the XML is emitted line by line
|
|
51
51
|
def finished(_inspected_files)
|
|
52
52
|
output.puts %(<?xml version='1.0'?>)
|
|
53
53
|
output.puts %(<testsuites>)
|
|
@@ -70,10 +70,17 @@ module RuboCop
|
|
|
70
70
|
output.puts %( </testsuite>)
|
|
71
71
|
output.puts %(</testsuites>)
|
|
72
72
|
end
|
|
73
|
-
# rubocop:enable Layout/LineLength,Metrics/AbcSize,Metrics/MethodLength
|
|
74
73
|
|
|
75
74
|
private
|
|
76
75
|
|
|
76
|
+
def cops_for(file)
|
|
77
|
+
# `file_started` is not called when this formatter is used directly through the API,
|
|
78
|
+
# in which case all cops are returned for compatibility.
|
|
79
|
+
return Cop::Registry.all if @config_store.nil?
|
|
80
|
+
|
|
81
|
+
registry.enabled(@config_store.for_file(file))
|
|
82
|
+
end
|
|
83
|
+
|
|
77
84
|
def relevant_for_output?(options, target_offenses)
|
|
78
85
|
!options[:display_only_failed] || target_offenses.any?
|
|
79
86
|
end
|
|
@@ -91,6 +98,16 @@ module RuboCop
|
|
|
91
98
|
end
|
|
92
99
|
end
|
|
93
100
|
|
|
101
|
+
# Filtering by badge keeps lazy-loaded cops unloaded; `Registry#enabled` then loads only
|
|
102
|
+
# the enabled cops, the same set the runner mobilizes.
|
|
103
|
+
def registry
|
|
104
|
+
@registry ||= Cop::Registry.global.filter_by_badge(options) do |badge|
|
|
105
|
+
next false if badge.department == :Test || badge.match_name?(options[:except])
|
|
106
|
+
|
|
107
|
+
options[:only].nil? || badge.match_name?(options[:only])
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
94
111
|
def classname_attribute_value(file)
|
|
95
112
|
@classname_attribute_value_cache ||= Hash.new do |hash, key|
|
|
96
113
|
hash[key] = key.delete_suffix('.rb').gsub("#{PathUtil.pwd}/", '').tr('/', '.')
|
|
@@ -52,7 +52,7 @@ module RuboCop
|
|
|
52
52
|
report_summary(@offense_counts, @offending_files_count)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
# rubocop:disable Metrics/AbcSize
|
|
55
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
56
56
|
def report_summary(offense_counts, offending_files_count)
|
|
57
57
|
per_cop_counts = ordered_offense_counts(offense_counts)
|
|
58
58
|
total_count = total_offense_count(offense_counts)
|
|
@@ -68,7 +68,6 @@ module RuboCop
|
|
|
68
68
|
|
|
69
69
|
output.puts
|
|
70
70
|
end
|
|
71
|
-
# rubocop:enable Metrics/AbcSize
|
|
72
71
|
|
|
73
72
|
def ordered_offense_counts(offense_counts)
|
|
74
73
|
offense_counts.sort_by { |k, v| [-v, k] }.to_h
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'digest'
|
|
4
|
+
|
|
5
|
+
module RuboCop
|
|
6
|
+
module Formatter
|
|
7
|
+
# This formatter formats the report data in SARIF 2.1.0, the OASIS standard
|
|
8
|
+
# for static analysis results. It's understood by GitHub code scanning,
|
|
9
|
+
# Azure DevOps, and other tools that aggregate analyzer output.
|
|
10
|
+
#
|
|
11
|
+
# SARIF only knows three severity levels, so RuboCop's `info`, `refactor`
|
|
12
|
+
# and `convention` severities are all reported as `note`.
|
|
13
|
+
class SARIFFormatter < BaseFormatter
|
|
14
|
+
SCHEMA_URI = 'https://json.schemastore.org/sarif-2.1.0.json'
|
|
15
|
+
SARIF_VERSION = '2.1.0'
|
|
16
|
+
INFORMATION_URI = 'https://rubocop.org'
|
|
17
|
+
|
|
18
|
+
SEVERITY_LEVELS = {
|
|
19
|
+
info: 'note',
|
|
20
|
+
refactor: 'note',
|
|
21
|
+
convention: 'note',
|
|
22
|
+
warning: 'warning',
|
|
23
|
+
error: 'error',
|
|
24
|
+
fatal: 'error'
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
def initialize(output, options = {})
|
|
28
|
+
super
|
|
29
|
+
|
|
30
|
+
@rules = []
|
|
31
|
+
@rule_indexes = {}
|
|
32
|
+
@results = []
|
|
33
|
+
@config_store = nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def file_started(_file, options)
|
|
37
|
+
@config_store = options[:config_store]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def file_finished(file, offenses)
|
|
41
|
+
offenses.each do |offense|
|
|
42
|
+
@results << result_for(file, offense)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def finished(_inspected_files)
|
|
47
|
+
output.write(report.to_json)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def report
|
|
53
|
+
{
|
|
54
|
+
'$schema': SCHEMA_URI,
|
|
55
|
+
version: SARIF_VERSION,
|
|
56
|
+
runs: [{ tool: { driver: driver }, results: @results }]
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def driver
|
|
61
|
+
{
|
|
62
|
+
name: 'RuboCop',
|
|
63
|
+
version: RuboCop::Version::STRING,
|
|
64
|
+
semanticVersion: RuboCop::Version::STRING,
|
|
65
|
+
informationUri: INFORMATION_URI,
|
|
66
|
+
rules: @rules
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def result_for(file, offense)
|
|
71
|
+
result = {
|
|
72
|
+
ruleId: offense.cop_name,
|
|
73
|
+
ruleIndex: rule_index_for(file, offense),
|
|
74
|
+
level: SEVERITY_LEVELS.fetch(offense.severity.name, 'warning'),
|
|
75
|
+
message: { text: offense.message },
|
|
76
|
+
locations: [location_for(file, offense)],
|
|
77
|
+
partialFingerprints: fingerprints_for(offense)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# Suppressed offenses are only reported under `--display-suppressed`.
|
|
81
|
+
# SARIF has a first-class representation for them, so consumers can
|
|
82
|
+
# tell them apart from offenses that were never triggered.
|
|
83
|
+
result[:suppressions] = [suppression_for(offense)] if offense.disabled?
|
|
84
|
+
result
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# The URI is relative to the working directory, which is what consumers
|
|
88
|
+
# expect to resolve against their own checkout. No `uriBaseId`: it would
|
|
89
|
+
# have to be declared under `originalUriBaseIds` to mean anything, and
|
|
90
|
+
# every consumer that matters resolves relative paths without it.
|
|
91
|
+
def location_for(file, offense)
|
|
92
|
+
{
|
|
93
|
+
physicalLocation: {
|
|
94
|
+
artifactLocation: { uri: uri_for(file) },
|
|
95
|
+
region: region_for(offense)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def region_for(offense)
|
|
101
|
+
# SARIF columns are 1-based and `endColumn` points at the character
|
|
102
|
+
# *after* the region, while `real_last_column` is the last character.
|
|
103
|
+
{
|
|
104
|
+
startLine: offense.first_line,
|
|
105
|
+
startColumn: offense.real_column,
|
|
106
|
+
endLine: offense.last_line,
|
|
107
|
+
endColumn: offense.real_last_column + 1
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# GitHub uses these to match an alert across runs. Without them it falls
|
|
112
|
+
# back to the file path, which makes alerts churn whenever a file moves.
|
|
113
|
+
def fingerprints_for(offense)
|
|
114
|
+
source_line = offense.location.source_line
|
|
115
|
+
{ primaryLocationLineHash: Digest::SHA256.hexdigest("#{offense.cop_name}#{source_line}") }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def suppression_for(offense)
|
|
119
|
+
suppression = { kind: 'inSource' }
|
|
120
|
+
suppression[:justification] = offense.justification if offense.justification
|
|
121
|
+
suppression
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def rule_index_for(file, offense)
|
|
125
|
+
@rule_indexes[offense.cop_name] ||= begin
|
|
126
|
+
@rules << rule_for(file, offense)
|
|
127
|
+
@rules.size - 1
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def rule_for(file, offense)
|
|
132
|
+
cop_class = Cop::Registry.global.find_by_cop_name(offense.cop_name)
|
|
133
|
+
description = description_for(file, offense)
|
|
134
|
+
help_uri = cop_class && Cop::Documentation.url_for(cop_class, config_for(file))
|
|
135
|
+
|
|
136
|
+
rule = {
|
|
137
|
+
id: offense.cop_name,
|
|
138
|
+
name: offense.cop_name,
|
|
139
|
+
shortDescription: { text: description },
|
|
140
|
+
fullDescription: { text: description },
|
|
141
|
+
help: help_for(description, help_uri),
|
|
142
|
+
defaultConfiguration: { level: default_level_for(file, offense, cop_class) },
|
|
143
|
+
properties: { tags: [offense.cop_name.split('/').first] }
|
|
144
|
+
}
|
|
145
|
+
rule[:helpUri] = help_uri if help_uri
|
|
146
|
+
rule
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def help_for(description, help_uri)
|
|
150
|
+
help = { text: description }
|
|
151
|
+
help[:markdown] = "#{description}\n\n[Documentation](#{help_uri})" if help_uri
|
|
152
|
+
help
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def description_for(file, offense)
|
|
156
|
+
cop_config(file, offense)['Description'] || offense.cop_name
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def default_level_for(file, offense, cop_class)
|
|
160
|
+
severity = cop_config(file, offense)['Severity'] ||
|
|
161
|
+
(cop_class&.lint? ? :warning : :convention)
|
|
162
|
+
|
|
163
|
+
SEVERITY_LEVELS.fetch(severity.to_sym, 'warning')
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def cop_config(file, offense)
|
|
167
|
+
config_for(file)&.for_cop(offense.cop_name) || {}
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# `file_started` is not called when a formatter is used directly through
|
|
171
|
+
# the API, so there may be no config to consult.
|
|
172
|
+
def config_for(file)
|
|
173
|
+
@config_store&.for_file(file)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def uri_for(file)
|
|
177
|
+
PathUtil.smart_path(file).tr('\\', '/')
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
@@ -86,7 +86,9 @@ module RuboCop
|
|
|
86
86
|
|
|
87
87
|
def message(offense)
|
|
88
88
|
message =
|
|
89
|
-
if offense.
|
|
89
|
+
if offense.disabled?
|
|
90
|
+
magenta('[Suppressed] ')
|
|
91
|
+
elsif offense.corrected_with_todo?
|
|
90
92
|
green('[Todo] ')
|
|
91
93
|
elsif offense.corrected?
|
|
92
94
|
green('[Corrected] ')
|
|
@@ -104,7 +106,7 @@ module RuboCop
|
|
|
104
106
|
include Colorizable
|
|
105
107
|
include TextUtil
|
|
106
108
|
|
|
107
|
-
# rubocop:disable Metrics/ParameterLists
|
|
109
|
+
# rubocop:disable-next Metrics/ParameterLists
|
|
108
110
|
def initialize(
|
|
109
111
|
file_count, offense_count, correction_count, correctable_count, rainbow,
|
|
110
112
|
safe_autocorrect: false
|
|
@@ -116,7 +118,6 @@ module RuboCop
|
|
|
116
118
|
@rainbow = rainbow
|
|
117
119
|
@safe_autocorrect = safe_autocorrect
|
|
118
120
|
end
|
|
119
|
-
# rubocop:enable Metrics/ParameterLists
|
|
120
121
|
|
|
121
122
|
def summary
|
|
122
123
|
if @correction_count.positive?
|
|
@@ -32,7 +32,7 @@ module RuboCop
|
|
|
32
32
|
report_summary(@offense_counts)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
# rubocop:disable Metrics/AbcSize
|
|
35
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
36
36
|
def report_summary(offense_counts)
|
|
37
37
|
per_file_counts = ordered_offense_counts(offense_counts)
|
|
38
38
|
total_count = total_offense_count(offense_counts)
|
|
@@ -50,7 +50,6 @@ module RuboCop
|
|
|
50
50
|
|
|
51
51
|
output.puts
|
|
52
52
|
end
|
|
53
|
-
# rubocop:enable Metrics/AbcSize
|
|
54
53
|
|
|
55
54
|
def ordered_offense_counts(offense_counts)
|
|
56
55
|
offense_counts.sort_by { |k, v| [-v, k] }.to_h
|
data/lib/rubocop/formatter.rb
CHANGED
|
@@ -24,6 +24,7 @@ module RuboCop
|
|
|
24
24
|
autoload :PacmanFormatter, 'rubocop/formatter/pacman_formatter'
|
|
25
25
|
autoload :ProgressFormatter, 'rubocop/formatter/progress_formatter'
|
|
26
26
|
autoload :QuietFormatter, 'rubocop/formatter/quiet_formatter'
|
|
27
|
+
autoload :SARIFFormatter, 'rubocop/formatter/sarif_formatter'
|
|
27
28
|
autoload :TapFormatter, 'rubocop/formatter/tap_formatter'
|
|
28
29
|
autoload :WorstOffendersFormatter, 'rubocop/formatter/worst_offenders_formatter'
|
|
29
30
|
|
data/lib/rubocop/lockfile.rb
CHANGED
|
@@ -59,6 +59,18 @@ module RuboCop
|
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
# Names of gems sourced from a local path, i.e. `path:` dependencies and the
|
|
63
|
+
# project's own gem when the `Gemfile` uses `gemspec`. Git sources are not
|
|
64
|
+
# included: their code lives outside the project, like a released gem's.
|
|
65
|
+
# @return [Array<String>]
|
|
66
|
+
def path_sourced_gem_names
|
|
67
|
+
return [] unless parser
|
|
68
|
+
|
|
69
|
+
parser.specs.filter_map do |spec|
|
|
70
|
+
spec.name if path_source?(spec.source)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
62
74
|
# Whether this lockfile includes the named gem, directly or indirectly.
|
|
63
75
|
# @param [String] name
|
|
64
76
|
# @return [Boolean]
|
|
@@ -68,6 +80,12 @@ module RuboCop
|
|
|
68
80
|
|
|
69
81
|
private
|
|
70
82
|
|
|
83
|
+
# `Bundler::Source::Git` is a subclass of `Bundler::Source::Path`, but a git
|
|
84
|
+
# source is a remote one.
|
|
85
|
+
def path_source?(source)
|
|
86
|
+
source.is_a?(::Bundler::Source::Path) && !source.is_a?(::Bundler::Source::Git)
|
|
87
|
+
end
|
|
88
|
+
|
|
71
89
|
# @return [Bundler::LockfileParser, nil]
|
|
72
90
|
def parser
|
|
73
91
|
return @parser if defined?(@parser)
|
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
|
35
35
|
code_actions
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
38
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength
|
|
39
39
|
def to_lsp_diagnostic(config)
|
|
40
40
|
highlighted = @offense.highlighted_area
|
|
41
41
|
|
|
@@ -61,7 +61,6 @@ module RuboCop
|
|
|
61
61
|
}
|
|
62
62
|
)
|
|
63
63
|
end
|
|
64
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
65
64
|
|
|
66
65
|
private
|
|
67
66
|
|
|
@@ -82,7 +81,7 @@ module RuboCop
|
|
|
82
81
|
LanguageServer::Protocol::Interface::CodeDescription.new(href: doc_url)
|
|
83
82
|
end
|
|
84
83
|
|
|
85
|
-
# rubocop:disable Metrics/MethodLength
|
|
84
|
+
# rubocop:disable-next Metrics/MethodLength
|
|
86
85
|
def autocorrect_action
|
|
87
86
|
LanguageServer::Protocol::Interface::CodeAction.new(
|
|
88
87
|
title: "Autocorrect #{@offense.cop_name}",
|
|
@@ -101,9 +100,8 @@ module RuboCop
|
|
|
101
100
|
is_preferred: true
|
|
102
101
|
)
|
|
103
102
|
end
|
|
104
|
-
# rubocop:enable Metrics/MethodLength
|
|
105
103
|
|
|
106
|
-
# rubocop:disable Metrics/MethodLength
|
|
104
|
+
# rubocop:disable-next Metrics/MethodLength
|
|
107
105
|
def offense_replacements
|
|
108
106
|
@offense.corrector.as_replacements.map do |range, replacement|
|
|
109
107
|
LanguageServer::Protocol::Interface::TextEdit.new(
|
|
@@ -121,9 +119,8 @@ module RuboCop
|
|
|
121
119
|
)
|
|
122
120
|
end
|
|
123
121
|
end
|
|
124
|
-
# rubocop:enable Metrics/MethodLength
|
|
125
122
|
|
|
126
|
-
# rubocop:disable Metrics/MethodLength
|
|
123
|
+
# rubocop:disable-next Metrics/MethodLength
|
|
127
124
|
def disable_line_action
|
|
128
125
|
LanguageServer::Protocol::Interface::CodeAction.new(
|
|
129
126
|
title: "Disable #{@offense.cop_name} for this line",
|
|
@@ -141,7 +138,6 @@ module RuboCop
|
|
|
141
138
|
)
|
|
142
139
|
)
|
|
143
140
|
end
|
|
144
|
-
# rubocop:enable Metrics/MethodLength
|
|
145
141
|
|
|
146
142
|
def line_disable_comment
|
|
147
143
|
DisableCommentEdits.new(
|
data/lib/rubocop/lsp/routes.rb
CHANGED
|
@@ -151,25 +151,13 @@ module RuboCop
|
|
|
151
151
|
return
|
|
152
152
|
end
|
|
153
153
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
@server.write(
|
|
162
|
-
id: request[:id],
|
|
163
|
-
method: 'workspace/applyEdit',
|
|
164
|
-
params: {
|
|
165
|
-
label: label,
|
|
166
|
-
edit: {
|
|
167
|
-
changes: {
|
|
168
|
-
uri => formatted
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
)
|
|
154
|
+
# Clients such as Eglot can invoke a command without arguments, so respond with
|
|
155
|
+
# an error instead of letting the server crash on a missing URI.
|
|
156
|
+
if (uri = document_uri_from(request))
|
|
157
|
+
write_formatting_edits(request, uri: uri, command: command, label: label)
|
|
158
|
+
else
|
|
159
|
+
write_invalid_arguments_error(request, command)
|
|
160
|
+
end
|
|
173
161
|
end
|
|
174
162
|
|
|
175
163
|
handle 'textDocument/willSave' do |_request|
|
|
@@ -219,6 +207,47 @@ module RuboCop
|
|
|
219
207
|
}
|
|
220
208
|
end
|
|
221
209
|
|
|
210
|
+
def document_uri_from(request)
|
|
211
|
+
argument = request.dig(:params, :arguments, 0)
|
|
212
|
+
|
|
213
|
+
argument[:uri] if argument.is_a?(Hash)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def write_formatting_edits(request, uri:, command:, label:)
|
|
217
|
+
formatted = nil
|
|
218
|
+
|
|
219
|
+
# The `workspace/executeCommand` is an LSP method triggered by intentional user actions,
|
|
220
|
+
# so the user's intention for autocorrection is respected.
|
|
221
|
+
LSP.disable { formatted = format_file(uri, command: command) }
|
|
222
|
+
|
|
223
|
+
@server.write(
|
|
224
|
+
id: request[:id],
|
|
225
|
+
method: 'workspace/applyEdit',
|
|
226
|
+
params: {
|
|
227
|
+
label: label,
|
|
228
|
+
edit: {
|
|
229
|
+
changes: {
|
|
230
|
+
uri => formatted
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def write_invalid_arguments_error(request, command)
|
|
238
|
+
message = "Missing document URI in arguments for #{command}"
|
|
239
|
+
|
|
240
|
+
@server.write(
|
|
241
|
+
id: request[:id],
|
|
242
|
+
error: LanguageServer::Protocol::Interface::ResponseError.new(
|
|
243
|
+
code: LanguageServer::Protocol::Constant::ErrorCodes::INVALID_PARAMS,
|
|
244
|
+
message: message
|
|
245
|
+
)
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
Logger.log(message)
|
|
249
|
+
end
|
|
250
|
+
|
|
222
251
|
def format_file(file_uri, command: nil)
|
|
223
252
|
unless (text = @text_cache[file_uri])
|
|
224
253
|
Logger.log("Format request arrived before text synchronized; skipping: `#{file_uri}'")
|
|
@@ -12,6 +12,7 @@ module RuboCop
|
|
|
12
12
|
encoding: '(?:en)?coding',
|
|
13
13
|
frozen_string_literal: 'frozen[_-]string[_-]literal',
|
|
14
14
|
rbs_inline: 'rbs_inline',
|
|
15
|
+
warn_indent: 'warn[_-]indent',
|
|
15
16
|
shareable_constant_value: 'shareable[_-]constant[_-]value',
|
|
16
17
|
typed: 'typed'
|
|
17
18
|
}.freeze
|
|
@@ -38,6 +39,7 @@ module RuboCop
|
|
|
38
39
|
frozen_string_literal_specified? ||
|
|
39
40
|
encoding_specified? ||
|
|
40
41
|
rbs_inline_specified? ||
|
|
42
|
+
warn_indent_specified? ||
|
|
41
43
|
shareable_constant_value_specified? ||
|
|
42
44
|
typed_specified?
|
|
43
45
|
end
|
|
@@ -77,6 +79,13 @@ module RuboCop
|
|
|
77
79
|
specified?(frozen_string_literal)
|
|
78
80
|
end
|
|
79
81
|
|
|
82
|
+
# Was a warn_indent specified?
|
|
83
|
+
#
|
|
84
|
+
# @return [Boolean]
|
|
85
|
+
def warn_indent_specified?
|
|
86
|
+
specified?(warn_indent)
|
|
87
|
+
end
|
|
88
|
+
|
|
80
89
|
# Was a shareable_constant_value specified?
|
|
81
90
|
#
|
|
82
91
|
# @return [Boolean]
|
|
@@ -100,6 +109,13 @@ module RuboCop
|
|
|
100
109
|
end
|
|
101
110
|
end
|
|
102
111
|
|
|
112
|
+
# Expose the `warn_indent` value.
|
|
113
|
+
#
|
|
114
|
+
# @return [String] for warn_indent config
|
|
115
|
+
def warn_indent
|
|
116
|
+
extract_warn_indent
|
|
117
|
+
end
|
|
118
|
+
|
|
103
119
|
# Expose the `shareable_constant_value` value coerced to a boolean if possible.
|
|
104
120
|
#
|
|
105
121
|
# @return [String] for shareable_constant_value config
|
|
@@ -216,6 +232,10 @@ module RuboCop
|
|
|
216
232
|
# Emacs comments cannot specify RBS::inline behavior.
|
|
217
233
|
def extract_rbs_inline_value; end
|
|
218
234
|
|
|
235
|
+
def extract_warn_indent
|
|
236
|
+
match(KEYWORDS[:warn_indent])
|
|
237
|
+
end
|
|
238
|
+
|
|
219
239
|
def extract_shareable_constant_value
|
|
220
240
|
match(KEYWORDS[:shareable_constant_value])
|
|
221
241
|
end
|
|
@@ -258,6 +278,9 @@ module RuboCop
|
|
|
258
278
|
# Vim comments cannot specify RBS::inline behavior.
|
|
259
279
|
def extract_rbs_inline_value; end
|
|
260
280
|
|
|
281
|
+
# Vim comments cannot specify indentation warning behavior.
|
|
282
|
+
def warn_indent; end
|
|
283
|
+
|
|
261
284
|
# Vim comments cannot specify shareable constant values behavior.
|
|
262
285
|
def shareable_constant_value; end
|
|
263
286
|
|
|
@@ -316,6 +339,10 @@ module RuboCop
|
|
|
316
339
|
extract(/\A\s*#\s*#{KEYWORDS[:rbs_inline]}:\s*#{TOKEN}\s*\z/io)
|
|
317
340
|
end
|
|
318
341
|
|
|
342
|
+
def extract_warn_indent
|
|
343
|
+
extract(/\A\s*#\s*#{KEYWORDS[:warn_indent]}:\s*#{TOKEN}\s*\z/io)
|
|
344
|
+
end
|
|
345
|
+
|
|
319
346
|
def extract_shareable_constant_value
|
|
320
347
|
extract(/\A\s*#\s*#{KEYWORDS[:shareable_constant_value]}:\s*#{TOKEN}\s*\z/io)
|
|
321
348
|
end
|
data/lib/rubocop/mcp/server.rb
CHANGED
|
@@ -156,7 +156,7 @@ module RuboCop
|
|
|
156
156
|
summary
|
|
157
157
|
end
|
|
158
158
|
|
|
159
|
-
# rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
|
|
159
|
+
# rubocop:disable-next Metrics/MethodLength, Metrics/ParameterLists
|
|
160
160
|
def build_tool(
|
|
161
161
|
name:, description:,
|
|
162
162
|
title:, destructive_hint:, idempotent_hint:, read_only_hint:, safety_required:
|
|
@@ -194,7 +194,6 @@ module RuboCop
|
|
|
194
194
|
::MCP::Tool::Response.new([{ type: 'text', text: e.message }], error: true)
|
|
195
195
|
end
|
|
196
196
|
end
|
|
197
|
-
# rubocop:enable Metrics/MethodLength, Metrics/ParameterLists
|
|
198
197
|
end
|
|
199
198
|
end
|
|
200
199
|
end
|