Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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言語の概念と標準ライブラリに関する知識が必要です。

  1. Go言語のパッケージとインポート:

    • Go言語のコードは「パッケージ」という単位で整理されます。パッケージは関連する機能の集合であり、再利用可能なコードの最小単位です。
    • あるパッケージの機能を利用するには、import キーワードを使ってそのパッケージをインポートする必要があります。例えば、import "fmt" は標準ライブラリの fmt パッケージをインポートします。
    • インポートパスは、パッケージを一意に識別するための文字列です(例: "fmt", "net/http", "github.com/user/repo/mypkg")。
  2. go/doc パッケージ:

    • go/doc はGoの標準ライブラリの一部で、Goのソースコードからドキュメントを生成するためのAPIを提供します。
    • godoc コマンドは、この go/doc パッケージを利用してGoのドキュメントを生成し、Webサーバーとして提供します。
  3. go/ast パッケージ (Abstract Syntax Tree):

    • go/ast はGoのソースコードを抽象構文木(AST)として表現するためのデータ構造と関数を提供します。
    • Goコンパイラやツール(go/doc など)は、ソースコードを直接解析するのではなく、まずASTに変換し、そのASTを操作することでコードの構造や意味を理解します。
    • ASTは、パッケージ宣言、インポート宣言、関数宣言、型宣言、変数宣言など、コードのあらゆる要素をノードとして表現します。
  4. go/token パッケージ:

    • go/token は、Goのソースコード内のトークン(キーワード、識別子、演算子など)やファイルの位置情報を扱うためのパッケージです。
    • ASTノードは、go/token.Pos 型を使ってソースコード内の正確な位置(ファイル、行、列)を保持します。
  5. 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 の変更

  1. import "strconv" の追加:

    • 解説: インポートパスは文字列リテラルとしてASTに格納されており、通常はダブルクォートで囲まれています(例: "fmt")。これらのクォートを削除して純粋なパス文字列を得るために、strconv.Unquote 関数が必要となるため、strconv パッケージがインポートされました。
  2. docReader 構造体への imports フィールド追加:

    • type docReader struct { ... }imports map[string]int が追加されました。
    • 解説: docReader は、Goソースファイルを読み込み、ASTを解析してドキュメント情報を抽出する役割を担う構造体です。imports マップは、解析中に見つかったすべてのユニークなインポートパスを一時的に格納するために使用されます。マップのキーとしてインポートパス(文字列)を使用することで、重複するインポートパスが自動的に排除されます。値の int は単に存在を示すためのプレースホルダーです。
  3. init メソッドでの imports マップの初期化:

    • func (doc *docReader) init(...) { ... } 内で doc.imports = make(map[string]int) が追加されました。
    • 解説: docReader が新しいパッケージの解析を開始する際に、imports マップが適切に初期化され、以前の解析からのデータが残らないようにします。
  4. addDecl メソッドでのインポート宣言の処理:

    • func (doc *docReader) addDecl(decl ast.Decl) { ... } 内の case *ast.GenDecl:switch d.Tokcase token.IMPORT: ブロックが追加されました。
    • 解説: addDecl 関数は、ASTの一般的な宣言ノード(ast.GenDecl)を処理します。token.IMPORT はインポート宣言を表します。このブロックでは、d.Specs(インポート宣言のリスト)をループし、各 ast.ImportSpec から Path.Value を取得します。strconv.Unquote を使ってパス文字列からクォートを外し、結果のインポートパスを doc.imports マップに追加します。これにより、すべてのインポートパスが収集されます。
  5. makeImports ヘルパー関数の追加:

    • func (doc *docReader) makeImports() []string { ... } という新しい関数が追加されました。
    • 解説: この関数は、doc.imports マップに収集されたインポートパスを []string スライスに変換し、アルファベット順にソートして返します。ソートすることで、ドキュメントに表示されるインポートリストが一貫した順序になります。
  6. newDoc メソッドでの Imports フィールドの設定:

    • func (doc *docReader) newDoc(...) *Package { ... } 内で p.Imports = doc.makeImports() が追加されました。
    • 解説: newDoc 関数は、解析された情報から最終的な Package 構造体を作成します。ここで、新しく追加された makeImports 関数を呼び出し、収集・ソートされたインポートパスのリストを Package 構造体の Imports フィールドに割り当てます。これにより、Package オブジェクトが完全なインポート情報を持つことになります。

これらの変更により、go/doc はGoのソースコードを解析する過程で、そのパッケージが依存するすべてのインポートパスを正確に抽出し、生成されるドキュメントデータに含めることができるようになりました。

関連リンク

