Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 17759] ファイルの概要

このコミットは、Go言語のEmacsメジャーモードであるgo-mode.elにおける、未使用インポートの検出ロジックの改善と、コメント内のタイポ修正を含んでいます。特に、Goコンパイラがパスとパッケージ名が異なるインポートに対して出力する追加情報(例: "sandbox/foo_bar" as bar)に対応できるよう、正規表現が更新されました。

コミット

commit 989a63eb0b1f692c7d2aa0a4d3deed97b4505d15
Author: Dominik Honnef <dominik.honnef@gmail.com>
Date:   Mon Oct 7 13:08:26 2013 -0400

    misc/emacs: find unused imports where path and package name differ

    The Go compiler emits extra information for this case:

    imported and not used: "sandbox/foo_bar" as bar

    R=adonovan
    CC=golang-dev
    https://golang.org/cl/14111043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/989a63eb0b1f692c7d2aa0a4d3deed97b4505d15

元コミット内容

このコミットの元の内容は、misc/emacs/go-mode.elファイルにおいて、未使用のインポートを検出するための正規表現を修正し、Goコンパイラが特定のケースで出力する追加情報に対応することです。具体的には、インポートパスとパッケージ名が異なる場合にGoコンパイラが生成するメッセージ(例: imported and not used: "sandbox/foo_bar" as bar)を正しく解析できるように、正規表現のパターンが拡張されました。また、コードコメント内の「infered」というスペルミスを「inferred」に修正するタイポ修正も含まれています。

変更の背景

Go言語では、インポートされたパッケージがコード内で使用されていない場合、コンパイラが警告またはエラーを生成します。これは、不要な依存関係を排除し、コードのクリーンさを保つための重要な機能です。

従来のgo-mode.elの未使用インポート検出ロジックは、Goコンパイラが生成するメッセージの特定の形式に依存していました。しかし、Goコンパイラは、インポートパスとパッケージ名が異なる場合(例えば、import bar "sandbox/foo_bar"のように、パッケージに別名が付けられている場合)、通常の「imported and not used: "path/to/package"」というメッセージに加えて、「as [別名]」という追加情報を出力することがありました。

この追加情報がある場合、既存の正規表現ではメッセージ全体を正しくマッチさせることができず、結果としてgo-mode.elが未使用のインポートを検出できないという問題が発生していました。このコミットは、このGoコンパイラの出力形式のバリエーションに対応し、より堅牢な未使用インポート検出を実現するために行われました。

前提知識の解説

  • Go言語のインポート: Go言語では、他のパッケージの機能を利用するためにimportキーワードを使用します。通常、import "path/to/package"のように記述しますが、import alias "path/to/package"のように別名を付けてインポートすることも可能です。
  • 未使用インポート: Goコンパイラは、インポートされたパッケージがコード内で一度も使用されていない場合に警告またはエラーを報告します。これは、ビルド時に自動的にチェックされ、開発者に不要なコードの存在を知らせます。
  • Emacs Lisp (Elisp): Emacsエディタの拡張機能や設定を記述するために使用されるプログラミング言語です。go-mode.elはElispで書かれたEmacsのメジャーモードであり、Go言語のコード編集をサポートします。
  • 正規表現 (Regular Expression): 文字列のパターンを記述するための強力なツールです。Emacs Lispのstring-match関数は、文字列が特定の正規表現パターンにマッチするかどうかを判定するために使用されます。
    • ^: 行の先頭にマッチします。
    • \\(.+\\): 任意の文字(+は1回以上)にマッチし、それをグループとしてキャプチャします。Go言語のファイルパスや行番号をキャプチャするために使用されます。
    • [[:digit:]]+: 1つ以上の数字にマッチします。
    • \": 二重引用符そのものにマッチします。正規表現内で特別な意味を持つ文字(例: .*)をリテラルとしてマッチさせるには、バックスラッシュでエスケープする必要があります。Emacs Lispの文字列リテラル内でバックスラッシュを表現するためには、さらにバックスラッシュでエスケープする必要があるため、\\"となります。
    • .*: 任意の文字(.)が0回以上(*)繰り返されるパターンにマッチします。
    • $: 行の末尾にマッチします。

技術的詳細

このコミットの主要な技術的変更は、go-mode.el内のgo-find-unused-imports関数で使用されている正規表現の修正です。この関数は、Goコンパイラの出力(具体的にはgo buildgo vetなどのコマンドの出力)を解析し、未使用のインポートに関するメッセージを抽出します。

修正前の正規表現は以下の通りでした。 ^\\\\(.+\\\\):\\\\([[:digit:]]+\\\\): imported and not used: \\\".+\\\"$

この正規表現は、以下のような形式の行にマッチすることを意図していました。 [ファイル名]:[行番号]: imported and not used: "インポートパス"

