[インデックス 15832] ファイルの概要
このコミットは、Go言語のドキュメンテーションツールであるgo/doc
およびgodoc
における「ノート(note)」の読み込みと表示方法を改善するものです。具体的には、コメントグループ内でのノートの配置に関する柔軟性を高め、ノートのメタデータ(UIDや位置情報)を保持するための新しい型doc.Note
を導入し、godoc
の出力におけるノートのフォーマットを改善しています。
コミット
commit 5268119f26728ddd2ee9f8eebcbfcec83ac5bd69
Author: Robert Griesemer <gri@golang.org>
Date: Tue Mar 19 11:14:35 2013 -0700
go/doc, godoc: improved note reading
- A note doesn't have to be in the first
comment of a comment group anymore, and
several notes may appear in the same comment
group (e.g., it is fairly common to have a
TODO(uid) note immediately following another
comment).
- Define a doc.Note type which also contains
note uid and position info.
- Better formatting in godoc output. The position
information is not yet used, but could be used to
locate the note in the source text if desired.
Fixes #4843.
R=r, cnicolaou
CC=gobot, golang-dev
https://golang.org/cl/7496048
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5268119f26728ddd2ee9f8eebcbfcec83ac5bd69
元コミット内容
go/doc, godoc: improved note reading
- ノートはコメントグループの最初のコメントにある必要がなくなり、同じコメントグループ内に複数のノートが存在できるようになりました(例:別のコメントの直後にTODO(uid)ノートがあるのはよくあることです)。
- ノートのUIDと位置情報も含む
doc.Note
型を定義しました。 godoc
出力でのフォーマットを改善しました。位置情報はまだ使用されていませんが、必要に応じてソーステキスト内のノートを特定するために使用できます。
Fixes #4843.
変更の背景
Go言語のドキュメンテーションツールであるgodoc
は、ソースコード内のコメントからドキュメントを生成します。このツールは、特定の形式のコメント、特にMARKER(uid):
のような形式で記述された「ノート」を認識し、特別な情報として扱います。例えば、TODO(userid):
やBUG(userid):
といったコメントは、それぞれTODOリストやバグ報告として抽出され、ドキュメントに表示されます。
このコミットが行われる以前は、ノートの認識にはいくつかの制限がありました。
- コメントグループの最初のコメントに限定: ノートはコメントグループ(連続するコメントのブロック)の最初のコメントに記述されている必要がありました。これにより、開発者がコメントの途中にTODOなどを追記したい場合に、既存のコメント構造を崩すか、ノートとして認識されないリスクがありました。
- 複数のノートの認識の制限: 同じコメントグループ内に複数のノートが存在する場合、それらが適切に認識されない可能性がありました。
- メタデータの欠如: 抽出されたノートは単なる文字列として扱われ、そのノートがソースコードのどこに位置しているか、誰が記述したか(UID)といった詳細なメタ情報が失われていました。これにより、
godoc
の出力でノートをよりリッチに表示したり、IDE連携などでソースコード上の位置にジャンプしたりする機能の実装が困難でした。
これらの制限は、開発者がコードにノートを埋め込む際の柔軟性を低下させ、godoc
が提供できる情報の質を制限していました。特に、Fixes #4843
とあるように、このコミットは特定の課題(おそらくGitHub issue #4843)を解決するために行われました。この課題は、コメントグループ内のノートの認識に関する問題であったと推測されます。
前提知識の解説
このコミットを理解するためには、以下のGo言語の基本的な概念とツールの知識が必要です。
- Go言語のコメント: Go言語では、単一行コメント(
//
)と複数行コメント(/* ... */
)が使用されます。godoc
はこれらのコメントを解析してドキュメントを生成します。 go/ast
パッケージ: Goの抽象構文木(AST: Abstract Syntax Tree)を扱うためのパッケージです。ソースコードを解析し、その構造をプログラムで操作可能なデータ構造として表現します。コメントもASTの一部として扱われます。go/token
パッケージ: ソースコード内のトークン(キーワード、識別子、演算子など)や、それらの位置情報(ファイル名、行番号、列番号など)を扱うためのパッケージです。token.Pos
型は、ソースコード内の特定の位置を表します。go/doc
パッケージ: Goのソースコードからドキュメントを抽出・生成するためのライブラリです。godoc
ツールはこのパッケージを利用しています。go/doc
は、パッケージ、関数、型、変数などのドキュメントだけでなく、特定の形式のコメント(例:TODO
,BUG
)を「ノート」として認識し、抽出する機能を持っています。godoc
ツール: Go言語の標準ドキュメンテーションツールです。ローカルのGoパッケージのドキュメントを生成し、Webブラウザで表示したり、コマンドラインで表示したりできます。開発者がコードに記述したコメントや、go/doc
が抽出したノートなどを整形して表示します。- コメントグループ:
godoc
の文脈では、連続するコメント行や、コードブロックの直前にあるコメントブロックは「コメントグループ」として扱われます。通常、このコメントグループが、その後に続く宣言(関数、型など)のドキュメントとして認識されます。 - ノートのマーカーとUID:
godoc
が認識するノートは、通常MARKER(uid):
という形式で始まります。MARKER
: 大文字2文字以上の文字列(例:TODO
,BUG
,FIXME
,SECURITY
など)。uid
: ノートの作成者や関連するIDなどを示す文字列。:
: UIDの後に続くコロンは、このコミット以前は必須でしたが、このコミットでオプションになりました。
技術的詳細
このコミットの技術的な変更点は多岐にわたりますが、主に以下の3つの側面があります。
-
doc.Note
型の導入:- 以前は、抽出されたノートは単なる
string
のスライス(map[string][]string
)としてPackage.Notes
に格納されていました。 - このコミットでは、
src/pkg/go/doc/doc.go
に新しい構造体doc.Note
が定義されました。type Note struct { Pos token.Pos // position of the comment containing the marker UID string // uid found with the marker Body string // note body text }
- この
Note
型は、ノートの本文(Body
)だけでなく、そのノートがソースコードのどこに記述されているかを示すPos
(token.Pos
型)と、ノートのUID(UID
)を保持します。 - これにより、
Package.Notes
の型がmap[string][]string
からmap[string][]*Note
に変更され、よりリッチなメタデータを保持できるようになりました。
- 以前は、抽出されたノートは単なる
-
ノート読み込みロジックの改善 (
src/pkg/go/doc/reader.go
):go/doc
パッケージの内部でコメントを解析し、ノートを抽出するreader
構造体とその関連メソッドが大幅に修正されました。- 柔軟なノート認識: 以前は
readNote
関数がコメントグループの最初のコメントのみを対象としていましたが、新しいreadNotes
関数はコメントグループ内のすべてのコメントを走査し、個々のコメント行の先頭にMARKER(uid):
パターンが存在するかどうかをチェックするようになりました。これにより、コメントグループの途中や、複数のノートが連続して記述されている場合でも、それぞれを独立したノートとして認識できるようになりました。 - 正規表現の変更: ノートのマーカーを認識するための正規表現
noteMarker
が更新され、UIDの後のコロン(:
)がオプションになりました(:
?)。また、コメントの先頭にマーカーがあることを厳密にチェックするための
noteMarkerRxと
noteCommentRx`が導入されました。 clean
関数の導入: 抽出されたノートの本文から余分な空白や改行を削除し、整形するためのclean
関数が追加されました。これにより、godoc
出力での表示がよりきれいになります。Package.Bugs
の非推奨化: 以前はPackage.Bugs
フィールドにバグ関連のノートが格納されていましたが、このコミットによりPackage.Notes
に統一され、Package.Bugs
は非推奨(deprecated)となりました。noteBodies
ヘルパー関数が追加され、Package.Bugs
はPackage.Notes["BUG"]
から派生する形で互換性が保たれています。
-
godoc
出力のフォーマット改善 (lib/godoc/package.html
,lib/godoc/package.txt
,src/cmd/godoc/godoc.go
):godoc
のHTMLテンプレート(package.html
)とテキストテンプレート(package.txt
)が更新され、新しいdoc.Note
型に対応しました。- HTML出力では、ノートが
<ul>
(リスト)要素で囲まれ、各ノートが<li>
要素として表示されるようになりました。これにより、ノートがより構造化されて表示されます。 - テキスト出力でも、ノートの本文とUIDが適切に表示されるように変更されました。
src/cmd/godoc/godoc.go
のPageInfo
構造体内のNotes
フィールドの型がmap[string][]string
からmap[string][]*doc.Note
に変更され、新しいデータ構造に対応しました。
これらの変更により、godoc
はより柔軟にノートを認識し、より詳細な情報を保持し、より見やすい形でドキュメントに表示できるようになりました。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は以下のファイルに集中しています。
-
src/pkg/go/doc/doc.go
:doc.Note
構造体の定義が追加されました。Package
構造体のNotes
フィールドの型がmap[string][]string
からmap[string][]*Note
に変更されました。Bugs
フィールドが非推奨となり、Notes["BUG"]
から派生するように変更されました。noteBodies
ヘルパー関数が追加されました。
-
src/pkg/go/doc/reader.go
:- ノートを読み込むロジックが大幅に修正されました。
readNote
関数がreadNotes
メソッドに置き換えられ、コメントグループ内の複数のノートを認識できるようになりました。- ノートマーカーを認識するための正規表現が更新されました。
clean
関数が追加されました。readFile
メソッド内でsrc.Comments
からノートを収集する部分がr.readNotes(src.Comments)
に置き換えられました。
-
src/cmd/godoc/godoc.go
:PageInfo
構造体のNotes
フィールドの型がmap[string][]string
からmap[string][]*doc.Note
に変更されました。getPageInfo
メソッド内でノートを収集するロジックが新しいdoc.Note
型に対応するように修正されました。
-
lib/godoc/package.html
およびlib/godoc/package.txt
:godoc
の出力テンプレートが更新され、新しいdoc.Note
型と、そのBody
およびUID
フィールドを使用してノートを整形して表示するようになりました。特にHTMLでは<ul>
と<li>
が導入されました。
-
src/pkg/go/doc/testdata/a0.go
およびsrc/pkg/go/doc/testdata/*.golden
:- 新しいノート認識ロジックをテストするためのサンプルコード(
a0.go
)が追加されました。これには、コメントグループ内に複数のノートがあるケースや、コロンが省略されたケースなどが含まれます。 - テストの期待される出力(
.golden
ファイル)が更新され、新しいフォーマットとノートの認識結果が反映されました。
- 新しいノート認識ロジックをテストするためのサンプルコード(
コアとなるコードの解説
src/pkg/go/doc/doc.go
// A Note represents marked comments starting with "MARKER(uid): note body".
// Any note with a marker of 2 or more upper case [A-Z] letters and a uid of
// at least one character is recognized. The ":" following the uid is optional.
// Notes are collected in the Package.Notes map indexed by the notes marker.
type Note struct {
Pos token.Pos // position of the comment containing the marker
UID string // uid found with the marker
Body string // note body text
}
このNote
構造体が、このコミットの核となる変更の一つです。以前はノートの本文しか保持していませんでしたが、Pos
(ソースコード上の位置)とUID
(ノートの識別子)が追加されたことで、ノートに関するより豊富なメタデータが扱えるようになりました。
src/pkg/go/doc/reader.go
var (
noteMarker = `([A-Z][A-Z]+)\(([^)]+)\):?` // MARKER(uid), MARKER at least 2 chars, uid at least 1 char
noteMarkerRx = regexp.MustCompile(`^[ \t]*` + noteMarker) // MARKER(uid) at text start
noteCommentRx = regexp.MustCompile(`^/[/*][ \t]*` + noteMarker) // MARKER(uid) at comment start
)
// readNote collects a single note from a sequence of comments.
func (r *reader) readNote(list []*ast.Comment) {
text := (&ast.CommentGroup{List: list}).Text()
if m := noteMarkerRx.FindStringSubmatchIndex(text); m != nil {
body := clean(text[m[1]:])
if body != "" {
marker := text[m[2]:m[3]]
r.notes[marker] = append(r.notes[marker], &Note{
Pos: list[0].Pos(),
UID: text[m[4]:m[5]],
Body: body,
})
}
}
}
// readNotes extracts notes from comments.
// A note must start at the beginning of a comment with "MARKER(uid):"
// and is followed by the note body (e.g., "// BUG(gri): fix this").
// The note ends at the end of the comment group or at the start of
// another note in the same comment group, whichever comes first.
func (r *reader) readNotes(comments []*ast.CommentGroup) {
for _, group := range comments {
i := -1 // comment index of most recent note start, valid if >= 0
list := group.List
for j, c := range list {
if noteCommentRx.MatchString(c.Text) {
if i >= 0 {
r.readNote(list[i:j])
}
i = j
}
}
if i >= 0 {
r.readNote(list[i:])
}
}
}
reader.go
におけるreadNotes
メソッドの導入が、ノート認識の柔軟性を高める鍵です。このメソッドは、コメントグループ内の各コメントを走査し、noteCommentRx
正規表現(コメントの先頭にMARKER(uid):
パターンがあるか)にマッチするかどうかをチェックします。マッチした場合、そのコメントから次のノートの開始、またはコメントグループの終わりまでの範囲を一つのノートとして抽出し、readNote
メソッドに渡します。
noteMarker
正規表現の:
の後に?
が付いている点(:?
)は、コロンがオプションになったことを示しています。これにより、TODO(uid)
のようにコロンがない形式でもノートとして認識されるようになりました。
lib/godoc/package.html
{{with $.Notes}}
{{range $marker, $content := .}}
<h2 id="pkg-note-{{$marker}}">{{noteTitle $marker | html}}s</h2>
<ul>
{{range .}}
<li>{{html .Body}}</li>
{{end}}
</ul>
{{end}}
{{end}}
package.html
の変更は、godoc
のHTML出力におけるノートの表示方法を改善しています。{{with $.Notes}}
でPageInfo.Notes
が存在するかを確認し、存在する場合には各マーカー(例: TODO
, BUG
)ごとに見出しを生成します。そして、<ul>
と<li>
タグを使用して、各ノートのBody
をリスト形式で表示します。これにより、ノートがより構造化され、視覚的に分かりやすくなりました。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/5268119f26728ddd2ee9f8eebcbfcec83ac5bd69
- Gerrit Change-Id:
https://golang.org/cl/7496048
(GoプロジェクトのコードレビューシステムであるGerritのリンク) - 関連するGo Issue:
#4843
(コミットメッセージに記載されているが、直接的な公開Issueページは見つからなかった)
参考にした情報源リンク
- Go言語の公式ドキュメント (
go/doc
パッケージ): https://pkg.go.dev/go/doc - Go言語の公式ドキュメント (
go/ast
パッケージ): https://pkg.go.dev/go/ast - Go言語の公式ドキュメント (
go/token
パッケージ): https://pkg.go.dev/go/token godoc
コマンドの概要: https://go.dev/blog/godoc- 正規表現に関する一般的な情報 (Goの
regexp
パッケージ): https://pkg.go.dev/regexp - HTMLリスト要素 (
<ul>
,<li>
): https://developer.mozilla.org/ja/docs/Web/HTML/Element/ul - Go言語のテンプレート構文 (
text/template
,html/template
): https://pkg.go.dev/text/template