From 4a759953dc48465daabe068d323f6a220306ea02 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Mon, 31 Jul 2023 08:20:41 +0300 Subject: [PATCH 01/17] Switch back the docs version --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index b303585e2120..9c897ea03d1d 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop title: RuboCop # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: '1.55' +version: ~ nav: - modules/ROOT/nav.adoc From 43879cecd75ed06b75e70be5579ed6e693c5ff21 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Tue, 1 Aug 2023 03:12:29 +0900 Subject: [PATCH 02/17] [Fix #12085] Fix an error for `Lint/SuppressedException` Fixes #12085. This PR fixes an error for `Lint/SuppressedException` when `AllowNil: true` is set and endless method definition is used. --- ...fix_error_for_lint_suppressed_exception.md | 1 + lib/rubocop/cop/lint/suppressed_exception.rb | 2 +- .../cop/lint/suppressed_exception_spec.rb | 28 ++++++++++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 changelog/fix_error_for_lint_suppressed_exception.md diff --git a/changelog/fix_error_for_lint_suppressed_exception.md b/changelog/fix_error_for_lint_suppressed_exception.md new file mode 100644 index 000000000000..4b8501388553 --- /dev/null +++ b/changelog/fix_error_for_lint_suppressed_exception.md @@ -0,0 +1 @@ +* [#12085](https://github.com/rubocop/rubocop/issues/12085): Fix an error for `Lint/SuppressedException` when `AllowNil: true` is set and endless method definition is used. ([@koic][]) diff --git a/lib/rubocop/cop/lint/suppressed_exception.rb b/lib/rubocop/cop/lint/suppressed_exception.rb index 8e8a14f25821..33a1170191e0 100644 --- a/lib/rubocop/cop/lint/suppressed_exception.rb +++ b/lib/rubocop/cop/lint/suppressed_exception.rb @@ -119,7 +119,7 @@ def comment_between_rescue_and_end?(node) ancestor = node.each_ancestor(:kwbegin, :def, :defs, :block, :numblock).first return false unless ancestor - end_line = ancestor.loc.end.line + end_line = ancestor.loc.end&.line || ancestor.loc.last_line processed_source[node.first_line...end_line].any? { |line| comment_line?(line) } end diff --git a/spec/rubocop/cop/lint/suppressed_exception_spec.rb b/spec/rubocop/cop/lint/suppressed_exception_spec.rb index 50e40a2ce9e1..b4e4446aba59 100644 --- a/spec/rubocop/cop/lint/suppressed_exception_spec.rb +++ b/spec/rubocop/cop/lint/suppressed_exception_spec.rb @@ -140,7 +140,8 @@ def self.foo end context 'with AllowComments set to true' do - let(:cop_config) { { 'AllowComments' => true } } + let(:cop_config) { { 'AllowComments' => true, 'AllowNil' => allow_nil } } + let(:allow_nil) { true } it 'does not register an offense for empty rescue with comment' do expect_no_offenses(<<~RUBY) @@ -244,6 +245,31 @@ def self.foo end end + context 'with AllowNil set to true' do + let(:allow_nil) { true } + + context 'when using endless method definition', :ruby30 do + it 'does not register an offense for inline nil rescue' do + expect_no_offenses(<<~RUBY) + def some_method = other_method(42) rescue nil + RUBY + end + end + end + + context 'with AllowNil set to false' do + let(:allow_nil) { false } + + context 'when using endless method definition', :ruby30 do + it 'registers an offense for inline nil rescue' do + expect_offense(<<~RUBY) + def some_method = other_method(42) rescue nil + ^^^^^^^^^^ Do not suppress exceptions. + RUBY + end + end + end + it 'registers an offense for empty rescue on single line with a comment after it' do expect_offense(<<~RUBY) RSpec.describe Dummy do From c5cefaeb3961bfdd2863fc598d7e374049cec030 Mon Sep 17 00:00:00 2001 From: Jason Dougherty Date: Mon, 31 Jul 2023 18:23:16 -0700 Subject: [PATCH 03/17] [Fix #12071] Fix Style/SymbolArray false positives --- .../fix_style_symbol_array_false_positives.md | 1 + lib/rubocop/cop/style/symbol_array.rb | 6 +-- spec/rubocop/cop/style/symbol_array_spec.rb | 50 ++++++++++++++++++- 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 changelog/fix_style_symbol_array_false_positives.md diff --git a/changelog/fix_style_symbol_array_false_positives.md b/changelog/fix_style_symbol_array_false_positives.md new file mode 100644 index 000000000000..91c7917fb2a0 --- /dev/null +++ b/changelog/fix_style_symbol_array_false_positives.md @@ -0,0 +1 @@ +* [#12071](https://github.com/rubocop/rubocop/issues/12071): Fix `Style/SymbolArray` false positives when using square brackets or interpolation in a symbol literal in a percent style array. ([@jasondoc3][]) diff --git a/lib/rubocop/cop/style/symbol_array.rb b/lib/rubocop/cop/style/symbol_array.rb index c425c0a6db62..a01ad7908586 100644 --- a/lib/rubocop/cop/style/symbol_array.rb +++ b/lib/rubocop/cop/style/symbol_array.rb @@ -69,9 +69,9 @@ def on_array(node) def complex_content?(node) node.children.any? do |sym| - content, = *sym - content = content.to_s - content_without_delimiter_pairs = content.gsub(/(\[\])|(\(\))/, '') + content = *sym + content = content.map { |c| c.is_a?(AST::Node) ? c.source : c }.join + content_without_delimiter_pairs = content.gsub(/(\[[^\s\[\]]*\])|(\([^\s\(\)]*\))/, '') content.include?(' ') || DELIMITERS.any? do |delimiter| content_without_delimiter_pairs.include?(delimiter) diff --git a/spec/rubocop/cop/style/symbol_array_spec.rb b/spec/rubocop/cop/style/symbol_array_spec.rb index 5baede791453..7f4cd2a6b06b 100644 --- a/spec/rubocop/cop/style/symbol_array_spec.rb +++ b/spec/rubocop/cop/style/symbol_array_spec.rb @@ -88,7 +88,11 @@ end it 'does not register an offense for array containing delimiters without spaces' do - expect_no_offenses('%i[one two [] ()]') + expect_no_offenses('%i[zero (one) [two] three[4] five[six] seven(8) nine(ten) ([]) [] ()]') + end + + it 'does not register an offense for a percent array with interpolations' do + expect_no_offenses('%I[one_#{two} three #{four}_five six#{seven}eight [nine_#{ten}]]') end it 'does not register an offense if symbol contains whitespace' do @@ -145,6 +149,28 @@ RUBY end + it 'registers an offense for a %i array containing whitespace between brackets' do + expect_offense(<<~'RUBY') + %i[one two \[three\ four\ five\]] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `[:one, :two, :'[three four five]']` for an array of symbols. + RUBY + + expect_correction(<<~RUBY) + [:one, :two, :'[three four five]'] + RUBY + end + + it 'registers an offense for a %i array containing brackets between brackets' do + expect_offense(<<~'RUBY') + %i[one two \[\[\]] + ^^^^^^^^^^^^^^^^^^ Use `[:one, :two, :'[[]']` for an array of symbols. + RUBY + + expect_correction(<<~RUBY) + [:one, :two, :'[[]'] + RUBY + end + it 'registers an offense for a %i array containing ( )' do expect_offense(<<~'RUBY') %i(one \( \) two) @@ -156,6 +182,28 @@ RUBY end + it 'registers an offense for a %i array containing parentheses between parentheses' do + expect_offense(<<~'RUBY') + %i(one two \(\(\)) + ^^^^^^^^^^^^^^^^^^ Use `[:one, :two, :'(()']` for an array of symbols. + RUBY + + expect_correction(<<~RUBY) + [:one, :two, :'(()'] + RUBY + end + + it 'registers an offense for a %i array containing whitespace between parentheses' do + expect_offense(<<~'RUBY') + %i(one two \(three\ four\ five\)) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `[:one, :two, :'(three four five)']` for an array of symbols. + RUBY + + expect_correction(<<~RUBY) + [:one, :two, :'(three four five)'] + RUBY + end + context 'when PreferredDelimiters is specified' do let(:other_cops) do { From 8b4de3aa1e2715de1f2a0d4dcea8482a40b15061 Mon Sep 17 00:00:00 2001 From: Jonas Arvidsson Date: Wed, 2 Aug 2023 13:29:58 +0200 Subject: [PATCH 04/17] [Fix #12061] Support regex in StringLiteralsInInterpolation Interpolation can occur in strings, symbols, and regular expressions, so update code to support regex and extend code examples in documentation comments. --- ...gex_in_string_literals_in_interpolation.md | 1 + lib/rubocop/cop/mixin/string_help.rb | 6 ++-- .../style/string_literals_in_interpolation.rb | 35 ++++++++++++++++--- .../string_literals_in_interpolation_spec.rb | 12 +++++++ 4 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 changelog/fix_support_regex_in_string_literals_in_interpolation.md diff --git a/changelog/fix_support_regex_in_string_literals_in_interpolation.md b/changelog/fix_support_regex_in_string_literals_in_interpolation.md new file mode 100644 index 000000000000..ac6bc83f2cbc --- /dev/null +++ b/changelog/fix_support_regex_in_string_literals_in_interpolation.md @@ -0,0 +1 @@ +* [#12061](https://github.com/rubocop/rubocop/issues/12061): Support regex in StringLiteralsInInterpolation. ([@jonas054][]) diff --git a/lib/rubocop/cop/mixin/string_help.rb b/lib/rubocop/cop/mixin/string_help.rb index d1f89aa5f570..d8f4c8ebec84 100644 --- a/lib/rubocop/cop/mixin/string_help.rb +++ b/lib/rubocop/cop/mixin/string_help.rb @@ -30,8 +30,10 @@ def on_regexp(node) private def inside_interpolation?(node) - # A :begin node inside a :dstr or :dsym node is an interpolation. - node.ancestors.drop_while { |a| !a.begin_type? }.any? { |a| a.dstr_type? || a.dsym_type? } + # A :begin node inside a :dstr, :dsym, or :regexp node is an interpolation. + node.ancestors + .drop_while { |a| !a.begin_type? } + .any? { |a| a.dstr_type? || a.dsym_type? || a.regexp_type? } end end end diff --git a/lib/rubocop/cop/style/string_literals_in_interpolation.rb b/lib/rubocop/cop/style/string_literals_in_interpolation.rb index ef14379d7f83..de2f3e4deeb9 100644 --- a/lib/rubocop/cop/style/string_literals_in_interpolation.rb +++ b/lib/rubocop/cop/style/string_literals_in_interpolation.rb @@ -3,22 +3,42 @@ module RuboCop module Cop module Style - # Checks that quotes inside the string interpolation + # Checks that quotes inside string, symbol, and regexp interpolations # match the configured preference. # # @example EnforcedStyle: single_quotes (default) # # bad - # result = "Tests #{success ? "PASS" : "FAIL"}" + # string = "Tests #{success ? "PASS" : "FAIL"}" + # symbol = :"Tests #{success ? "PASS" : "FAIL"}" + # heredoc = <<~TEXT + # Tests #{success ? "PASS" : "FAIL"} + # TEXT + # regexp = /Tests #{success ? "PASS" : "FAIL"}/ # # # good - # result = "Tests #{success ? 'PASS' : 'FAIL'}" + # string = "Tests #{success ? 'PASS' : 'FAIL'}" + # symbol = :"Tests #{success ? 'PASS' : 'FAIL'}" + # heredoc = <<~TEXT + # Tests #{success ? 'PASS' : 'FAIL'} + # TEXT + # regexp = /Tests #{success ? 'PASS' : 'FAIL'}/ # # @example EnforcedStyle: double_quotes # # bad - # result = "Tests #{success ? 'PASS' : 'FAIL'}" + # string = "Tests #{success ? 'PASS' : 'FAIL'}" + # symbol = :"Tests #{success ? 'PASS' : 'FAIL'}" + # heredoc = <<~TEXT + # Tests #{success ? 'PASS' : 'FAIL'} + # TEXT + # regexp = /Tests #{success ? 'PASS' : 'FAIL'}/ # # # good - # result = "Tests #{success ? "PASS" : "FAIL"}" + # string = "Tests #{success ? "PASS" : "FAIL"}" + # symbol = :"Tests #{success ? "PASS" : "FAIL"}" + # heredoc = <<~TEXT + # Tests #{success ? "PASS" : "FAIL"} + # TEXT + # regexp = /Tests #{success ? "PASS" : "FAIL"}/ class StringLiteralsInInterpolation < Base include ConfigurableEnforcedStyle include StringLiteralsHelp @@ -29,6 +49,11 @@ def autocorrect(corrector, node) StringLiteralCorrector.correct(corrector, node, style) end + # Cop classes that include the StringHelp module usually ignore regexp + # nodes. Not so for this cop, which is why we override the on_regexp + # definition with an empty one. + def on_regexp(node); end + private def message(_node) diff --git a/spec/rubocop/cop/style/string_literals_in_interpolation_spec.rb b/spec/rubocop/cop/style/string_literals_in_interpolation_spec.rb index 099bb345f1c7..27a580d1710e 100644 --- a/spec/rubocop/cop/style/string_literals_in_interpolation_spec.rb +++ b/spec/rubocop/cop/style/string_literals_in_interpolation_spec.rb @@ -41,6 +41,18 @@ SOURCE end + it 'registers an offense for double quotes within a regexp' do + expect_offense(<<~'RUBY') + /foo#{"sar".sub("s", 'b')}/ + ^^^^^ Prefer single-quoted strings inside interpolations. + ^^^ Prefer single-quoted strings inside interpolations. + RUBY + + expect_correction(<<~'RUBY') + /foo#{'sar'.sub('s', 'b')}/ + RUBY + end + it 'accepts double quotes on a static string' do expect_no_offenses('"A"') end From edde3ebc746f94ed7fa06feda5964190560b516f Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Thu, 3 Aug 2023 12:19:35 +0900 Subject: [PATCH 05/17] Add `base64` to runtime dependency This PR add `base64` to runtime dependency to suppress the following Ruby 3.3's warning: ```console $ ruby -v ruby 3.3.0dev (2023-08-03T00:11:08Z master 4b6c584023) [x86_64-darwin22] $ bundle exec rubocop base64 is not part of the default gems since Ruby 3.4.0. Add it to your Gemfile. ``` --- changelog/change_add_base64_to_runtime_dependency.md | 1 + rubocop.gemspec | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelog/change_add_base64_to_runtime_dependency.md diff --git a/changelog/change_add_base64_to_runtime_dependency.md b/changelog/change_add_base64_to_runtime_dependency.md new file mode 100644 index 000000000000..30f2cb71b9fc --- /dev/null +++ b/changelog/change_add_base64_to_runtime_dependency.md @@ -0,0 +1 @@ +* [#12094](https://github.com/rubocop/rubocop/pull/12094): Add `base64` gem to runtime dependency to suppress Ruby 3.3's warning. ([@koic][]) diff --git a/rubocop.gemspec b/rubocop.gemspec index eb80c0d71919..e4517d9b6e98 100644 --- a/rubocop.gemspec +++ b/rubocop.gemspec @@ -31,6 +31,7 @@ Gem::Specification.new do |s| 'rubygems_mfa_required' => 'true' } + s.add_runtime_dependency('base64', '~> 0.1.1') s.add_runtime_dependency('json', '~> 2.3') s.add_runtime_dependency('language_server-protocol', '>= 3.17.0') s.add_runtime_dependency('parallel', '~> 1.10') From f94f42657fac7e6ecb0ef8fc6c96cc62ee262536 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 29 Jul 2023 01:03:27 +0900 Subject: [PATCH 06/17] Make LSP server support `rubocop.formatAutocorrectsAll` execute command This PR makes LSP server support `rubocop.formatAutocorrectsAll` execute command. The user can run `rubocop -A` with the execute command in the editor. The existing `rubocop.formatAutocorrects` execute command equivalent to `rubocop -a` can be used as follows: https://github.com/rubocop/vscode-rubocop#manually-triggering-a-format-with-autocorrects The new `rubocop.formatAutocorrectsAll` execute command is the provide execute command for that `rubocop -A`. --- ...format_autocorrects_all_execute_command.md | 1 + docs/modules/ROOT/pages/usage/lsp.adoc | 6 ++ lib/rubocop/lsp/routes.rb | 40 ++++++++------ lib/rubocop/lsp/runtime.rb | 10 +++- lib/rubocop/lsp/server.rb | 4 +- spec/rubocop/lsp/server_spec.rb | 55 ++++++++++++++++++- 6 files changed, 94 insertions(+), 22 deletions(-) create mode 100644 changelog/new_make_lsp_server_support_format_autocorrects_all_execute_command.md diff --git a/changelog/new_make_lsp_server_support_format_autocorrects_all_execute_command.md b/changelog/new_make_lsp_server_support_format_autocorrects_all_execute_command.md new file mode 100644 index 000000000000..602ca2f84473 --- /dev/null +++ b/changelog/new_make_lsp_server_support_format_autocorrects_all_execute_command.md @@ -0,0 +1 @@ +* [#12078](https://github.com/rubocop/rubocop/pull/12078): Make LSP server support `rubocop.formatAutocorrectsAll` execute command. ([@koic][]) diff --git a/docs/modules/ROOT/pages/usage/lsp.adoc b/docs/modules/ROOT/pages/usage/lsp.adoc index 922d377731e8..baf9f006a8d8 100644 --- a/docs/modules/ROOT/pages/usage/lsp.adoc +++ b/docs/modules/ROOT/pages/usage/lsp.adoc @@ -132,6 +132,12 @@ For detailed instructions on setting the parameter, please refer to the configur NOTE: The `safeAutocorrect` parameter was introduced in RuboCop 1.54. +As execute commands in the `workspace/executeCommand` parameters, it provides `rubocop.formatAutocorrects` for safe autocorrections (`rubocop -a`) and +`rubocop.formatAutocorrectsAll` for unsafe autocorrections (`rubocop -A`). +These parameters take precedence over the `initializationOptions:safeAutocorrect` value set in the `initialize` parameter. + +NOTE: The `rubocop.formatAutocorrectsAll` execute command was introduced in RuboCop 1.56. + == Lint Mode LSP client can run lint cops by passing the following `lintMode` parameter in the `initialize` request diff --git a/lib/rubocop/lsp/routes.rb b/lib/rubocop/lsp/routes.rb index 764bda93aaa3..ed8583f01585 100644 --- a/lib/rubocop/lsp/routes.rb +++ b/lib/rubocop/lsp/routes.rb @@ -112,23 +112,29 @@ def for(name) end handle 'workspace/executeCommand' do |request| - if request[:params][:command] == 'rubocop.formatAutocorrects' - uri = request[:params][:arguments][0][:uri] - @server.write( - id: request[:id], - method: 'workspace/applyEdit', - params: { - label: 'Format with RuboCop autocorrects', - edit: { - changes: { - uri => format_file(uri) - } - } - } - ) + case (command = request[:params][:command]) + when 'rubocop.formatAutocorrects' + label = 'Format with RuboCop autocorrects' + when 'rubocop.formatAutocorrectsAll' + label = 'Format all with RuboCop autocorrects' else - handle_unsupported_method(request, request[:params][:command]) + handle_unsupported_method(request, command) + return end + + uri = request[:params][:arguments][0][:uri] + @server.write( + id: request[:id], + method: 'workspace/applyEdit', + params: { + label: label, + edit: { + changes: { + uri => format_file(uri, command: command) + } + } + } + ) end handle 'textDocument/willSave' do |_request| @@ -176,14 +182,14 @@ def extract_initialization_options_from(request) } end - def format_file(file_uri) + def format_file(file_uri, command: nil) unless (text = @text_cache[file_uri]) Logger.log("Format request arrived before text synchronized; skipping: `#{file_uri}'") return [] end - new_text = @server.format(remove_file_protocol_from(file_uri), text) + new_text = @server.format(remove_file_protocol_from(file_uri), text, command: command) return [] if new_text == text diff --git a/lib/rubocop/lsp/runtime.rb b/lib/rubocop/lsp/runtime.rb index 2e6b96bb0adf..c47a83cac19b 100644 --- a/lib/rubocop/lsp/runtime.rb +++ b/lib/rubocop/lsp/runtime.rb @@ -35,9 +35,15 @@ def initialize(config_store) # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/cli/command/execute_runner.rb#L95 # Setting `parallel: true` would break this here: # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/runner.rb#L72 - def format(path, text) + def format(path, text, command:) + safe_autocorrect = if command + command == 'rubocop.formatAutocorrects' + else + @safe_autocorrect + end + formatting_options = { - stdin: text, force_exclusion: true, autocorrect: true, safe_autocorrect: @safe_autocorrect + stdin: text, force_exclusion: true, autocorrect: true, safe_autocorrect: safe_autocorrect } formatting_options[:only] = config_only_options if @lint_mode || @layout_mode diff --git a/lib/rubocop/lsp/server.rb b/lib/rubocop/lsp/server.rb index 5e97e1c40061..db24be542283 100644 --- a/lib/rubocop/lsp/server.rb +++ b/lib/rubocop/lsp/server.rb @@ -45,8 +45,8 @@ def write(response) @writer.write(response) end - def format(path, text) - @runtime.format(path, text) + def format(path, text, command:) + @runtime.format(path, text, command: command) end def offenses(path, text) diff --git a/spec/rubocop/lsp/server_spec.rb b/spec/rubocop/lsp/server_spec.rb index 218493f00714..eab8bceb4dbe 100644 --- a/spec/rubocop/lsp/server_spec.rb +++ b/spec/rubocop/lsp/server_spec.rb @@ -980,7 +980,7 @@ end end - describe 'execute command formatting' do + describe 'execute command safe formatting' do let(:requests) do [ { @@ -1029,6 +1029,59 @@ end end + describe 'execute command unsafe formatting' do + let(:requests) do + [ + { + jsonrpc: '2.0', + method: 'textDocument/didOpen', + params: { + textDocument: { + languageId: 'ruby', + text: 'something.map { |s| s.upcase }', + uri: 'file:///path/to/file.rb', + version: 0 + } + } + }, { + jsonrpc: '2.0', + id: 99, + method: 'workspace/executeCommand', + params: { + command: 'rubocop.formatAutocorrectsAll', + arguments: [uri: 'file:///path/to/file.rb'] + } + } + ] + end + + it 'handles requests' do + expect(stderr).to eq('') + expect(messages.last).to eq( + jsonrpc: '2.0', + id: 99, + method: 'workspace/applyEdit', + params: { + label: 'Format all with RuboCop autocorrects', + edit: { + changes: { + 'file:///path/to/file.rb': [ + newText: <<~RUBY, + # frozen_string_literal: true + + something.map(&:upcase) + RUBY + range: { + start: { line: 0, character: 0 }, end: { line: 1, character: 0 } + } + ] + } + } + } + ) + end + end + describe 'execute command with unsupported command' do let(:requests) do [ From d5e572061991c83578dd2b64dae87ad458480a05 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Fri, 4 Aug 2023 12:06:54 +0900 Subject: [PATCH 07/17] Fix a false positive for `Style/Alias` This PR fixes the following false positive to prevent incorrect autocorrection for `Style/Alias` when `EncforcedStyle: prefer_alias` and using `alias` with interpolated symbol argument: ```console $ ruby -ce 'alias :"string#{interpolation}" :symbol' Syntax OK ``` ```console $ echo 'alias :"string#{interpolation}" :symbol' | bundle exec rubocop --stdin example.rb -a --only Style/Alias Inspecting 1 file F Offenses: example.rb:1:7: F: Lint/Syntax: unexpected token tSTRING_BEG (Using Ruby 2.7 parser; configure using TargetRubyVersion parameter, under AllCops) alias "string#{interpolation}" symbol ^ example.rb:1:7: C: [Corrected] Style/Alias: Use alias "string#{interpolation}" symbol instead of alias :"string#{interpolation}" :symbol. alias :"string#{interpolation}" :symbol ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ example.rb:1:32: F: Lint/Syntax: unexpected token tIDENTIFIER (Using Ruby 2.7 parser; configure using TargetRubyVersion parameter, under AllCops) alias "string#{interpolation}" symbol ^^^^^^ 1 file inspected, 3 offenses detected, 1 offense corrected ==================== alias "string#{interpolation}" symbol ``` --- changelog/fix_a_false_positive_for_style_alias.md | 1 + lib/rubocop/cop/style/alias.rb | 2 +- spec/rubocop/cop/style/alias_spec.rb | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changelog/fix_a_false_positive_for_style_alias.md diff --git a/changelog/fix_a_false_positive_for_style_alias.md b/changelog/fix_a_false_positive_for_style_alias.md new file mode 100644 index 000000000000..bd53647984ee --- /dev/null +++ b/changelog/fix_a_false_positive_for_style_alias.md @@ -0,0 +1 @@ +* [#12095](https://github.com/rubocop/rubocop/pull/12095): Fix a false positive for `Style/Alias` when `EncforcedStyle: prefer_alias` and using `alias` with interpolated symbol argument. ([@koic][]) diff --git a/lib/rubocop/cop/style/alias.rb b/lib/rubocop/cop/style/alias.rb index fe70ff01dd2d..302c763d7034 100644 --- a/lib/rubocop/cop/style/alias.rb +++ b/lib/rubocop/cop/style/alias.rb @@ -122,7 +122,7 @@ def lexical_scope_type(node) end def bareword?(sym_node) - !sym_node.source.start_with?(':') + !sym_node.source.start_with?(':') || sym_node.dsym_type? end def correct_alias_method_to_alias(corrector, send_node) diff --git a/spec/rubocop/cop/style/alias_spec.rb b/spec/rubocop/cop/style/alias_spec.rb index e7e527604df2..94554f21e62c 100644 --- a/spec/rubocop/cop/style/alias_spec.rb +++ b/spec/rubocop/cop/style/alias_spec.rb @@ -114,6 +114,12 @@ def foo RUBY end + it 'does not register an offense for `alias` with interpolated symbol argument' do + expect_no_offenses(<<~'RUBY') + alias :"string#{interpolation}" :symbol + RUBY + end + it 'registers an offense for alias in a defs' do expect_offense(<<~RUBY) def some_obj.foo From 55fd38019e40330ea2b34d857ba47912dae96135 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 5 Aug 2023 04:45:36 +0900 Subject: [PATCH 08/17] Fix a false positive for `Style/ClassEqualityComparison` This PR fixes a false positive to prevent an incorrect autocorrect for `Style/ClassEqualityComparison` when comparing interpolated string class name for equality. For example, autocorrect the code below: ```console $ cat example.rb var.class.name == "String#{interpolation}" $ bundle exec rubocop --only Style/ClassEqualityComparison -a Inspecting 1 file C Offenses: example.rb:1:5: C: [Corrected] Style/ClassEqualityComparison: Use instance_of?("String#{interpolation}") instead of comparing classes. var.class.name == "String#{interpolation}" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1 file inspected, 1 offense detected, 1 offense corrected ``` The `instance_of?` argument is still a string. ```console $ cat example.rb var.instance_of?("String#{interpolation}") ``` But the `instance_of?` argument requires class or module. So the above case cannot be replaced by `instace_of?`. ```console $ ruby -e "''.instance_of?('String')" -e:1:in `instance_of?': class or module required (TypeError) ''.instance_of?('String') ^^^^^^^^ from -e:1:in `
' ``` --- ..._a_false_positive_for_style_class_equality_comparison.md | 1 + lib/rubocop/cop/style/class_equality_comparison.rb | 2 ++ spec/rubocop/cop/style/class_equality_comparison_spec.rb | 6 ++++++ 3 files changed, 9 insertions(+) create mode 100644 changelog/fix_a_false_positive_for_style_class_equality_comparison.md diff --git a/changelog/fix_a_false_positive_for_style_class_equality_comparison.md b/changelog/fix_a_false_positive_for_style_class_equality_comparison.md new file mode 100644 index 000000000000..2e5c2fba8067 --- /dev/null +++ b/changelog/fix_a_false_positive_for_style_class_equality_comparison.md @@ -0,0 +1 @@ +* [#12098](https://github.com/rubocop/rubocop/pull/12098): Fix a false positive for `Style/ClassEqualityComparison` when comparing interpolated string class name for equality. ([@koic][]) diff --git a/lib/rubocop/cop/style/class_equality_comparison.rb b/lib/rubocop/cop/style/class_equality_comparison.rb index fcc439615114..a242a8578be1 100644 --- a/lib/rubocop/cop/style/class_equality_comparison.rb +++ b/lib/rubocop/cop/style/class_equality_comparison.rb @@ -69,6 +69,8 @@ def on_send(node) matches_allowed_pattern?(def_node.method_name)) class_comparison_candidate?(node) do |receiver_node, class_node| + return if class_node.dstr_type? + range = offense_range(receiver_node, node) class_argument = (class_name = class_name(class_node, node)) ? "(#{class_name})" : '' diff --git a/spec/rubocop/cop/style/class_equality_comparison_spec.rb b/spec/rubocop/cop/style/class_equality_comparison_spec.rb index 62d5613316fb..9887dff8693a 100644 --- a/spec/rubocop/cop/style/class_equality_comparison_spec.rb +++ b/spec/rubocop/cop/style/class_equality_comparison_spec.rb @@ -70,6 +70,12 @@ RUBY end + it 'does not register an offense when comparing interpolated string class name for equality' do + expect_no_offenses(<<~'RUBY') + var.class.name == "String#{interpolation}" + RUBY + end + it 'registers an offense but does not correct when comparing local variable for equality' do expect_offense(<<~RUBY) class_name = 'Model' From e068bdd60bab1df9e544467ead23bd6f86d6bf64 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sun, 6 Aug 2023 01:16:19 +0900 Subject: [PATCH 09/17] Fix an incorrect autocorrect for `Style/Alias` This PR fixes the following incorrect autocorrection for `Style/Alias` when `EncforcedStyle: prefer_alias_method` and using `alias` with interpolated symbol argument: ```console $ cat example.rb alias :"string#{interpolation}" :symbol $ cat .rubocop.yml Style/Alias: EnforcedStyle: prefer_alias_method ``` ```console $ bundle exec rubocop -a --only Style/Alias (snip) Offenses: example.rb:1:1: C: [Corrected] Style/Alias: Use alias_method instead of alias. alias :"string#{interpolation}" :symbol ^^^^^ example.rb:1:14: F: Lint/Syntax: unexpected token tCOLON (Using Ruby 3.2 parser; configure using TargetRubyVersion parameter, under AllCops) alias_method :, :symbol ^ 1 file inspected, 2 offenses detected, 1 offense corrected ``` ```console $ cat example.rb alias_method :, :symbol $ ruby -c example.rb example.rb: example.rb:1: syntax error, unexpected ',', expecting literal content or terminator or tSTRING_DBEG or tSTRING_DVAR (SyntaxError) alias_method :, :symbol ^ ``` --- changelog/fix_an_incorrect_for_style_alias.md | 1 + lib/rubocop/cop/style/alias.rb | 15 ++++++++------- spec/rubocop/cop/style/alias_spec.rb | 11 +++++++++++ 3 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 changelog/fix_an_incorrect_for_style_alias.md diff --git a/changelog/fix_an_incorrect_for_style_alias.md b/changelog/fix_an_incorrect_for_style_alias.md new file mode 100644 index 000000000000..267cadfee662 --- /dev/null +++ b/changelog/fix_an_incorrect_for_style_alias.md @@ -0,0 +1 @@ +* [#12099](https://github.com/rubocop/rubocop/pull/12099): Fix an incorrect autocorrect for `Style/Alias` when `EncforcedStyle: prefer_alias_method` and using `alias` with interpolated symbol argument. ([@koic][]) diff --git a/lib/rubocop/cop/style/alias.rb b/lib/rubocop/cop/style/alias.rb index fe70ff01dd2d..b25bfe1ab32f 100644 --- a/lib/rubocop/cop/style/alias.rb +++ b/lib/rubocop/cop/style/alias.rb @@ -134,9 +134,7 @@ def correct_alias_method_to_alias(corrector, send_node) def correct_alias_to_alias_method(corrector, node) replacement = - 'alias_method ' \ - ":#{identifier(node.new_identifier)}, " \ - ":#{identifier(node.old_identifier)}" + "alias_method #{identifier(node.new_identifier)}, #{identifier(node.old_identifier)}" corrector.replace(node, replacement) end @@ -146,10 +144,13 @@ def correct_alias_with_symbol_args(corrector, node) corrector.replace(node.old_identifier, node.old_identifier.source[1..]) end - # @!method identifier(node) - def_node_matcher :identifier, <<~PATTERN - (sym $_) - PATTERN + def identifier(node) + if node.sym_type? + ":#{node.children.first}" + else + node.source + end + end end end end diff --git a/spec/rubocop/cop/style/alias_spec.rb b/spec/rubocop/cop/style/alias_spec.rb index e7e527604df2..9014923dcae4 100644 --- a/spec/rubocop/cop/style/alias_spec.rb +++ b/spec/rubocop/cop/style/alias_spec.rb @@ -26,6 +26,17 @@ RUBY end + it 'registers an offense for `alias` with interpolated symbol argument' do + expect_offense(<<~'RUBY') + alias :"string#{interpolation}" :symbol + ^^^^^ Use `alias_method` instead of `alias`. + RUBY + + expect_correction(<<~'RUBY') + alias_method :"string#{interpolation}", :symbol + RUBY + end + it 'does not register an offense for alias_method' do expect_no_offenses('alias_method :ala, :bala') end From 57dd39246028b70ef493d8898675b92b19e01390 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Tue, 8 Aug 2023 01:00:02 +0900 Subject: [PATCH 10/17] Fix an error for `Style/LambdaCall` This PR fixes an error for `Style/LambdaCall` when using nested lambda call `x.().()`: ```console $ cat example.rb x.(a, b).(c) $ buncle exec rubocop example.rb --only Style/LambdaCall -a -d (snip) An error occurred while Style/LambdaCall cop was inspecting /Users/koic/src/github.com/koic/rubocop-issues/lambda_call/example.rb:1:0. Parser::Source::TreeRewriter detected clobbering /Users/koic/.rbenv/versions/3.2.2/lib/ruby/gems/3.2.0/gems/parser-3.2.2.3/lib/parser/source/tree_rewriter.rb:427:in `trigger_policy' ``` --- changelog/fix_an_error_for_style_lambda_call.md | 1 + lib/rubocop/cop/style/lambda_call.rb | 5 +++++ spec/rubocop/cop/style/lambda_call_spec.rb | 12 ++++++++++++ 3 files changed, 18 insertions(+) create mode 100644 changelog/fix_an_error_for_style_lambda_call.md diff --git a/changelog/fix_an_error_for_style_lambda_call.md b/changelog/fix_an_error_for_style_lambda_call.md new file mode 100644 index 000000000000..c5c354f59a70 --- /dev/null +++ b/changelog/fix_an_error_for_style_lambda_call.md @@ -0,0 +1 @@ +* [#12102](https://github.com/rubocop/rubocop/pull/12102): Fix an error for `Style/LambdaCall` when using nested lambda call `x.().()`. ([@koic][]) diff --git a/lib/rubocop/cop/style/lambda_call.rb b/lib/rubocop/cop/style/lambda_call.rb index 81abf811c943..1b2a8cafcb1b 100644 --- a/lib/rubocop/cop/style/lambda_call.rb +++ b/lib/rubocop/cop/style/lambda_call.rb @@ -20,6 +20,7 @@ module Style # lambda.(x, y) class LambdaCall < Base include ConfigurableEnforcedStyle + include IgnoredNode extend AutoCorrector MSG = 'Prefer the use of `%s` over `%s`.' @@ -33,8 +34,12 @@ def on_send(node) current = node.source add_offense(node, message: format(MSG, prefer: prefer, current: current)) do |corrector| + next if part_of_ignored_node?(node) + opposite_style_detected corrector.replace(node, prefer) + + ignore_node(node) end else correct_style_detected diff --git a/spec/rubocop/cop/style/lambda_call_spec.rb b/spec/rubocop/cop/style/lambda_call_spec.rb index 65404ec1b4eb..1a2c0d089675 100644 --- a/spec/rubocop/cop/style/lambda_call_spec.rb +++ b/spec/rubocop/cop/style/lambda_call_spec.rb @@ -15,6 +15,18 @@ RUBY end + it 'registers an offense for x.().()' do + expect_offense(<<~RUBY) + x.(a, b).(c) + ^^^^^^^^^^^^ Prefer the use of `x.(a, b).call(c)` over `x.(a, b).(c)`. + ^^^^^^^^ Prefer the use of `x.call(a, b)` over `x.(a, b)`. + RUBY + + expect_correction(<<~RUBY) + x.(a, b).call(c) + RUBY + end + it 'registers an offense for correct + opposite' do expect_offense(<<~RUBY) x.call(a, b) From f871c38c5f40d0e5b4c110843b862b3aa424a2c2 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Wed, 9 Aug 2023 00:14:27 +0900 Subject: [PATCH 11/17] [Fix #12106] Fix a false negative for `Style/RedundantReturn` Fixes #12106. This PR fixes a false negative for `Style/RedundantReturn` when returning value with guard clause and `return` is used. --- ...lse_negative_for_style_redundant_return.md | 1 + lib/rubocop/config_finder.rb | 4 ++-- .../layout/empty_line_after_guard_clause.rb | 2 +- lib/rubocop/cop/layout/indentation_width.rb | 2 +- lib/rubocop/cop/layout/space_inside_parens.rb | 2 +- lib/rubocop/cop/lint/struct_new_override.rb | 24 +++++++++---------- lib/rubocop/cop/style/block_delimiters.rb | 3 ++- lib/rubocop/cop/style/redundant_return.rb | 9 +++++-- .../cop/style/redundant_return_spec.rb | 19 +++++++++++++-- 9 files changed, 44 insertions(+), 22 deletions(-) create mode 100644 changelog/fix_a_false_negative_for_style_redundant_return.md diff --git a/changelog/fix_a_false_negative_for_style_redundant_return.md b/changelog/fix_a_false_negative_for_style_redundant_return.md new file mode 100644 index 000000000000..bf6910fafacf --- /dev/null +++ b/changelog/fix_a_false_negative_for_style_redundant_return.md @@ -0,0 +1 @@ +* [#12106](https://github.com/rubocop/rubocop/issues/12106): Fix a false negative for `Style/RedundantReturn` when returning value with guard clause and `return` is used. ([@koic][]) diff --git a/lib/rubocop/config_finder.rb b/lib/rubocop/config_finder.rb index c990969f197d..648034501ef8 100644 --- a/lib/rubocop/config_finder.rb +++ b/lib/rubocop/config_finder.rb @@ -46,14 +46,14 @@ def find_user_dotfile file = File.join(Dir.home, DOTFILE) - return file if File.exist?(file) + file if File.exist?(file) end def find_user_xdg_config xdg_config_home = expand_path(ENV.fetch('XDG_CONFIG_HOME', '~/.config')) xdg_config = File.join(xdg_config_home, 'rubocop', XDG_CONFIG) - return xdg_config if File.exist?(xdg_config) + xdg_config if File.exist?(xdg_config) end def expand_path(path) diff --git a/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb b/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb index 048547e5c294..1576641e8d9d 100644 --- a/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +++ b/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb @@ -137,7 +137,7 @@ def last_heredoc_argument(node) return node if node end - return last_heredoc_argument(n.receiver) if n.respond_to?(:receiver) + last_heredoc_argument(n.receiver) if n.respond_to?(:receiver) end def last_heredoc_argument_node(node) diff --git a/lib/rubocop/cop/layout/indentation_width.rb b/lib/rubocop/cop/layout/indentation_width.rb index f4d29f5dcaf0..e8f3fbefa958 100644 --- a/lib/rubocop/cop/layout/indentation_width.rb +++ b/lib/rubocop/cop/layout/indentation_width.rb @@ -354,7 +354,7 @@ def skip_check?(base_loc, body_node) # Don't check indentation if the line doesn't start with the body. # For example, lines like "else do_something". first_char_pos_on_line = body_node.source_range.source_line =~ /\S/ - return true unless body_node.loc.column == first_char_pos_on_line + true unless body_node.loc.column == first_char_pos_on_line end def offending_range(body_node, indentation) diff --git a/lib/rubocop/cop/layout/space_inside_parens.rb b/lib/rubocop/cop/layout/space_inside_parens.rb index caeb3c244c96..7396fc5d511f 100644 --- a/lib/rubocop/cop/layout/space_inside_parens.rb +++ b/lib/rubocop/cop/layout/space_inside_parens.rb @@ -168,7 +168,7 @@ def can_be_ignored?(token1, token2) # follows, and that the rules for space inside don't apply. return true if token2.comment? - return true unless same_line?(token1, token2) && !token1.space_after? + true unless same_line?(token1, token2) && !token1.space_after? end end end diff --git a/lib/rubocop/cop/lint/struct_new_override.rb b/lib/rubocop/cop/lint/struct_new_override.rb index e74ea6243fb8..f08129c73c40 100644 --- a/lib/rubocop/cop/lint/struct_new_override.rb +++ b/lib/rubocop/cop/lint/struct_new_override.rb @@ -32,25 +32,25 @@ class StructNewOverride < Base # @!method struct_new(node) def_node_matcher :struct_new, <<~PATTERN (send - (const ${nil? cbase} :Struct) :new ...) + (const {nil? cbase} :Struct) :new ...) PATTERN def on_send(node) - return unless struct_new(node) do - node.arguments.each_with_index do |arg, index| - # Ignore if the first argument is a class name - next if index.zero? && arg.str_type? + return unless struct_new(node) - # Ignore if the argument is not a member name - next unless STRUCT_MEMBER_NAME_TYPES.include?(arg.type) + node.arguments.each_with_index do |arg, index| + # Ignore if the first argument is a class name + next if index.zero? && arg.str_type? - member_name = arg.value + # Ignore if the argument is not a member name + next unless STRUCT_MEMBER_NAME_TYPES.include?(arg.type) - next unless STRUCT_METHOD_NAMES.include?(member_name.to_sym) + member_name = arg.value - message = format(MSG, member_name: member_name.inspect, method_name: member_name.to_s) - add_offense(arg, message: message) - end + next unless STRUCT_METHOD_NAMES.include?(member_name.to_sym) + + message = format(MSG, member_name: member_name.inspect, method_name: member_name.to_s) + add_offense(arg, message: message) end end end diff --git a/lib/rubocop/cop/style/block_delimiters.rb b/lib/rubocop/cop/style/block_delimiters.rb index 64a380d15f11..d713a3b09045 100644 --- a/lib/rubocop/cop/style/block_delimiters.rb +++ b/lib/rubocop/cop/style/block_delimiters.rb @@ -370,7 +370,8 @@ def special_method?(method_name) def special_method_proper_block_style?(node) method_name = node.method_name return true if allowed_method?(method_name) || matches_allowed_pattern?(method_name) - return node.braces? if braces_required_method?(method_name) + + node.braces? if braces_required_method?(method_name) end def braces_required_method?(method_name) diff --git a/lib/rubocop/cop/style/redundant_return.rb b/lib/rubocop/cop/style/redundant_return.rb index 6fd65e4dd3f3..d1b5e8fc975f 100644 --- a/lib/rubocop/cop/style/redundant_return.rb +++ b/lib/rubocop/cop/style/redundant_return.rb @@ -22,13 +22,18 @@ module Style # return something # end # - # # good + # # bad # def test # return something if something_else # end # # # good # def test + # something if something_else + # end + # + # # good + # def test # if x # elsif y # else @@ -136,7 +141,7 @@ def check_case_node(node) end def check_if_node(node) - return if node.modifier_form? || node.ternary? + return if node.ternary? check_branch(node.if_branch) check_branch(node.else_branch) diff --git a/spec/rubocop/cop/style/redundant_return_spec.rb b/spec/rubocop/cop/style/redundant_return_spec.rb index b9fc9c96b36a..e11fd48c65de 100644 --- a/spec/rubocop/cop/style/redundant_return_spec.rb +++ b/spec/rubocop/cop/style/redundant_return_spec.rb @@ -152,10 +152,25 @@ def self.func RUBY end - it 'accepts return in a non-final position' do - expect_no_offenses(<<~RUBY) + it 'registers an offense when returning value with guard clause and `return` is used' do + expect_offense(<<~RUBY) def func return something if something_else + ^^^^^^ Redundant `return` detected. + end + RUBY + + expect_correction(<<~RUBY) + def func + something if something_else + end + RUBY + end + + it 'does not register an offense when returning value with guard clause and `return` is not used' do + expect_no_offenses(<<~RUBY) + def func + something if something_else end RUBY end From 08e614ff64f153fff8b746619f28701a5a79e732 Mon Sep 17 00:00:00 2001 From: Owen Stephens Date: Tue, 8 Aug 2023 09:20:37 +0100 Subject: [PATCH 12/17] [Fix #12087] Fix false positives for Style/ArgumentsForwarding Additionally fixes: * #12089 * #12096 * #12100 In Ruby < 3.2 this cop was overzealous and not considering various additional args/kwargs and other reasons to not allow forward-all (`...`), and was additionally assuming that forward-all meant all arguments were replaced, which was not always the case. --- ...ositives_for_style_arguments_forwarding.md | 1 + lib/rubocop/cop/style/arguments_forwarding.rb | 109 +++--- .../cop/style/arguments_forwarding_spec.rb | 309 ++++++++++++++++++ 3 files changed, 379 insertions(+), 40 deletions(-) create mode 100644 changelog/fix_false_positives_for_style_arguments_forwarding.md diff --git a/changelog/fix_false_positives_for_style_arguments_forwarding.md b/changelog/fix_false_positives_for_style_arguments_forwarding.md new file mode 100644 index 000000000000..5d11d7441554 --- /dev/null +++ b/changelog/fix_false_positives_for_style_arguments_forwarding.md @@ -0,0 +1 @@ +* [#12087](https://github.com/rubocop/rubocop/issues/12087): Fix false positives for `Style/ArgumentsForwarding` with additional args/kwargs in def/send nodes. ([@owst][]) diff --git a/lib/rubocop/cop/style/arguments_forwarding.rb b/lib/rubocop/cop/style/arguments_forwarding.rb index f231e5c83686..d53712f1ba0b 100644 --- a/lib/rubocop/cop/style/arguments_forwarding.rb +++ b/lib/rubocop/cop/style/arguments_forwarding.rb @@ -100,7 +100,7 @@ def on_def(node) return if send_classifications.empty? if only_forwards_all?(send_classifications) - add_forward_all_offenses(node, send_classifications) + add_forward_all_offenses(node, send_classifications, forwardable_args) elsif target_ruby_version >= 3.2 add_post_ruby_32_offenses(node, send_classifications, forwardable_args) end @@ -118,12 +118,13 @@ def only_forwards_all?(send_classifications) send_classifications.each_value.all? { |c, _, _| c == :all } end - def add_forward_all_offenses(node, send_classifications) - send_classifications.each_key do |send_node| - register_forward_all_offense_on_forwarding_method(send_node) + def add_forward_all_offenses(node, send_classifications, forwardable_args) + send_classifications.each do |send_node, (_c, forward_rest, _forward_kwrest)| + register_forward_all_offense(send_node, send_node, forward_rest) end - register_forward_all_offense_on_method_def(node) + rest_arg, _kwrest_arg, _block_arg = *forwardable_args + register_forward_all_offense(node, node.arguments, rest_arg) end def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args) @@ -186,9 +187,7 @@ def classification_and_forwards(def_node, send_node, referenced_lvars, forwardab def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat) add_offense(rest_arg_or_splat, message: ARGS_MSG) do |corrector| - unless parentheses?(def_arguments_or_send) - add_parentheses(def_arguments_or_send, corrector) - end + add_parens_if_missing(def_arguments_or_send, corrector) corrector.replace(rest_arg_or_splat, '*') end @@ -196,36 +195,28 @@ def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat) def register_forward_kwargs_offense(add_parens, def_arguments_or_send, kwrest_arg_or_splat) add_offense(kwrest_arg_or_splat, message: KWARGS_MSG) do |corrector| - if add_parens && !parentheses?(def_arguments_or_send) - add_parentheses(def_arguments_or_send, corrector) - end + add_parens_if_missing(def_arguments_or_send, corrector) if add_parens corrector.replace(kwrest_arg_or_splat, '**') end end - def register_forward_all_offense_on_forwarding_method(forwarding_method) - add_offense(arguments_range(forwarding_method), message: FORWARDING_MSG) do |corrector| - begin_pos = forwarding_method.loc.selector&.end_pos || forwarding_method.loc.dot.end_pos - range = range_between(begin_pos, forwarding_method.source_range.end_pos) + def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat) + arg_range = arguments_range(def_or_send, rest_or_splat) - corrector.replace(range, '(...)') - end - end + add_offense(arg_range, message: FORWARDING_MSG) do |corrector| + add_parens_if_missing(send_or_arguments, corrector) - def register_forward_all_offense_on_method_def(method_definition) - add_offense(arguments_range(method_definition), message: FORWARDING_MSG) do |corrector| - arguments_range = range_with_surrounding_space( - method_definition.arguments.source_range, side: :left - ) - corrector.replace(arguments_range, '(...)') + corrector.replace(arg_range, '...') end end - def arguments_range(node) + def arguments_range(node, first_node) arguments = node.arguments - range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos) + start_node = first_node || arguments.first + + range_between(start_node.source_range.begin_pos, arguments.last.source_range.end_pos) end def allow_only_rest_arguments? @@ -236,6 +227,12 @@ def use_anonymous_forwarding? cop_config.fetch('UseAnonymousForwarding', false) end + def add_parens_if_missing(node, corrector) + return if parentheses?(node) + + add_parentheses(node, corrector) + end + # Classifies send nodes for possible rest/kwrest/all (including block) forwarding. class SendNodeClassifier extend NodePattern::Macros @@ -280,7 +277,7 @@ def forwarded_block_arg def classification return nil unless forwarded_rest_arg || forwarded_kwrest_arg - if referenced_none? && (forwarded_exactly_all? || pre_ruby_32_allow_forward_all?) + if can_forward_all? :all elsif target_ruby_version >= 3.2 :rest_or_kwrest @@ -289,6 +286,27 @@ def classification private + def can_forward_all? + return false if any_arg_referenced? + return false if ruby_32_missing_rest_or_kwest? + return false unless offensive_block_forwarding? + return false if forward_additional_kwargs? + + no_additional_args? || (target_ruby_version >= 3.0 && no_post_splat_args?) + end + + def ruby_32_missing_rest_or_kwest? + target_ruby_version >= 3.2 && !forwarded_rest_and_kwrest_args + end + + def offensive_block_forwarding? + @block_arg ? forwarded_block_arg : allow_offense_for_no_block? + end + + def forwarded_rest_and_kwrest_args + forwarded_rest_arg && forwarded_kwrest_arg + end + def arguments @send_node.arguments end @@ -305,25 +323,36 @@ def referenced_block_arg? @referenced_lvars.include?(@block_arg_name) end - def referenced_none? - !(referenced_rest_arg? || referenced_kwrest_arg? || referenced_block_arg?) - end - - def forwarded_exactly_all? - @send_node.arguments.size == 3 && - forwarded_rest_arg && - forwarded_kwrest_arg && - forwarded_block_arg + def any_arg_referenced? + referenced_rest_arg? || referenced_kwrest_arg? || referenced_block_arg? end def target_ruby_version @config.fetch(:target_ruby_version) end - def pre_ruby_32_allow_forward_all? - target_ruby_version < 3.2 && - @def_node.arguments.none?(&:default?) && - (@block_arg ? forwarded_block_arg : !@config.fetch(:allow_only_rest_arguments)) + def no_post_splat_args? + splat_index = arguments.index(forwarded_rest_arg) + arg_after_splat = arguments[splat_index + 1] + + [nil, :hash, :block_pass].include?(arg_after_splat&.type) + end + + def forward_additional_kwargs? + return false unless forwarded_kwrest_arg + + !forwarded_kwrest_arg.parent.children.one? + end + + def allow_offense_for_no_block? + !@config.fetch(:allow_only_rest_arguments) + end + + def no_additional_args? + forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size + + @def_node.arguments.size == forwardable_count && + @send_node.arguments.size == forwardable_count end end end diff --git a/spec/rubocop/cop/style/arguments_forwarding_spec.rb b/spec/rubocop/cop/style/arguments_forwarding_spec.rb index b7cb3dbb1034..1aeb81abfdcb 100644 --- a/spec/rubocop/cop/style/arguments_forwarding_spec.rb +++ b/spec/rubocop/cop/style/arguments_forwarding_spec.rb @@ -247,6 +247,14 @@ def foo(*args, &block) RUBY end + it 'does not register an offense with arg destructuring' do + expect_no_offenses(<<~RUBY) + def foo((bar, baz), **kwargs) + forwarded(bar, baz, **kwargs) + end + RUBY + end + context 'AllowOnlyRestArgument: true' do let(:cop_config) { { 'AllowOnlyRestArgument' => true } } @@ -342,6 +350,175 @@ def foo(*args, **kwargs, &block) end RUBY end + + it 'does not register an offense if an additional positional parameter is present' do + # Technically, forward-all supports leading additional arguments in Ruby >= 2.7.3, but for + # simplicity we do not correct for any Ruby < 3.0 + # https://github.com/rubocop/rubocop/issues/12087#issuecomment-1662972732 + expect_no_offenses(<<~RUBY) + def method_missing(m, *args, **kwargs, &block) + if @template.respond_to?(m) + @template.send(m, *args, **kwargs, &block) + else + super + end + end + RUBY + end + + it 'does not register an offense if kwargs are forwarded with a positional parameter' do + expect_no_offenses(<<~RUBY) + def foo(m, **kwargs, &block) + bar(m, **kwargs, &block) + end + RUBY + end + + it 'does not register an offense if args are forwarded with a positional parameter last' do + expect_no_offenses(<<~RUBY) + def foo(m, *args, &block) + bar(*args, m, &block) + end + RUBY + end + + it 'does not register an offense if args/kwargs are forwarded with a positional parameter' do + expect_no_offenses(<<~RUBY) + def foo(m, *args, **kwargs, &block) + bar(m, *args, **kwargs, &block) + end + RUBY + end + + it 'does not register an offense when forwarding args/kwargs with an additional arg' do + expect_no_offenses(<<~RUBY) + def self.get(*args, **kwargs, &block) + CanvasHttp.request(Net::HTTP::Get, *args, **kwargs, &block) + end + RUBY + end + + it 'does not register an offense when forwarding args with an additional arg' do + expect_no_offenses(<<~RUBY) + def post(*args, &block) + future_on(executor, *args, &block) + end + RUBY + end + end + + context 'TargetRubyVersion >= 3.0', :ruby30 do + it 'does not register an offense if args are forwarded with a positional parameter last' do + expect_no_offenses(<<~RUBY) + def foo(m, *args, &block) + bar(*args, m, &block) + end + RUBY + end + + it 'does not register an offense if args/kwargs are forwarded with a positional parameter last' do + expect_no_offenses(<<~RUBY) + def foo(m, *args, **kwargs, &block) + bar(*args, m, **kwargs, &block) + end + RUBY + end + + it 'registers an offense if args/kwargs are forwarded with a positional parameter' do + expect_offense(<<~RUBY) + def foo(m, *args, **kwargs, &block) + ^^^^^^^^^^^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + bar(m, *args, **kwargs, &block) + ^^^^^^^^^^^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + end + RUBY + + expect_correction(<<~RUBY) + def foo(m, ...) + bar(m, ...) + end + RUBY + end + + it 'does not register an offense if args/kwargs are forwarded with additional pre-kwarg' do + expect_no_offenses(<<~RUBY) + def foo(m, *args, **kwargs, &block) + bar(m, *args, extra: :kwarg, **kwargs, &block) + end + RUBY + end + + it 'does not register an offense if args/kwargs are forwarded with additional post-kwarg' do + expect_no_offenses(<<~RUBY) + def foo(m, *args, **kwargs, &block) + bar(m, *args, **kwargs, extra: :kwarg, &block) + end + RUBY + end + + it 'registers an offense when forwarding args after dropping an additional arg' do + expect_offense(<<~RUBY) + def foo(x, *args, &block) + ^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + bar(*args, &block) + ^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + end + RUBY + + expect_correction(<<~RUBY) + def foo(x, ...) + bar(...) + end + RUBY + end + + it 'registers an offense when forwarding args with a leading default arg' do + expect_offense(<<~RUBY) + def foo(x, y = 42, *args, &block) + ^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + bar(x, y, *args, &block) + ^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + end + RUBY + + expect_correction(<<~RUBY) + def foo(x, y = 42, ...) + bar(x, y, ...) + end + RUBY + end + + it 'registers an offense when forwarding args with an additional arg' do + expect_offense(<<~RUBY) + def post(*args, &block) + ^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + future_on(executor, *args, &block) + ^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + end + RUBY + + expect_correction(<<~RUBY) + def post(...) + future_on(executor, ...) + end + RUBY + end + + it 'registers an offense when forwarding args/kwargs with an additional arg' do + expect_offense(<<~RUBY) + def self.get(*args, **kwargs, &block) + ^^^^^^^^^^^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + CanvasHttp.request(Net::HTTP::Get, *args, **kwargs, &block) + ^^^^^^^^^^^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + end + RUBY + + expect_correction(<<~RUBY) + def self.get(...) + CanvasHttp.request(Net::HTTP::Get, ...) + end + RUBY + end end context 'TargetRubyVersion >= 3.1', :ruby31 do @@ -437,6 +614,122 @@ def foo(arg, *, kwarg:, **) RUBY end + it 'registers an offense when an additional positional parameter is present without block' do + expect_offense(<<~RUBY) + def method_missing(m, *args, **kwargs) + ^^^^^ Use anonymous positional arguments forwarding (`*`). + ^^^^^^^^ Use anonymous keyword arguments forwarding (`**`). + if @template.respond_to?(m) + @template.send(m, *args, **kwargs) + ^^^^^ Use anonymous positional arguments forwarding (`*`). + ^^^^^^^^ Use anonymous keyword arguments forwarding (`**`). + else + super + end + end + RUBY + + expect_correction(<<~RUBY) + def method_missing(m, *, **) + if @template.respond_to?(m) + @template.send(m, *, **) + else + super + end + end + RUBY + end + + it 'registers an offense when an additional positional parameter is present' do + expect_offense(<<~RUBY) + def method_missing(m, *args, **kwargs, &block) + ^^^^^^^^^^^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + if @template.respond_to?(m) + @template.send(m, *args, **kwargs, &block) + ^^^^^^^^^^^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + else + super + end + end + RUBY + + expect_correction(<<~RUBY) + def method_missing(m, ...) + if @template.respond_to?(m) + @template.send(m, ...) + else + super + end + end + RUBY + end + + it 'registers an offense when args are forwarded with a positional parameter last' do + expect_offense(<<~RUBY) + def foo(m, *args, &block) + ^^^^^ Use anonymous positional arguments forwarding (`*`). + bar(*args, m, &block) + ^^^^^ Use anonymous positional arguments forwarding (`*`). + end + RUBY + + expect_correction(<<~RUBY) + def foo(m, *, &block) + bar(*, m, &block) + end + RUBY + end + + it 'registers an offense when forwarding args with an additional arg' do + expect_offense(<<~RUBY) + def post(*args, &block) + ^^^^^ Use anonymous positional arguments forwarding (`*`). + future_on(executor, *args, &block) + ^^^^^ Use anonymous positional arguments forwarding (`*`). + end + RUBY + + expect_correction(<<~RUBY) + def post(*, &block) + future_on(executor, *, &block) + end + RUBY + end + + it 'registers an offense when forwarding args/kwargs with an additional arg' do + expect_offense(<<~RUBY) + def self.get(*args, **kwargs, &block) + ^^^^^^^^^^^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + CanvasHttp.request(Net::HTTP::Get, *args, **kwargs, &block) + ^^^^^^^^^^^^^^^^^^^^^^^ Use shorthand syntax `...` for arguments forwarding. + end + RUBY + + expect_correction(<<~RUBY) + def self.get(...) + CanvasHttp.request(Net::HTTP::Get, ...) + end + RUBY + end + + it 'registers an offense if args/kwargs are forwarded with additional arg/kwarg' do + expect_offense(<<~RUBY) + def foo(m, *args, foo:, **kwargs, &block) + ^^^^^ Use anonymous positional arguments forwarding (`*`). + ^^^^^^^^ Use anonymous keyword arguments forwarding (`**`). + bar(m, *args, foo:, extra: :kwarg, **kwargs, &block) + ^^^^^ Use anonymous positional arguments forwarding (`*`). + ^^^^^^^^ Use anonymous keyword arguments forwarding (`**`). + end + RUBY + + expect_correction(<<~RUBY) + def foo(m, *, foo:, **, &block) + bar(m, *, foo:, extra: :kwarg, **, &block) + end + RUBY + end + it 'registers an offense when using arg/kwarg forwarding with additional forwarded arg/kwarg' do expect_offense(<<~RUBY) def foo(*args, **kwargs) @@ -523,6 +816,22 @@ def foo(*, **) RUBY end + it 'registers an offense for kwarg forwarding with arg destructuring' do + expect_offense(<<~RUBY) + def foo((bar, baz), **kwargs) + ^^^^^^^^ Use anonymous keyword arguments forwarding (`**`). + forwarded(bar, baz, **kwargs) + ^^^^^^^^ Use anonymous keyword arguments forwarding (`**`). + end + RUBY + + expect_correction(<<~RUBY) + def foo((bar, baz), **) + forwarded(bar, baz, **) + end + RUBY + end + it 'registers an offense only for kwrestarg when using the restarg outside forwarding' do expect_offense(<<~RUBY) def foo(*args, **kwargs) From c078235581f0c361c441c35b78de1d3e94c15874 Mon Sep 17 00:00:00 2001 From: Evan Goldenberg Date: Tue, 1 Aug 2023 14:27:41 -0700 Subject: [PATCH 13/17] With `--fail-level A` ignore non-correctable offenses at :info severity The current implementation of `--fail-level autocorrect` fails for all offenses, no matter what. Notably, this includes non-correctable offenses with the :info severity. Change the implementation to only fail: * Any _correctable_ offense, regardless of severity * Non-correctable offenses with severity :refactor (the default) or higher --- ...level_a_ignore_non_correctable_offenses.md | 1 + .../modules/ROOT/pages/usage/basic_usage.adoc | 2 +- lib/rubocop/runner.rb | 8 ++++--- spec/rubocop/cli/options_spec.rb | 23 +++++++++++++++++++ 4 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 changelog/fix_with_fail_level_a_ignore_non_correctable_offenses.md diff --git a/changelog/fix_with_fail_level_a_ignore_non_correctable_offenses.md b/changelog/fix_with_fail_level_a_ignore_non_correctable_offenses.md new file mode 100644 index 000000000000..88c735bbb5e9 --- /dev/null +++ b/changelog/fix_with_fail_level_a_ignore_non_correctable_offenses.md @@ -0,0 +1 @@ +* [#12091](https://github.com/rubocop/rubocop/pull/12091): With `--fail-level A` ignore non-correctable offenses at :info severity. ([@naveg][]) diff --git a/docs/modules/ROOT/pages/usage/basic_usage.adoc b/docs/modules/ROOT/pages/usage/basic_usage.adoc index 1cae5d09664f..36bc30587518 100644 --- a/docs/modules/ROOT/pages/usage/basic_usage.adoc +++ b/docs/modules/ROOT/pages/usage/basic_usage.adoc @@ -196,7 +196,7 @@ $ rubocop --only Rails/Blank,Layout/HeredocIndentation,Naming/FileName | Inspect files in order of modification time and stops after first file with offenses. | `--fail-level` -| Minimum xref:configuration.adoc#severity[severity] for exit with error code. Full severity name or upper case initial can be given. Normally, autocorrected offenses are ignored. Use `A` or `autocorrect` if you'd like them to trigger failure. +| Minimum xref:configuration.adoc#severity[severity] for exit with error code. Full severity name or upper case initial can be given. Normally, autocorrected offenses are ignored. Use `A` or `autocorrect` if you'd like any autocorrectable offense to trigger failure, regardless of severity. | `--force-exclusion` | Force excluding files specified in the configuration `Exclude` even if they are explicitly passed as arguments. diff --git a/lib/rubocop/runner.rb b/lib/rubocop/runner.rb index 0f49dabc3c53..3200035ae182 100644 --- a/lib/rubocop/runner.rb +++ b/lib/rubocop/runner.rb @@ -421,10 +421,10 @@ def formatter_set end def considered_failure?(offense) - # For :autocorrect level, any offense - corrected or not - is a failure. return false if offense.disabled? - return true if @options[:fail_level] == :autocorrect + # For :autocorrect level, any correctable offense is a failure, regardless of severity + return true if @options[:fail_level] == :autocorrect && offense.correctable? !offense.corrected? && offense.severity >= minimum_severity_to_fail end @@ -461,7 +461,9 @@ def minimum_severity_to_fail @minimum_severity_to_fail ||= begin # Unless given explicitly as `fail_level`, `:info` severity offenses do not fail name = @options[:fail_level] || :refactor - RuboCop::Cop::Severity.new(name) + + # autocorrect is a fake level - use the default + RuboCop::Cop::Severity.new(name == :autocorrect ? :refactor : name) end end diff --git a/spec/rubocop/cli/options_spec.rb b/spec/rubocop/cli/options_spec.rb index 59062c0db689..883954e249f5 100644 --- a/spec/rubocop/cli/options_spec.rb +++ b/spec/rubocop/cli/options_spec.rb @@ -1797,6 +1797,29 @@ def expect_offense_detected expect_offense_detected end + context 'when the cop has the "info" severity' do + before do + create_file(target_file, <<~RUBY) + Long::Line::Not::Autocorrectable + RUBY + + create_file('.rubocop.yml', <<~YAML) + Layout/LineLength: + Max: 10 + Severity: info + YAML + end + + it 'succeeds when option is autocorrect and the offense is not autocorrectable' do + expect(cli.run(['--fail-level', 'autocorrect', + '--only', 'Layout/LineLength', + target_file])).to eq(0) + expect($stderr.string).to eq('') + expect($stdout.string.include?('1 file inspected, 1 offense detected')).to be(true) + expect($stdout.string.include?('Layout/LineLength')).to be(true) + end + end + context 'with --display-only-fail-level-offenses' do it 'outputs offense message when fail-level is less than the severity' do expect(cli.run(['--fail-level', 'refactor', From 964235ce6453f13851dc88118ed4d954d6aa788f Mon Sep 17 00:00:00 2001 From: OwlKing Date: Wed, 9 Aug 2023 07:28:47 +0100 Subject: [PATCH 14/17] Add new `Bundler/DuplicatedGroup` cop (#12074) --- ...ew_add_new_bundler_duplicated_group_cop.md | 1 + config/default.yml | 10 ++ lib/rubocop.rb | 1 + lib/rubocop/cop/bundler/duplicated_group.rb | 80 ++++++++++++++++ .../cop/bundler/duplicated_group_spec.rb | 94 +++++++++++++++++++ 5 files changed, 186 insertions(+) create mode 100644 changelog/new_add_new_bundler_duplicated_group_cop.md create mode 100644 lib/rubocop/cop/bundler/duplicated_group.rb create mode 100644 spec/rubocop/cop/bundler/duplicated_group_spec.rb diff --git a/changelog/new_add_new_bundler_duplicated_group_cop.md b/changelog/new_add_new_bundler_duplicated_group_cop.md new file mode 100644 index 000000000000..11b07e89e49c --- /dev/null +++ b/changelog/new_add_new_bundler_duplicated_group_cop.md @@ -0,0 +1 @@ +* [#12074](https://github.com/rubocop/rubocop/pull/12074): Add new `Bundler/DuplicatedGroup` cop. ([@OwlKing][]) diff --git a/config/default.yml b/config/default.yml index 093de80bc429..354a646a8006 100644 --- a/config/default.yml +++ b/config/default.yml @@ -173,6 +173,16 @@ Bundler/DuplicatedGem: - '**/Gemfile' - '**/gems.rb' +Bundler/DuplicatedGroup: + Description: 'Checks for duplicate group entries in Gemfile.' + Enabled: true + Severity: warning + VersionAdded: '<>' + Include: + - '**/*.gemfile' + - '**/Gemfile' + - '**/gems.rb' + Bundler/GemComment: Description: 'Add a comment describing each gem.' Enabled: false diff --git a/lib/rubocop.rb b/lib/rubocop.rb index 3376ff5f8112..725a1daaba6f 100644 --- a/lib/rubocop.rb +++ b/lib/rubocop.rb @@ -162,6 +162,7 @@ require_relative 'rubocop/cop/correctors/unused_arg_corrector' require_relative 'rubocop/cop/bundler/duplicated_gem' +require_relative 'rubocop/cop/bundler/duplicated_group' require_relative 'rubocop/cop/bundler/gem_comment' require_relative 'rubocop/cop/bundler/gem_filename' require_relative 'rubocop/cop/bundler/gem_version' diff --git a/lib/rubocop/cop/bundler/duplicated_group.rb b/lib/rubocop/cop/bundler/duplicated_group.rb new file mode 100644 index 000000000000..8b90a7618e29 --- /dev/null +++ b/lib/rubocop/cop/bundler/duplicated_group.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Bundler + # A Gem group, or a set of groups should be listed only once in a Gemfile. + # @example + # # bad + # group :development do + # gem 'rubocop' + # end + # + # group :development do + # gem 'rubocop-rails' + # end + # + # # bad (same set of groups declared twice) + # group :development, :test do + # gem 'rubocop' + # end + # + # group :test, :development do + # gem 'rspec' + # end + # + # # good + # group :development do + # gem 'rubocop' + # end + # + # group :development, :test do + # gem 'rspec' + # end + # + # # good + # gem 'rubocop', groups: [:development, :test] + # gem 'rspec', groups: [:development, :test] + # + class DuplicatedGroup < Base + include RangeHelp + + MSG = 'Gem group `%s` already defined on line ' \ + '%d of the Gemfile.' + + def on_new_investigation + return if processed_source.blank? + + duplicated_group_nodes.each do |nodes| + nodes[1..].each do |node| + register_offense(node, node.arguments.map(&:value).join(', '), nodes.first.first_line) + end + end + end + + private + + # @!method group_declarations(node) + def_node_search :group_declarations, '(send nil? :group ...)' + + def duplicated_group_nodes + group_declarations(processed_source.ast) + .group_by { |node| node.arguments.map(&:value).map(&:to_s).sort } + .values + .select { |nodes| nodes.size > 1 } + end + + def register_offense(node, group_name, line_of_first_occurrence) + line_range = node.loc.column...node.loc.last_column + offense_location = source_range(processed_source.buffer, node.first_line, line_range) + message = format( + MSG, + group_name: group_name, + line_of_first_occurrence: line_of_first_occurrence + ) + add_offense(offense_location, message: message) + end + end + end + end +end diff --git a/spec/rubocop/cop/bundler/duplicated_group_spec.rb b/spec/rubocop/cop/bundler/duplicated_group_spec.rb new file mode 100644 index 000000000000..af407fb35667 --- /dev/null +++ b/spec/rubocop/cop/bundler/duplicated_group_spec.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::Bundler::DuplicatedGroup, :config do + let(:cop_config) { { 'Include' => ['**/Gemfile'] } } + + context 'when investigating Ruby files' do + it 'does not register any offenses' do + expect_no_offenses(<<~RUBY, 'foo.rb') + # cop will not read these contents + group :development + group :development + RUBY + end + end + + context 'when investigating Gemfiles' do + context 'and the file is empty' do + it 'does not register any offenses' do + expect_no_offenses('', 'Gemfile') + end + end + + context 'and no duplicate groups are present' do + it 'does not register any offenses' do + expect_no_offenses(<<~RUBY, 'Gemfile') + group :development do + gem 'rubocop' + end + group :test do + gem 'flog' + end + RUBY + end + end + + context 'and a group is duplicated' do + it 'registers an offense' do + expect_offense(<<-RUBY, 'Gemfile') + group :development do + gem 'rubocop' + end + group :development do + ^^^^^^^^^^^^^^^^^^ Gem group `development` already defined on line 1 of the Gemfile. + gem 'rubocop-rails' + end + RUBY + end + end + + context 'and a group is duplicated using different argument types' do + it 'registers an offense' do + expect_offense(<<-RUBY, 'Gemfile') + group :development do + gem 'rubocop' + end + group 'development' do + ^^^^^^^^^^^^^^^^^^^ Gem group `development` already defined on line 1 of the Gemfile. + gem 'rubocop-rails' + end + RUBY + end + end + + context 'and a group is present in different sets of groups' do + it 'does not register any offenses' do + expect_no_offenses(<<~RUBY, 'Gemfile') + group :development do + gem 'rubocop' + end + group :development, :test do + gem 'rspec' + end + group :ci, :development do + gem 'flog' + end + RUBY + end + end + + context 'and a set of groups is duplicated' do + it 'registers an offense' do + expect_offense(<<-RUBY, 'Gemfile') + group :test, :development do + gem 'rubocop' + end + group :development, :test do + ^^^^^^^^^^^^^^^^^^^^^^^^^ Gem group `development, test` already defined on line 1 of the Gemfile. + gem 'rubocop-rails' + end + RUBY + end + end + end +end From 74f00323ddc76a98797c099483ace3dfbbf58149 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Wed, 9 Aug 2023 09:29:46 +0300 Subject: [PATCH 15/17] Update Changelog --- CHANGELOG.md | 23 +++++++++++++++++++ ...change_add_base64_to_runtime_dependency.md | 1 - ...lse_negative_for_style_redundant_return.md | 1 - .../fix_a_false_positive_for_style_alias.md | 1 - ...ive_for_style_class_equality_comparison.md | 1 - .../fix_an_error_for_style_lambda_call.md | 1 - changelog/fix_an_incorrect_for_style_alias.md | 1 - ...fix_error_for_lint_suppressed_exception.md | 1 - ...ositives_for_style_arguments_forwarding.md | 1 - .../fix_style_symbol_array_false_positives.md | 1 - ...gex_in_string_literals_in_interpolation.md | 1 - ...level_a_ignore_non_correctable_offenses.md | 1 - ...ew_add_new_bundler_duplicated_group_cop.md | 1 - ...format_autocorrects_all_execute_command.md | 1 - 14 files changed, 23 insertions(+), 13 deletions(-) delete mode 100644 changelog/change_add_base64_to_runtime_dependency.md delete mode 100644 changelog/fix_a_false_negative_for_style_redundant_return.md delete mode 100644 changelog/fix_a_false_positive_for_style_alias.md delete mode 100644 changelog/fix_a_false_positive_for_style_class_equality_comparison.md delete mode 100644 changelog/fix_an_error_for_style_lambda_call.md delete mode 100644 changelog/fix_an_incorrect_for_style_alias.md delete mode 100644 changelog/fix_error_for_lint_suppressed_exception.md delete mode 100644 changelog/fix_false_positives_for_style_arguments_forwarding.md delete mode 100644 changelog/fix_style_symbol_array_false_positives.md delete mode 100644 changelog/fix_support_regex_in_string_literals_in_interpolation.md delete mode 100644 changelog/fix_with_fail_level_a_ignore_non_correctable_offenses.md delete mode 100644 changelog/new_add_new_bundler_duplicated_group_cop.md delete mode 100644 changelog/new_make_lsp_server_support_format_autocorrects_all_execute_command.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 440d13c2b320..e408e3310af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,28 @@ ## master (unreleased) +### New features + +* [#12074](https://github.com/rubocop/rubocop/pull/12074): Add new `Bundler/DuplicatedGroup` cop. ([@OwlKing][]) +* [#12078](https://github.com/rubocop/rubocop/pull/12078): Make LSP server support `rubocop.formatAutocorrectsAll` execute command. ([@koic][]) + +### Bug fixes + +* [#12106](https://github.com/rubocop/rubocop/issues/12106): Fix a false negative for `Style/RedundantReturn` when returning value with guard clause and `return` is used. ([@koic][]) +* [#12095](https://github.com/rubocop/rubocop/pull/12095): Fix a false positive for `Style/Alias` when `EncforcedStyle: prefer_alias` and using `alias` with interpolated symbol argument. ([@koic][]) +* [#12098](https://github.com/rubocop/rubocop/pull/12098): Fix a false positive for `Style/ClassEqualityComparison` when comparing interpolated string class name for equality. ([@koic][]) +* [#12102](https://github.com/rubocop/rubocop/pull/12102): Fix an error for `Style/LambdaCall` when using nested lambda call `x.().()`. ([@koic][]) +* [#12099](https://github.com/rubocop/rubocop/pull/12099): Fix an incorrect autocorrect for `Style/Alias` when `EncforcedStyle: prefer_alias_method` and using `alias` with interpolated symbol argument. ([@koic][]) +* [#12085](https://github.com/rubocop/rubocop/issues/12085): Fix an error for `Lint/SuppressedException` when `AllowNil: true` is set and endless method definition is used. ([@koic][]) +* [#12087](https://github.com/rubocop/rubocop/issues/12087): Fix false positives for `Style/ArgumentsForwarding` with additional args/kwargs in def/send nodes. ([@owst][]) +* [#12071](https://github.com/rubocop/rubocop/issues/12071): Fix `Style/SymbolArray` false positives when using square brackets or interpolation in a symbol literal in a percent style array. ([@jasondoc3][]) +* [#12061](https://github.com/rubocop/rubocop/issues/12061): Support regex in StringLiteralsInInterpolation. ([@jonas054][]) +* [#12091](https://github.com/rubocop/rubocop/pull/12091): With `--fail-level A` ignore non-correctable offenses at :info severity. ([@naveg][]) + +### Changes + +* [#12094](https://github.com/rubocop/rubocop/pull/12094): Add `base64` gem to runtime dependency to suppress Ruby 3.3's warning. ([@koic][]) + ## 1.55.1 (2023-07-31) ### Bug fixes @@ -7265,3 +7287,4 @@ [@loveo]: https://github.com/loveo [@p0deje]: https://github.com/p0deje [@bigzed]: https://github.com/bigzed +[@OwlKing]: https://github.com/OwlKing diff --git a/changelog/change_add_base64_to_runtime_dependency.md b/changelog/change_add_base64_to_runtime_dependency.md deleted file mode 100644 index 30f2cb71b9fc..000000000000 --- a/changelog/change_add_base64_to_runtime_dependency.md +++ /dev/null @@ -1 +0,0 @@ -* [#12094](https://github.com/rubocop/rubocop/pull/12094): Add `base64` gem to runtime dependency to suppress Ruby 3.3's warning. ([@koic][]) diff --git a/changelog/fix_a_false_negative_for_style_redundant_return.md b/changelog/fix_a_false_negative_for_style_redundant_return.md deleted file mode 100644 index bf6910fafacf..000000000000 --- a/changelog/fix_a_false_negative_for_style_redundant_return.md +++ /dev/null @@ -1 +0,0 @@ -* [#12106](https://github.com/rubocop/rubocop/issues/12106): Fix a false negative for `Style/RedundantReturn` when returning value with guard clause and `return` is used. ([@koic][]) diff --git a/changelog/fix_a_false_positive_for_style_alias.md b/changelog/fix_a_false_positive_for_style_alias.md deleted file mode 100644 index bd53647984ee..000000000000 --- a/changelog/fix_a_false_positive_for_style_alias.md +++ /dev/null @@ -1 +0,0 @@ -* [#12095](https://github.com/rubocop/rubocop/pull/12095): Fix a false positive for `Style/Alias` when `EncforcedStyle: prefer_alias` and using `alias` with interpolated symbol argument. ([@koic][]) diff --git a/changelog/fix_a_false_positive_for_style_class_equality_comparison.md b/changelog/fix_a_false_positive_for_style_class_equality_comparison.md deleted file mode 100644 index 2e5c2fba8067..000000000000 --- a/changelog/fix_a_false_positive_for_style_class_equality_comparison.md +++ /dev/null @@ -1 +0,0 @@ -* [#12098](https://github.com/rubocop/rubocop/pull/12098): Fix a false positive for `Style/ClassEqualityComparison` when comparing interpolated string class name for equality. ([@koic][]) diff --git a/changelog/fix_an_error_for_style_lambda_call.md b/changelog/fix_an_error_for_style_lambda_call.md deleted file mode 100644 index c5c354f59a70..000000000000 --- a/changelog/fix_an_error_for_style_lambda_call.md +++ /dev/null @@ -1 +0,0 @@ -* [#12102](https://github.com/rubocop/rubocop/pull/12102): Fix an error for `Style/LambdaCall` when using nested lambda call `x.().()`. ([@koic][]) diff --git a/changelog/fix_an_incorrect_for_style_alias.md b/changelog/fix_an_incorrect_for_style_alias.md deleted file mode 100644 index 267cadfee662..000000000000 --- a/changelog/fix_an_incorrect_for_style_alias.md +++ /dev/null @@ -1 +0,0 @@ -* [#12099](https://github.com/rubocop/rubocop/pull/12099): Fix an incorrect autocorrect for `Style/Alias` when `EncforcedStyle: prefer_alias_method` and using `alias` with interpolated symbol argument. ([@koic][]) diff --git a/changelog/fix_error_for_lint_suppressed_exception.md b/changelog/fix_error_for_lint_suppressed_exception.md deleted file mode 100644 index 4b8501388553..000000000000 --- a/changelog/fix_error_for_lint_suppressed_exception.md +++ /dev/null @@ -1 +0,0 @@ -* [#12085](https://github.com/rubocop/rubocop/issues/12085): Fix an error for `Lint/SuppressedException` when `AllowNil: true` is set and endless method definition is used. ([@koic][]) diff --git a/changelog/fix_false_positives_for_style_arguments_forwarding.md b/changelog/fix_false_positives_for_style_arguments_forwarding.md deleted file mode 100644 index 5d11d7441554..000000000000 --- a/changelog/fix_false_positives_for_style_arguments_forwarding.md +++ /dev/null @@ -1 +0,0 @@ -* [#12087](https://github.com/rubocop/rubocop/issues/12087): Fix false positives for `Style/ArgumentsForwarding` with additional args/kwargs in def/send nodes. ([@owst][]) diff --git a/changelog/fix_style_symbol_array_false_positives.md b/changelog/fix_style_symbol_array_false_positives.md deleted file mode 100644 index 91c7917fb2a0..000000000000 --- a/changelog/fix_style_symbol_array_false_positives.md +++ /dev/null @@ -1 +0,0 @@ -* [#12071](https://github.com/rubocop/rubocop/issues/12071): Fix `Style/SymbolArray` false positives when using square brackets or interpolation in a symbol literal in a percent style array. ([@jasondoc3][]) diff --git a/changelog/fix_support_regex_in_string_literals_in_interpolation.md b/changelog/fix_support_regex_in_string_literals_in_interpolation.md deleted file mode 100644 index ac6bc83f2cbc..000000000000 --- a/changelog/fix_support_regex_in_string_literals_in_interpolation.md +++ /dev/null @@ -1 +0,0 @@ -* [#12061](https://github.com/rubocop/rubocop/issues/12061): Support regex in StringLiteralsInInterpolation. ([@jonas054][]) diff --git a/changelog/fix_with_fail_level_a_ignore_non_correctable_offenses.md b/changelog/fix_with_fail_level_a_ignore_non_correctable_offenses.md deleted file mode 100644 index 88c735bbb5e9..000000000000 --- a/changelog/fix_with_fail_level_a_ignore_non_correctable_offenses.md +++ /dev/null @@ -1 +0,0 @@ -* [#12091](https://github.com/rubocop/rubocop/pull/12091): With `--fail-level A` ignore non-correctable offenses at :info severity. ([@naveg][]) diff --git a/changelog/new_add_new_bundler_duplicated_group_cop.md b/changelog/new_add_new_bundler_duplicated_group_cop.md deleted file mode 100644 index 11b07e89e49c..000000000000 --- a/changelog/new_add_new_bundler_duplicated_group_cop.md +++ /dev/null @@ -1 +0,0 @@ -* [#12074](https://github.com/rubocop/rubocop/pull/12074): Add new `Bundler/DuplicatedGroup` cop. ([@OwlKing][]) diff --git a/changelog/new_make_lsp_server_support_format_autocorrects_all_execute_command.md b/changelog/new_make_lsp_server_support_format_autocorrects_all_execute_command.md deleted file mode 100644 index 602ca2f84473..000000000000 --- a/changelog/new_make_lsp_server_support_format_autocorrects_all_execute_command.md +++ /dev/null @@ -1 +0,0 @@ -* [#12078](https://github.com/rubocop/rubocop/pull/12078): Make LSP server support `rubocop.formatAutocorrectsAll` execute command. ([@koic][]) From 3036b2c4eff493f1032964a988c739e3ad14d839 Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Wed, 9 Aug 2023 09:33:11 +0300 Subject: [PATCH 16/17] Tweak whitespace --- lib/rubocop/cop/bundler/duplicated_gem.rb | 1 + lib/rubocop/cop/bundler/duplicated_group.rb | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/rubocop/cop/bundler/duplicated_gem.rb b/lib/rubocop/cop/bundler/duplicated_gem.rb index eca531593550..2efa8d4a00dc 100644 --- a/lib/rubocop/cop/bundler/duplicated_gem.rb +++ b/lib/rubocop/cop/bundler/duplicated_gem.rb @@ -4,6 +4,7 @@ module RuboCop module Cop module Bundler # A Gem's requirements should be listed only once in a Gemfile. + # # @example # # bad # gem 'rubocop' diff --git a/lib/rubocop/cop/bundler/duplicated_group.rb b/lib/rubocop/cop/bundler/duplicated_group.rb index 8b90a7618e29..a056825dcaa8 100644 --- a/lib/rubocop/cop/bundler/duplicated_group.rb +++ b/lib/rubocop/cop/bundler/duplicated_group.rb @@ -3,7 +3,8 @@ module RuboCop module Cop module Bundler - # A Gem group, or a set of groups should be listed only once in a Gemfile. + # A Gem group, or a set of groups, should be listed only once in a Gemfile. + # # @example # # bad # group :development do From e597ca1121705764b6d009ff85a0caf8cd98000c Mon Sep 17 00:00:00 2001 From: Bozhidar Batsov Date: Wed, 9 Aug 2023 09:33:53 +0300 Subject: [PATCH 17/17] Cut 1.56 --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- CHANGELOG.md | 2 + CONTRIBUTING.md | 2 +- README.md | 2 +- config/default.yml | 2 +- docs/antora.yml | 2 +- docs/modules/ROOT/pages/cops.adoc | 1 + docs/modules/ROOT/pages/cops_bundler.adoc | 64 +++++++++++++++++++++++ docs/modules/ROOT/pages/cops_style.adoc | 37 ++++++++++--- docs/modules/ROOT/pages/installation.adoc | 2 +- lib/rubocop/version.rb | 2 +- relnotes/v1.56.0.md | 28 ++++++++++ 12 files changed, 133 insertions(+), 13 deletions(-) create mode 100644 relnotes/v1.56.0.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 709fe11276e5..7cd0c16a4515 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -38,7 +38,7 @@ output by `rubocop -V`, include them as well. Here's an example: ``` $ [bundle exec] rubocop -V -1.55.1 (using Parser 2.7.2.0, rubocop-ast 1.1.1, running on ruby 2.7.2) [x86_64-linux] +1.56.0 (using Parser 2.7.2.0, rubocop-ast 1.1.1, running on ruby 2.7.2) [x86_64-linux] - rubocop-performance 1.9.1 - rubocop-rspec 2.0.0 ``` diff --git a/CHANGELOG.md b/CHANGELOG.md index e408e3310af4..60f7e4e34599 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ ## master (unreleased) +## 1.56.0 (2023-08-09) + ### New features * [#12074](https://github.com/rubocop/rubocop/pull/12074): Add new `Bundler/DuplicatedGroup` cop. ([@OwlKing][]) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 772749ef36a6..74cf9992c266 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,7 +17,7 @@ do so. ```console $ rubocop -V -1.55.1 (using Parser 2.7.2.0, rubocop-ast 1.1.1, running on ruby 2.7.2) [x86_64-linux] +1.56.0 (using Parser 2.7.2.0, rubocop-ast 1.1.1, running on ruby 2.7.2) [x86_64-linux] - rubocop-performance 1.9.1 - rubocop-rspec 2.0.0 ``` diff --git a/README.md b/README.md index fbcba530f692..010f26cbe145 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi in your `Gemfile`: ```rb -gem 'rubocop', '~> 1.55', require: false +gem 'rubocop', '~> 1.56', require: false ``` See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details. diff --git a/config/default.yml b/config/default.yml index 354a646a8006..5a644aa12adb 100644 --- a/config/default.yml +++ b/config/default.yml @@ -177,7 +177,7 @@ Bundler/DuplicatedGroup: Description: 'Checks for duplicate group entries in Gemfile.' Enabled: true Severity: warning - VersionAdded: '<>' + VersionAdded: '1.56' Include: - '**/*.gemfile' - '**/Gemfile' diff --git a/docs/antora.yml b/docs/antora.yml index 9c897ea03d1d..b4de30cfda13 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop title: RuboCop # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: ~ +version: '1.56' nav: - modules/ROOT/nav.adoc diff --git a/docs/modules/ROOT/pages/cops.adoc b/docs/modules/ROOT/pages/cops.adoc index fd7bfecb24d4..e2b4fb26834f 100644 --- a/docs/modules/ROOT/pages/cops.adoc +++ b/docs/modules/ROOT/pages/cops.adoc @@ -77,6 +77,7 @@ In the following section you find all available cops: === Department xref:cops_bundler.adoc[Bundler] * xref:cops_bundler.adoc#bundlerduplicatedgem[Bundler/DuplicatedGem] +* xref:cops_bundler.adoc#bundlerduplicatedgroup[Bundler/DuplicatedGroup] * xref:cops_bundler.adoc#bundlergemcomment[Bundler/GemComment] * xref:cops_bundler.adoc#bundlergemfilename[Bundler/GemFilename] * xref:cops_bundler.adoc#bundlergemversion[Bundler/GemVersion] diff --git a/docs/modules/ROOT/pages/cops_bundler.adoc b/docs/modules/ROOT/pages/cops_bundler.adoc index a60bc34e8644..b73165ff2dc2 100644 --- a/docs/modules/ROOT/pages/cops_bundler.adoc +++ b/docs/modules/ROOT/pages/cops_bundler.adoc @@ -63,6 +63,70 @@ end | Array |=== +== Bundler/DuplicatedGroup + +|=== +| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed + +| Enabled +| Yes +| No +| 1.56 +| - +|=== + +A Gem group, or a set of groups, should be listed only once in a Gemfile. + +=== Examples + +[source,ruby] +---- +# bad +group :development do + gem 'rubocop' +end + +group :development do + gem 'rubocop-rails' +end + +# bad (same set of groups declared twice) +group :development, :test do + gem 'rubocop' +end + +group :test, :development do + gem 'rspec' +end + +# good +group :development do + gem 'rubocop' +end + +group :development, :test do + gem 'rspec' +end + +# good +gem 'rubocop', groups: [:development, :test] +gem 'rspec', groups: [:development, :test] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Severity +| `warning` +| String + +| Include +| `+**/*.gemfile+`, `+**/Gemfile+`, `+**/gems.rb+` +| Array +|=== + == Bundler/GemComment |=== diff --git a/docs/modules/ROOT/pages/cops_style.adoc b/docs/modules/ROOT/pages/cops_style.adoc index 9d60c352a247..4f9e28ca2dc6 100644 --- a/docs/modules/ROOT/pages/cops_style.adoc +++ b/docs/modules/ROOT/pages/cops_style.adoc @@ -11993,11 +11993,16 @@ def test return something end -# good +# bad def test return something if something_else end +# good +def test + something if something_else +end + # good def test if x @@ -14126,7 +14131,7 @@ Checks if uses of quotes match the configured preference. | - |=== -Checks that quotes inside the string interpolation +Checks that quotes inside string, symbol, and regexp interpolations match the configured preference. === Examples @@ -14136,10 +14141,20 @@ match the configured preference. [source,ruby] ---- # bad -result = "Tests #{success ? "PASS" : "FAIL"}" +string = "Tests #{success ? "PASS" : "FAIL"}" +symbol = :"Tests #{success ? "PASS" : "FAIL"}" +heredoc = <<~TEXT + Tests #{success ? "PASS" : "FAIL"} +TEXT +regexp = /Tests #{success ? "PASS" : "FAIL"}/ # good -result = "Tests #{success ? 'PASS' : 'FAIL'}" +string = "Tests #{success ? 'PASS' : 'FAIL'}" +symbol = :"Tests #{success ? 'PASS' : 'FAIL'}" +heredoc = <<~TEXT + Tests #{success ? 'PASS' : 'FAIL'} +TEXT +regexp = /Tests #{success ? 'PASS' : 'FAIL'}/ ---- ==== EnforcedStyle: double_quotes @@ -14147,10 +14162,20 @@ result = "Tests #{success ? 'PASS' : 'FAIL'}" [source,ruby] ---- # bad -result = "Tests #{success ? 'PASS' : 'FAIL'}" +string = "Tests #{success ? 'PASS' : 'FAIL'}" +symbol = :"Tests #{success ? 'PASS' : 'FAIL'}" +heredoc = <<~TEXT + Tests #{success ? 'PASS' : 'FAIL'} +TEXT +regexp = /Tests #{success ? 'PASS' : 'FAIL'}/ # good -result = "Tests #{success ? "PASS" : "FAIL"}" +string = "Tests #{success ? "PASS" : "FAIL"}" +symbol = :"Tests #{success ? "PASS" : "FAIL"}" +heredoc = <<~TEXT + Tests #{success ? "PASS" : "FAIL"} +TEXT +regexp = /Tests #{success ? "PASS" : "FAIL"}/ ---- === Configurable attributes diff --git a/docs/modules/ROOT/pages/installation.adoc b/docs/modules/ROOT/pages/installation.adoc index cd48873ba478..c78eca60c71d 100644 --- a/docs/modules/ROOT/pages/installation.adoc +++ b/docs/modules/ROOT/pages/installation.adoc @@ -22,7 +22,7 @@ in your `Gemfile`: [source,rb] ---- -gem 'rubocop', '~> 1.55', require: false +gem 'rubocop', '~> 1.56', require: false ---- .A Modular RuboCop diff --git a/lib/rubocop/version.rb b/lib/rubocop/version.rb index 8551c984e3b9..f3f5e071ad06 100644 --- a/lib/rubocop/version.rb +++ b/lib/rubocop/version.rb @@ -3,7 +3,7 @@ module RuboCop # This module holds the RuboCop version information. module Version - STRING = '1.55.1' + STRING = '1.56.0' MSG = '%s (using Parser %s, ' \ 'rubocop-ast %s, ' \ diff --git a/relnotes/v1.56.0.md b/relnotes/v1.56.0.md new file mode 100644 index 000000000000..083727156de9 --- /dev/null +++ b/relnotes/v1.56.0.md @@ -0,0 +1,28 @@ +### New features + +* [#12074](https://github.com/rubocop/rubocop/pull/12074): Add new `Bundler/DuplicatedGroup` cop. ([@OwlKing][]) +* [#12078](https://github.com/rubocop/rubocop/pull/12078): Make LSP server support `rubocop.formatAutocorrectsAll` execute command. ([@koic][]) + +### Bug fixes + +* [#12106](https://github.com/rubocop/rubocop/issues/12106): Fix a false negative for `Style/RedundantReturn` when returning value with guard clause and `return` is used. ([@koic][]) +* [#12095](https://github.com/rubocop/rubocop/pull/12095): Fix a false positive for `Style/Alias` when `EncforcedStyle: prefer_alias` and using `alias` with interpolated symbol argument. ([@koic][]) +* [#12098](https://github.com/rubocop/rubocop/pull/12098): Fix a false positive for `Style/ClassEqualityComparison` when comparing interpolated string class name for equality. ([@koic][]) +* [#12102](https://github.com/rubocop/rubocop/pull/12102): Fix an error for `Style/LambdaCall` when using nested lambda call `x.().()`. ([@koic][]) +* [#12099](https://github.com/rubocop/rubocop/pull/12099): Fix an incorrect autocorrect for `Style/Alias` when `EncforcedStyle: prefer_alias_method` and using `alias` with interpolated symbol argument. ([@koic][]) +* [#12085](https://github.com/rubocop/rubocop/issues/12085): Fix an error for `Lint/SuppressedException` when `AllowNil: true` is set and endless method definition is used. ([@koic][]) +* [#12087](https://github.com/rubocop/rubocop/issues/12087): Fix false positives for `Style/ArgumentsForwarding` with additional args/kwargs in def/send nodes. ([@owst][]) +* [#12071](https://github.com/rubocop/rubocop/issues/12071): Fix `Style/SymbolArray` false positives when using square brackets or interpolation in a symbol literal in a percent style array. ([@jasondoc3][]) +* [#12061](https://github.com/rubocop/rubocop/issues/12061): Support regex in StringLiteralsInInterpolation. ([@jonas054][]) +* [#12091](https://github.com/rubocop/rubocop/pull/12091): With `--fail-level A` ignore non-correctable offenses at :info severity. ([@naveg][]) + +### Changes + +* [#12094](https://github.com/rubocop/rubocop/pull/12094): Add `base64` gem to runtime dependency to suppress Ruby 3.3's warning. ([@koic][]) + +[@OwlKing]: https://github.com/OwlKing +[@koic]: https://github.com/koic +[@owst]: https://github.com/owst +[@jasondoc3]: https://github.com/jasondoc3 +[@jonas054]: https://github.com/jonas054 +[@naveg]: https://github.com/naveg