[インデックス 15962] ファイルの概要
このコミットは、Go言語の公式ドキュメントツールである godoc
の内部実装における重要なリファクタリングとバグ修正を含んでいます。具体的には、テンプレートに渡されるコンテキスト情報を *token.FileSet
からより包括的な *PageInfo
オブジェクトへと変更し、これにより将来的な機能拡張とより柔軟なフォーマットを可能にしています。
コミット
commit 12cf2ff00ba0a0816c1e572dae1476341f0bf3ed
Author: Robert Griesemer <gri@golang.org>
Date: Tue Mar 26 18:28:16 2013 -0700
godoc: pass *PageInfos instead of *token.FileSets in templates
- convert all formatters that require a *token.FileSet to
consistenly use a *PageInfo as first argument instead
- adjust templates correspondingly
- fix outstanding bug from previous CL 8005044
Going forward, with this change the affected functions have
access to the full page "context" (PageInfo), not just the
respective file set. This will permit better context-dependent
formatting in the future.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/7860049
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/12cf2ff00ba0a0816c1e572dae1476341f0bf3ed
元コミット内容
godoc: pass *PageInfos instead of *token.FileSets in templates
このコミットは、godoc
ツールがテンプレート内で使用するデータ構造を、*token.FileSet
から *PageInfo
へと変更することを目的としています。これにより、関連するフォーマッタ関数とテンプレートが調整され、以前の変更リスト (CL 8005044) から残っていたバグも修正されます。この変更により、関数は単なるファイルセットだけでなく、ページ全体の「コンテキスト」(PageInfo
)にアクセスできるようになり、将来的にコンテキストに応じたより良いフォーマットが可能になります。
変更の背景
godoc
はGo言語のソースコードからドキュメントを生成するツールです。以前のバージョンでは、ドキュメント生成の際に、コードの構文木(AST)のノードをフォーマットするために *token.FileSet
(ファイルセット)が頻繁に引数として渡されていました。FileSet
はソースコードのファイルと位置情報を管理するための重要な情報ですが、それだけではドキュメント生成に必要な全てのコンテキスト(例えば、コード例、パッケージ全体の情報、ASTのルートノードなど)をカバーできませんでした。
この制限により、特にコードスニペット内の識別子にリンクを張る際などに、十分なコンテキストがないために正確な処理ができないバグ(BUG(gri)
としてコメントされていたもの)が存在していました。また、将来的に godoc
のフォーマット機能を拡張する際にも、より豊富なコンテキスト情報が必要となることが予想されました。
このコミットは、これらの課題を解決し、godoc
の内部構造をより堅牢で拡張性の高いものにするために行われました。
前提知識の解説
このコミットを理解するためには、以下のGo言語の標準ライブラリと概念に関する知識が必要です。
go/token
パッケージ:token.FileSet
: Goのソースコードのファイルと、そのファイル内の位置情報(行番号、列番号、オフセットなど)を管理するための構造体です。コンパイラやツールがソースコードを解析する際に、コードのどの部分がどこにあるかを正確に特定するために使用されます。
go/ast
パッケージ:ast.Node
: Goのソースコードを抽象構文木(AST)として表現する際の基本的なインターフェースです。ASTは、ソースコードの構造を木構造で表現したもので、コンパイラやコード分析ツールがコードの意味を理解するために利用します。
go/doc
パッケージ:doc.Example
: Goのコード例(Example)に関する情報を持つ構造体です。godoc
はこの情報を使用して、ドキュメントにコード例を埋め込みます。
- Go言語のテンプレート (
text/template
,html/template
):- Goのテンプレートエンジンは、データ構造をテンプレートに渡して、動的にテキストやHTMLを生成します。
.
(ドット): 現在のデータコンテキストを参照します。$
(ダラー): テンプレートのルートデータコンテキストを参照します。このコミットでは、*PageInfo
がルートコンテキストとして渡されるようになるため、$
が*PageInfo
を指すようになります。
- ポインタ: Go言語におけるポインタは、変数のメモリアドレスを指す値です。関数にポインタを渡すことで、元の変数を変更したり、大きなデータ構造をコピーせずに効率的に渡したりすることができます。このコミットでは、
PageInfo
の値渡しからポインタ渡し (*PageInfo
) へと変更されています。 godoc
ツール: Go言語のパッケージやプログラムのドキュメントを生成し、表示するためのコマンドラインツールです。Goのソースコード内のコメントや構造から自動的にドキュメントを抽出します。
技術的詳細
このコミットの核心は、godoc
の内部でドキュメント生成のコンテキストを管理する方法の変更です。
-
*PageInfo
の導入と一元化:- 以前は、
nodeFunc
やexample_htmlFunc
のようなフォーマッタ関数は、*token.FileSet
や[]*doc.Example
のように、必要な情報を個別に引数として受け取っていました。 - この変更により、これらの関数は
*PageInfo
という単一の構造体を最初の引数として受け取るようになります。PageInfo
は、FileSet
、Examples
、そしてパッケージのASTのルートノード (PAst
) など、ドキュメント生成に必要な全てのコンテキスト情報をカプセル化しています。 - これにより、関数のシグネチャが簡素化され、必要な情報へのアクセスが一元化されます。
- 以前は、
-
テンプレートの変更:
lib/godoc/package.html
およびlib/godoc/package.txt
テンプレートでは、$.FSet
のようにルートコンテキストからFileSet
を直接参照していた箇所が、$
(現在のコンテキスト、つまり*PageInfo
)を引数として渡す形式に変更されています。例えば、{{node_html .Decl $.FSet}}
は{{node_html $ .Decl}}
になります。これは、node_html
関数が*PageInfo
を受け取るように変更されたことに対応しています。
-
node_htmlFunc
のバグ修正:node_htmlFunc
は、ASTノードをHTMLとしてフォーマットする関数です。以前は、*declLinks
が有効な場合に、識別子にリンクを張る処理を行っていましたが、info.PAst != nil
(つまり、完全なソースコードが表示されている場合)には、型チェックなしでは識別子の解決が不十分であるため、誤ったリンクが生成される可能性がありました。- このコミットでは、
if n, _ := node.(ast.Node); n != nil && *declLinks && info.PAst == nil {
という条件が追加されました。これにより、完全なソースコードが表示されている場合には識別子リンクが生成されないようになり、以前のバグが修正されました。この修正は、PageInfo
がPAst
(パッケージのAST)情報を持つようになったことで可能になりました。
-
getPageInfo
の戻り値の変更:src/cmd/godoc/godoc.go
内のgetPageInfo
関数は、PageInfo
の値ではなく、*PageInfo
(ポインタ)を返すように変更されました。これにより、main.go
などでgetPageInfo
の結果を受け取る際に、同じPageInfo
オブジェクトへの参照を共有できるようになり、メモリ効率と一貫性が向上します。
これらの変更は、godoc
のコードベースをよりモジュール化し、将来の機能追加(例えば、より高度なクロスリファレンスやコード分析に基づくドキュメント生成)のための基盤を強化するものです。
コアとなるコードの変更箇所
主要な変更は以下のファイルに集中しています。
lib/godoc/package.html
: HTMLテンプレート。node_html
、example_html
、posLink_url
などの関数呼び出しで、$.FSet
の代わりに$
を引数として渡すように変更。lib/godoc/package.txt
: テキストテンプレート。HTMLテンプレートと同様の変更。src/cmd/godoc/godoc.go
:godoc
の主要なロジックが含まれるファイル。nodeFunc
,node_htmlFunc
,example_textFunc
,example_htmlFunc
,posLink_urlFunc
の関数シグネチャが変更され、*token.FileSet
や[]*doc.Example
の代わりに*PageInfo
を受け取るようになった。node_htmlFunc
内で、識別子リンク生成の条件にinfo.PAst == nil
が追加された。getPageInfo
関数の戻り値がPageInfo
から*PageInfo
に変更された。
src/cmd/godoc/main.go
:godoc
コマンドのエントリポイント。getPageInfo
の戻り値の型変更に合わせて、PageInfo
型の変数が*PageInfo
型に変更された。
コアとなるコードの解説
src/cmd/godoc/godoc.go
における変更例
// 変更前
func node_htmlFunc(node interface{}, fset *token.FileSet) string {
var buf1 bytes.Buffer
writeNode(&buf1, fset, node) // fset を直接使用
var buf2 bytes.Buffer
// BUG(gri): ...
if n, _ := node.(ast.Node); n != nil && *declLinks {
LinkifyText(&buf2, buf1.Bytes(), n)
} else {
FormatText(&buf2, buf1.Bytes(), -1, true, "", nil)
}
return buf2.String()
}
// 変更後
func node_htmlFunc(info *PageInfo, node interface{}) string {
var buf1 bytes.Buffer
writeNode(&buf1, info.FSet, node) // info.FSet を使用
var buf2 bytes.Buffer
// Don't linkify full source text (info.PAst != nil) - identifier
// resolution is not strong enough without full type checking.
if n, _ := node.(ast.Node); n != nil && *declLinks && info.PAst == nil { // info.PAst == nil が追加
LinkifyText(&buf2, buf1.Bytes(), n)
} else {
FormatText(&buf2, buf1.Bytes(), -1, true, "", nil)
}
return buf2.String()
}
この変更では、node_htmlFunc
が *token.FileSet
の代わりに *PageInfo
を受け取るようになり、内部で info.FSet
を使用してファイルセットにアクセスしています。さらに、info.PAst == nil
という条件が追加され、PageInfo
が持つAST情報に基づいて、完全なソースコードが表示されている場合には識別子リンクを生成しないように制御しています。これにより、以前のバグが修正され、より正確なドキュメント生成が可能になりました。
テンプレートにおける変更例
lib/godoc/package.html
からの抜粋:
<!-- 変更前 -->
<dd><a href="#{{$name_html}}">{{node_html .Decl $.FSet}}</a></dd>
<!-- 変更後 -->
<dd><a href="#{{$name_html}}">{{node_html $ .Decl}}</a></dd>
この例では、node_html
関数に渡される引数が変更されています。以前は、現在のコンテキスト (.
) の Decl
フィールドと、ルートコンテキスト ($
) の FSet
フィールドを渡していました。変更後は、node_html
関数が *PageInfo
を受け取るようになったため、ルートコンテキストである $
(この場合は *PageInfo
オブジェクト自体)と Decl
フィールドを渡すように変更されています。これにより、node_html
関数は PageInfo
オブジェクトから必要な FileSet
やその他のコンテキスト情報を取得できるようになります。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
go/token
パッケージのドキュメント: https://pkg.go.dev/go/tokengo/ast
パッケージのドキュメント: https://pkg.go.dev/go/astgo/doc
パッケージのドキュメント: https://pkg.go.dev/go/doc- Go言語のテンプレートに関するドキュメント: https://pkg.go.dev/text/template
参考にした情報源リンク
- GitHub上のコミットページ: https://github.com/golang/go/commit/12cf2ff00ba0a0816c1e572dae1476341f0bf3ed
- Gerrit Change-ID:
https://golang.org/cl/7860049
(Goプロジェクトの変更履歴システム) - Go言語のソースコード (特に
src/cmd/godoc
ディレクトリ) - Go言語の標準ライブラリのドキュメント (上記「関連リンク」に記載)