[インデックス 11251] ファイルの概要
このコミットは、Go言語の公式ドキュメント生成ツールである go/doc
パッケージに、パッケージがインポートしている他のパッケージの情報を収集する機能を追加するものです。これにより、生成されるドキュメントにインポートパスのリストが含まれるようになり、パッケージの依存関係をより明確に把握できるようになります。
コミット
- Author: Robert Griesemer gri@golang.org
- Date: Wed Jan 18 19:35:53 2012 -0800
- Commit Message: go/doc: collect imports
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c109705c6f30d568b7c7af8a203bdd69c6fb99af
元コミット内容
go/doc: collect imports
R=r
CC=golang-dev
https://golang.org/cl/5556051
変更の背景
Go言語の go/doc
パッケージは、Goのソースコードからドキュメントを生成するためのツールです。このツールは、パッケージの公開された型、関数、変数、定数などを抽出し、人間が読みやすい形式で表示します。しかし、このコミット以前は、生成されるドキュメントにはそのパッケージがインポートしている他のパッケージの情報が含まれていませんでした。
パッケージのインポート情報は、そのパッケージがどのような外部依存を持っているかを理解するために非常に重要です。例えば、あるパッケージが特定の標準ライブラリやサードパーティライブラリに依存している場合、その情報がドキュメントに明示されていれば、利用者はそのパッケージの機能や利用方法をより深く理解できます。また、依存関係の可視化は、コードの保守性や再利用性を高める上でも役立ちます。
このコミットは、この欠落していたインポート情報の収集機能を追加することで、go/doc
が生成するドキュメントの完全性と有用性を向上させることを目的としています。
前提知識の解説
このコミットの変更内容を理解するためには、以下のGo言語の概念と標準ライブラリに関する知識が必要です。
-
Go言語のパッケージとインポート:
- Go言語のコードは「パッケージ」という単位で整理されます。パッケージは関連する機能の集合であり、再利用可能なコードの最小単位です。
- あるパッケージの機能を利用するには、
import
キーワードを使ってそのパッケージをインポートする必要があります。例えば、import "fmt"
は標準ライブラリのfmt
パッケージをインポートします。 - インポートパスは、パッケージを一意に識別するための文字列です(例:
"fmt"
,"net/http"
,"github.com/user/repo/mypkg"
)。
-
go/doc
パッケージ:go/doc
はGoの標準ライブラリの一部で、Goのソースコードからドキュメントを生成するためのAPIを提供します。godoc
コマンドは、このgo/doc
パッケージを利用してGoのドキュメントを生成し、Webサーバーとして提供します。
-
go/ast
パッケージ (Abstract Syntax Tree):go/ast
はGoのソースコードを抽象構文木(AST)として表現するためのデータ構造と関数を提供します。- Goコンパイラやツール(
go/doc
など)は、ソースコードを直接解析するのではなく、まずASTに変換し、そのASTを操作することでコードの構造や意味を理解します。 - ASTは、パッケージ宣言、インポート宣言、関数宣言、型宣言、変数宣言など、コードのあらゆる要素をノードとして表現します。
-
go/token
パッケージ:go/token
は、Goのソースコード内のトークン(キーワード、識別子、演算子など)やファイルの位置情報を扱うためのパッケージです。- ASTノードは、
go/token.Pos
型を使ってソースコード内の正確な位置(ファイル、行、列)を保持します。
-
ast.ImportSpec
:go/ast
パッケージにおいて、import "path/to/package"
のようなインポート宣言はast.ImportSpec
というASTノードで表現されます。ast.ImportSpec
には、インポートパス(Path
フィールド)や、エイリアス(Name
フィールド、例:import io "fmt"
のio
)などの情報が含まれます。
技術的詳細
このコミットの主要な変更点は、go/doc
パッケージがGoソースコードのASTを走査する際に、インポート宣言を識別し、そのインポートパスを収集するロジックを追加したことです。
具体的には、以下のファイルが変更されています。
src/pkg/go/doc/doc.go
:Package
構造体にImports []string
フィールドを追加し、生成されるドキュメントにインポートパスのリストを含める準備をします。src/pkg/go/doc/exports.go
: ASTをフィルタリングする際に、ast.ImportSpec
を常に保持するように変更します。これにより、インポート情報が後続の処理で利用可能になります。src/pkg/go/doc/reader.go
:docReader
構造体にimports map[string]int
を追加し、重複を避けてインポートパスを一時的に格納するためのマップを用意します。int
は単に存在を示すためのプレースホルダーです。init
メソッドでimports
マップを初期化します。addDecl
メソッド内で、token.IMPORT
型のast.GenDecl
(一般的な宣言ノード)を処理するロジックを追加します。ここで、各ast.ImportSpec
からインポートパスを抽出し、strconv.Unquote
を使ってクォートを外し、doc.imports
マップに追加します。makeImports
という新しいヘルパー関数を追加します。この関数は、doc.imports
マップからインポートパスのリストを抽出し、ソートして[]string
スライスとして返します。newDoc
メソッド内で、doc.makeImports()
を呼び出してインポートパスのリストを取得し、Package
構造体のImports
フィールドに設定します。
src/pkg/go/doc/testdata/b.out
,src/pkg/go/doc/testdata/template.txt
,src/pkg/go/doc/testdata/testing.out
: これらのファイルはテストデータとテンプレートであり、インポート情報がドキュメント出力に含まれるようになったことを反映するために更新されています。特にtemplate.txt
は、{{with .Imports}}
と{{range .}}
を使ってImports
フィールドの内容を整形して表示するロジックが追加されています。
この変更により、go/doc
はGoソースコードを解析する際に、パッケージのインポート宣言を正確に抽出し、その情報を Package
構造体の一部として提供できるようになります。これにより、godoc
などのツールがよりリッチなドキュメントを生成することが可能になります。
コアとなるコードの変更箇所
src/pkg/go/doc/doc.go
--- a/src/pkg/go/doc/doc.go
+++ b/src/pkg/go/doc/doc.go
@@ -15,7 +15,7 @@ type Package struct {
Doc string
Name string
ImportPath string
- Imports []string // TODO(gri) this field is not computed at the moment
+ Imports []string
Filenames []string
Consts []*Value
Types []*Type
src/pkg/go/doc/exports.go
--- a/src/pkg/go/doc/exports.go
+++ b/src/pkg/go/doc/exports.go
@@ -124,6 +124,9 @@ func (doc *docReader) filterType(tinfo *typeInfo, typ ast.Expr) bool {
func (doc *docReader) filterSpec(spec ast.Spec) bool {
switch s := spec.(type) {
+ case *ast.ImportSpec:
+ // always keep imports so we can collect them
+ return true
case *ast.ValueSpec:
s.Names = filterIdentList(s.Names)
if len(s.Names) > 0 {
src/pkg/go/doc/reader.go
--- a/src/pkg/go/doc/reader.go
+++ b/src/pkg/go/doc/reader.go
@@ -9,6 +9,7 @@ import (
"go/token"
"regexp"
"sort"
+ "strconv"
)
// ----------------------------------------------------------------------------
@@ -55,6 +56,7 @@ type docReader struct {
doc *ast.CommentGroup // package documentation, if any
pkgName string
mode Mode
+ imports map[string]int
values []*ast.GenDecl // consts and vars
types map[string]*typeInfo
embedded map[string]*typeInfo // embedded types, possibly not exported
@@ -65,6 +67,7 @@ type docReader struct {
func (doc *docReader) init(pkgName string, mode Mode) {
doc.pkgName = pkgName
doc.mode = mode
+ doc.imports = make(map[string]int)
doc.types = make(map[string]*typeInfo)
doc.embedded = make(map[string]*typeInfo)
doc.funcs = make(map[string]*ast.FuncDecl)
@@ -244,6 +247,13 @@ func (doc *docReader) addDecl(decl ast.Decl) {
case *ast.GenDecl:
if len(d.Specs) > 0 {
switch d.Tok {
+ case token.IMPORT:
+ // imports are handled individually
+ for _, spec := range d.Specs {
+ if import_, err := strconv.Unquote(spec.(*ast.ImportSpec).Path.Value); err == nil {
+ doc.imports[import_] = 1
+ }
+ }
case token.CONST, token.VAR:
// constants and variables are always handled as a group
doc.addValue(d)
@@ -346,6 +356,17 @@ func (doc *docReader) addFile(src *ast.File) {
// ----------------------------------------------------------------------------
// Conversion to external representation
+func (doc *docReader) makeImports() []string {
+ list := make([]string, len(doc.imports))
+ i := 0
+ for import_ := range doc.imports {
+ list[i] = import_
+ i++
+ }
+ sort.Strings(list)
+ return list
+}
+
type sortValue []*Value
func (p sortValue) Len() int { return len(p) }
@@ -661,6 +682,7 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *Package {
// doc.funcs and thus must be called before any other
// function consuming those lists
p.Types = doc.makeTypes(doc.types)
+ p.Imports = doc.makeImports()
p.Consts = makeValues(doc.values, token.CONST)
p.Vars = makeValues(doc.values, token.VAR)
p.Funcs = makeFuncs(doc.funcs)
コアとなるコードの解説
src/pkg/go/doc/doc.go
の変更
type Package struct { ... }
にImports []string
フィールドが追加されました。- 解説:
Package
構造体は、Goの単一パッケージに関するドキュメント情報を保持するための主要なデータ構造です。この変更により、生成されるパッケージドキュメントオブジェクトが、そのパッケージがインポートしている他のパッケージのパス(文字列スライス)を保持できるようになります。以前はTODO(gri) this field is not computed at the moment
というコメントがありましたが、このコミットでその機能が実装されました。
src/pkg/go/doc/exports.go
の変更
func (doc *docReader) filterSpec(spec ast.Spec) bool
内のswitch s := spec.(type)
にcase *ast.ImportSpec:
が追加され、return true
となっています。- 解説:
filterSpec
関数は、ASTの仕様(ast.Spec
)をフィルタリングし、ドキュメントに含めるべきかどうかを決定します。この変更により、インポート宣言(ast.ImportSpec
)が常にフィルタリングを通過し、docReader
が後でインポート情報を収集できるようになります。これは、インポート情報がドキュメントの重要な一部となるため、破棄されないようにするための措置です。
src/pkg/go/doc/reader.go
の変更
-
import "strconv"
の追加:- 解説: インポートパスは文字列リテラルとしてASTに格納されており、通常はダブルクォートで囲まれています(例:
"fmt"
)。これらのクォートを削除して純粋なパス文字列を得るために、strconv.Unquote
関数が必要となるため、strconv
パッケージがインポートされました。
- 解説: インポートパスは文字列リテラルとしてASTに格納されており、通常はダブルクォートで囲まれています(例:
-
docReader
構造体へのimports
フィールド追加:type docReader struct { ... }
にimports map[string]int
が追加されました。- 解説:
docReader
は、Goソースファイルを読み込み、ASTを解析してドキュメント情報を抽出する役割を担う構造体です。imports
マップは、解析中に見つかったすべてのユニークなインポートパスを一時的に格納するために使用されます。マップのキーとしてインポートパス(文字列)を使用することで、重複するインポートパスが自動的に排除されます。値のint
は単に存在を示すためのプレースホルダーです。
-
init
メソッドでのimports
マップの初期化:func (doc *docReader) init(...) { ... }
内でdoc.imports = make(map[string]int)
が追加されました。- 解説:
docReader
が新しいパッケージの解析を開始する際に、imports
マップが適切に初期化され、以前の解析からのデータが残らないようにします。
-
addDecl
メソッドでのインポート宣言の処理:func (doc *docReader) addDecl(decl ast.Decl) { ... }
内のcase *ast.GenDecl:
のswitch d.Tok
にcase token.IMPORT:
ブロックが追加されました。- 解説:
addDecl
関数は、ASTの一般的な宣言ノード(ast.GenDecl
)を処理します。token.IMPORT
はインポート宣言を表します。このブロックでは、d.Specs
(インポート宣言のリスト)をループし、各ast.ImportSpec
からPath.Value
を取得します。strconv.Unquote
を使ってパス文字列からクォートを外し、結果のインポートパスをdoc.imports
マップに追加します。これにより、すべてのインポートパスが収集されます。
-
makeImports
ヘルパー関数の追加:func (doc *docReader) makeImports() []string { ... }
という新しい関数が追加されました。- 解説: この関数は、
doc.imports
マップに収集されたインポートパスを[]string
スライスに変換し、アルファベット順にソートして返します。ソートすることで、ドキュメントに表示されるインポートリストが一貫した順序になります。
-
newDoc
メソッドでのImports
フィールドの設定:func (doc *docReader) newDoc(...) *Package { ... }
内でp.Imports = doc.makeImports()
が追加されました。- 解説:
newDoc
関数は、解析された情報から最終的なPackage
構造体を作成します。ここで、新しく追加されたmakeImports
関数を呼び出し、収集・ソートされたインポートパスのリストをPackage
構造体のImports
フィールドに割り当てます。これにより、Package
オブジェクトが完全なインポート情報を持つことになります。
これらの変更により、go/doc
はGoのソースコードを解析する過程で、そのパッケージが依存するすべてのインポートパスを正確に抽出し、生成されるドキュメントデータに含めることができるようになりました。
関連リンク
- Go言語公式ドキュメント: https://go.dev/doc/
go/doc
パッケージのドキュメント: https://pkg.go.dev/go/docgo/ast
パッケージのドキュメント: https://pkg.go.dev/go/astgo/token
パッケージのドキュメント: https://pkg.go.dev/go/tokenstrconv
パッケージのドキュメント: https://pkg.go.dev/strconv
参考にした情報源リンク
- Go言語の公式ドキュメントおよびパッケージドキュメント
- Go言語のソースコード(特に
go/doc
パッケージ) - 抽象構文木(AST)に関する一般的なプログラミング概念
[インデックス 11251] ファイルの概要
このコミットは、Go言語の公式ドキュメント生成ツールである go/doc
パッケージに、パッケージがインポートしている他のパッケージの情報を収集する機能を追加するものです。これにより、生成されるドキュメントにインポートパスのリストが含まれるようになり、パッケージの依存関係をより明確に把握できるようになります。
コミット
- Author: Robert Griesemer gri@golang.org
- Date: Wed Jan 18 19:35:53 2012 -0800
- Commit Message: go/doc: collect imports
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c109705c6f30d568b7c7af8a203bdd69c6fb99af
元コミット内容
go/doc: collect imports
R=r
CC=golang-dev
https://golang.org/cl/5556051
変更の背景
Go言語の go/doc
パッケージは、Goのソースコードからドキュメントを生成するためのツールです。このツールは、パッケージの公開された型、関数、変数、定数などを抽出し、人間が読みやすい形式で表示します。しかし、このコミット以前は、生成されるドキュメントにはそのパッケージがインポートしている他のパッケージの情報が含まれていませんでした。
パッケージのインポート情報は、そのパッケージがどのような外部依存を持っているかを理解するために非常に重要です。例えば、あるパッケージが特定の標準ライブラリやサードパーティライブラリに依存している場合、その情報がドキュメントに明示されていれば、利用者はそのパッケージの機能や利用方法をより深く理解できます。また、依存関係の可視化は、コードの保守性や再利用性を高める上でも役立ちます。
このコミットは、この欠落していたインポート情報の収集機能を追加することで、go/doc
が生成するドキュメントの完全性と有用性を向上させることを目的としています。
前提知識の解説
このコミットの変更内容を理解するためには、以下のGo言語の概念と標準ライブラリに関する知識が必要です。
-
Go言語のパッケージとインポート:
- Go言語のコードは「パッケージ」という単位で整理されます。パッケージは関連する機能の集合であり、再利用可能なコードの最小単位です。
- あるパッケージの機能を利用するには、
import
キーワードを使ってそのパッケージをインポートする必要があります。例えば、import "fmt"
は標準ライブラリのfmt
パッケージをインポートします。 - インポートパスは、パッケージを一意に識別するための文字列です(例:
"fmt"
,"net/http"
,"github.com/user/repo/mypkg"
)。
-
go/doc
パッケージ:go/doc
はGoの標準ライブラリの一部で、Goのソースコードからドキュメントを生成するためのAPIを提供します。godoc
コマンドは、このgo/doc
パッケージを利用してGoのドキュメントを生成し、Webサーバーとして提供します。
-
go/ast
パッケージ (Abstract Syntax Tree):go/ast
はGoのソースコードを抽象構文木(AST)として表現するためのデータ構造と関数を提供します。- Goコンパイラやツール(
go/doc
など)は、ソースコードを直接解析するのではなく、まずASTに変換し、そのASTを操作することでコードの構造や意味を理解します。 - ASTは、パッケージ宣言、インポート宣言、関数宣言、型宣言、変数宣言など、コードのあらゆる要素をノードとして表現します。
-
go/token
パッケージ:go/token
は、Goのソースコード内のトークン(キーワード、識別子、演算子など)やファイルの位置情報を扱うためのパッケージです。- ASTノードは、
go/token.Pos
型を使ってソースコード内の正確な位置(ファイル、行、列)を保持します。
-
ast.ImportSpec
:go/ast
パッケージにおいて、import "path/to/package"
のようなインポート宣言はast.ImportSpec
というASTノードで表現されます。ast.ImportSpec
には、インポートパス(Path
フィールド)や、エイリアス(Name
フィールド、例:import io "fmt"
のio
)などの情報が含まれます。
技術的詳細
このコミットの主要な変更点は、go/doc
パッケージがGoソースコードのASTを走査する際に、インポート宣言を識別し、そのインポートパスを収集するロジックを追加したことです。
具体的には、以下のファイルが変更されています。
src/pkg/go/doc/doc.go
:Package
構造体にImports []string
フィールドを追加し、生成されるドキュメントにインポートパスのリストを含める準備をします。src/pkg/go/doc/exports.go
: ASTをフィルタリングする際に、ast.ImportSpec
を常に保持するように変更します。これにより、インポート情報が後続の処理で利用可能になります。src/pkg/go/doc/reader.go
:docReader
構造体にimports map[string]int
を追加し、重複を避けてインポートパスを一時的に格納するためのマップを用意します。int
は単に存在を示すためのプレースホルダーです。init
メソッドでimports
マップを初期化します。addDecl
メソッド内で、token.IMPORT
型のast.GenDecl
(一般的な宣言ノード)を処理するロジックを追加します。ここで、各ast.ImportSpec
からインポートパスを抽出し、strconv.Unquote
を使ってクォートを外し、doc.imports
マップに追加します。makeImports
という新しいヘルパー関数を追加します。この関数は、doc.imports
マップからインポートパスのリストを抽出し、ソートして[]string
スライスとして返します。newDoc
メソッド内で、doc.makeImports()
を呼び出してインポートパスのリストを取得し、Package
構造体のImports
フィールドに設定します。
src/pkg/go/doc/testdata/b.out
,src/pkg/go/doc/testdata/template.txt
,src/pkg/go/doc/testdata/testing.out
: これらのファイルはテストデータとテンプレートであり、インポート情報がドキュメント出力に含まれるようになったことを反映するために更新されています。特にtemplate.txt
は、{{with .Imports}}
と{{range .}}
を使ってImports
フィールドの内容を整形して表示するロジックが追加されています。
この変更により、go/doc
はGoソースコードを解析する際に、パッケージのインポート宣言を正確に抽出し、その情報を Package
構造体の一部として提供できるようになります。これにより、godoc
などのツールがよりリッチなドキュメントを生成することが可能になります。
コアとなるコードの変更箇所
src/pkg/go/doc/doc.go
--- a/src/pkg/go/doc/doc.go
+++ b/src/pkg/go/doc/doc.go
@@ -15,7 +15,7 @@ type Package struct {
Doc string
Name string
ImportPath string
- Imports []string // TODO(gri) this field is not computed at the moment
+ Imports []string
Filenames []string
Consts []*Value
Types []*Type
src/pkg/go/doc/exports.go
--- a/src/pkg/go/doc/exports.go
+++ b/src/pkg/go/doc/exports.go
@@ -124,6 +124,9 @@ func (doc *docReader) filterType(tinfo *typeInfo, typ ast.Expr) bool {
func (doc *docReader) filterSpec(spec ast.Spec) bool {
switch s := spec.(type) {
+ case *ast.ImportSpec:
+ // always keep imports so we can collect them
+ return true
case *ast.ValueSpec:
s.Names = filterIdentList(s.Names)
if len(s.Names) > 0 {
src/pkg/go/doc/reader.go
--- a/src/pkg/go/doc/reader.go
+++ b/src/pkg/go/doc/reader.go
@@ -9,6 +9,7 @@ import (
"go/token"
"regexp"
"sort"
+ "strconv"
)
// ----------------------------------------------------------------------------
@@ -55,6 +56,7 @@ type docReader struct {
doc *ast.CommentGroup // package documentation, if any
pkgName string
mode Mode
+ imports map[string]int
values []*ast.GenDecl // consts and vars
types map[string]*typeInfo
embedded map[string]*typeInfo // embedded types, possibly not exported
@@ -65,6 +67,7 @@ type docReader struct {
func (doc *docReader) init(pkgName string, mode Mode) {
doc.pkgName = pkgName
doc.mode = mode
+ doc.imports = make(map[string]int)
doc.types = make(map[string]*typeInfo)
doc.embedded = make(map[string]*typeInfo)
doc.funcs = make(map[string]*ast.FuncDecl)
@@ -244,6 +247,13 @@ func (doc *docReader) addDecl(decl ast.Decl) {
case *ast.GenDecl:
if len(d.Specs) > 0 {
switch d.Tok {
+ case token.IMPORT:
+ // imports are handled individually
+ for _, spec := range d.Specs {
+ if import_, err := strconv.Unquote(spec.(*ast.ImportSpec).Path.Value); err == nil {
+ doc.imports[import_] = 1
+ }
+ }
case token.CONST, token.VAR:
// constants and variables are always handled as a group
doc.addValue(d)
@@ -346,6 +356,17 @@ func (doc *docReader) addFile(src *ast.File) {
// ----------------------------------------------------------------------------
// Conversion to external representation
+func (doc *docReader) makeImports() []string {
+ list := make([]string, len(doc.imports))
+ i := 0
+ for import_ := range doc.imports {
+ list[i] = import_
+ i++
+ }
+ sort.Strings(list)
+ return list
+}
+
type sortValue []*Value
func (p sortValue) Len() int { return len(p) }
@@ -661,6 +682,7 @@ func (doc *docReader) newDoc(importpath string, filenames []string) *Package {\n // doc.funcs and thus must be called before any other
// function consuming those lists
p.Types = doc.makeTypes(doc.types)
+ p.Imports = doc.makeImports()
p.Consts = makeValues(doc.values, token.CONST)
p.Vars = makeValues(doc.values, token.VAR)
p.Funcs = makeFuncs(doc.funcs)
コアとなるコードの解説
src/pkg/go/doc/doc.go
の変更
type Package struct { ... }
にImports []string
フィールドが追加されました。- 解説:
Package
構造体は、Goの単一パッケージに関するドキュメント情報を保持するための主要なデータ構造です。この変更により、生成されるパッケージドキュメントオブジェクトが、そのパッケージがインポートしている他のパッケージのパス(文字列スライス)を保持できるようになります。以前はTODO(gri) this field is not computed at the moment
というコメントがありましたが、このコミットでその機能が実装されました。
src/pkg/go/doc/exports.go
の変更
func (doc *docReader) filterSpec(spec ast.Spec) bool
内のswitch s := spec.(type)
にcase *ast.ImportSpec:
が追加され、return true
となっています。- 解説:
filterSpec
関数は、ASTの仕様(ast.Spec
)をフィルタリングし、ドキュメントに含めるべきかどうかを決定します。この変更により、インポート宣言(ast.ImportSpec
)が常にフィルタリングを通過し、docReader
が後でインポート情報を収集できるようになります。これは、インポート情報がドキュメントの重要な一部となるため、破棄されないようにするための措置です。
src/pkg/go/doc/reader.go
の変更
-
import "strconv"
の追加:- 解説: インポートパスは文字列リテラルとしてASTに格納されており、通常はダブルクォートで囲まれています(例:
"fmt"
)。これらのクォートを削除して純粋なパス文字列を得るために、strconv.Unquote
関数が必要となるため、strconv
パッケージがインポートされました。
- 解説: インポートパスは文字列リテラルとしてASTに格納されており、通常はダブルクォートで囲まれています(例:
-
docReader
構造体へのimports
フィールド追加:type docReader struct { ... }
にimports map[string]int
が追加されました。- 解説:
docReader
は、Goソースファイルを読み込み、ASTを解析してドキュメント情報を抽出する役割を担う構造体です。imports
マップは、解析中に見つかったすべてのユニークなインポートパスを一時的に格納するために使用されます。マップのキーとしてインポートパス(文字列)を使用することで、重複するインポートパスが自動的に排除されます。値のint
は単に存在を示すためのプレースホルダーです。
-
init
メソッドでのimports
マップの初期化:func (doc *docReader) init(...) { ... }
内でdoc.imports = make(map[string]int)
が追加されました。- 解説:
docReader
が新しいパッケージの解析を開始する際に、imports
マップが適切に初期化され、以前の解析からのデータが残らないようにします。
-
addDecl
メソッドでのインポート宣言の処理:func (doc *docReader) addDecl(decl ast.Decl) { ... }
内のcase *ast.GenDecl:
のswitch d.Tok
にcase token.IMPORT:
ブロックが追加されました。- 解説:
addDecl
関数は、ASTの一般的な宣言ノード(ast.GenDecl
)を処理します。token.IMPORT
はインポート宣言を表します。このブロックでは、d.Specs
(インポート宣言のリスト)をループし、各ast.ImportSpec
からPath.Value
を取得します。strconv.Unquote
を使ってパス文字列からクォートを外し、結果のインポートパスをdoc.imports
マップに追加します。これにより、すべてのインポートパスが収集されます。
-
makeImports
ヘルパー関数の追加:func (doc *docReader) makeImports() []string { ... }
という新しい関数が追加されました。- 解説: この関数は、
doc.imports
マップに収集されたインポートパスを[]string
スライスに変換し、アルファベット順にソートして返します。ソートすることで、ドキュメントに表示されるインポートリストが一貫した順序になります。
-
newDoc
メソッドでのImports
フィールドの設定:func (doc *docReader) newDoc(...) *Package { ... }
内でp.Imports = doc.makeImports()
が追加されました。- 解説:
newDoc
関数は、解析された情報から最終的なPackage
構造体を作成します。ここで、新しく追加されたmakeImports
関数を呼び出し、収集・ソートされたインポートパスのリストをPackage
構造体のImports
フィールドに割り当てます。これにより、Package
オブジェクトが完全なインポート情報を持つことになります。
これらの変更により、go/doc
はGoのソースコードを解析する過程で、そのパッケージが依存するすべてのインポートパスを正確に抽出し、生成されるドキュメントデータに含めることができるようになりました。
関連リンク
- Go言語公式ドキュメント: https://go.dev/doc/
go/doc
パッケージのドキュメント: https://pkg.go.dev/go/docgo/ast
パッケージのドキュメント: https://pkg.go.dev/go/astgo/token
パッケージのドキュメント: https://pkg.go.dev/go/tokenstrconv
パッケージのドキュメント: https://pkg.go.dev/strconv
参考にした情報源リンク
- Go言語の公式ドキュメントおよびパッケージドキュメント
- Go言語のソースコード(特に
go/doc
パッケージ) - 抽象構文木(AST)に関する一般的なプログラミング概念