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

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

このコミットは、Go言語の静的解析ツールである cmd/vet における誤検知を修正するものです。具体的には、fmt パッケージのフォーマット動詞 %q# フラグを組み合わせた %#q が、cmd/vet によって誤って無効なフォーマットとして報告される問題を解決します。この修正により、%#q を使用した fmt.Printf などの呼び出しが正しく検証されるようになります。

コミット

  • コミットハッシュ: 86aad668c0022f17a202fc8d4dd76a0456401048
  • 作者: David Symonds dsymonds@golang.org
  • コミット日時: 2013年1月7日 月曜日 15:31:51 +1100
  • 変更ファイル: src/cmd/vet/print.go

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

https://github.com/golang/go/commit/86aad668c0022f17a202fc8d4dd76a0456401048

元コミット内容

cmd/vet: %#q is a valid format (uses raw quotes).

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7057051

変更の背景

Go言語には、コードの潜在的なバグや疑わしい構造を検出するための静的解析ツール cmd/vet があります。このツールは、fmt パッケージの関数(Printfなど)のフォーマット文字列と引数の整合性をチェックする機能を持っています。

このコミットが行われる前は、cmd/vetfmt.Printf などで %#q というフォーマット動詞が使用された場合に、これを無効なフォーマットとして誤って報告していました。%#q はGo言語の fmt パッケージにおいて有効なフォーマットであり、「raw quotes」(生のリテラル表現)で値を引用符で囲んで出力するために使用されます。例えば、文字列 foo%#q でフォーマットすると、"foo" と出力されます。

cmd/vet がこの有効なフォーマットを誤検知することは、開発者にとって不必要な警告となり、実際のバグを見逃す原因となる可能性がありました。このコミットは、cmd/vet の内部ロジックを更新し、%#q が正しく認識されるようにすることで、この誤検知を解消することを目的としています。

前提知識の解説

Go言語の fmt パッケージとフォーマット動詞

Go言語の fmt パッケージは、C言語の printf に似た書式指定文字列を用いた入出力機能を提供します。フォーマット動詞は % に続く文字で、値の表示形式を指定します。

  • %q (quoted string): 文字列をGoのシンタックスで引用符で囲んで出力します。非表示文字はエスケープされます。例: fmt.Printf("%q", "hello\nworld")"hello\\nworld" と出力されます。
  • %#q (raw quoted string): %q と似ていますが、Goのバッククォート文字列リテラル(raw string literal)のように、可能な限りエスケープせずに引用符で囲んで出力します。これは、特に複数行の文字列や特殊文字を含む文字列をデバッグ目的で表示する際に便利です。例: fmt.Printf("%#q", "hello\nworld")`hello\nworld` と出力されます。ただし、このコミットの文脈では、%#qstring 型に対しては " で囲み、runebyte 型に対してはシングルクォートで囲む動作を指しています。特に、string 型に対しては、%q と同様にエスケープされた文字列をダブルクォートで囲んで出力しますが、# フラグが付くことで、fmt パッケージの内部的な処理で「raw quotes」として扱われるようになります。このコミットの修正は、cmd/vet がこの # フラグの存在を正しく認識するようにするためのものです。

cmd/vet ツールの役割と目的

cmd/vet は、Go言語のソースコードを静的に解析し、疑わしい構造や潜在的なエラーを検出するツールです。Goの標準ツールチェーンの一部として提供されており、以下のようなチェックを行います。

  • fmt パッケージのフォーマット文字列の検証: fmt.Printf などの関数呼び出しにおいて、フォーマット文字列と引数の型や数が一致しているかを確認します。例えば、fmt.Printf("%d", "hello") のようなコードは、%d が整数を期待しているのに文字列が渡されているため、vet によって警告されます。
  • 構造体タグの検証: json:"foo" のような構造体タグの書式が正しいかを確認します。
  • メソッドシグネチャの検証: Error() メソッドを持つ型が error インターフェースを正しく実装しているかなどを確認します。
  • その他: 到達不能なコード、ロックの誤用、アトミック操作の誤用など、様々な潜在的な問題を検出します。

cmd/vet は、コンパイルエラーにはならないが実行時に問題を引き起こす可能性のあるコードパターンを早期に発見し、コードの品質と信頼性を向上させるのに役立ちます。

Printf 系の関数の引数チェック

