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

[インデックス 17585] ファイルの概要

このコミットは、Go言語のgo/tokenパッケージにおけるRemoveLine関数の名称をMergeLineに変更し、そのドキュメンテーションを改善するものです。この変更は、既存の関数の振る舞いをより正確に反映させ、利用者がその意図を誤解しないようにすることを目的としています。特に、行を「削除」するのではなく、次の行と「結合」するという機能のニュアンスを明確にしています。

コミット

commit 1ea0c480dc16a986c2c335ff2965e70d99bfa654
Author: Josh Bleecher Snyder <josharian@gmail.com>
Date:   Thu Sep 12 09:31:07 2013 -0700

    go/token: rename RemoveLine to MergeLine, improve documentation
    
    This is a follow-up to feedback from gri in
    https://golang.org/cl/12837044/. Most of the wording
    and naming improvements are lifted shamelessly from him.
    
    R=gri
    CC=golang-dev
    https://golang.org/cl/13670043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/1ea0c480dc16a986c2c335ff2965e70d99bfa654

元コミット内容

このコミットは、go/tokenパッケージ内のFile構造体のメソッドであるRemoveLineMergeLineにリネームし、そのドキュメンテーションを大幅に改善しています。また、go/astパッケージ内でこの関数を呼び出している箇所も、新しい関数名に合わせて更新されています。

具体的な変更点は以下の通りです。

  • src/pkg/go/token/position.go
    • File構造体のlinesフィールドのコメントが追加され、その役割が明確化されました。
    • RemoveLine関数がMergeLineにリネームされました。
    • MergeLine関数のドキュメンテーションが、その実際の動作(行を次の行と結合する)をより正確に説明するように書き換えられました。
    • 無効な行番号が指定された場合にパニックを引き起こすためのバリデーションチェックが追加されました。
    • ミューテックスのアンロック処理がdeferステートメントに移動され、ロックの解放が保証されるようになりました。
  • src/pkg/go/ast/import.go
    • fset.File(...).RemoveLine(...)の呼び出しがfset.File(...).MergeLine(...)に更新されました。

変更の背景

このコミットは、Goのコードベースにおける命名の一貫性と明確性を向上させるためのものです。元の関数名RemoveLineは、その機能が「行を削除する」というよりも「行を次の行と結合する」という実態と乖離していました。これは、Goのソースコードを解析し、抽象構文木(AST)を構築する際に、行番号の管理が非常に重要であるため、誤解を招く可能性がありました。

コミットメッセージによると、この変更はgriからのフィードバックに基づいています。golang.org/cl/12837044/で議論された内容が、この命名とドキュメンテーションの改善に繋がったとされています。goimportsのようなツールがソースコードを整形する際に、行の結合が必要となるシナリオがあり、その際の内部的な行管理のロジックをより正確に表現するために、このリネームとドキュメンテーションの改善が行われました。

前提知識の解説

このコミットを理解するためには、以下のGo言語の概念とパッケージに関する知識が必要です。

  1. go/tokenパッケージ: Go言語のソースコードにおけるトークン(キーワード、識別子、演算子など)の位置情報(ファイル名、行番号、列番号、オフセット)を管理するためのパッケージです。FileSetFileという主要な型を提供します。

    • token.FileSet: 複数のソースファイルにわたる位置情報を一元的に管理するセットです。各ファイルはFileSetに登録され、一意のIDが割り当てられます。
    • token.File: 個々のソースファイルに関する位置情報(ファイル名、サイズ、行オフセットなど)を保持します。linesフィールドは、各行の開始オフセットを格納するスライスであり、これによって行番号からファイル内のバイトオフセットを効率的に計算できます。
    • token.Pos: ソースコード内の特定の位置を表す抽象的な型です。通常、FileSetと組み合わせて具体的なファイル名、行番号、列番号に変換されます。
    • token.Position: token.Posを具体的なファイル名、行番号、列番号、オフセットに変換した構造体です。
  2. go/astパッケージ: Go言語のソースコードの抽象構文木(AST: Abstract Syntax Tree)を表現するためのパッケージです。go/parserパッケージによって生成されたASTは、このパッケージの型で表現されます。ASTは、プログラムの構造を木構造で表現したもので、コンパイラ、リンター、コード整形ツールなどがコードを理解し、操作するために使用します。

    • ast.File: Goのソースファイル全体のASTを表すルートノードです。
    • ast.ImportSpec: import宣言内の個々のインポートパスを表すノードです。
  3. 行オフセットと行番号: Goのソースコードでは、各行の開始位置はファイル内のバイトオフセットで管理されます。token.Filelinesスライスは、これらのオフセットを格納しており、これにより特定の行番号に対応するオフセットを素早く見つけることができます。行を「削除」または「結合」するという操作は、このlinesスライスを操作することで実現されます。

  4. goimportsツール: Goの標準ツールの一つで、Goのソースファイルを整形し、インポート文を自動的に追加、削除、整理する機能を提供します。このツールはgo/parsergo/astパッケージを利用してASTを操作し、go/tokenパッケージで位置情報を管理します。このコミットで変更されたMergeLine関数は、goimportsのようなツールがインポートブロックを整形する際に、不要な空行を削除したり、インポート文を結合したりする内部処理で利用される可能性があります。