しかし、Goコンパイラが以下のような形式のメッセージを出力する場合、この正規表現ではマッチしませんでした。 [ファイル名]:[行番号]: imported and not used: "インポートパス" as [別名]

これは、元の正規表現が\"$(引用符で終わる)で厳密にマッチするように定義されていたためです。as [別名]という追加情報がある場合、行の末尾が引用符ではなくなるため、マッチに失敗していました。

この問題を解決するため、正規表現は以下のように変更されました。 ^\\\\(.+\\\\):\\\\([[:digit:]]+\\\\): imported and not used: \\\".+\\\".*$

変更点である.*$は、引用符の後に任意の文字(.)が0回以上(*)続き、その後に改行($)が来るパターンにマッチすることを意味します。これにより、「as [別名]」のような追加情報があっても、正規表現がメッセージ全体を正しく捉えることができるようになりました。

もう一つの変更は、コメント内のタイポ修正です。inferedというスペルミスがinferredに修正されました。これは機能的な変更ではありませんが、コードの可読性と品質を向上させます。

コアとなるコードの変更箇所

misc/emacs/go-mode.elファイル内の以下の部分が変更されました。

--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -907,7 +907,7 @@ If IGNORE-CASE is non-nil, the comparison is case-insensitive.\"
   (reverse (remove nil
                            (mapcar
                             (lambda (line)
-                      (if (string-match \"^\\\\(.+\\\\):\\\\([[:digit:]]+\\\\): imported and not used: \\\".+\\\"$\" line)\
+                      (if (string-match \"^\\\\(.+\\\\):\\\\([[:digit:]]+\\\\): imported and not used: \\\".+\\\".*$\" line)\
                               (if (string= (file-truename (match-string 1 line)) (file-truename buffer-file-name))\
                                   (string-to-number (match-string 2 line)))))\
                             (split-string (shell-command-to-string\
@@ -1107,7 +1107,7 @@ divisor for FILE-NAME.\"\
       \"Open a clone of the current buffer and overlay it with\
     coverage information gathered via go test -coverprofile=COVERAGE-FILE.\
     \
-If COVERAGE-FILE is nil, it will either be infered from the\
+If COVERAGE-FILE is nil, it will either be inferred from the\
     current buffer if it\'s already a coverage buffer, or be prompted\
     for.\"\
       (interactive)\

コアとなるコードの解説

変更されたコードスニペットは、go-mode.elgo-find-unused-imports関数の一部です。この関数は、shell-command-to-stringを使ってGoコンパイラの出力を取得し、その各行をlambda関数で処理しています。

  • (shell-command-to-string ...): この部分でGoコンパイラ(または関連ツール)を実行し、その標準出力を文字列として取得します。
  • (split-string ...): 取得した文字列を改行で分割し、各行をリストとして取得します。
  • (mapcar (lambda (line) ...)):リストの各行(line)に対して匿名関数(lambda)を適用します。
  • (if (string-match ... line)): ここが正規表現によるマッチングが行われる核心部分です。
    • 変更前: (string-match "^\\\\(.+\\\\):\\\\([[:digit:]]+\\\\): imported and not used: \\\".+\\\"$" line)
      • この正規表現は、行が「ファイル名:行番号: imported and not used: "インポートパス"」という厳密な形式で終わることを期待していました。
    • 変更後: (string-match "^\\\\(.+\\\\):\\\\([[:digit:]]+\\\\): imported and not used: \\\".+\\\".*$" line)
      • .*$が追加されたことで、引用符の後に任意の文字が続く場合でもマッチするようになりました。これにより、「as [別名]」のような追加情報を含むGoコンパイラの出力にも対応できるようになりました。
  • (if (string= (file-truename (match-string 1 line)) (file-truename buffer-file-name))): 正規表現でキャプチャしたファイル名(match-string 1 line)が現在のバッファのファイル名と一致するかどうかを確認します。
  • (string-to-number (match-string 2 line)): マッチした行番号(match-string 2 line)を数値に変換します。

この修正により、go-mode.elはGoコンパイラの出力形式のバリエーションに柔軟に対応できるようになり、より正確に未使用のインポートを検出してユーザーに通知できるようになりました。

コメントの修正は、go-mode.elの別の関数であるgo-coverage-overlayのドキュメント文字列(docstring)内で行われました。inferedというスペルミスがinferredに修正され、ドキュメントの正確性が向上しました。

関連リンク

参考にした情報源リンク

  • Go言語のコンパイラとツールのドキュメント
  • Emacs Lispのドキュメント(特にstring-match関数と正規表現に関する部分)
  • Go言語のソースコードリポジトリ(特にgo-mode.elの履歴)
  • Go言語のコードレビューシステム (Gerrit) の変更リスト: https://golang.org/cl/14111043 (コミットメッセージに記載)