cmd/vetPrintf 系の関数をチェックする際、その内部では各フォーマット動詞がどのようなフラグ(#, +, -, , 0 など)や幅、精度を許容するかという情報を持っています。この情報に基づいて、実際のフォーマット文字列がその動詞のルールに合致しているかを検証します。もし、許容されていないフラグが使われていたり、引数の型が期待と異なったりすると、vet は警告を発します。

技術的詳細

このコミットの技術的な核心は、cmd/vetfmt パッケージのフォーマット動詞の有効性をチェックする際に使用する内部データ構造 printVerbs の更新にあります。

src/cmd/vet/print.go ファイルは、cmd/vetfmt パッケージのフォーマット文字列を解析し、その引数を検証するためのロジックを含んでいます。このファイル内には、printVerbs という配列が定義されており、これは各フォーマット動詞(例: %d, %s, %q)がどのようなフラグ(#, +, - など)を許容するかを記述しています。

変更前は、%q フォーマット動詞に対応するエントリは以下のようになっていました。

{'q', " -+.0"},

これは、%q (スペース), - (左寄せ), + (符号), . (精度), 0 (ゼロ埋め) の各フラグを許容することを意味します。しかし、Goの fmt パッケージの仕様では、%q# フラグも許容し、その場合は「raw quotes」として動作します。cmd/vet のこの定義には # フラグが含まれていなかったため、%#q という有効なフォーマットが使われた際に、vet は「無効なフラグが使われている」と誤解し、警告を発していました。

このコミットでは、%q のエントリに # フラグを追加することで、cmd/vet%#q を有効なフォーマットとして正しく認識できるように修正しています。

{'q', " -+.0#"},

この変更により、cmd/vetfmt.Printf("%#q", blah) のようなコードを正しく解析し、警告を発しなくなります。これは、cmd/vet の精度を向上させ、開発者がより正確な静的解析結果を得られるようにするための重要な修正です。

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

--- a/src/cmd/vet/print.go
+++ b/src/cmd/vet/print.go
@@ -208,7 +208,7 @@ var printVerbs = []printVerb{\
 	{'G', numFlag},\
 	{'o', sharpNumFlag},\
 	{'p', \"-#\"},\
-\t{'q', \" -+.0\"},\
+\t{'q', \" -+.0#\"},\
 	{'s', \" -+.0\"},\
 	{'t', \"-\"},\
 	{'T', \"-\"},\
@@ -287,6 +287,7 @@ func BadFunctionUsedInTests() {\
 	fmt.Printf(\"%.*d\", 3, 3)           // correct
 	fmt.Printf(\"%.*d\", 3, 3, 3)        // ERROR \"wrong number of args in Printf call\"
 	fmt.Printf(\"%q %q\", multi()...)    // ok
+\tfmt.Printf(\"%#q\", `blah`)          // ok
 	printf(\"now is the time\", \"buddy\") // ERROR \"no formatting directive\"
 	Printf(\"now is the time\", \"buddy\") // ERROR \"no formatting directive\"
 	Printf(\"hi\")                       // ok

コアとなるコードの解説

変更の中心は src/cmd/vet/print.go ファイル内の printVerbs 配列の定義です。

printVerbsprintVerb 型の構造体のスライスであり、各要素は特定のフォーマット動詞とその動詞が許容するフラグのセットを定義しています。

  • {'q', " -+.0"}: この行は、フォーマット動詞 %q が、スペース、マイナス、プラス、ピリオド、ゼロの各フラグを許容することを定義していました。
  • {'q', " -+.0#"}: 修正後の行です。既存のフラグに加えて、# フラグが追加されています。これにより、cmd/vet%q 動詞が # フラグと組み合わせて使用されることを正しく認識し、誤検知を回避できるようになります。

また、コミットの差分には、テストケースの追加も示されています。

  • fmt.Printf("%#q", blah) // ok: この行は、%#q を使用した Printf 呼び出しが、cmd/vet によって「ok」(エラーなし)と判断されるべきであることを示すテストケースです。このテストケースの追加は、修正が意図通りに機能することを確認するために重要です。

この修正は、cmd/vet の内部的なフォーマット動詞の定義をGo言語の fmt パッケージの実際の動作と一致させることで、ツールの正確性を向上させています。

関連リンク

  • Go CL (Change List): https://golang.org/cl/7057051 このリンクは、このコミットに対応するGoのコードレビューシステム(Gerrit)上の変更リストを示しています。通常、Goプロジェクトのコミットは、まずこのシステムでレビューされ、承認されてからメインリポジトリにマージされます。

参考にした情報源リンク

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

このコミットは、Go言語の静的解析ツールである cmd/vet における誤検知を修正するものです。具体的には、fmt パッケージのフォーマット動詞 %q# フラグを組み合わせた %#q が、cmd/vet によって誤って無効なフォーマットとして報告される問題を解決します。この修正により、%#q を使用した fmt.Printf などの呼び出しが正しく検証されるようになります。

コミット

  • コミットハッシュ: 86aad668c0022f17a202fc8d4dd76a0456401048
  • 作者: David Symonds dsymonds@golang.org
  • コミット日時: 2013年1月7日 月曜日 15:31:51 +1100
  • 変更ファイル: src/cmd/vet/print.go

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

https://github.com/golang/go/commit/86aad668c0022f17a202fc8d4dd76a0456401048

元コミット内容

cmd/vet: %#q is a valid format (uses raw quotes).

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7057051

変更の背景

Go言語には、コードの潜在的なバグや疑わしい構造を検出するための静的解析ツール cmd/vet があります。このツールは、fmt パッケージの関数(Printfなど)のフォーマット文字列と引数の整合性をチェックする機能を持っています。

このコミットが行われる前は、cmd/vetfmt.Printf などで %#q というフォーマット動詞が使用された場合に、これを無効なフォーマットとして誤って報告していました。%#q はGo言語の fmt パッケージにおいて有効なフォーマットであり、「raw quotes」(生のリテラル表現)で値を引用符で囲んで出力するために使用されます。例えば、文字列 foo%#q でフォーマットすると、"foo" と出力されます。

cmd/vet がこの有効なフォーマットを誤検知することは、開発者にとって不必要な警告となり、実際のバグを見逃す原因となる可能性がありました。このコミットは、cmd/vet の内部ロジックを更新し、%#q が正しく認識されるようにすることで、この誤検知を解消することを目的としています。

前提知識の解説

Go言語の fmt パッケージとフォーマット動詞

Go言語の fmt パッケージは、C言語の printf に似た書式指定文字列を用いた入出力機能を提供します。フォーマット動詞は % に続く文字で、値の表示形式を指定します。

  • %q (quoted string): この動詞は、文字列をGoのシンタックスで二重引用符で囲み、特殊文字(バックスラッシュや二重引用符など)をエスケープして出力します。これにより、出力された文字列はGoの有効な文字列リテラルとなり、Goコードに直接コピー&ペーストして使用できます。

    • : fmt.Printf("%q", "hello\nworld")"hello\\nworld" と出力されます。
  • %#q (backquoted string/raw string literal): この動詞も文字列をGoの文字列リテラルとしてフォーマットしますが、可能な場合はバッククォート(`)を使用した生文字列リテラル(raw string literal)を試みます。生文字列リテラルはバックスラッシュエスケープを解釈しません。文字列にバッククォートが含まれる場合は、二重引用符で囲まれたエスケープされた文字列にフォールバックします。

    • : fmt.Printf("%#q", "hello\nworld")`hello\nworld` と出力されます。
    • これは、特に文字列がエスケープを必要とする特殊文字を含む場合に非常に便利です。

本質的に、%q は「解釈された文字列リテラル」(" とエスケープを含む)を生成し、%#q は可能な限り「生文字列リテラル」(` を含む)を目指します。どちらの出力もGoのソースコードで直接使用可能です。

cmd/vet ツールの役割と目的

cmd/vet は、Go言語のソースコードを静的に解析し、疑わしい構造や潜在的なエラーを検出するツールです。Goの標準ツールチェーンの一部として提供されており、以下のようなチェックを行います。

  • fmt パッケージのフォーマット文字列の検証: fmt.Printf などの関数呼び出しにおいて、フォーマット文字列と引数の型や数が一致しているかを確認します。例えば、fmt.Printf("%d", "hello") のようなコードは、%d が整数を期待しているのに文字列が渡されているため、vet によって警告されます。
  • 構造体タグの検証: json:"foo" のような構造体タグの書式が正しいかを確認します。
  • メソッドシグネチャの検証: Error() メソッドを持つ型が error インターフェースを正しく実装しているかなどを確認します。
  • その他: 到達不能なコード、ロックの誤用、アトミック操作の誤用など、様々な潜在的な問題を検出します。

cmd/vet は、コンパイルエラーにはならないが実行時に問題を引き起こす可能性のあるコードパターンを早期に発見し、コードの品質と信頼性を向上させるのに役立ちます。

Printf 系の関数の引数チェック

cmd/vetPrintf 系の関数をチェックする際、その内部では各フォーマット動詞がどのようなフラグ(#, +, -, , 0 など)や幅、精度を許容するかという情報を持っています。この情報に基づいて、実際のフォーマット文字列がその動詞のルールに合致しているかを検証します。もし、許容されていないフラグが使われていたり、引数の型が期待と異なったりすると、vet は警告を発します。

技術的詳細

このコミットの技術的な核心は、cmd/vetfmt パッケージのフォーマット動詞の有効性をチェックする際に使用する内部データ構造 printVerbs の更新にあります。

src/cmd/vet/print.go ファイルは、cmd/vetfmt パッケージのフォーマット文字列を解析し、その引数を検証するためのロジックを含んでいます。このファイル内には、printVerbs という配列が定義されており、これは各フォーマット動詞(例: %d, %s, %q)がどのようなフラグ(#, +, - など)を許容するかを記述しています。

変更前は、%q フォーマット動詞に対応するエントリは以下のようになっていました。

{'q', " -+.0"},

これは、%q (スペース), - (左寄せ), + (符号), . (精度), 0 (ゼロ埋め) の各フラグを許容することを意味します。しかし、Goの fmt パッケージの仕様では、%q# フラグも許容し、その場合は「raw quotes」として動作します。cmd/vet のこの定義には # フラグが含まれていなかったため、%#q という有効なフォーマットが使われた際に、vet は「無効なフラグが使われている」と誤解し、警告を発していました。

このコミットでは、%q のエントリに # フラグを追加することで、cmd/vet%#q を有効なフォーマットとして正しく認識できるように修正しています。

{'q', " -+.0#"},

この変更により、cmd/vetfmt.Printf("%#q", blah) のようなコードを正しく解析し、警告を発しなくなります。これは、cmd/vet の精度を向上させ、開発者がより正確な静的解析結果を得られるようにするための重要な修正です。

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

--- a/src/cmd/vet/print.go
+++ b/src/cmd/vet/print.go
@@ -208,7 +208,7 @@ var printVerbs = []printVerb{\
 	{'G', numFlag},\
 	{'o', sharpNumFlag},\
 	{'p', \"-#\"},\
-\t{'q', \" -+.0\"},\
+\t{'q', \" -+.0#\"},\
 	{'s', \" -+.0\"},\
 	{'t', \"-\"},\
 	{'T', \"-\"},\
@@ -287,6 +287,7 @@ func BadFunctionUsedInTests() {\
 	fmt.Printf(\"%.*d\", 3, 3)           // correct
 	fmt.Printf(\"%.*d\", 3, 3, 3)        // ERROR \"wrong number of args in Printf call\"
 	fmt.Printf(\"%q %q\", multi()...)    // ok
+\tfmt.Printf(\"%#q\", `blah`)          // ok
 	printf(\"now is the time\", \"buddy\") // ERROR \"no formatting directive\"
 	Printf(\"now is the time\", \"buddy\") // ERROR \"no formatting directive\"
 	Printf(\"hi\")                       // ok

コアとなるコードの解説

変更の中心は src/cmd/vet/print.go ファイル内の printVerbs 配列の定義です。

printVerbsprintVerb 型の構造体のスライスであり、各要素は特定のフォーマット動詞とその動詞が許容するフラグのセットを定義しています。

  • {'q', " -+.0"}: この行は、フォーマット動詞 %q が、スペース、マイナス、プラス、ピリオド、ゼロの各フラグを許容することを定義していました。
  • {'q', " -+.0#"}: 修正後の行です。既存のフラグに加えて、# フラグが追加されています。これにより、cmd/vet%q 動詞が # フラグと組み合わせて使用されることを正しく認識し、誤検知を回避できるようになります。

また、コミットの差分には、テストケースの追加も示されています。

  • fmt.Printf("%#q", blah) // ok: この行は、%#q を使用した Printf 呼び出しが、cmd/vet によって「ok」(エラーなし)と判断されるべきであることを示すテストケースです。このテストケースの追加は、修正が意図通りに機能することを確認するために重要です。

この修正は、cmd/vet の内部的なフォーマット動詞の定義をGo言語の fmt パッケージの実際の動作と一致させることで、ツールの正確性を向上させています。

関連リンク

  • Go CL (Change List): https://golang.org/cl/7057051 このリンクは、このコミットに対応するGoのコードレビューシステム(Gerrit)上の変更リストを示しています。通常、Goプロジェクトのコミットは、まずこのシステムでレビューされ、承認されてからメインリポジトリにマージされます。

参考にした情報源リンク