技術的詳細

このコミットの技術的な核心は、go/token.File構造体における行管理のセマンティクスを明確化することにあります。

token.File構造体は、ソースファイル内の各行の開始オフセットをlinesという[]intスライスで保持しています。例えば、lines[0]はファイルの開始オフセット(通常は0)、lines[1]は2行目の開始オフセット、といった具合です。

元のRemoveLine関数は、指定された行番号に対応するlinesスライス内のエントリを削除していました。これにより、その行が「存在しない」かのように扱われ、後続の行が1つ前の行に「結合」されたかのような効果が得られます。しかし、「Remove」という名前は、ソースコードのテキスト自体から行が物理的に削除されるという誤解を招く可能性がありました。実際には、この操作は行のオフセット情報を変更するだけであり、ソースコードのテキスト内容には直接影響を与えません。

新しいMergeLineという名前は、この動作をより正確に表現しています。つまり、指定された行の改行文字が、あたかもスペースに置き換えられたかのように、その行が次の行と論理的に結合されることを意味します。これにより、後続の行のオフセットが調整され、行番号が再割り当てされますが、ファイル全体のバイトオフセットは維持されます。これは、goimportsのようなツールが、インポートブロック内の空行を削除したり、重複するインポートを結合したりする際に、ソースコードの物理的な変更を伴わずに、行番号の整合性を保つために重要な機能です。

また、MergeLine関数には、無効な行番号が渡された場合にpanicを引き起こすための堅牢なチェックが追加されました。これは、APIの誤用を防ぎ、デバッグを容易にするための重要な改善です。

src/pkg/go/ast/import.goにおける変更は、go/astパッケージがgo/tokenパッケージの新しいAPIを使用するように適応したものです。このファイルは、Goのインポート宣言をソートするロジックを含んでおり、インポートブロック内の不要な空行や重複するインポートを処理する際に、MergeLineの機能を利用しています。例えば、SortImports関数内で、インポートグループの閉じ括弧の行が、最後のインポートスペックの行から2行以上離れている場合(つまり間に空行がある場合)、その空行を「マージ」して削除する処理が行われています。また、重複するインポートスペックを処理するsortSpecs関数でも同様にMergeLineが使用されています。

コアとなるコードの変更箇所

src/pkg/go/token/position.go

--- a/src/pkg/go/token/position.go
+++ b/src/pkg/go/token/position.go
@@ -97,7 +97,7 @@ type File struct {
 	size int    // file size as provided to AddFile
 
 	// lines and infos are protected by set.mutex
-	lines []int
+	lines []int // lines contains the offset of the first character for each line (the first entry is always 0)
 	infos []lineInfo
 }
 
@@ -136,13 +136,27 @@ func (f *File) AddLine(offset int) {
 	f.set.mutex.Unlock()
 }
 
