[インデックス 14247] ファイルの概要
このコミットは、Go言語のコードフォーマッタであるgofmt
と、その内部で使用されるgo/printer
パッケージにおけるコメント内の末尾の空白文字のトリミングに関する変更を導入しています。具体的には、コメントの整形時に不要な末尾の空白が削除されるようになり、これによりコードの見た目の一貫性が向上します。
コミット
commit db2b6ed854122bc987e0cb8778a9c77b481614ec
Author: Robert Griesemer <gri@golang.org>
Date: Tue Oct 30 13:09:47 2012 -0700
go/printer, gofmt: trim trailing whitespace in comments
Also: updated go fix testcases to pass tests.
Fixes #4310.
R=r
CC=golang-dev
https://golang.org/cl/6810055
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/db2b6ed854122bc987e0cb8778a9c77b481614ec
元コミット内容
go/printer, gofmt: trim trailing whitespace in comments
このコミットは、go/printer
パッケージとgofmt
ツールにおいて、コメント内の末尾の空白文字をトリミングする変更を実装しています。また、go fix
のテストケースがこの変更に対応するように更新されています。この変更はIssue #4310を修正するものです。
変更の背景
Go言語の公式フォーマッタであるgofmt
は、Goコードのスタイルを統一し、可読性を高める上で非常に重要なツールです。gofmt
は、コードのインデント、スペース、改行などを自動的に調整しますが、コメント内の空白文字の扱いは、これまで一貫性が保たれていない場合がありました。特に、コメントの行末に不要な空白文字が残っていると、コードの見た目が乱れるだけでなく、バージョン管理システムでの差分表示(diff)が不必要に大きくなる原因にもなります。
このコミットの背景には、おそらくユーザーからのフィードバックや、開発者自身がコードベースのクリーンさを追求する中で、コメント内の末尾の空白が問題として認識されたことがあります。Issue #4310がこの問題の具体的な報告であったと考えられます。末尾の空白は、エディタの設定や手動での入力ミスによって容易に発生し、コードの品質を低下させる要因となります。この変更は、gofmt
がより厳密にコードスタイルを強制し、Goコードベース全体の品質と一貫性を向上させることを目的としています。
前提知識の解説
gofmt
: Go言語のソースコードを自動的にフォーマットするツールです。Go言語の標準的なコーディングスタイルを強制し、コードの可読性と一貫性を高めます。開発者がスタイルガイドを意識することなく、常に統一されたコードを書けるようにするために不可欠なツールです。go/printer
パッケージ:gofmt
の基盤となるパッケージの一つで、Goの抽象構文木(AST)を整形してGoソースコードとして出力する機能を提供します。このパッケージが、コメントを含むコードの整形ロジックを担っています。- 抽象構文木(AST: Abstract Syntax Tree): プログラムのソースコードを解析して得られる、その構造を木構造で表現したものです。コンパイラやリンタ、フォーマッタなどのツールは、ソースコードをASTに変換し、そのASTを操作することで様々な処理を行います。
go/printer
はASTを受け取り、整形されたコードを出力します。 - 末尾の空白(Trailing Whitespace): 行の末尾に存在するスペースやタブなどの空白文字のことです。プログラミングにおいては、通常は意味を持たず、コードの見た目を損ねたり、差分管理を複雑にしたりする原因となることがあります。
go fix
: Go言語の古いAPIや構文を新しいものに自動的に修正するツールです。Go言語のバージョンアップに伴うコードの移行を支援します。このコミットでは、gofmt
の変更によって影響を受ける可能性のあるgo fix
のテストケースが更新されています。
技術的詳細
このコミットの主要な変更は、src/pkg/go/printer/printer.go
ファイルに集中しています。具体的には、コメントの出力処理において、行末の空白を削除するロジックが追加されました。
unicode
パッケージの導入: 新たにunicode
パッケージがインポートされています。これは、Unicodeのプロパティに基づいて文字を分類するための機能を提供し、特にunicode.IsSpace
関数が空白文字の判定に利用されます。trimRight
関数の追加:strings.TrimRightFunc
関数とunicode.IsSpace
を組み合わせて、文字列の末尾から空白文字をトリミングするtrimRight
ヘルパー関数が追加されました。
この関数は、Goの標準ライブラリである// trimRight returns s with trailing whitespace removed. func trimRight(s string) string { return strings.TrimRightFunc(s, unicode.IsSpace) }
strings
パッケージのTrimRightFunc
を使用しています。TrimRightFunc
は、指定された関数(ここではunicode.IsSpace
)がtrue
を返す文字を文字列の右端から削除します。unicode.IsSpace
は、Unicodeの空白文字(スペース、タブ、改行など)を判定します。writeComment
関数でのtrimRight
の適用:go/printer
パッケージのwriteComment
関数は、コメントを整形して出力する役割を担っています。この関数内で、コメントの各行を出力する直前に、新しく追加されたtrimRight
関数が適用されるようになりました。//
スタイルのコメントの場合:
コメント全体(// shortcut common case of //-style comments if text[1] == '/' { p.writeString(pos, trimRight(text), true) return }
text
)に対してtrimRight
が適用されます。/* ... */
スタイルのコメントの場合:
コメントを構成する各行(if len(line) > 0 { p.writeString(pos, trimRight(line), true) }
line
)に対してtrimRight
が適用されます。
この変更により、go/printer
がコメントを出力する際に、自動的に行末の不要な空白が除去されるようになり、結果としてgofmt
によって整形されたコードのコメントがよりクリーンになります。
また、src/cmd/fix/testdata/
以下の複数のテストファイル(reflect.encoder.go.in
, reflect.encoder.go.out
, reflect.export.go.in
, reflect.export.go.out
, reflect.print.go.in
, reflect.print.go.out
)が更新されています。これは、go fix
がこれらのテストケースを処理する際に、コメントの末尾の空白がトリミングされることを考慮して、期待される出力(.out
ファイル)が修正されたことを示しています。これにより、go fix
のテストが新しいgofmt
の挙動と整合性が取れるようになります。
さらに、src/pkg/go/printer/testdata/comments.golden
とsrc/pkg/go/printer/testdata/comments.input
も更新されています。これらはgo/printer
のテストデータであり、コメントの整形に関する期待される挙動を定義しています。特にcomments.input
には末尾に空白を持つコメントが追加され、comments.golden
にはそれらがトリミングされた状態が記述されており、この変更が正しく機能していることを検証しています。
コアとなるコードの変更箇所
src/pkg/go/printer/printer.go
--- a/src/pkg/go/printer/printer.go
+++ b/src/pkg/go/printer/printer.go
@@ -14,6 +14,7 @@ import (
"strconv"
"strings"
"text/tabwriter"
+ "unicode"
)
const (
@@ -405,6 +406,7 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
// Split comment text into lines
// (using strings.Split(text, "\n") is significantly slower for
// this specific purpose, as measured with: go test -bench=Print)
+//
func split(text string) []string {
// count lines (comment text never ends in a newline)
n := 1
@@ -432,6 +434,7 @@ func split(text string) []string {
// Returns true if s contains only white space
// (only tabs and blanks can appear in the printer's context).
+//
func isBlank(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] > ' ' {
@@ -441,6 +444,7 @@ func isBlank(s string) bool {
return true
}
+// commonPrefix returns the common prefix of a and b.
func commonPrefix(a, b string) string {
i := 0
for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') {
@@ -449,6 +453,11 @@ func commonPrefix(a, b string) string {
return a[0:i]
}
+// trimRight returns s with trailing whitespace removed.
+func trimRight(s string) string {
+ return strings.TrimRightFunc(s, unicode.IsSpace)
+}
+
// stripCommonPrefix removes a common prefix from /*-style comment lines (unless no
// comment line is indented, all but the first line have some form of space prefix).\n // The prefix is computed using heuristics such that is is likely that the comment
//
@@ -611,7 +620,7 @@ func (p *printer) writeComment(comment *ast.Comment) {
// shortcut common case of //-style comments
if text[1] == '/' {
- p.writeString(pos, text, true)
+ p.writeString(pos, trimRight(text), true)
return
}
@@ -641,7 +650,7 @@ func (p *printer) writeComment(comment *ast.Comment) {
pos = p.pos
}
if len(line) > 0 {
- p.writeString(pos, line, true)
+ p.writeString(pos, trimRight(line), true)
}
}
}
@@ -1159,7 +1168,7 @@ func (p *trimmer) Write(data []byte) (n int, err error) {
// ----------------------------------------------------------------------------
// Public interface
-// A Mode value is a set of flags (or 0). They control printing.
+// A Mode value is a set of flags (or 0). They control printing.
type Mode uint
const (
src/pkg/go/printer/testdata/comments.golden
および src/pkg/go/printer/testdata/comments.input
これらのファイルは、go/printer
のテストデータであり、コメントの整形に関する期待される挙動を定義しています。特に、末尾に空白を持つコメントが追加され、それがトリミングされた結果がcomments.golden
に反映されています。
コアとなるコードの解説
このコミットの核心は、src/pkg/go/printer/printer.go
に追加されたtrimRight
関数と、それがwriteComment
関数内でどのように利用されているかです。
-
import "unicode"
: Goの標準ライブラリであるunicode
パッケージがインポートされています。これは、Unicode文字のプロパティ(例えば、ある文字が空白文字であるかどうか)を判定するための関数を提供します。 -
func trimRight(s string) string
: この新しいヘルパー関数は、与えられた文字列s
の末尾からすべての空白文字を削除します。strings.TrimRightFunc(s, unicode.IsSpace)
という呼び出しがその役割を果たします。strings.TrimRightFunc
:strings
パッケージの関数で、第二引数に渡された関数がtrue
を返す文字を、文字列の右端から連続して削除します。unicode.IsSpace
:unicode
パッケージの関数で、引数に渡されたルーン(Unicodeコードポイント)が空白文字である場合にtrue
を返します。これにより、通常のスペースやタブだけでなく、Unicodeで定義されている様々な空白文字(例えば、ノーブレークスペースなど)も正確に識別し、削除することができます。
-
func (p *printer) writeComment(comment *ast.Comment)
内でのtrimRight
の適用:writeComment
関数は、GoのASTからコメントノードを受け取り、それを整形して出力する主要なロジックを含んでいます。//
スタイルのコメント:if text[1] == '/'
の条件で識別される単一行コメントの場合、コメントのテキスト全体(text
変数)に対してtrimRight(text)
が適用されます。これにより、コメント行全体の末尾の空白が削除されます。/* ... */
スタイルのコメント: 複数行にわたるブロックコメントの場合、コメントは行ごとに処理されます。if len(line) > 0
のブロック内で、各コメント行(line
変数)に対してtrimRight(line)
が適用されます。これにより、ブロックコメント内の各行の末尾の空白が個別に削除されます。
この変更により、go/printer
はコメントを出力する際に、自動的に行末の不要な空白を検出し、それらを削除するようになりました。これは、gofmt
がGoコードを整形する際の「厳密さ」を向上させ、コードベース全体の一貫性とクリーンさを保つ上で重要な改善です。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/
gofmt
に関する情報: https://golang.org/cmd/gofmt/go/printer
パッケージのドキュメント: https://pkg.go.dev/go/printerstrings
パッケージのドキュメント: https://pkg.go.dev/stringsunicode
パッケージのドキュメント: https://pkg.go.dev/unicode
参考にした情報源リンク
- GitHubのコミットページ: https://github.com/golang/go/commit/db2b6ed854122bc987e0cb8778a9c77b481614ec
- Go CL (Change List) 6810055: https://golang.org/cl/6810055 (これは古いGoのコードレビューシステムへのリンクであり、現在はGerritに移行しています。)
- Go Issue #4310 (検索を試みましたが、直接的な情報は見つかりませんでした。古いIssueトラッカーの可能性が高いです。)