valid,invalid

関心を持てる事柄について

rubocopのNaming/MethodParameterName, Naming/BlockParameterNameで警告の指摘箇所がずれているのを修正してみた

ActiveRecord Association Extensionとwith_optionsを併用するとrubocop-railsのRails/HasManyOrHasOneDependent警告が出るので修正してみた - valid,invalid でrubocopの中身に少し興味を持ったのでシュッと倒せそうなissueがないかを拙作の goofi で検索してみたところ、過去に遭遇したことあるバグを見かけたので対応してpull requestを送ってみた。

事象

issueはこれ Faulty calculation in UncommunicativeName · Issue #8229 · rubocop-hq/rubocop · GitHub

Naming/MethodParameterName, Naming/BlockParameterName copsで警告する対象に _*といったprefixが付いていると警告の表示位置がずれる…、実際の挙動を見たほうがわかりやすい。

以下のファイルがあるとする。

def test1(_a); end

def test2(__a); end

def test3(*a); end

def test4(**a); end

def test5(**__a); end

rubocopを実行すると、警告箇所を示すlocation ^ が引数名の全体にかかっていないことがわかる。

$ rubocop test.rb
Inspecting 1 file
C

Offenses:

test.rb:3:11: C: Naming/MethodParameterName: Method parameter must be at least 3 characters long.
def test1(_a); end
          ^
test.rb:5:11: C: Naming/MethodParameterName: Method parameter must be at least 3 characters long.
def test2(__a); end
          ^
test.rb:7:11: C: Naming/MethodParameterName: Method parameter must be at least 3 characters long.
def test3(*a); end
          ^
test.rb:9:11: C: Naming/MethodParameterName: Method parameter must be at least 3 characters long.
def test4(**a); end
          ^
test.rb:11:11: C: Naming/MethodParameterName: Method parameter must be at least 3 characters long.
def test5(**__a); end
          ^

1 file inspected, 5 offenses detected

本来はこうあるべき。

$ rubocop test.rb
Inspecting 1 file
C

Offenses:

test.rb:3:11: C: Naming/MethodParameterName: Method parameter must be at least 3 characters long.
def test1(_a); end
          ^^
test.rb:5:11: C: Naming/MethodParameterName: Method parameter must be at least 3 characters long.
def test2(__a); end
          ^^^
test.rb:7:11: C: Naming/MethodParameterName: Method parameter must be at least 3 characters long.
def test3(*a); end
          ^^
test.rb:9:11: C: Naming/MethodParameterName: Method parameter must be at least 3 characters long.
def test4(**a); end
          ^^^
test.rb:11:11: C: Naming/MethodParameterName: Method parameter must be at least 3 characters long.
def test5(**__a); end
          ^^^^^

1 file inspected, 5 offenses detected

修正

Naming/MethodParameterName, Naming/BlockParameterName copsでincludeしているUncommunicativeName moduleにて、引数名の長さの計算が誤っていたようだ。

def check(node, args)
  args.each do |arg|
    # Argument names might be "_" or prefixed with "_" to indicate they
    # are unused. Trim away this prefix and only analyse the basename.
    name_child = arg.children.first
    next if name_child.nil?
    full_name = name_child.to_s
    next if full_name == '_'
    name = full_name.gsub(/\A(_+)/, '')
    next if allowed_names.include?(name)

    # name.size が location の range を決めている
    # name は prefix を除いた文字列
    range = arg_range(arg, name.size)
    issue_offenses(node, range, name)
  end
end

lengthを愚直に再計算して渡すようにした。

def check(node, args)
  args.each do |arg|
    # Argument names might be "_" or prefixed with "_" to indicate they
    # are unused. Trim away this prefix and only analyse the basename.
    name_child = arg.children.first
    next if name_child.nil?
    full_name = name_child.to_s
    next if full_name == '_'
    name = full_name.gsub(/\A(_+)/, '')
    next if allowed_names.include?(name)

-   range = arg_range(arg, name.size)
+   length = full_name.size
+   length += 1 if arg.restarg_type?
+   length += 2 if arg.kwrestarg_type?

+   range = arg_range(arg, length)
    issue_offenses(node, range, name)
  end
end

rubocopへのpull requestは初めてだったがシュッとマージしてもらえて良かった。

環境

  • rubocop 1.8.0

This article is for ohbarye Advent Calendar 2020.