-// RemoveLine removes a line by line number as reported by Position.Line.
+// MergeLine merges a line with the following line. It is akin to replacing
+// the newline character at the end of the line with a space (to not change the
+// remaining offsets). To obtain the line number, consult e.g. Position.Line.
+// MergeLine will panic if given an invalid line number.
 //
-func (f *File) RemoveLine(line int) {
+func (f *File) MergeLine(line int) {
+	if line <= 0 {
+		panic("illegal line number (line numbering starts at 1)")
+	}
 	f.set.mutex.Lock()
+	defer f.set.mutex.Unlock()
+	if line >= len(f.lines) {
+		panic("illegal line number")
+	}
+	// To merge the line numbered <line> with the line numbered <line+1>,
+	// we need to remove the entry in lines corresponding to the line
+	// numbered <line+1>. The entry in lines corresponding to the line
+	// numbered <line+1> is located at index <line>, since indices in lines
+	// are 0-based and line numbers are 1-based.
 	copy(f.lines[line:], f.lines[line+1:])
 	f.lines = f.lines[:len(f.lines)-1]
-	f.set.mutex.Unlock()
 }
 
 // SetLines sets the line offsets for a file and returns true if successful.

src/pkg/go/ast/import.go

--- a/src/pkg/go/ast/import.go
+++ b/src/pkg/go/ast/import.go
@@ -44,7 +44,7 @@ func SortImports(fset *token.FileSet, f *File) {
 			lastSpec := d.Specs[len(d.Specs)-1]
 			lastLine := fset.Position(lastSpec.Pos()).Line
 			if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 {
-				fset.File(d.Rparen).RemoveLine(rParenLine - 1)
+				fset.File(d.Rparen).MergeLine(rParenLine - 1)
 			}
 		}
 	}
@@ -146,7 +146,7 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
 			deduped = append(deduped, s)
 		} else {
 			p := s.Pos()
-			fset.File(p).RemoveLine(fset.Position(p).Line)
+			fset.File(p).MergeLine(fset.Position(p).Line)
 		}
 	}
 	specs = deduped

コアとなるコードの解説

src/pkg/go/token/position.go の変更点

  1. linesフィールドのコメント追加: lines []intの行に// lines contains the offset of the first character for each line (the first entry is always 0)というコメントが追加されました。これは、linesスライスが各行の開始オフセットを格納していることを明確にし、その最初の要素が常に0であることを示しています。これにより、このフィールドの役割がより理解しやすくなりました。

  2. RemoveLineからMergeLineへのリネームとドキュメンテーションの改善: 関数名がRemoveLineからMergeLineに変更されました。新しいドキュメンテーションは、この関数の動作を非常に詳細かつ正確に説明しています。

    • MergeLine merges a line with the following line. (行を次の行と結合する)
    • It is akin to replacing the newline character at the end of the line with a space (to not change the remaining offsets). (これは、行末の改行文字をスペースに置き換えることに似ており、残りのオフセットを変更しない)
    • To obtain the line number, consult e.g. Position.Line. (行番号を取得するには、例えばPosition.Lineを参照する)
    • MergeLine will panic if given an invalid line number. (無効な行番号が与えられた場合、MergeLineはパニックを引き起こす) この説明により、関数が物理的に行を削除するのではなく、行のオフセット情報を操作して論理的に行を結合するものであることが明確になります。
  3. 引数バリデーションの追加: if line <= 0 { panic("illegal line number (line numbering starts at 1)") }if line >= len(f.lines) { panic("illegal line number") }という2つのバリデーションチェックが追加されました。これにより、MergeLine関数が不正な行番号で呼び出された場合に、早期にエラーを検出し、プログラムのクラッシュを防ぐか、デバッグを容易にします。行番号は1から始まるため、0以下の値は不正です。また、f.linesスライスの範囲外のインデックスも不正です。

  4. ミューテックスのdefer: f.set.mutex.Unlock()defer f.set.mutex.Unlock()に変更されました。これにより、関数の実行がどのように終了しても(正常終了、returnpanicなど)、ミューテックスが確実に解放されるようになります。これは、並行処理におけるデッドロックやリソースリークを防ぐためのベストプラクティスです。

  5. 内部ロジックのコメント追加: copy(f.lines[line:], f.lines[line+1:])f.lines = f.lines[:len(f.lines)-1]の前に、// To merge the line numbered <line> with the line numbered <line+1>, ...という詳細なコメントが追加されました。このコメントは、行を結合するためにlinesスライスから対応するエントリを削除する理由と、そのインデックス計算のロジックを説明しています。具体的には、1-basedの行番号lineに対応するlinesスライスのインデックスはline-1であり、line+1行目を結合するためには、line番目のインデックスにあるエントリ(つまりline+1行目の開始オフセット)を削除する必要があることを示しています。

