rubocop 1.86.1 → 1.87.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 +15 -1
- data/lib/rubocop/cli/command/auto_generate_config.rb +27 -1
- data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
- data/lib/rubocop/cli/command/show_docs_url.rb +3 -7
- data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
- data/lib/rubocop/cli.rb +6 -7
- data/lib/rubocop/comment_config.rb +12 -15
- data/lib/rubocop/config_loader.rb +17 -2
- data/lib/rubocop/config_loader_resolver.rb +11 -3
- data/lib/rubocop/config_store.rb +1 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +2 -1
- data/lib/rubocop/cop/base.rb +8 -2
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +33 -2
- data/lib/rubocop/cop/correctors.rb +28 -0
- data/lib/rubocop/cop/exclude_limit.rb +31 -5
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +4 -4
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
- data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +14 -5
- data/lib/rubocop/cop/layout/end_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/indentation_width.rb +13 -1
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +26 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/constant_reassignment.rb +36 -4
- data/lib/rubocop/cop/lint/constant_resolution.rb +5 -5
- data/lib/rubocop/cop/lint/deprecated_constants.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +5 -5
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +3 -3
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +3 -1
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_code.rb +2 -2
- data/lib/rubocop/cop/lint/useless_assignment.rb +3 -8
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +18 -7
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
- data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
- data/lib/rubocop/cop/mixin.rb +86 -0
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_method.rb +2 -2
- data/lib/rubocop/cop/naming/predicate_prefix.rb +1 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +8 -0
- data/lib/rubocop/cop/registry.rb +42 -25
- data/lib/rubocop/cop/security/io_methods.rb +1 -1
- data/lib/rubocop/cop/style/alias.rb +10 -1
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +8 -0
- data/lib/rubocop/cop/style/copyright.rb +21 -10
- data/lib/rubocop/cop/style/date_time.rb +2 -2
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
- data/lib/rubocop/cop/style/file_write.rb +18 -16
- data/lib/rubocop/cop/style/format_string.rb +4 -3
- data/lib/rubocop/cop/style/hash_conversion.rb +1 -1
- data/lib/rubocop/cop/style/hash_lookup_method.rb +12 -7
- data/lib/rubocop/cop/style/if_inside_else.rb +15 -2
- data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
- data/lib/rubocop/cop/style/min_max_comparison.rb +1 -1
- data/lib/rubocop/cop/style/module_member_existence_check.rb +6 -3
- data/lib/rubocop/cop/style/reduce_to_hash.rb +16 -0
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_self.rb +2 -2
- data/lib/rubocop/cop/style/regexp_literal.rb +31 -2
- data/lib/rubocop/cop/style/rescue_modifier.rb +3 -3
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
- data/lib/rubocop/cop/style/struct_inheritance.rb +13 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +3 -3
- data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
- data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
- data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
- data/lib/rubocop/cop/team.rb +86 -35
- data/lib/rubocop/file_patterns.rb +9 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +4 -1
- data/lib/rubocop/lsp/runtime.rb +1 -2
- data/lib/rubocop/options.rb +26 -4
- data/lib/rubocop/project_index_loader.rb +66 -0
- data/lib/rubocop/rspec/shared_contexts.rb +21 -0
- data/lib/rubocop/runner.rb +123 -57
- data/lib/rubocop/target_finder.rb +13 -6
- data/lib/rubocop/version.rb +20 -2
- data/lib/rubocop.rb +8 -96
- metadata +8 -3
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
# Common helpers for cops that consult the project-wide static-analysis index
|
|
6
|
+
# via `Cop::Base#project_index`.
|
|
7
|
+
#
|
|
8
|
+
# Mixed-in cops gain the `external_dependency_checksum` override that invalidates
|
|
9
|
+
# the `ResultCache` whenever the indexed project files change on disk.
|
|
10
|
+
# To run index-backed analysis, cops should simply check whether `project_index` is non-nil;
|
|
11
|
+
# the runner only exposes a non-nil index when the user opted in via `AllCops/UseProjectIndex`
|
|
12
|
+
# and the underlying gem is available.
|
|
13
|
+
module ProjectIndexHelp
|
|
14
|
+
BUILTIN_DOCUMENT_URI = 'rubydex:built-in'
|
|
15
|
+
FILE_URI_PREFIX = 'file://'
|
|
16
|
+
# Matches the spurious leading slash before a Windows drive letter that
|
|
17
|
+
# remains after stripping `file://` from a `file:///C:/...` URI.
|
|
18
|
+
WINDOWS_DRIVE_PREFIX = %r{\A/(?=[A-Za-z]:[/\\])}.freeze
|
|
19
|
+
|
|
20
|
+
def external_dependency_checksum
|
|
21
|
+
return nil unless project_index
|
|
22
|
+
|
|
23
|
+
@external_dependency_checksum ||= Digest::SHA1.hexdigest(
|
|
24
|
+
project_index_signature.join("\n")
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def project_index_signature
|
|
31
|
+
project_index.documents.filter_map do |doc|
|
|
32
|
+
uri = doc.uri
|
|
33
|
+
next if uri == BUILTIN_DOCUMENT_URI
|
|
34
|
+
|
|
35
|
+
path = uri.delete_prefix(FILE_URI_PREFIX).sub(WINDOWS_DRIVE_PREFIX, '')
|
|
36
|
+
mtime, size = begin
|
|
37
|
+
stat = File.stat(path)
|
|
38
|
+
[stat.mtime.to_f, stat.size]
|
|
39
|
+
rescue StandardError
|
|
40
|
+
[0, 0]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
"#{path}:#{mtime}:#{size}"
|
|
44
|
+
end.sort
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop # rubocop:disable Style/Documentation
|
|
5
|
+
# Autoloads mixin modules included by cops. Mixins are autoloaded to reduce the number of
|
|
6
|
+
# requires because they're used only when the relevant cop class is loaded.
|
|
7
|
+
|
|
8
|
+
autoload :ArrayMinSize, 'rubocop/cop/mixin/array_min_size'
|
|
9
|
+
autoload :ArraySyntax, 'rubocop/cop/mixin/array_syntax'
|
|
10
|
+
autoload :Alignment, 'rubocop/cop/mixin/alignment'
|
|
11
|
+
autoload :AllowedIdentifiers, 'rubocop/cop/mixin/allowed_identifiers'
|
|
12
|
+
autoload :AllowedMethods, 'rubocop/cop/mixin/allowed_methods'
|
|
13
|
+
autoload :AllowedPattern, 'rubocop/cop/mixin/allowed_pattern'
|
|
14
|
+
autoload :AllowedReceivers, 'rubocop/cop/mixin/allowed_receivers'
|
|
15
|
+
autoload :ForbiddenIdentifiers, 'rubocop/cop/mixin/forbidden_identifiers'
|
|
16
|
+
autoload :ForbiddenPattern, 'rubocop/cop/mixin/forbidden_pattern'
|
|
17
|
+
autoload :AutoCorrector, 'rubocop/cop/mixin/auto_corrector' # rubocop:todo Naming/InclusiveLanguage
|
|
18
|
+
autoload :CheckAssignment, 'rubocop/cop/mixin/check_assignment'
|
|
19
|
+
autoload :CheckLineBreakable, 'rubocop/cop/mixin/check_line_breakable'
|
|
20
|
+
autoload :CheckSingleLineSuitability, 'rubocop/cop/mixin/check_single_line_suitability'
|
|
21
|
+
autoload :ConfigurableMax, 'rubocop/cop/mixin/configurable_max'
|
|
22
|
+
autoload :CodeLength, 'rubocop/cop/mixin/code_length'
|
|
23
|
+
autoload :ConfigurableEnforcedStyle, 'rubocop/cop/mixin/configurable_enforced_style'
|
|
24
|
+
autoload :ConfigurableFormatting, 'rubocop/cop/mixin/configurable_formatting'
|
|
25
|
+
autoload :ConfigurableNaming, 'rubocop/cop/mixin/configurable_naming'
|
|
26
|
+
autoload :ConfigurableNumbering, 'rubocop/cop/mixin/configurable_numbering'
|
|
27
|
+
autoload :DigHelp, 'rubocop/cop/mixin/dig_help'
|
|
28
|
+
autoload :DocumentationComment, 'rubocop/cop/mixin/documentation_comment'
|
|
29
|
+
autoload :Duplication, 'rubocop/cop/mixin/duplication'
|
|
30
|
+
autoload :RangeHelp, 'rubocop/cop/mixin/range_help'
|
|
31
|
+
autoload :ProjectIndexHelp, 'rubocop/cop/mixin/project_index_help'
|
|
32
|
+
autoload :AnnotationComment, 'rubocop/cop/mixin/annotation_comment'
|
|
33
|
+
autoload :EmptyParameter, 'rubocop/cop/mixin/empty_parameter'
|
|
34
|
+
autoload :EndKeywordAlignment, 'rubocop/cop/mixin/end_keyword_alignment'
|
|
35
|
+
autoload :EndlessMethodRewriter, 'rubocop/cop/mixin/endless_method_rewriter'
|
|
36
|
+
autoload :EnforceSuperclass, 'rubocop/cop/mixin/enforce_superclass'
|
|
37
|
+
autoload :FirstElementLineBreak, 'rubocop/cop/mixin/first_element_line_break'
|
|
38
|
+
autoload :FrozenStringLiteral, 'rubocop/cop/mixin/frozen_string_literal'
|
|
39
|
+
autoload :GemDeclaration, 'rubocop/cop/mixin/gem_declaration'
|
|
40
|
+
autoload :GemspecHelp, 'rubocop/cop/mixin/gemspec_help'
|
|
41
|
+
autoload :HashAlignmentStyles, 'rubocop/cop/mixin/hash_alignment_styles'
|
|
42
|
+
autoload :HashSubset, 'rubocop/cop/mixin/hash_subset'
|
|
43
|
+
autoload :HashTransformMethod, 'rubocop/cop/mixin/hash_transform_method'
|
|
44
|
+
autoload :IntegerNode, 'rubocop/cop/mixin/integer_node'
|
|
45
|
+
autoload :Interpolation, 'rubocop/cop/mixin/interpolation'
|
|
46
|
+
autoload :LineLengthHelp, 'rubocop/cop/mixin/line_length_help'
|
|
47
|
+
autoload :MatchRange, 'rubocop/cop/mixin/match_range'
|
|
48
|
+
autoload :HashShorthandSyntax, 'rubocop/cop/mixin/hash_shorthand_syntax'
|
|
49
|
+
autoload :MethodComplexity, 'rubocop/cop/mixin/method_complexity'
|
|
50
|
+
autoload :MethodPreference, 'rubocop/cop/mixin/method_preference'
|
|
51
|
+
autoload :MinBodyLength, 'rubocop/cop/mixin/min_body_length'
|
|
52
|
+
autoload :MinBranchesCount, 'rubocop/cop/mixin/min_branches_count'
|
|
53
|
+
autoload :MultilineElementIndentation, 'rubocop/cop/mixin/multiline_element_indentation'
|
|
54
|
+
autoload :MultilineElementLineBreaks, 'rubocop/cop/mixin/multiline_element_line_breaks'
|
|
55
|
+
autoload :MultilineExpressionIndentation, 'rubocop/cop/mixin/multiline_expression_indentation'
|
|
56
|
+
autoload :MultilineLiteralBraceLayout, 'rubocop/cop/mixin/multiline_literal_brace_layout'
|
|
57
|
+
autoload :NegativeConditional, 'rubocop/cop/mixin/negative_conditional'
|
|
58
|
+
autoload :Heredoc, 'rubocop/cop/mixin/heredoc'
|
|
59
|
+
autoload :NilMethods, 'rubocop/cop/mixin/nil_methods'
|
|
60
|
+
autoload :OnNormalIfUnless, 'rubocop/cop/mixin/on_normal_if_unless'
|
|
61
|
+
autoload :OrderedGemNode, 'rubocop/cop/mixin/ordered_gem_node'
|
|
62
|
+
autoload :Parentheses, 'rubocop/cop/mixin/parentheses'
|
|
63
|
+
autoload :PercentArray, 'rubocop/cop/mixin/percent_array'
|
|
64
|
+
autoload :PercentLiteral, 'rubocop/cop/mixin/percent_literal'
|
|
65
|
+
autoload :PrecedingFollowingAlignment, 'rubocop/cop/mixin/preceding_following_alignment'
|
|
66
|
+
autoload :PreferredDelimiters, 'rubocop/cop/mixin/preferred_delimiters'
|
|
67
|
+
autoload :RationalLiteral, 'rubocop/cop/mixin/rational_literal'
|
|
68
|
+
autoload :RequireLibrary, 'rubocop/cop/mixin/require_library'
|
|
69
|
+
autoload :RescueNode, 'rubocop/cop/mixin/rescue_node'
|
|
70
|
+
autoload :SafeAssignment, 'rubocop/cop/mixin/safe_assignment'
|
|
71
|
+
autoload :SpaceAfterPunctuation, 'rubocop/cop/mixin/space_after_punctuation'
|
|
72
|
+
autoload :SpaceBeforePunctuation, 'rubocop/cop/mixin/space_before_punctuation'
|
|
73
|
+
autoload :SurroundingSpace, 'rubocop/cop/mixin/surrounding_space'
|
|
74
|
+
autoload :StatementModifier, 'rubocop/cop/mixin/statement_modifier'
|
|
75
|
+
autoload :StringHelp, 'rubocop/cop/mixin/string_help'
|
|
76
|
+
autoload :StringLiteralsHelp, 'rubocop/cop/mixin/string_literals_help'
|
|
77
|
+
autoload :SymbolHelp, 'rubocop/cop/mixin/symbol_help'
|
|
78
|
+
autoload :TargetRubyVersion, 'rubocop/cop/mixin/target_ruby_version'
|
|
79
|
+
autoload :TrailingBody, 'rubocop/cop/mixin/trailing_body'
|
|
80
|
+
autoload :TrailingComma, 'rubocop/cop/mixin/trailing_comma'
|
|
81
|
+
autoload :UncommunicativeName, 'rubocop/cop/mixin/uncommunicative_name'
|
|
82
|
+
autoload :VisibilityHelp, 'rubocop/cop/mixin/visibility_help'
|
|
83
|
+
autoload :CommentsHelp, 'rubocop/cop/mixin/comments_help'
|
|
84
|
+
autoload :DefNode, 'rubocop/cop/mixin/def_node'
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -109,7 +109,7 @@ module RuboCop
|
|
|
109
109
|
# @_foo = calculate_expensive_thing
|
|
110
110
|
# end
|
|
111
111
|
#
|
|
112
|
-
# @example EnforcedStyleForLeadingUnderscores
|
|
112
|
+
# @example EnforcedStyleForLeadingUnderscores: optional
|
|
113
113
|
# # bad
|
|
114
114
|
# def foo
|
|
115
115
|
# @something ||= calculate_expensive_thing
|
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
|
6
6
|
# Checks that predicate methods end with `?` and non-predicate methods do not.
|
|
7
7
|
#
|
|
8
8
|
# The names of predicate methods (methods that return a boolean value) should end
|
|
9
|
-
# in a question mark. Methods that don't return a boolean
|
|
9
|
+
# in a question mark. Methods that don't return a boolean shouldn't
|
|
10
10
|
# end in a question mark.
|
|
11
11
|
#
|
|
12
12
|
# The cop assesses a predicate method as one that returns boolean values. Likewise,
|
|
@@ -22,7 +22,7 @@ module RuboCop
|
|
|
22
22
|
# return values are detected.
|
|
23
23
|
#
|
|
24
24
|
# The cop also has `AllowedMethods` configuration in order to prevent the cop from
|
|
25
|
-
# registering an offense from a method name that does not
|
|
25
|
+
# registering an offense from a method name that does not conform to the naming
|
|
26
26
|
# guidelines. By default, `call` is allowed. The cop also has `AllowedPatterns`
|
|
27
27
|
# configuration to allow method names by regular expression.
|
|
28
28
|
#
|
|
@@ -17,7 +17,7 @@ module RuboCop
|
|
|
17
17
|
# they end with a `?`. These methods should be changed to remove the
|
|
18
18
|
# prefix.
|
|
19
19
|
#
|
|
20
|
-
# When `UseSorbetSigs` set to true (optional), the cop will only report
|
|
20
|
+
# When `UseSorbetSigs` is set to true (optional), the cop will only report
|
|
21
21
|
# offenses if the method has a Sorbet `sig` with a return type of
|
|
22
22
|
# `T::Boolean`. Dynamic methods are not supported with this configuration.
|
|
23
23
|
#
|
data/lib/rubocop/cop/offense.rb
CHANGED
|
@@ -98,6 +98,14 @@ module RuboCop
|
|
|
98
98
|
freeze
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
+
def marshal_dump
|
|
102
|
+
[@severity, @location, @message, @cop_name, @status]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def marshal_load(array)
|
|
106
|
+
@severity, @location, @message, @cop_name, @status = array
|
|
107
|
+
end
|
|
108
|
+
|
|
101
109
|
# @api public
|
|
102
110
|
#
|
|
103
111
|
# @!attribute [r] correctable?
|
data/lib/rubocop/cop/registry.rb
CHANGED
|
@@ -49,9 +49,9 @@ module RuboCop
|
|
|
49
49
|
attr_reader :options, :warnings
|
|
50
50
|
|
|
51
51
|
def initialize(cops = [], options = {})
|
|
52
|
-
@
|
|
53
|
-
@
|
|
54
|
-
@
|
|
52
|
+
@departments = Set.new
|
|
53
|
+
@cops_by_badge = {}
|
|
54
|
+
@lazy_loaded_cops_by_badge = {}
|
|
55
55
|
|
|
56
56
|
@enrollment_queue = cops
|
|
57
57
|
@options = options
|
|
@@ -61,6 +61,12 @@ module RuboCop
|
|
|
61
61
|
@warnings = {}
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
def lazy_load(cop_name, constant_name)
|
|
65
|
+
badge = Badge.parse(cop_name)
|
|
66
|
+
@departments << badge.department
|
|
67
|
+
@lazy_loaded_cops_by_badge[badge] = constant_name
|
|
68
|
+
end
|
|
69
|
+
|
|
64
70
|
def enlist(cop)
|
|
65
71
|
@enrollment_queue << cop
|
|
66
72
|
end
|
|
@@ -72,22 +78,17 @@ module RuboCop
|
|
|
72
78
|
# @return [Array<Symbol>] list of departments for current cops.
|
|
73
79
|
def departments
|
|
74
80
|
clear_enrollment_queue
|
|
75
|
-
@departments.
|
|
81
|
+
@departments.to_a
|
|
76
82
|
end
|
|
77
83
|
|
|
78
84
|
# @return [Registry] Cops for that specific department.
|
|
79
85
|
def with_department(department)
|
|
80
|
-
|
|
81
|
-
with(@departments.fetch(department, []))
|
|
86
|
+
with(cops.select { |cop| cop.department == department })
|
|
82
87
|
end
|
|
83
88
|
|
|
84
89
|
# @return [Registry] Cops not for a specific department.
|
|
85
90
|
def without_department(department)
|
|
86
|
-
|
|
87
|
-
without_department = @departments.dup
|
|
88
|
-
without_department.delete(department)
|
|
89
|
-
|
|
90
|
-
with(without_department.values.flatten)
|
|
91
|
+
with(cops.reject { |cop| cop.department == department })
|
|
91
92
|
end
|
|
92
93
|
|
|
93
94
|
# @return [Boolean] Checks if given name is department
|
|
@@ -160,31 +161,33 @@ module RuboCop
|
|
|
160
161
|
def unqualified_cop_names
|
|
161
162
|
clear_enrollment_queue
|
|
162
163
|
@unqualified_cop_names ||=
|
|
163
|
-
|
|
164
|
-
'RedundantCopDisableDirective'
|
|
164
|
+
(@cops_by_badge.keys | @lazy_loaded_cops_by_badge.keys)
|
|
165
|
+
.to_set { |badge| File.basename(badge.to_s) } << 'RedundantCopDisableDirective'
|
|
165
166
|
end
|
|
166
167
|
|
|
167
168
|
def qualify_badge(badge)
|
|
168
169
|
clear_enrollment_queue
|
|
169
170
|
@departments
|
|
170
|
-
.map { |department
|
|
171
|
+
.map { |department| badge.with_department(department) }
|
|
171
172
|
.select { |potential_badge| registered?(potential_badge) }
|
|
172
173
|
end
|
|
173
174
|
|
|
174
175
|
# @return [Hash{String => Array<Class>}]
|
|
175
176
|
def to_h
|
|
176
177
|
clear_enrollment_queue
|
|
177
|
-
|
|
178
|
+
load_all_lazy_cops
|
|
179
|
+
@cops_by_badge.to_h { |_badge, cop| [cop.cop_name, [cop]] }
|
|
178
180
|
end
|
|
179
181
|
|
|
180
182
|
def cops
|
|
181
183
|
clear_enrollment_queue
|
|
182
|
-
|
|
184
|
+
load_all_lazy_cops
|
|
185
|
+
@cops_by_badge.values
|
|
183
186
|
end
|
|
184
187
|
|
|
185
188
|
def length
|
|
186
189
|
clear_enrollment_queue
|
|
187
|
-
@
|
|
190
|
+
@cops_by_badge.size + @lazy_loaded_cops_by_badge.size
|
|
188
191
|
end
|
|
189
192
|
|
|
190
193
|
def enabled(config)
|
|
@@ -219,7 +222,8 @@ module RuboCop
|
|
|
219
222
|
end
|
|
220
223
|
|
|
221
224
|
def names
|
|
222
|
-
|
|
225
|
+
clear_enrollment_queue
|
|
226
|
+
@cops_by_badge.keys.map(&:to_s) | @lazy_loaded_cops_by_badge.keys.map(&:to_s)
|
|
223
227
|
end
|
|
224
228
|
|
|
225
229
|
def cops_for_department(department)
|
|
@@ -236,7 +240,8 @@ module RuboCop
|
|
|
236
240
|
|
|
237
241
|
def sort!
|
|
238
242
|
clear_enrollment_queue
|
|
239
|
-
|
|
243
|
+
load_all_lazy_cops
|
|
244
|
+
@cops_by_badge = @cops_by_badge.sort_by { |badge, _cop| badge.cop_name }.to_h
|
|
240
245
|
|
|
241
246
|
self
|
|
242
247
|
end
|
|
@@ -252,7 +257,9 @@ module RuboCop
|
|
|
252
257
|
# @param [String] cop_name
|
|
253
258
|
# @return [Class, nil]
|
|
254
259
|
def find_by_cop_name(cop_name)
|
|
255
|
-
|
|
260
|
+
clear_enrollment_queue
|
|
261
|
+
badge = Badge.parse(cop_name)
|
|
262
|
+
@cops_by_badge[badge] || load_lazy_cop(badge)
|
|
256
263
|
end
|
|
257
264
|
|
|
258
265
|
# When a cop name is given returns a single-element array with the cop class.
|
|
@@ -265,6 +272,7 @@ module RuboCop
|
|
|
265
272
|
|
|
266
273
|
def freeze
|
|
267
274
|
clear_enrollment_queue
|
|
275
|
+
load_all_lazy_cops
|
|
268
276
|
unqualified_cop_names # build cache
|
|
269
277
|
super
|
|
270
278
|
end
|
|
@@ -289,14 +297,23 @@ module RuboCop
|
|
|
289
297
|
return if @enrollment_queue.empty?
|
|
290
298
|
|
|
291
299
|
@enrollment_queue.each do |cop|
|
|
292
|
-
@
|
|
293
|
-
@departments
|
|
294
|
-
@departments[cop.department] << cop
|
|
295
|
-
@cops_by_cop_name[cop.cop_name] << cop
|
|
300
|
+
@cops_by_badge[cop.badge] = cop
|
|
301
|
+
@departments << cop.department
|
|
296
302
|
end
|
|
297
303
|
@enrollment_queue = []
|
|
298
304
|
end
|
|
299
305
|
|
|
306
|
+
def load_all_lazy_cops
|
|
307
|
+
@lazy_loaded_cops_by_badge.each_key { |badge| load_lazy_cop(badge) }
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def load_lazy_cop(badge)
|
|
311
|
+
constant_name = @lazy_loaded_cops_by_badge.delete(badge)
|
|
312
|
+
return unless constant_name
|
|
313
|
+
|
|
314
|
+
@cops_by_badge[badge] = Kernel.const_get(constant_name)
|
|
315
|
+
end
|
|
316
|
+
|
|
300
317
|
def with(cops)
|
|
301
318
|
self.class.new(cops)
|
|
302
319
|
end
|
|
@@ -318,7 +335,7 @@ module RuboCop
|
|
|
318
335
|
|
|
319
336
|
def registered?(badge)
|
|
320
337
|
clear_enrollment_queue
|
|
321
|
-
@
|
|
338
|
+
@cops_by_badge.key?(badge) || @lazy_loaded_cops_by_badge.key?(badge)
|
|
322
339
|
end
|
|
323
340
|
end
|
|
324
341
|
end
|
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
|
10
10
|
# a subprocess is created in the same way as `Kernel#open`, and its output is returned.
|
|
11
11
|
# `Kernel#open` may allow unintentional command injection, which is the reason these
|
|
12
12
|
# `IO` methods are a security risk.
|
|
13
|
-
# Consider
|
|
13
|
+
# Consider using `File.read` to disable the behavior of subprocess invocation.
|
|
14
14
|
#
|
|
15
15
|
# @safety
|
|
16
16
|
# This cop is unsafe because false positive will occur if the variable passed as
|
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
|
10
10
|
# is resolved at runtime).
|
|
11
11
|
# It also flags uses of `alias :symbol` rather than `alias bareword`.
|
|
12
12
|
#
|
|
13
|
-
# However, it will always enforce `
|
|
13
|
+
# However, it will always enforce `alias_method` when `alias` is used
|
|
14
14
|
# in an instance method definition and in a singleton method definition.
|
|
15
15
|
# If used in a block, always enforce `alias_method`
|
|
16
16
|
# unless it is an `instance_eval` block.
|
|
@@ -45,6 +45,7 @@ module RuboCop
|
|
|
45
45
|
return unless node.command?(:alias_method)
|
|
46
46
|
return unless style == :prefer_alias && alias_keyword_possible?(node)
|
|
47
47
|
return unless node.arguments.count == 2
|
|
48
|
+
return if alias_method_value_used?(node)
|
|
48
49
|
|
|
49
50
|
msg = format(MSG_ALIAS_METHOD, current: lexical_scope_type(node))
|
|
50
51
|
add_offense(node.loc.selector, message: msg) do |corrector|
|
|
@@ -80,6 +81,14 @@ module RuboCop
|
|
|
80
81
|
scope_type(node) != :dynamic && node.arguments.all?(&:sym_type?)
|
|
81
82
|
end
|
|
82
83
|
|
|
84
|
+
# `alias_method` is a method call whose return value can be used
|
|
85
|
+
# (e.g., as an argument to `public`/`module_function`, or as an assignment),
|
|
86
|
+
# but `alias` is a keyword statement that cannot appear in such positions.
|
|
87
|
+
# Detect these positions so the conversion does not produce a syntax error.
|
|
88
|
+
def alias_method_value_used?(node)
|
|
89
|
+
node.argument? || node.parent&.assignment?
|
|
90
|
+
end
|
|
91
|
+
|
|
83
92
|
def alias_method_possible?(node)
|
|
84
93
|
scope_type(node) != :instance_eval &&
|
|
85
94
|
node.children.none?(&:gvar_type?) &&
|
|
@@ -8,8 +8,8 @@ module RuboCop
|
|
|
8
8
|
# essentially one-character strings, so this syntax
|
|
9
9
|
# is mostly redundant at this point.
|
|
10
10
|
#
|
|
11
|
-
#
|
|
12
|
-
# That's a good use case of
|
|
11
|
+
# A `?` character literal can be used to express meta and control characters.
|
|
12
|
+
# That's a good use case of a `?` literal so it doesn't count as an offense.
|
|
13
13
|
#
|
|
14
14
|
# @example
|
|
15
15
|
# # bad
|
|
@@ -181,6 +181,7 @@ module RuboCop
|
|
|
181
181
|
|
|
182
182
|
def check_style(node, body, style)
|
|
183
183
|
return if node.identifier.namespace&.cbase_type?
|
|
184
|
+
return unless const_namespace?(node.identifier.namespace)
|
|
184
185
|
|
|
185
186
|
if style == :nested
|
|
186
187
|
check_nested_style(node)
|
|
@@ -189,6 +190,13 @@ module RuboCop
|
|
|
189
190
|
end
|
|
190
191
|
end
|
|
191
192
|
|
|
193
|
+
def const_namespace?(node)
|
|
194
|
+
return true if node.nil? || node.cbase_type?
|
|
195
|
+
return false unless node.const_type?
|
|
196
|
+
|
|
197
|
+
const_namespace?(node.namespace)
|
|
198
|
+
end
|
|
199
|
+
|
|
192
200
|
def check_nested_style(node)
|
|
193
201
|
return unless compact_node_name?(node)
|
|
194
202
|
return if node.parent&.type?(:class, :module)
|
|
@@ -46,15 +46,16 @@ module RuboCop
|
|
|
46
46
|
token = insert_notice_before(processed_source)
|
|
47
47
|
range = token.nil? ? range_between(0, 0) : token.pos
|
|
48
48
|
|
|
49
|
-
corrector.insert_before(range, "#{
|
|
49
|
+
corrector.insert_before(range, "#{normalized_autocorrect_notice}\n")
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
def normalized_autocorrect_notice
|
|
53
|
+
autocorrect_notice.lines.map do |line|
|
|
54
|
+
next line if line.start_with?('#')
|
|
55
|
+
next "#\n" if line.chomp.empty?
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
"# #{line}"
|
|
58
|
+
end.join
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
def verify_autocorrect_notice!
|
|
@@ -62,8 +63,7 @@ module RuboCop
|
|
|
62
63
|
raise Warning, "#{cop_name}: #{AUTOCORRECT_EMPTY_WARNING}"
|
|
63
64
|
end
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
return if autocorrect_notice.gsub(/^# */, '').match?(regex)
|
|
66
|
+
return if normalized_autocorrect_notice.gsub(/^# */, '').match?(notice_regexp)
|
|
67
67
|
|
|
68
68
|
message = "AutocorrectNotice '#{autocorrect_notice}' must match Notice /#{notice}/"
|
|
69
69
|
raise Warning, "#{cop_name}: #{message}"
|
|
@@ -91,18 +91,29 @@ module RuboCop
|
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
def notice_found?(processed_source)
|
|
94
|
-
notice_regexp = Regexp.new(notice.lines.map(&:strip).join)
|
|
95
94
|
multiline_notice = +''
|
|
96
95
|
processed_source.tokens.each do |token|
|
|
97
96
|
break unless token.comment?
|
|
98
97
|
|
|
99
|
-
multiline_notice << token.text.sub(/\A# */, '')
|
|
98
|
+
multiline_notice << token.text.sub(/\A# */, '') << "\n"
|
|
100
99
|
|
|
101
100
|
break if notice_regexp.match?(token.text)
|
|
102
101
|
end
|
|
103
102
|
|
|
104
103
|
multiline_notice.match?(notice_regexp)
|
|
105
104
|
end
|
|
105
|
+
|
|
106
|
+
def notice_regexp
|
|
107
|
+
@notice_regexp ||= Regexp.new(notice.sub(/\A(?:\\A|\^)?#(?:\\s[*+?]?|\s)*/, ''))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def notice
|
|
111
|
+
cop_config['Notice']
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def autocorrect_notice
|
|
115
|
+
cop_config['AutocorrectNotice']
|
|
116
|
+
end
|
|
106
117
|
end
|
|
107
118
|
end
|
|
108
119
|
end
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for consistent usage of the `
|
|
7
|
-
# `
|
|
6
|
+
# Checks for consistent usage of the `Time` class over the
|
|
7
|
+
# `DateTime` class. This cop is disabled by default since these classes,
|
|
8
8
|
# although highly overlapping, have particularities that make them not
|
|
9
9
|
# replaceable in certain situations when dealing with multiple timezones
|
|
10
10
|
# and/or DST.
|
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
|
6
6
|
module Cop
|
|
7
7
|
module Style
|
|
8
8
|
# Detects comments to enable/disable RuboCop.
|
|
9
|
-
# This is useful if want to make sure that every RuboCop error gets fixed
|
|
9
|
+
# This is useful if you want to make sure that every RuboCop error gets fixed
|
|
10
10
|
# and not quickly disabled with a comment.
|
|
11
11
|
#
|
|
12
12
|
# Specific cops can be allowed with the `AllowedCops` configuration. Note that
|
|
@@ -161,7 +161,12 @@ module RuboCop
|
|
|
161
161
|
source = source.gsub(COMMENT_REGEXP, '')
|
|
162
162
|
return if source.blank?
|
|
163
163
|
|
|
164
|
-
|
|
164
|
+
# Treat `\#` (an escaped interpolation marker in the heredoc) as matching
|
|
165
|
+
# either `\#` or `#` in the comment, since the comment may show either
|
|
166
|
+
# the literal source form or the runtime appearance.
|
|
167
|
+
segments = source.strip.split('\\#', -1).map { |segment| Regexp.escape(segment) }
|
|
168
|
+
|
|
169
|
+
/\s*#{segments.join('\\\\?#')}/
|
|
165
170
|
end
|
|
166
171
|
end
|
|
167
172
|
end
|
|
@@ -104,28 +104,30 @@ module RuboCop
|
|
|
104
104
|
|
|
105
105
|
def replacement(mode, filename, content, write_node)
|
|
106
106
|
replacement = "#{write_method(mode)}(#{filename.source}, #{content.source})"
|
|
107
|
+
heredoc = heredoc_in_write(write_node)
|
|
108
|
+
return replacement unless heredoc
|
|
107
109
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
<<~REPLACEMENT.chomp
|
|
111
|
+
#{replacement}
|
|
112
|
+
#{heredoc_range(heredoc).source}
|
|
113
|
+
REPLACEMENT
|
|
114
|
+
end
|
|
110
115
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
else
|
|
116
|
-
replacement
|
|
117
|
-
end
|
|
116
|
+
def heredoc_in_write(write_node)
|
|
117
|
+
return unless write_node.block_type? && (first_argument = write_node.body.first_argument)
|
|
118
|
+
|
|
119
|
+
find_heredoc(first_argument)
|
|
118
120
|
end
|
|
119
121
|
|
|
120
|
-
def heredoc
|
|
121
|
-
|
|
122
|
-
first_argument.respond_to?(:heredoc?) && first_argument.heredoc?
|
|
122
|
+
def heredoc_range(heredoc)
|
|
123
|
+
range_between(heredoc.loc.heredoc_body.begin_pos, heredoc.loc.heredoc_end.end_pos)
|
|
123
124
|
end
|
|
124
125
|
|
|
125
|
-
def
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
126
|
+
def find_heredoc(node)
|
|
127
|
+
return node if node.respond_to?(:heredoc?) && node.heredoc?
|
|
128
|
+
return if node.send_type? && !(receiver = node.receiver)
|
|
129
|
+
|
|
130
|
+
find_heredoc(receiver)
|
|
129
131
|
end
|
|
130
132
|
end
|
|
131
133
|
end
|
|
@@ -11,9 +11,10 @@ module RuboCop
|
|
|
11
11
|
# if the first argument is a string literal and if the second
|
|
12
12
|
# argument is an array literal.
|
|
13
13
|
#
|
|
14
|
-
# Autocorrection will be applied when
|
|
15
|
-
#
|
|
16
|
-
# provided that their return value is not an array.
|
|
14
|
+
# Autocorrection will be applied when the argument is a literal or uses a known
|
|
15
|
+
# built-in conversion method such as `to_d`, `to_f`, `to_h`, `to_i`, `to_r`, `to_s`,
|
|
16
|
+
# and `to_sym` on variables, provided that their return value is not an array.
|
|
17
|
+
# For example, when using `to_s`,
|
|
17
18
|
# `'%s' % [1, 2, 3].to_s` can be autocorrected without any incompatibility:
|
|
18
19
|
#
|
|
19
20
|
# [source,ruby]
|
|
@@ -73,7 +73,7 @@ module RuboCop
|
|
|
73
73
|
first_argument = node.first_argument
|
|
74
74
|
if first_argument.hash_type?
|
|
75
75
|
register_offense_for_hash(node, first_argument)
|
|
76
|
-
elsif first_argument.
|
|
76
|
+
elsif first_argument.type?(:splat, :forwarded_restarg)
|
|
77
77
|
add_offense(node, message: MSG_SPLAT) unless allowed_splat_argument?
|
|
78
78
|
elsif use_zip_method_without_argument?(first_argument)
|
|
79
79
|
register_offense_for_zip_method(node, first_argument)
|
|
@@ -82,18 +82,23 @@ module RuboCop
|
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
def correct_fetch_to_brackets(corrector, node)
|
|
85
|
-
receiver = node.receiver.source
|
|
86
85
|
key = node.first_argument.source
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
86
|
+
|
|
87
|
+
if node.csend_type?
|
|
88
|
+
corrector.replace(node, "(#{node.receiver.source}[#{key}])")
|
|
89
|
+
else
|
|
90
|
+
corrector.replace(node.loc.dot.join(node.source_range.end), "[#{key}]")
|
|
91
|
+
end
|
|
90
92
|
end
|
|
91
93
|
|
|
92
94
|
def correct_brackets_to_fetch(corrector, node)
|
|
93
|
-
receiver = node.receiver.source
|
|
94
95
|
key = node.first_argument.source
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
|
|
97
|
+
if node.csend_type?
|
|
98
|
+
corrector.replace(node.loc.dot.join(node.source_range.end), "&.fetch(#{key})")
|
|
99
|
+
else
|
|
100
|
+
corrector.replace(node.loc.selector.join(node.source_range.end), ".fetch(#{key})")
|
|
101
|
+
end
|
|
97
102
|
end
|
|
98
103
|
end
|
|
99
104
|
end
|