参考にした情報源リンク

  • 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言語の概念と標準ライブラリに関する知識が必要です。

  1. Go言語のパッケージとインポート:

    • Go言語のコードは「パッケージ」という単位で整理されます。パッケージは関連する機能の集合であり、再利用可能なコードの最小単位です。
    • あるパッケージの機能を利用するには、import キーワードを使ってそのパッケージをインポートする必要があります。例えば、import "fmt" は標準ライブラリの fmt パッケージをインポートします。
    • インポートパスは、パッケージを一意に識別するための文字列です(例: "fmt", "net/http", "github.com/user/repo/mypkg")。
  2. go/doc パッケージ:

    • go/doc はGoの標準ライブラリの一部で、Goのソースコードからドキュメントを生成するためのAPIを提供します。
    • godoc コマンドは、この go/doc パッケージを利用してGoのドキュメントを生成し、Webサーバーとして提供します。
  3. go/ast パッケージ (Abstract Syntax Tree):

    • go/ast はGoのソースコードを抽象構文木(AST)として表現するためのデータ構造と関数を提供します。
    • Goコンパイラやツール(go/doc など)は、ソースコードを直接解析するのではなく、まずASTに変換し、そのASTを操作することでコードの構造や意味を理解します。
    • ASTは、パッケージ宣言、インポート宣言、関数宣言、型宣言、変数宣言など、コードのあらゆる要素をノードとして表現します。
  4. go/token パッケージ:

    • go/token は、Goのソースコード内のトークン(キーワード、識別子、演算子など)やファイルの位置情報を扱うためのパッケージです。
    • ASTノードは、go/token.Pos 型を使ってソースコード内の正確な位置(ファイル、行、列)を保持します。
  5. 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 の変更

  1. import "strconv" の追加:

    • 解説: インポートパスは文字列リテラルとしてASTに格納されており、通常はダブルクォートで囲まれています(例: "fmt")。これらのクォートを削除して純粋なパス文字列を得るために、strconv.Unquote 関数が必要となるため、strconv パッケージがインポートされました。
  2. docReader 構造体への imports フィールド追加:

    • type docReader struct { ... }imports map[string]int が追加されました。
    • 解説: docReader は、Goソースファイルを読み込み、ASTを解析してドキュメント情報を抽出する役割を担う構造体です。imports マップは、解析中に見つかったすべてのユニークなインポートパスを一時的に格納するために使用されます。マップのキーとしてインポートパス(文字列)を使用することで、重複するインポートパスが自動的に排除されます。値の int は単に存在を示すためのプレースホルダーです。
  3. init メソッドでの imports マップの初期化:

    • func (doc *docReader) init(...) { ... } 内で doc.imports = make(map[string]int) が追加されました。
    • 解説: docReader が新しいパッケージの解析を開始する際に、imports マップが適切に初期化され、以前の解析からのデータが残らないようにします。
  4. addDecl メソッドでのインポート宣言の処理:

    • func (doc *docReader) addDecl(decl ast.Decl) { ... } 内の case *ast.GenDecl:switch d.Tokcase token.IMPORT: ブロックが追加されました。
    • 解説: addDecl 関数は、ASTの一般的な宣言ノード(ast.GenDecl)を処理します。token.IMPORT はインポート宣言を表します。このブロックでは、d.Specs(インポート宣言のリスト)をループし、各 ast.ImportSpec から Path.Value を取得します。strconv.Unquote を使ってパス文字列からクォートを外し、結果のインポートパスを doc.imports マップに追加します。これにより、すべてのインポートパスが収集されます。
  5. makeImports ヘルパー関数の追加:

    • func (doc *docReader) makeImports() []string { ... } という新しい関数が追加されました。
    • 解説: この関数は、doc.imports マップに収集されたインポートパスを []string スライスに変換し、アルファベット順にソートして返します。ソートすることで、ドキュメントに表示されるインポートリストが一貫した順序になります。
  6. newDoc メソッドでの Imports フィールドの設定:

    • func (doc *docReader) newDoc(...) *Package { ... } 内で p.Imports = doc.makeImports() が追加されました。
    • 解説: newDoc 関数は、解析された情報から最終的な Package 構造体を作成します。ここで、新しく追加された makeImports 関数を呼び出し、収集・ソートされたインポートパスのリストを Package 構造体の Imports フィールドに割り当てます。これにより、Package オブジェクトが完全なインポート情報を持つことになります。

これらの変更により、go/doc はGoのソースコードを解析する過程で、そのパッケージが依存するすべてのインポートパスを正確に抽出し、生成されるドキュメントデータに含めることができるようになりました。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメントおよびパッケージドキュメント
  • Go言語のソースコード(特に go/doc パッケージ)
  • 抽象構文木(AST)に関する一般的なプログラミング概念