src/pkg/go/ast/import.go の変更点

このファイルでは、go/token.FileRemoveLineメソッドの呼び出しが、新しいMergeLineメソッドの呼び出しに単純に置き換えられています。これは、go/astパッケージがgo/tokenパッケージのAPI変更に適応したことを示しています。

  • SortImports関数内では、インポートグループの閉じ括弧の行と最後のインポートスペックの行の間に空行がある場合、その空行を削除するためにMergeLineが使用されます。
  • sortSpecs関数内では、重複するインポートスペックを処理する際に、重複したインポートの行を「マージ」するためにMergeLineが使用されます。

これらの変更は、goimportsのようなツールがGoのソースコードを整形する際に、行番号の整合性を保ちつつ、不要な空行や重複するインポートを効率的に処理するための基盤を提供します。

関連リンク

参考にした情報源リンク

  • 元のフィードバックがあったGoのChange List (CL): https://golang.org/cl/12837044/
  • このコミットに対応するGoのChange List (CL): https://golang.org/cl/13670043
  • Go言語のソースコード(GitHubリポジトリ): https://github.com/golang/go
  • Go言語の公式ドキュメンテーション: https://go.dev/doc/
  • Go言語のgo/tokenパッケージのFile構造体に関する議論(Stack Overflowなど、一般的なGoの知識源)
  • Go言語のASTとツールに関する一般的な情報源(ブログ記事、チュートリアルなど)

[インデックス 17585] ファイルの概要

このコミットは、Go言語のgo/tokenパッケージにおけるRemoveLine関数の名称をMergeLineに変更し、そのドキュメンテーションを改善するものです。この変更は、既存の関数の振る舞いをより正確に反映させ、利用者がその意図を誤解しないようにすることを目的としています。特に、行を「削除」するのではなく、次の行と「結合」するという機能のニュアンスを明確にしています。

コミット

commit 1ea0c480dc16a986c2c335ff2965e70d99bfa654
Author: Josh Bleecher Snyder <josharian@gmail.com>
Date:   Thu Sep 12 09:31:07 2013 -0700

    go/token: rename RemoveLine to MergeLine, improve documentation
    
    This is a follow-up to feedback from gri in
    https://golang.org/cl/12837044/. Most of the wording
    and naming improvements are lifted shamelessly from him.
    
    R=gri
    CC=golang-dev
    https://golang.org/cl/13670043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/1ea0c480dc16a986c2c335ff2965e70d99bfa654

元コミット内容

このコミットは、go/tokenパッケージ内のFile構造体のメソッドであるRemoveLineMergeLineにリネームし、そのドキュメンテーションを大幅に改善しています。また、go/astパッケージ内でこの関数を呼び出している箇所も、新しい関数名に合わせて更新されています。

具体的な変更点は以下の通りです。

  • src/pkg/go/token/position.go
    • File構造体のlinesフィールドのコメントが追加され、その役割が明確化されました。
    • RemoveLine関数がMergeLineにリネームされました。
    • MergeLine関数のドキュメンテーションが、その実際の動作(行を次の行と結合する)をより正確に説明するように書き換えられました。
    • 無効な行番号が指定された場合にパニックを引き起こすためのバリデーションチェックが追加されました。
    • ミューテックスのアンロック処理がdeferステートメントに移動され、ロックの解放が保証されるようになりました。
  • src/pkg/go/ast/import.go
    • fset.File(...).RemoveLine(...)の呼び出しがfset.File(...).MergeLine(...)に更新されました。

