[インデックス 11149] ファイルの概要
このコミットは、Go言語の標準ライブラリであるgo/doc
パッケージのAPIを合理化し、より使いやすく、将来の拡張性を持たせるための変更を導入しています。主な変更点としては、型名から冗長なDoc
サフィックスを削除し、エクスポートされた型にName
フィールドを追加し、メソッドに関する情報を拡充し、パッケージの動作を制御するためのブール値の代わりにMode
フィールドを導入しています。これにより、go/doc
パッケージを利用するツール(例: godoc
)が、よりクリーンで一貫性のあるAPIを通じてドキュメント情報を取得できるようになります。
コミット
commit eac31c67a8fd94b9e91043a40b3a3cb1bf6daa4f
Author: Robert Griesemer <gri@golang.org>
Date: Thu Jan 12 17:36:57 2012 -0800
go/doc: streamlined go/doc API
- the main changes are removing the Doc suffix
from the exported types, so instead of
doc.TypeDoc one will have doc.Type, etc.
- All exported types now have a Name (or Names) field.
For Values, the Names field lists all declared variables
or constants.
- Methods have additional information about where they are
coming from.
- There's a mode field instead of a bool to
control the package's operation, which makes
it easier to extend w/o API changes.
Except for the partially implemented new Method type,
this is based on existing code. A clean rewrite is in
progress based on this new API.
R=rsc, kevlar
CC=golang-dev
https://golang.org/cl/5528060
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/eac31c67a8fd94b9e91043a40b3a3cb1bf6daa4f
元コミット内容
go/doc: streamlined go/doc API
- the main changes are removing the Doc suffix
from the exported types, so instead of
doc.TypeDoc one will have doc.Type, etc.
- All exported types now have a Name (or Names) field.
For Values, the Names field lists all declared variables
or constants.
- Methods have additional information about where they are
coming from.
- There's a mode field instead of a bool to
control the package's operation, which makes
it easier to extend w/o API changes.
Except for the partially implemented new Method type,
this is based on existing code. A clean rewrite is in
progress based on this new API.
R=rsc, kevlar
CC=golang-dev
https://golang.org/cl/5528060
変更の背景
このコミットの背景には、Go言語のドキュメンテーションツールであるgodoc
の基盤となるgo/doc
パッケージのAPIを改善し、より直感的で拡張性の高いものにするという目的があります。
従来のgo/doc
パッケージのAPIは、型名にDoc
というサフィックス(例: TypeDoc
, ValueDoc
, FuncDoc
, PackageDoc
)が付与されており、これは冗長であり、Goの慣習的な命名規則(例えば、io.Reader
ではなくio.ReaderDoc
とはしない)とは異なっていました。このコミットでは、この冗長なサフィックスを削除し、Type
, Value
, Func
, Package
といったより簡潔な名前に変更することで、APIの利用を簡素化しています。
また、ドキュメント生成の柔軟性を高めるため、パッケージの動作を制御するブール値のフラグ(exportsOnly
など)を、より拡張性の高いMode
型に置き換えています。これにより、将来的にドキュメント抽出のオプションが増えた場合でも、APIの変更なしに対応できるようになります。
さらに、ドキュメントの品質と詳細度を向上させるため、エクスポートされたすべての型にName
フィールドを追加し、Value
型には関連する変数や定数の名前をリストするNames
フィールドを導入しています。これにより、ドキュメント生成時にこれらの情報をより容易に利用できるようになります。メソッドに関しても、その起源に関する追加情報を提供することで、より詳細なドキュメント生成を可能にしています。
これらの変更は、godoc
ツールが生成するドキュメントの品質と、go/doc
パッケージの保守性および拡張性を向上させることを目的としています。コミットメッセージにある「A clean rewrite is in progress based on this new API.」という記述からも、このAPI変更が将来的な大規模なリファクタリングの基盤となることが示唆されています。
前提知識の解説
このコミットを理解するためには、以下のGo言語および関連ツールの基本的な知識が必要です。
-
Go言語のパッケージとドキュメンテーション:
- パッケージ: Go言語のコードはパッケージにまとめられます。パッケージは関連する機能の集合であり、再利用可能なコードの単位です。
- エクスポートされた識別子: Goでは、識別子(変数、関数、型など)の名前が大文字で始まる場合、その識別子はパッケージ外にエクスポートされ、他のパッケージから利用可能になります。小文字で始まる場合はパッケージ内でのみ利用可能です。
- Goのドキュメンテーションコメント: Goでは、エクスポートされた識別子の直前に書かれたコメントがその識別子のドキュメンテーションとして扱われます。
godoc
ツールはこのコメントを解析してドキュメントを生成します。
-
go/ast
パッケージ:go/ast
パッケージは、Goのソースコードを抽象構文木(AST: Abstract Syntax Tree)として表現するための型と関数を提供します。コンパイラやコード分析ツールは、このASTを操作してコードを理解・変換します。ast.Package
: 複数のGoソースファイルから構成されるパッケージ全体のAST表現です。ast.File
: 単一のGoソースファイルのAST表現です。ast.GenDecl
:var
,const
,type
宣言を表すASTノードです。ast.FuncDecl
: 関数宣言を表すASTノードです。ast.TypeSpec
: 型宣言(type MyType struct {}
など)を表すASTノードです。
-
go/token
パッケージ:go/token
パッケージは、Goのソースコード内のトークン(キーワード、識別子、演算子など)と、それらのソースコード上の位置(行番号、列番号など)を扱うための型と定数を提供します。token.FileSet
: 複数のソースファイルをまとめて管理し、ファイル内の位置情報を効率的に扱うための構造体です。
-
go/doc
パッケージ:go/doc
パッケージは、go/ast
パッケージが生成したASTからドキュメンテーションコメントを抽出し、構造化されたドキュメント情報を生成するためのライブラリです。godoc
ツールはこのパッケージを利用してHTMLやプレーンテキスト形式のドキュメントを生成します。- このコミットの変更の中心となるパッケージです。
-
godoc
ツール:- Go言語の標準ドキュメンテーションツールです。ソースコードから自動的にドキュメントを生成し、Webサーバーとして提供したり、コマンドラインで表示したりできます。
これらの知識があることで、コミットがgo/doc
パッケージの内部構造と、それがgodoc
のようなツールにどのように影響するかをより深く理解できます。
技術的詳細
このコミットは、go/doc
パッケージの内部構造と外部APIにわたる複数の重要な変更を含んでいます。
-
型名の変更とAPIの簡素化:
src/pkg/go/doc/doc.go
において、PackageDoc
,ValueDoc
,TypeDoc
,FuncDoc
といった型名からDoc
サフィックスが削除され、それぞれPackage
,Value
,Type
,Func
に変更されました。- これにより、APIがよりGoの慣習に沿ったものになり、利用時の冗長性が排除されます。例えば、
doc.TypeDoc
の代わりにdoc.Type
を使用するようになります。 - この変更に伴い、
src/cmd/godoc/godoc.go
やlib/godoc/package.html
,lib/godoc/package.txt
など、これらの型を参照している箇所がすべて更新されています。
-
Name
およびNames
フィールドの追加:Package
型にはName
フィールドが追加され、パッケージ名が直接アクセスできるようになりました(以前はPackageName
)。Type
型にはName
フィールドが追加され、型名が直接アクセスできるようになりました。Value
型にはNames []string
フィールドが追加されました。これは、var
やconst
宣言で複数の識別子が同時に宣言されている場合に、それらの名前をリストするために使用されます。これにより、ドキュメント生成時にグループ化された宣言内の個々の名前を正確に表示できるようになります。- この変更は、
src/pkg/go/doc/reader.go
のmakeValues
関数でspecNames
ヘルパー関数を導入し、Value
構造体のNames
フィールドを埋めることで実現されています。
-
Method
型の導入と情報拡充:src/pkg/go/doc/doc.go
に新しいMethod
型が導入されました。これは既存のFunc
型を埋め込み、さらにRecv
(元のレシーバの基底型)とLevel
(埋め込みレベル)といったメソッド固有の情報を保持できるように設計されています。- コミットメッセージには「partially implemented new Method type」とあり、
Recv
とLevel
フィールドはまだ完全に設定されていないことが示唆されています。しかし、この構造の導入により、将来的にメソッドのドキュメントをより詳細に、例えばそれがどの型から埋め込まれたものかといった情報を含めて生成する基盤が作られました。 Type
型内のMethods
フィールドが[]*FuncDoc
から[]*Method
に変更されています。src/pkg/go/doc/reader.go
のmakeTypeDocs
(変更後はmakeTypes
)関数内で、Type
のMethods
フィールドを構築する際に、Func
をMethod
型にラップする処理が追加されています。
-
Mode
フィールドの導入(ブール値から列挙型へ):src/pkg/go/doc/doc.go
において、NewPackageDoc
関数がexportsOnly bool
引数を受け取っていたのに対し、新しいNew
関数はmode Mode
引数を受け取るようになりました。Mode
はint
型の新しい型として定義され、AllDecls Mode = 1 << iota
という定数が導入されています。これにより、ドキュメント抽出の動作を制御するためのフラグをビットマスクとして表現できるようになり、将来的に新しいオプションを追加する際にAPIを変更する必要がなくなります。src/pkg/go/doc/reader.go
のdocReader
構造体もexportsOnly bool
からmode Mode
に変更され、初期化関数init
もこれに合わせて更新されています。src/cmd/godoc/godoc.go
では、getPageInfo
関数内でdoc.NewPackageDoc
の呼び出しがdoc.New
に置き換えられ、exportsOnly
のロジックがdocMode
の計算に変換されています。
-
ファイル処理順序のソート:
src/pkg/go/doc/doc.go
のNew
関数内で、パッケージ内のファイルを処理する前にファイル名をソートするsort.Strings(filenames)
が追加されました。これにより、異なる環境(32bit/64bitなど)でドキュメントを生成した際に、結果が常に一貫するようになります。
これらの変更は、go/doc
パッケージのAPIをより現代的で、Goの設計思想に合致させ、将来の拡張に備えるための重要なステップです。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は、src/pkg/go/doc/doc.go
、src/pkg/go/doc/reader.go
、src/pkg/go/doc/filter.go
、そしてsrc/cmd/godoc/godoc.go
に集中しています。
src/pkg/go/doc/doc.go
--- a/src/pkg/go/doc/doc.go
+++ b/src/pkg/go/doc/doc.go
@@ -5,67 +5,96 @@
// Package doc extracts source code documentation from a Go AST.
package doc
-import "go/ast"
+import (
+ "go/ast"
+ "sort"
+)
-// PackageDoc is the documentation for an entire package.
-type PackageDoc struct {
- Doc string
- PackageName string
- ImportPath string
- Filenames []string
- Consts []*ValueDoc
- Types []*TypeDoc
- Vars []*ValueDoc
- Funcs []*FuncDoc
- Bugs []string
+// Package is the documentation for an entire package.
+type Package struct {
+ Doc string
+ Name string
+ ImportPath string
+ Imports []string // TODO(gri) this field is not computed at the moment
+ Filenames []string
+ Consts []*Value
+ Types []*Type
+ Vars []*Value
+ Funcs []*Func
+ Bugs []string
}
// Value is the documentation for a (possibly grouped) var or const declaration.
-type ValueDoc struct {
- Doc string
- Decl *ast.GenDecl
+type Value struct {
+ Doc string
+ Names []string // var or const names in declaration order
+ Decl *ast.GenDecl
order int
}
-// TypeDoc is the documentation for type declaration.
-type TypeDoc struct {
- Doc string
- Type *ast.TypeSpec
- Decl *ast.GenDecl
- Consts []*ValueDoc // sorted list of constants of (mostly) this type
- Vars []*ValueDoc // sorted list of variables of (mostly) this type
- Factories []*FuncDoc // sorted list of functions returning this type
- Methods []*FuncDoc // sorted list of methods (including embedded ones) of this type
+type Method struct {
+ *Func
+ // TODO(gri) The following fields are not set at the moment.
+ Recv *Type // original receiver base type
+ Level int // embedding level; 0 means Func is not embedded
+}
+
+// Type is the documentation for type declaration.
+type Type struct {
+ Doc string
+ Name string
+ Type *ast.TypeSpec
+ Decl *ast.GenDecl
+ Consts []*Value // sorted list of constants of (mostly) this type
+ Vars []*Value // sorted list of variables of (mostly) this type
+ Funcs []*Func // sorted list of functions returning this type
+ Methods []*Method // sorted list of methods (including embedded ones) of this type
-\tmethods []*FuncDoc // top-level methods only
-\tembedded methodSet // embedded methods only
+\tmethods []*Func // top-level methods only
+\tembedded methodSet // embedded methods only
\torder int
}
// Func is the documentation for a func declaration.
-type FuncDoc struct {\n \tDoc string\n-\tRecv ast.Expr // TODO(rsc): Would like string here\n+type Func struct {\n \tDoc string\n+\t// TODO(gri) remove Recv once we switch to new implementation\n+\tRecv ast.Expr // TODO(rsc): Would like string here\n \tName string\n \tDecl *ast.FuncDecl\n }\n \n-// NewPackageDoc computes the package documentation for the given package\n-// and import path. If exportsOnly is set, only exported objects are\n-// included in the documentation.\n-func NewPackageDoc(pkg *ast.Package, importpath string, exportsOnly bool) *PackageDoc {\n+// Mode values control the operation of New.\n+type Mode int\n+\n+const (\n+\t// extract documentation for all package-level declarations,\n+\t// not just exported ones\n+\tAllDecls Mode = 1 << iota\n+)\n+\n+// New computes the package documentation for the given package.\n+func New(pkg *ast.Package, importpath string, mode Mode) *Package {\n \tvar r docReader\n-\tr.init(pkg.Name, exportsOnly)\n+\tr.init(pkg.Name, mode)\n \tfilenames := make([]string, len(pkg.Files))\n+\t// sort package files before reading them so that the\n+\t// result is the same on different machines (32/64bit)\n \ti := 0\n-\tfor filename, f := range pkg.Files {\n-\t\tif exportsOnly {\n+\tfor filename := range pkg.Files {\n+\t\tfilenames[i] = filename\n+\t\ti++\n+\t}\n+\tsort.Strings(filenames)\n+\n+\t// process files in sorted order\n+\tfor _, filename := range filenames {\n+\t\tf := pkg.Files[filename]\n+\t\tif mode&AllDecls == 0 {\n \t\t\tr.fileExports(f)\n \t\t}\n \t\tr.addFile(f)\n-\t\tfilenames[i] = filename\n-\t\ti++\n \t}\n \treturn r.newDoc(importpath, filenames)\n }\n```
### `src/cmd/godoc/godoc.go`
```diff
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -917,17 +917,17 @@ func remoteSearchURL(query string, html bool) string {\n }\n \n type PageInfo struct {\n-\tDirname string // directory containing the package\n-\tPList []string // list of package names found\n-\tFSet *token.FileSet // corresponding file set\n-\tPAst *ast.File // nil if no single AST with package exports\n-\tPDoc *doc.PackageDoc // nil if no single package documentation\n-\tExamples []*doc.Example // nil if no example code\n-\tDirs *DirList // nil if no directory information\n-\tDirTime time.Time // directory time stamp\n-\tDirFlat bool // if set, show directory in a flat (non-indented) manner\n-\tIsPkg bool // false if this is not documenting a real package\n-\tErr error // I/O error or nil\n+\tDirname string // directory containing the package\n+\tPList []string // list of package names found\n+\tFSet *token.FileSet // corresponding file set\n+\tPAst *ast.File // nil if no single AST with package exports\n+\tPDoc *doc.Package // nil if no single package documentation\n+\tExamples []*doc.Example // nil if no example code\n+\tDirs *DirList // nil if no directory information\n+\tDirTime time.Time // directory time stamp\n+\tDirFlat bool // if set, show directory in a flat (non-indented) manner\n+\tIsPkg bool // false if this is not documenting a real package\n+\tErr error // I/O error or nil\n }\n \n func (info *PageInfo) IsEmpty() bool {\
@@ -1084,17 +1084,20 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf\n \n \t// compute package documentation\n \tvar past *ast.File\n-\tvar pdoc *doc.PackageDoc\n+\tvar pdoc *doc.Package\n \tif pkg != nil {\n-\t\texportsOnly := mode&noFiltering == 0\n+\t\tvar docMode doc.Mode\n+\t\tif mode&noFiltering != 0 {\n+\t\t\tdocMode = doc.AllDecls\n+\t\t}\n \t\tif mode&showSource == 0 {\n \t\t\t// show extracted documentation\n-\t\t\tpdoc = doc.NewPackageDoc(pkg, path.Clean(relpath), exportsOnly) // no trailing \'/\' in importpath\n+\t\t\tpdoc = doc.New(pkg, path.Clean(relpath), docMode) // no trailing \'/\' in importpath\n \t\t} else {\n \t\t\t// show source code\n \t\t\t// TODO(gri) Consider eliminating export filtering in this mode,\n \t\t\t// or perhaps eliminating the mode altogether.\n-\t\t\tif exportsOnly {\n+\t\t\tif docMode&doc.AllDecls == 0 {\n \t\t\t\tast.PackageExports(pkg)\n \t\t\t}\n \t\t\tpast = ast.MergePackageFiles(pkg, ast.FilterUnassociatedComments)\
@@ -1189,13 +1192,13 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {\n \tcase info.PDoc != nil:\n \t\tswitch {\n \t\tcase info.IsPkg:\n-\t\t\ttitle = \"Package \" + info.PDoc.PackageName\n-\t\tcase info.PDoc.PackageName == fakePkgName:\n+\t\t\ttitle = \"Package \" + info.PDoc.Name\n+\t\tcase info.PDoc.Name == fakePkgName:\n \t\t\t// assume that the directory name is the command name\n \t\t\t_, pkgname := path.Split(relpath)\n \t\t\ttitle = \"Command \" + pkgname\n \t\tdefault:\n-\t\t\ttitle = \"Command \" + info.PDoc.PackageName\n+\t\t\ttitle = \"Command \" + info.PDoc.Name\n \t\t}\n \tdefault:\n \t\ttitle = \"Directory \" + relativeURL(info.Dirname)\
src/pkg/go/doc/reader.go
--- a/src/pkg/go/doc/reader.go
+++ b/src/pkg/go/doc/reader.go
@@ -53,19 +53,19 @@ func (info *typeInfo) addEmbeddedType(embedded *typeInfo, isPtr bool) {\n // printing the corresponding AST node).\n //\n type docReader struct {\n-\tdoc *ast.CommentGroup // package documentation, if any\n-\tpkgName string\n-\texportsOnly bool\n-\tvalues []*ast.GenDecl // consts and vars\n-\ttypes map[string]*typeInfo\n-\tembedded map[string]*typeInfo // embedded types, possibly not exported\n-\tfuncs map[string]*ast.FuncDecl\n-\tbugs []*ast.CommentGroup\n+\tdoc *ast.CommentGroup // package documentation, if any\n+\tpkgName string\n+\tmode Mode\n+\tvalues []*ast.GenDecl // consts and vars\n+\ttypes map[string]*typeInfo\n+\tembedded map[string]*typeInfo // embedded types, possibly not exported\n+\tfuncs map[string]*ast.FuncDecl\n+\tbugs []*ast.CommentGroup\n }\n \n-func (doc *docReader) init(pkgName string, exportsOnly bool) {\n+func (doc *docReader) init(pkgName string, mode Mode) {\n \tdoc.pkgName = pkgName\n-\tdoc.exportsOnly = exportsOnly\n+\tdoc.mode = mode\n \tdoc.types = make(map[string]*typeInfo)\n \tdoc.embedded = make(map[string]*typeInfo)\n \tdoc.funcs = make(map[string]*ast.FuncDecl)\
@@ -347,10 +347,10 @@ func (doc *docReader) addFile(src *ast.File) {\n // ----------------------------------------------------------------------------\n // Conversion to external representation\n \n-type sortValueDoc []*ValueDoc\n+type sortValue []*Value\n \n-func (p sortValueDoc) Len() int { return len(p) }\n-func (p sortValueDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }\n+func (p sortValue) Len() int { return len(p) }\n+func (p sortValue) Swap(i, j int) { p[i], p[j] = p[j], p[i] }\n \n func declName(d *ast.GenDecl) string {\n \tif len(d.Specs) != 1 {\
@@ -367,7 +367,7 @@ func declName(d *ast.GenDecl) string {\n \treturn \"\"\n }\n \n-func (p sortValueDoc) Less(i, j int) bool {\n+func (p sortValue) Less(i, j int) bool {\n \t// sort by name\n \t// pull blocks (name = \"\") up to top\n \t// in original order\
@@ -377,32 +377,45 @@ func (p sortValueDoc) Less(i, j int) bool {\n \treturn p[i].order < p[j].order\n }\n \n-func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {\n-\td := make([]*ValueDoc, len(list)) // big enough in any case\n+func specNames(specs []ast.Spec) []string {\n+\tnames := make([]string, len(specs)) // reasonable estimate\n+\tfor _, s := range specs {\n+\t\t// should always be an *ast.ValueSpec, but be careful\n+\t\tif s, ok := s.(*ast.ValueSpec); ok {\n+\t\t\tfor _, ident := range s.Names {\n+\t\t\t\tnames = append(names, ident.Name)\n+\t\t\t}\n+\t\t}\n+\t}\n+\treturn names\n+}\n+\n+func makeValues(list []*ast.GenDecl, tok token.Token) []*Value {\n+\td := make([]*Value, len(list)) // big enough in any case\n \tn := 0\n \tfor i, decl := range list {\n \t\tif decl.Tok == tok {\n-\t\t\td[n] = &ValueDoc{decl.Doc.Text(), decl, i}\n+\t\t\td[n] = &Value{decl.Doc.Text(), specNames(decl.Specs), decl, i}\n \t\t\tn++\n \t\t\tdecl.Doc = nil // doc consumed - removed from AST\n \t\t}\n \t}\n \td = d[0:n]\n-\tsort.Sort(sortValueDoc(d))\n+\tsort.Sort(sortValue(d))\n \treturn d\n }\n \n-type sortFuncDoc []*FuncDoc\n+type sortFunc []*Func\n \n-func (p sortFuncDoc) Len() int { return len(p) }\n-func (p sortFuncDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }\n-func (p sortFuncDoc) Less(i, j int) bool { return p[i].Name < p[j].Name }\n+func (p sortFunc) Len() int { return len(p) }\n+func (p sortFunc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }\n+func (p sortFunc) Less(i, j int) bool { return p[i].Name < p[j].Name }\n \n-func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {\n-\td := make([]*FuncDoc, len(m))\n+func makeFuncs(m map[string]*ast.FuncDecl) []*Func {\n+\td := make([]*Func, len(m))\n \ti := 0\n \tfor _, f := range m {\n-\t\tdoc := new(FuncDoc)\n+\t\tdoc := new(Func)\n \t\tdoc.Doc = f.Doc.Text()\n \t\tf.Doc = nil // doc consumed - remove from ast.FuncDecl node\n \t\tif f.Recv != nil {\
@@ -413,34 +426,40 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {\n \t\td[i] = doc\n \t\ti++\n \t}\n-\tsort.Sort(sortFuncDoc(d))\n+\tsort.Sort(sortFunc(d))\n \treturn d\n }\n \n-type methodSet map[string]*FuncDoc\n+type methodSet map[string]*Func\n \n-func (mset methodSet) add(m *FuncDoc) {\n+func (mset methodSet) add(m *Func) {\n \tif mset[m.Name] == nil {\n \t\tmset[m.Name] = m\n \t}\n }\n \n-func (mset methodSet) sortedList() []*FuncDoc {\n-\tlist := make([]*FuncDoc, len(mset))\n+type sortMethod []*Method\n+\n+func (p sortMethod) Len() int { return len(p) }\n+func (p sortMethod) Swap(i, j int) { p[i], p[j] = p[j], p[i] }\n+func (p sortMethod) Less(i, j int) bool { return p[i].Func.Name < p[j].Func.Name }\n+\n+func (mset methodSet) sortedList() []*Method {\n+\tlist := make([]*Method, len(mset))\n \ti := 0\n \tfor _, m := range mset {\n-\t\tlist[i] = m\n+\t\tlist[i] = &Method{Func: m}\n \t\ti++\n \t}\n-\tsort.Sort(sortFuncDoc(list))\n+\tsort.Sort(sortMethod(list))\n \treturn list\n }\n \n-type sortTypeDoc []*TypeDoc\n+type sortType []*Type\n \n-func (p sortTypeDoc) Len() int { return len(p) }\n-func (p sortTypeDoc) Swap(i, j int) { p[i], p[j] = p[j], p[i] }\n-func (p sortTypeDoc) Less(i, j int) bool {\n+func (p sortType) Len() int { return len(p) }\n+func (p sortType) Swap(i, j int) { p[i], p[j] = p[j], p[i] }\n+func (p sortType) Less(i, j int) bool {\n \t// sort by name\n \t// pull blocks (name = \"\") up to top\n \t// in original order\
@@ -453,14 +472,14 @@ func (p sortTypeDoc) Less(i, j int) bool {\n // NOTE(rsc): This would appear not to be correct for type ( )\n // blocks, but the doc extractor above has split them into\n // individual declarations.\n-func (doc *docReader) makeTypeDocs(m map[string]*typeInfo) []*TypeDoc {\n+func (doc *docReader) makeTypes(m map[string]*typeInfo) []*Type {\n \t// TODO(gri) Consider computing the embedded method information\n-\t// before calling makeTypeDocs. Then this function can\n+\t// before calling makeTypes. Then this function can\n \t// be single-phased again. Also, it might simplify some\n \t// of the logic.\n \t//\n-\t// phase 1: associate collected declarations with TypeDocs\n-\tlist := make([]*TypeDoc, len(m))\n+\t// phase 1: associate collected declarations with Types\n+\tlist := make([]*Type, len(m))\n \ti := 0\n \tfor _, old := old := range m {\n \t\t// old typeInfos may not have a declaration associated with them\
@@ -469,7 +488,7 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeInfo) []*TypeDoc {\n \t\tif decl := old.decl; decl != nil || !old.exported() {\n \t\t\t// process the type even if not exported so that we have\n \t\t\t// its methods in case they are embedded somewhere\n-\t\t\tt := new(TypeDoc)\n+\t\t\tt := new(Type)\n \t\t\tif decl != nil {\n \t\t\t\ttypespec := decl.Specs[0].(*ast.TypeSpec)\n \t\t\t\tdoc := typespec.Doc\
@@ -482,10 +501,10 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeInfo) []*TypeDoc {\n \t\t\t\tt.Doc = doc.Text()\n \t\t\t\tt.Type = typespec\n \t\t\t}\n-\t\t\tt.Consts = makeValueDocs(old.values, token.CONST)\n-\t\t\tt.Vars = makeValueDocs(old.values, token.VAR)\n-\t\t\tt.Factories = makeFuncDocs(old.factories)\n-\t\t\tt.methods = makeFuncDocs(old.methods)\n+\t\t\tt.Consts = makeValues(old.values, token.CONST)\n+\t\t\tt.Vars = makeValues(old.values, token.VAR)\n+\t\t\tt.Funcs = makeFuncs(old.factories)\n+\t\t\tt.methods = makeFuncs(old.methods)\n \t\t\t// The list of embedded types\' methods is computed from the list\n \t\t\t// of embedded types, some of which may not have been processed\n \t\t\t// yet (i.e., their forward link is nil) - do this in a 2nd phase.\
@@ -496,7 +515,7 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeInfo) []*TypeDoc {\n \t\t\told.forward = t // old has been processed\n \t\t\t// only add the type to the final type list if it\n \t\t\t// is exported or if we want to see all types\n-\t\t\tif old.exported() || !doc.exportsOnly {\n+\t\t\tif old.exported() || doc.mode&AllDecls != 0 {\n \t\t\t\tlist[i] = t\n \t\t\t\ti++\n \t\t\t}\
@@ -540,7 +559,7 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeInfo) []*TypeDoc {\n \t\t}\n \t}\n \n-\t// phase 3: compute final method set for each TypeDoc\n+\t// phase 3: compute final method set for each Type\n \tfor _, d := range list {\n \t\tif len(d.embedded) > 0 {\n \t\t\t// there are embedded methods - exclude\
@@ -557,12 +576,15 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeInfo) []*TypeDoc {\n \t\t\t}\n \t\t\td.Methods = mset.sortedList()\n \t\t} else {\n-\t\t\t// no embedded methods\n-\t\t\td.Methods = d.methods\n+\t\t\t// no embedded methods - convert into a Method list\n+\t\t\td.Methods = make([]*Method, len(d.methods))\n+\t\t\tfor i, m := range d.methods {\n+\t\t\t\td.Methods[i] = &Method{Func: m}\n+\t\t\t}\n \t\t}\n \t}\n \n-\tsort.Sort(sortTypeDoc(list))\n+\tsort.Sort(sortType(list))\n \treturn list\n }\n \
@@ -589,7 +611,7 @@ func collectEmbeddedMethods(mset methodSet, info *typeInfo, recvTypeName string,\n \t}\n }\n \n-func customizeRecv(m *FuncDoc, embeddedIsPtr bool, recvTypeName string) *FuncDoc {\n+func customizeRecv(m *Func, embeddedIsPtr bool, recvTypeName string) *Func {\n \tif m == nil || m.Decl == nil || m.Decl.Recv == nil || len(m.Decl.Recv.List) != 1 {\n \t\treturn m // shouldn\'t happen, but be safe\n \t}\
@@ -619,7 +641,7 @@ func customizeRecv(m *FuncDoc, embeddedIsPtr bool, recvTypeName string) *FuncDoc\n \treturn &newM\n }\n \n-func makeBugDocs(list []*ast.CommentGroup) []string {\n+func makeBugs(list []*ast.CommentGroup) []string {\n \td := make([]string, len(list))\n \tfor i, g := range list {\n \t\td[i] = g.Text()\
@@ -629,20 +651,20 @@ func makeBugDocs(list []*ast.CommentGroup) []string {\n \n // newDoc returns the accumulated documentation for the package.\n //\n-func (doc *docReader) newDoc(importpath string, filenames []string) *PackageDoc {\n-\tp := new(PackageDoc)\n-\tp.PackageName = doc.pkgName\n+func (doc *docReader) newDoc(importpath string, filenames []string) *Package {\n+\tp := new(Package)\n+\tp.Name = doc.pkgName\n \tp.ImportPath = importpath\n \tsort.Strings(filenames)\n \tp.Filenames = filenames\n \tp.Doc = doc.doc.Text()\n-\t// makeTypeDocs may extend the list of doc.values and\n+\t// makeTypes may extend the list of doc.values and\n \t// doc.funcs and thus must be called before any other\n \t// function consuming those lists\n-\tp.Types = doc.makeTypeDocs(doc.types)\n-\tp.Consts = makeValueDocs(doc.values, token.CONST)\n-\tp.Vars = makeValueDocs(doc.values, token.VAR)\n-\tp.Funcs = makeFuncDocs(doc.funcs)\n-\tp.Bugs = makeBugDocs(doc.bugs)\n+\tp.Types = doc.makeTypes(doc.types)\n+\tp.Consts = makeValues(doc.values, token.CONST)\n+\tp.Vars = makeValues(doc.values, token.VAR)\n+\tp.Funcs = makeFuncs(doc.funcs)\n+\tp.Bugs = makeBugs(doc.bugs)\n \treturn p\n }\n```
## コアとなるコードの解説
### `src/pkg/go/doc/doc.go`
* **型名の変更**: `PackageDoc`, `ValueDoc`, `TypeDoc`, `FuncDoc`がそれぞれ`Package`, `Value`, `Type`, `Func`にリネームされました。これはAPIの簡潔化とGoの命名慣習への準拠を目的としています。
* **`Package`型の変更**:
* `PackageName`フィールドが`Name`に変更されました。
* **`Value`型の変更**:
* `Names []string`フィールドが追加されました。これにより、`const`や`var`のグループ宣言において、複数の識別子名を保持できるようになります。
* **`Method`型の新規導入**:
* `Method`という新しい構造体が定義されました。これは`Func`型を埋め込み、さらに`Recv`(レシーバの基底型)と`Level`(埋め込みレベル)といったメソッド固有の情報を保持するよう設計されています。これにより、埋め込みインターフェースなどから継承されたメソッドのドキュメントをより詳細に生成する基盤が作られました。
* **`Type`型の変更**:
* `Factories []*FuncDoc`が`Funcs []*Func`に変更されました。
* `Methods []*FuncDoc`が`Methods []*Method`に変更されました。
* **`Mode`型の導入**:
* `Mode`という新しい`int`型が定義され、`AllDecls`という定数が追加されました。これは、ドキュメント抽出の動作を制御するためのビットマスクとして機能し、将来的な拡張性を高めます。
* **`NewPackageDoc`から`New`への変更**:
* `NewPackageDoc`関数が`New`関数にリネームされ、引数も`exportsOnly bool`から`mode Mode`に変更されました。
* パッケージ内のファイルを処理する前に`sort.Strings(filenames)`が追加され、ファイル処理順序の一貫性が保証されるようになりました。
### `src/cmd/godoc/godoc.go`
* `PageInfo`構造体内の`PDoc`フィールドの型が`*doc.PackageDoc`から`*doc.Package`に変更されました。
* `getPageInfo`関数内で、`doc.NewPackageDoc`の呼び出しが`doc.New`に置き換えられ、`exportsOnly`のロジックが新しい`doc.Mode`型に変換されています。
* ドキュメントのタイトル生成ロジックにおいて、`info.PDoc.PackageName`が`info.PDoc.Name`に変更されました。
### `src/pkg/go/doc/reader.go`
* `docReader`構造体内の`exportsOnly bool`フィールドが`mode Mode`に変更され、初期化関数`init`もこれに合わせて更新されました。
* `makeValueDocs`関数が`makeValues`にリネームされ、`Value`構造体の`Names`フィールドを埋めるために`specNames`ヘルパー関数が導入されました。
* `makeFuncDocs`関数が`makeFuncs`にリネームされました。
* `methodSet`の`sortedList`メソッドが`[]*FuncDoc`を返す代わりに`[]*Method`を返すように変更され、`sortMethod`という新しいソートヘルパーが導入されました。
* `makeTypeDocs`関数が`makeTypes`にリネームされ、`Type`構造体の`Methods`フィールドを構築する際に、`Func`を`Method`型にラップするロジックが追加されました。
* `makeBugDocs`関数が`makeBugs`にリネームされました。
* `newDoc`関数内で、`PackageDoc`の代わりに`Package`がインスタンス化され、`PackageName`の代わりに`Name`が設定されるようになりました。また、各種`make*Docs`関数が新しい`make*`関数に置き換えられました。
これらの変更は、`go/doc`パッケージの内部実装と、それを呼び出す`godoc`ツールとの間の整合性を保ちつつ、APIの改善と将来の拡張性確保を目指したものです。
## 関連リンク
* Go言語のドキュメンテーション: [https://go.dev/doc/effective_go#commentary](https://go.dev/doc/effective_go#commentary)
* `go/doc`パッケージのドキュメンテーション: [https://pkg.go.dev/go/doc](https://pkg.go.dev/go/doc) (現在のAPI)
* `godoc`ツール: [https://go.dev/blog/godoc](https://go.dev/blog/godoc)
## 参考にした情報源リンク
* コミットメッセージに記載されているGoのコードレビューシステムへのリンク: [https://golang.org/cl/5528060](https://golang.org/cl/5528060) (現在はGoのGerritにリダイレクトされます)
* Go言語の公式ドキュメンテーション
* `go/ast`パッケージのドキュメンテーション
* `go/token`パッケージのドキュメンテーション
* `go/doc`パッケージのソースコード (変更前後の比較)
* `godoc`ツールのソースコード (変更前後の比較)
* Go言語の命名規則に関する一般的な情報源 (例: Effective Go)
* Go言語のAPI設計に関する議論 (GoのメーリングリストやIssueトラッカーなど)