[インデックス 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言語の標準ライブラリのドキュメント (上記「関連リンク」に記載)