変更の背景

このコミットは、Goのコードベースにおける命名の一貫性と明確性を向上させるためのものです。元の関数名RemoveLineは、その機能が「行を削除する」というよりも「行を次の行と結合する」という実態と乖離していました。これは、Goのソースコードを解析し、抽象構文木(AST)を構築する際に、行番号の管理が非常に重要であるため、誤解を招く可能性がありました。

コミットメッセージによると、この変更はgriからのフィードバックに基づいています。golang.org/cl/12837044/で議論された内容が、この命名とドキュメンテーションの改善に繋がったとされています。このCLは、cmd/gofmt(Goの標準コードフォーマッタ)のインポートソートロジックを強化し、重複するインポートを自動的に削除する機能を追加するものでした。この文脈において、行の「削除」ではなく「結合」という概念がより適切であると判断され、RemoveLineの名称とドキュメンテーションの改善が求められました。goimportsのようなツールがソースコードを整形する際に、行の結合が必要となるシナリオがあり、その際の内部的な行管理のロジックをより正確に表現するために、このリネームとドキュメンテーションの改善が行われました。

前提知識の解説

このコミットを理解するためには、以下のGo言語の概念とパッケージに関する知識が必要です。

  1. go/tokenパッケージ: Go言語のソースコードにおけるトークン(キーワード、識別子、演算子など)の位置情報(ファイル名、行番号、列番号、オフセット)を管理するためのパッケージです。FileSetFileという主要な型を提供します。

    • token.FileSet: 複数のソースファイルにわたる位置情報を一元的に管理するセットです。各ファイルはFileSetに登録され、一意のIDが割り当てられます。
    • token.File: 個々のソースファイルに関する位置情報(ファイル名、サイズ、行オフセットなど)を保持します。linesフィールドは、各行の開始オフセットを格納するスライスであり、これによって行番号からファイル内のバイトオフセットを効率的に計算できます。
    • token.Pos: ソースコード内の特定の位置を表す抽象的な型です。通常、FileSetと組み合わせて具体的なファイル名、行番号、列番号に変換されます。
    • token.Position: token.Posを具体的なファイル名、行番号、列番号、オフセットに変換した構造体です。
  2. go/astパッケージ: Go言語のソースコードの抽象構文木(AST: Abstract Syntax Tree)を表現するためのパッケージです。go/parserパッケージによって生成されたASTは、このパッケージの型で表現されます。ASTは、プログラムの構造を木構造で表現したもので、コンパイラ、リンター、コード整形ツールなどがコードを理解し、操作するために使用します。

    • ast.File: Goのソースファイル全体のASTを表すルートノードです。
    • ast.ImportSpec: import宣言内の個々のインポートパスを表すノードです。
  3. 行オフセットと行番号: Goのソースコードでは、各行の開始位置はファイル内のバイトオフセットで管理されます。token.Filelinesスライスは、これらのオフセットを格納しており、これにより特定の行番号に対応するオフセットを素早く見つけることができます。行を「削除」または「結合」するという操作は、このlinesスライスを操作することで実現されます。

  4. gofmtおよびgoimportsツール:

    • gofmt: Goの標準コードフォーマッタです。GoのソースコードをGoの公式スタイルガイドに沿って自動的に整形します。
    • goimports: gofmtの機能を拡張し、Goのソースファイルを整形するだけでなく、インポート文を自動的に追加、削除、整理する機能を提供します。これらのツールはgo/parsergo/astパッケージを利用してASTを操作し、go/tokenパッケージで位置情報を管理します。このコミットで変更されたMergeLine関数は、goimportsのようなツールがインポートブロックを整形する際に、行の結合が必要となる内部処理で利用される可能性があります。

技術的詳細

このコミットの技術的な核心は、go/token.File構造体における行管理のセマンティクスを明確化することにあります。

token.File構造体は、ソースファイル内の各行の開始オフセットをlinesという[]intスライスで保持しています。例えば、lines[0]はファイルの開始オフセット(通常は0)、lines[1]は2行目の開始オフセット、といった具合です。

