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

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

このコミットは、Go言語の静的解析ツールである cmd/vet における Printf フォーマット文字列の誤検出を修正するものです。具体的には、%e (指数表記) フォーマット動詞に + フラグと精度指定 (.2) を組み合わせた "%+5.2e" のような形式が、cmd/vet によって誤ってエラーとして報告される問題を解決します。この修正により、cmd/vet は有効な Printf フォーマットに対して不必要な警告を発しなくなります。

コミット

commit 04f110e5302f9846cb110d8fcab2666ce4220623
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Sat Feb 25 01:16:17 2012 +0800

    cmd/vet: don't give error for Printf("%+5.2e", x)
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5696048

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

https://github.com/golang/go/commit/04f110e5302f9846cb110d8fcab2666ce4220623

元コミット内容

commit 04f110e5302f9846cb110d8fcab2666ce4220623
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Sat Feb 25 01:16:17 2012 +0800

    cmd/vet: don't give error for Printf("%+5.2e", x)
    
    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5696048
---
 src/cmd/vet/print.go | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n
diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go
index e0717f8e8e..ee9a33c702 100644
--- a/src/cmd/vet/print.go
+++ b/src/cmd/vet/print.go
@@ -167,7 +167,7 @@ var printVerbs = []printVerb{\
 	{'b', numFlag},\
 	{'c', "-."},\
 	{'d', numFlag},\
-	{'e', "-."},\
+	{'e', numFlag},\
 	{'E', numFlag},\
 	{'f', numFlag},\
 	{'F', numFlag},\

変更の背景

Go言語の fmt パッケージが提供する Printf 関数群は、C言語の printf に似た強力なフォーマット機能を持っています。cmd/vet は、Goのソースコードを静的に解析し、潜在的なバグや疑わしい構成を検出するツールです。その機能の一つに、Printf のフォーマット文字列と引数の型が一致しているかを検証する機能があります。

このコミットが行われる前、cmd/vet%e (指数表記) フォーマット動詞に対して、+ フラグ(常に符号を出力する)や精度指定(小数点以下の桁数)が組み合わされた場合に、誤ってエラーを報告していました。例えば、fmt.Printf("%+5.2e", 123.45) のような有効なコードが、cmd/vet によって不適切なフォーマットとしてフラグ付けされていたと考えられます。

この誤検出は、開発者が有効な Printf フォーマットを使用しているにもかかわらず、cmd/vet の警告に直面するという不便さを引き起こしていました。このコミットは、cmd/vetPrintf フォーマット検証ロジックを改善し、このような誤検出を排除することを目的としています。

前提知識の解説

cmd/vet

cmd/vet は、Go言語の標準ツールチェーンに含まれる静的解析ツールです。コンパイル時には検出されないが、実行時に問題を引き起こす可能性のあるコードの慣用的な誤用や疑わしい構成を特定します。主なチェック項目には以下のようなものがあります。

  • Printf フォーマット文字列の検証: fmt.Printf などの関数で使用されるフォーマット文字列が、対応する引数の型と一致しているか、また有効なフォーマット動詞やフラグが使用されているかをチェックします。
  • 構造体タグの検証: json:"..."xml:"..." などの構造体タグの構文が正しいかをチェックします。
  • メソッドシグネチャの検証: Error() メソッドを持つ型が error インターフェースを正しく実装しているかなどをチェックします。
  • ロックの誤用: sync.Mutex などのロックが正しく使用されているか(例えば、ロックが解放されているか)をチェックします。

fmt.Printf とフォーマット動詞、フラグ

Go言語の fmt パッケージは、C言語の printf に似た書式設定されたI/O機能を提供します。Printf 関数は、第一引数にフォーマット文字列を取り、その後に可変個の引数を取ります。フォーマット文字列内の % で始まるシーケンスは「フォーマット動詞」と呼ばれ、対応する引数をどのように表示するかを制御します。

主要なフォーマット動詞の例:

  • %d: 整数を10進数で表示
  • %f: 浮動小数点数を標準の浮動小数点表記で表示
  • %e: 浮動小数点数を科学表記(指数表記)で表示 (例: 1.234500e+02)
  • %s: 文字列を表示
  • %v: 引数のデフォルトのフォーマットで表示(任意の型に対応)

フォーマット動詞には、表示をさらに制御するための「フラグ」を組み合わせることができます。

  • + フラグ: 数値の場合、常に符号を出力します(例: +123.45)。
  • - フラグ: フィールド内で値を左寄せします。
  • (スペース) フラグ: 数値が負でない場合、符号の代わりにスペースを出力します。
  • 0 フラグ: 数値の場合、幅指定の際に先頭をゼロで埋めます。
  • # フラグ: 代替フォーマットを使用します(例: %#x0x プレフィックスを追加)。

また、フォーマット動詞の前に「幅」や「精度」を指定することもできます。

  • %5d: 少なくとも5文字の幅で表示し、必要に応じてスペースで埋めます。
  • %.2f: 小数点以下2桁まで表示します。
  • %5.2e: 少なくとも5文字の幅で、小数点以下2桁の精度で指数表記します。

src/cmd/vet/print.go

このファイルは、cmd/vetPrintf フォーマット文字列を検証する際のロジックを定義しています。特に、各フォーマット動詞がどのようなフラグや精度指定を受け入れるかを記述したデータ構造が含まれています。

ファイル内の printVerbs 変数は、printVerb 型の構造体のスライスであり、各要素が特定のフォーマット動詞 ('b', 'c', 'd', 'e' など) と、その動詞が受け入れるフラグのパターンを定義しています。

  • printVerb 構造体は、動詞の文字と、その動詞に適用可能なフラグのセットを保持します。
  • numFlag: 数値型のフォーマット動詞(%d, %f, %e など)が一般的に受け入れるフラグのセットを表す定数です。これには +, -, , 0 などのフラグが含まれます。
  • "-.": これは、特定の動詞が - (左寄せ) と . (精度) フラグのみを受け入れることを示す文字列リテラルです。

技術的詳細

cmd/vetPrintf フォーマット検証は、src/cmd/vet/print.go 内の printVerbs というグローバル変数に定義されたルールに基づいて行われます。この printVerbs[]printVerb 型のスライスで、各 printVerb は特定のフォーマット動詞(例: 'e')と、その動詞がサポートするフラグの集合を関連付けています。

変更前のコードでは、'e' フォーマット動詞に対して "-." という文字列リテラルが関連付けられていました。これは、cmd/vet%e に対して - (左寄せ) フラグと . (精度) フラグのみを有効なものとして認識していたことを意味します。しかし、Goの fmt パッケージのドキュメントによると、%e は数値型のフォーマット動詞であるため、+ (常に符号を出力) や (負でない場合にスペースを出力) などの他の数値フラグもサポートしています。

例えば、fmt.Printf("%+5.2e", x) のようなフォーマット文字列では、+ フラグが使用されています。変更前の cmd/vet は、'e' 動詞が + フラグをサポートしないと誤解していたため、この有効なフォーマットに対してエラーを報告していました。

このコミットでは、'e' フォーマット動詞に関連付けられているフラグの定義を "-." から numFlag に変更しています。numFlag は、Goの fmt パッケージで数値型のフォーマット動詞が一般的にサポートするすべてのフラグ(+, -, , 0, # など)を網羅する定数です。この変更により、cmd/vet%e 動詞が + フラグを含むすべての標準的な数値フラグを正しくサポートすることを認識するようになり、"%+5.2e" のような有効なフォーマットに対する誤検出が解消されます。

この修正は、cmd/vet の正確性を向上させ、開発者が Printf の機能をより柔軟に、かつ誤検出の心配なく利用できるようにするために重要です。

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

変更は src/cmd/vet/print.go ファイルの1箇所のみです。

--- a/src/cmd/vet/print.go
+++ b/src/cmd/vet/print.go
@@ -167,7 +167,7 @@ var printVerbs = []printVerb{\
 	{'b', numFlag},\
 	{'c', "-."},\
 	{'d', numFlag},\
-	{'e', "-."},\
+	{'e', numFlag},\
 	{'E', numFlag},\
 	{'f', numFlag},\
 	{'F', numFlag},\

具体的には、printVerbs スライス内の 'e' フォーマット動詞に対応するエントリの2番目の要素が "-." から numFlag に変更されています。

コアとなるコードの解説

src/cmd/vet/print.go ファイルには、printVerbs という名前の []printVerb 型のグローバル変数が定義されています。このスライスは、fmt パッケージの Printf 関数がサポートする各フォーマット動詞に関するメタデータを含んでいます。

printVerb 構造体は以下の形式です。

type printVerb struct {
	verb rune   // フォーマット動詞の文字 (例: 'e', 'd', 's')
	flags string // その動詞がサポートするフラグのセット
}

flags フィールドは、その動詞が受け入れるフラグを示す文字列です。

  • numFlag: これは print.go 内で定義されている定数で、数値型のフォーマット動詞(%d, %f, %e など)が一般的にサポートするすべてのフラグ(+, -, , 0, #)を表します。
  • "-.": これは文字列リテラルで、- (左寄せ) と . (精度) フラグのみをサポートすることを示します。

変更前は、'e' (指数表記) 動詞に対して flags"-." と設定されていました。これは、cmd/vet%e に対して -. 以外のフラグ(特に + フラグ)が使用されると、それを不正なフォーマットとして認識してしまう原因となっていました。

このコミットでは、'e' 動詞の flagsnumFlag に変更しました。これにより、cmd/vet%enumFlag が表すすべての標準的な数値フラグ(+, -, , 0, #)をサポートすることを正しく認識するようになります。結果として、"%+5.2e" のような有効なフォーマット文字列が cmd/vet によって誤ってエラーとして報告されることがなくなりました。

この修正は、cmd/vetPrintf フォーマット検証ロジックの正確性を向上させ、ツールの信頼性を高める上で重要な役割を果たしています。

関連リンク

参考にした情報源リンク