元のRemoveLine関数は、指定された行番号に対応するlinesスライス内のエントリを削除していました。これにより、その行が「存在しない」かのように扱われ、後続の行が1つ前の行に「結合」されたかのような効果が得られます。しかし、「Remove」という名前は、ソースコードのテキスト自体から行が物理的に削除されるという誤解を招く可能性がありました。実際には、この操作は行のオフセット情報を変更するだけであり、ソースコードのテキスト内容には直接影響を与えません。

新しいMergeLineという名前は、この動作をより正確に表現しています。つまり、指定された行の改行文字が、あたかもスペースに置き換えられたかのように、その行が次の行と論理的に結合されることを意味します。これにより、後続の行のオフセットが調整され、行番号が再割り当てされますが、ファイル全体のバイトオフセットは維持されます。これは、goimportsのようなツールが、インポートブロック内の空行を削除したり、重複するインポートを結合したりする際に、ソースコードの物理的な変更を伴わずに、行番号の整合性を保つために重要な機能です。

また、MergeLine関数には、無効な行番号が渡された場合にpanicを引き起こすための堅牢なチェックが追加されました。これは、APIの誤用を防ぎ、デバッグを容易にするための重要な改善です。具体的には、行番号が1未満の場合や、f.linesスライスの範囲外の行番号が指定された場合にパニックが発生します。

src/pkg/go/ast/import.goにおける変更は、go/astパッケージがgo/tokenパッケージの新しいAPIを使用するように適応したものです。このファイルは、Goのインポート宣言をソートするロジックを含んでおり、インポートブロック内の不要な空行や重複するインポートを処理する際に、MergeLineの機能を利用しています。例えば、SortImports関数内で、インポートグループの閉じ括弧の行が、最後のインポートスペックの行から2行以上離れている場合(つまり間に空行がある場合)、その空行を「マージ」して削除する処理が行われています。また、重複するインポートスペックを処理するsortSpecs関数でも同様にMergeLineが使用されます。

コアとなるコードの変更箇所

src/pkg/go/token/position.go

--- a/src/pkg/go/token/position.go
+++ b/src/pkg/go/token/position.go
@@ -97,7 +97,7 @@ type File struct {
 	size int    // file size as provided to AddFile
 
 	// lines and infos are protected by set.mutex
-	lines []int
+	lines []int // lines contains the offset of the first character for each line (the first entry is always 0)
 	infos []lineInfo
 }
 
@@ -136,13 +136,27 @@ func (f *File) AddLine(offset int) {
 	f.set.mutex.Unlock()
 }
 
-// RemoveLine removes a line by line number as reported by Position.Line.
+// MergeLine merges a line with the following line. It is akin to replacing
+// the newline character at the end of the line with a space (to not change the
+// remaining offsets). To obtain the line number, consult e.g. Position.Line.
+// MergeLine will panic if given an invalid line number.
 //
-func (f *File) RemoveLine(line int) {
+func (f *File) MergeLine(line int) {
+	if line <= 0 {
+		panic("illegal line number (line numbering starts at 1)")
+	}
 	f.set.mutex.Lock()
+	defer f.set.mutex.Unlock()
+	if line >= len(f.lines) {
+		panic("illegal line number")
+	}
+	// To merge the line numbered <line> with the line numbered <line+1>,
+	// we need to remove the entry in lines corresponding to the line
+	// numbered <line+1>. The entry in lines corresponding to the line
+	// numbered <line+1> is located at index <line>, since indices in lines
+	// are 0-based and line numbers are 1-based.
 	copy(f.lines[line:], f.lines[line+1:])
 	f.lines = f.lines[:len(f.lines)-1]
-	f.set.mutex.Unlock()
 }
 
 // SetLines sets the line offsets for a file and returns true if successful.

src/pkg/go/ast/import.go

--- a/src/pkg/go/ast/import.go
+++ b/src/pkg/go/ast/import.go
@@ -44,7 +44,7 @@ func SortImports(fset *token.FileSet, f *File) {
 			lastSpec := d.Specs[len(d.Specs)-1]
 			lastLine := fset.Position(lastSpec.Pos()).Line
 			if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 {
-				fset.File(d.Rparen).RemoveLine(rParenLine - 1)
+				fset.File(d.Rparen).MergeLine(rParenLine - 1)
 			}
 		}
 	}
@@ -146,7 +146,7 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
 			deduped = append(deduped, s)
 		} else {
 			p := s.Pos()
-			fset.File(p).RemoveLine(fset.Position(p).Line)
+			fset.File(p).MergeLine(fset.Position(p).Line)
 		}
 	}
 	specs = deduped

コアとなるコードの解説

src/pkg/go/token/position.go の変更点

  1. linesフィールドのコメント追加: lines []intの行に// lines contains the offset of the first character for each line (the first entry is always 0)というコメントが追加されました。これは、linesスライスが各行の開始オフセットを格納していることを明確にし、その最初の要素が常に0であることを示しています。これにより、このフィールドの役割がより理解しやすくなりました。

  2. RemoveLineからMergeLineへのリネームとドキュメンテーションの改善: 関数名がRemoveLineからMergeLineに変更されました。新しいドキュメンテーションは、この関数の動作を非常に詳細かつ正確に説明しています。

    • MergeLine merges a line with the following line. (行を次の行と結合する)
    • It is akin to replacing the newline character at the end of the line with a space (to not change the remaining offsets). (これは、行末の改行文字をスペースに置き換えることに似ており、残りのオフセットを変更しない)
    • To obtain the line number, consult e.g. Position.Line. (行番号を取得するには、例えばPosition.Lineを参照する)
    • MergeLine will panic if given an invalid line number. (無効な行番号が与えられた場合、MergeLineはパニックを引き起こす) この説明により、関数が物理的に行を削除するのではなく、行のオフセット情報を操作して論理的に行を結合するものであることが明確になります。
  3. 引数バリデーションの追加: if line <= 0 { panic("illegal line number (line numbering starts at 1)") }if line >= len(f.lines) { panic("illegal line number") }という2つのバリデーションチェックが追加されました。これにより、MergeLine関数が不正な行番号で呼び出された場合に、早期にエラーを検出し、プログラムのクラッシュを防ぐか、デバッグを容易にします。行番号は1から始まるため、0以下の値は不正です。また、f.linesスライスの範囲外のインデックスも不正です。

  4. ミューテックスのdefer: f.set.mutex.Unlock()defer f.set.mutex.Unlock()に変更されました。これにより、関数の実行がどのように終了しても(正常終了、returnpanicなど)、ミューテックスが確実に解放されるようになります。これは、並行処理におけるデッドロックやリソースリークを防ぐためのベストプラクティスです。

  5. 内部ロジックのコメント追加: copy(f.lines[line:], f.lines[line+1:])f.lines = f.lines[:len(f.lines)-1]の前に、// To merge the line numbered <line> with the line numbered <line+1>, ...という詳細なコメントが追加されました。このコメントは、行を結合するためにlinesスライスから対応するエントリを削除する理由と、そのインデックス計算のロジックを説明しています。具体的には、1-basedの行番号lineに対応するlinesスライスのインデックスはline-1であり、line+1行目を結合するためには、line番目のインデックスにあるエントリ(つまりline+1行目の開始オフセット)を削除する必要があることを示しています。

src/pkg/go/ast/import.go の変更点

このファイルでは、go/token.FileRemoveLineメソッドの呼び出しが、新しいMergeLineメソッドの呼び出しに単純に置き換えられています。これは、go/astパッケージがgo/tokenパッケージのAPI変更に適応したことを示しています。

  • SortImports関数内では、インポートグループの閉じ括弧の行と最後のインポートスペックの行の間に空行がある場合、その空行を削除するためにMergeLineが使用されます。
  • sortSpecs関数内では、重複するインポートスペックを処理する際に、重複したインポートの行を「マージ」するためにMergeLineが使用されます。

これらの変更は、goimportsのようなツールがGoのソースコードを整形する際に、行番号の整合性を保ちつつ、不要な空行や重複するインポートを効率的に処理するための基盤を提供します。

関連リンク

参考にした情報源リンク