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

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

このコミットは、Notepad++ の Go 言語用 functionList.xml 設定ファイルにおける正規表現の不具合を修正するものです。具体的には、Go 言語のメソッド定義においてレシーバ名が省略された場合に、Notepad++ の関数リスト機能がそのメソッドを正しく認識できない問題を解決します。

コミット

commit d3450d85ec2223358f1e1724001f61e8a64b9a0c
Author: ChaiShushan <chaishushan@gmail.com>
Date:   Thu Aug 8 10:57:32 2013 -0700

    misc/notepadplus: fix functionList regex issue
    
    The receiver name is optional. when Method's receiver name messing,
    the functionList regex can't match the Method,
    e.g. `func (*T) ProtoMessage() {}`.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/12530044

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

https://github.com/golang/go/commit/d3450d85ec2223358f1e1724001f61e8a64b9a0c

元コミット内容

misc/notepadplus: fix functionList regex issue

The receiver name is optional. when Method's receiver name messing,
the functionList regex can't match the Method,
e.g. `func (*T) ProtoMessage() {}`.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12530044

変更の背景

この変更の背景には、Notepad++ の「関数リスト (Function List)」機能が Go 言語の特定のメソッド定義を正しく解析できないという問題がありました。Notepad++ は、functionList.xml という設定ファイルを使用して、各プログラミング言語の関数やメソッドの定義を正規表現で解析し、サイドバーに一覧表示する機能を提供しています。

Go 言語では、メソッドを定義する際にレシーバ(メソッドが関連付けられる型)を指定しますが、このレシーバには名前を付けることも、名前を省略して型のみを指定することも可能です。例えば、func (t *MyType) MyMethod() のようにレシーバ名 t を指定することもできますし、func (*MyType) MyMethod() のようにレシーバ名を省略して型 *MyType のみを指定することもできます。

従来の functionList.xml に記述されていた正規表現は、レシーバ名が必ず存在することを前提としていました。そのため、func (*T) ProtoMessage() {} のようにレシーバ名が省略された形式のメソッド定義に対しては、正規表現がマッチせず、Notepad++ の関数リストに表示されないという問題が発生していました。このコミットは、この正規表現の不備を修正し、レシーバ名が省略されたメソッドも正しく認識できるようにすることを目的としています。

前提知識の解説

Notepad++ の Function List 機能

Notepad++ は、Windows 環境で広く利用されている高機能なテキストエディタです。その主要な機能の一つに「関数リスト (Function List)」があります。この機能は、現在開いているソースコードファイル内の関数、メソッド、クラスなどの定義を解析し、サイドパネルにツリー形式で一覧表示します。これにより、コードの構造を素早く把握し、特定の定義にジャンプすることが容易になります。

関数リスト機能は、各言語の構文解析に特化した正規表現ルールを functionList.xml というXML形式の設定ファイルで定義しています。このファイルには、各言語(Go、Java、C++など)ごとに、関数やメソッドの開始を示す正規表現 (mainExpr) や、関数名を抽出するための正規表現 (nameExpr) などが記述されています。Notepad++ は、これらの正規表現を使ってコードをスキャンし、関数リストを生成します。

Go 言語のメソッドとレシーバ

Go 言語において、メソッドは特定の型に関連付けられた関数です。メソッドは、その型(レシーバ型)の値を操作するために使用されます。メソッドの定義は func (receiver) methodName(parameters) (results) の形式を取ります。

  • レシーバ (Receiver): メソッドが関連付けられる型を指定します。レシーバは、値レシーバ ((t MyType)) またはポインタレシーバ ((t *MyType)) のいずれかになります。
  • レシーバ名: レシーバには任意の名前を付けることができます(例: t)。この名前はメソッド内でレシーバの値を参照するために使用されます。
  • レシーバ名の省略: Go 言語の仕様では、レシーバ名を省略して型のみを指定することが許可されています。これは、メソッド内でレシーバの値を使用しない場合に、コードの簡潔さを保つためによく行われます。例えば、インターフェースを満たすために特定のシグネチャを持つメソッドを実装する必要があるが、そのメソッド内でレシーバの具体的な値が必要ない場合などに利用されます。
    • 例: func (*MyType) ProtoMessage() {} この例では、*MyType がレシーバ型であり、レシーバ名は省略されています。ProtoMessage() は、Protocol Buffers のメッセージ型が満たすべきインターフェースの一部として定義されることが多いメソッドです。

正規表現 (\w+\w*)

このコミットの核心は正規表現の変更です。

  • \w: 英数字(a-zA-Z0-9)とアンダースコア(_)にマッチします。
  • +: 直前の要素が1回以上繰り返される場合にマッチします。例えば、\w+ は1文字以上の英数字またはアンダースコアの並びにマッチします。
  • *: 直前の要素が0回以上繰り返される場合にマッチします。例えば、\w* は0文字以上の英数字またはアンダースコアの並びにマッチします。

この違いが、レシーバ名が「必須」であるか「省略可能」であるかを正規表現で表現する上で重要になります。

技術的詳細

このコミットは、Notepad++ の Go 言語用 functionList.xml ファイル内の mainExpr 正規表現を修正することで、Go メソッドのレシーバ名が省略されているケースに対応します。

元の mainExpr は以下のようでした。

mainExpr="(^func\\s+\\w+)|(^func\\s*\\(\\s*\\w+\\s*\\*?\\s*\\w+\\s*\\)\\s*\\w+)"

この正規表現は大きく2つの部分に分かれています(| で区切られています)。

  1. (^func\\s+\\w+): これは通常の関数定義(レシーバを持たない関数)にマッチします。func キーワードの後に1つ以上の空白文字 (\\s+) と1つ以上の単語文字 (\\w+) が続くパターンです。
  2. (^func\\s*\\(\\s*\\w+\\s*\\*?\\s*\\w+\\s*\\)\\s*\\w+): これはメソッド定義にマッチします。
    • ^func\\s*: 行頭の func キーワードとそれに続く0個以上の空白文字。
    • \\(: 開き括弧 (
    • \\s*: 0個以上の空白文字。
    • \\w+: ここが問題の箇所でした。 これはレシーバ名にマッチすることを意図しており、1文字以上の単語文字を要求します。つまり、レシーバ名が必須であると解釈されます。
    • \\s*\\*?: 0個以上の空白文字と、オプションのポインタ記号 *
    • \\s*\\w+: 0個以上の空白文字と、レシーバの型名(1文字以上の単語文字)。
    • \\s*\\): 0個以上の空白文字と閉じ括弧 )
    • \\s*\\w+: 0個以上の空白文字とメソッド名(1文字以上の単語文字)。

修正後の mainExpr は以下のようになります。

mainExpr="(^func\\s+\\w+)|(^func\\s*\\(\\s*\\w*\\s*\\*?\\s*\\w+\\s*\\)\\s*\\w+)"

変更点は、メソッド定義にマッチする部分の \\w+\\w* に変更された点です。

  • \\w*: この変更が重要です。 これはレシーバ名にマッチすることを意図していますが、0文字以上の単語文字を許可します。これにより、レシーバ名が省略されている場合(つまり、レシーバ名に該当する文字が0文字の場合)でも正規表現がマッチするようになります。

この修正により、func (*T) ProtoMessage() {} のような、レシーバ名が省略された Go メソッドも Notepad++ の関数リストで正しく認識され、表示されるようになります。

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

変更は misc/notepadplus/functionList.xml ファイルの1箇所のみです。

--- a/misc/notepadplus/functionList.xml
+++ b/misc/notepadplus/functionList.xml
@@ -7,7 +7,7 @@
 		<!-- <parsers> -->
 			<parser id="go" displayName="Go" commentExpr="((/\*.*?\*)/|(//.*?$))">
 				<function
-					mainExpr="(^func\\s+\\w+)|(^func\\s*\\(\\s*\\w+\\s*\\*?\\s*\\w+\\s*\\)\\s*\\w+)"
+					mainExpr="(^func\\s+\\w+)|(^func\\s*\\(\\s*\\w*\\s*\\*?\\s*\\w+\\s*\\)\\s*\\w+)"
 					displayMode="$className->$functionName">
 					<functionName>
 						<nameExpr expr="((func\\s+\\w+)|(\\)\\s*\\w+))"/>

具体的には、<function> タグの mainExpr 属性の値が変更されています。

コアとなるコードの解説

変更された mainExpr の正規表現は、Go 言語の関数およびメソッドの定義を識別するためのものです。

元の正規表現: (^func\\s+\\w+)|(^func\\s*\\(\\s*\\w+\\s*\\*?\\s*\\w+\\s*\\)\\s*\\w+)

修正後の正規表現: (^func\\s+\\w+)|(^func\\s*\\(\\s*\\w*\\s*\\*?\\s*\\w+\\s*\\)\\s*\\w+)

この変更のポイントは、メソッド定義を捕捉する正規表現の第2の部分 ((^func\\s*\\(\\s*\\w+\\s*\\*?\\s*\\w+\\s*\\)\\s*\\w+)) において、レシーバ名を捕捉する部分の \\w+\\w* に変更されたことです。

  • \\w+ (変更前): 1つ以上の単語文字(英数字またはアンダースコア)にマッチします。これは、レシーバ名が必ず存在し、かつ1文字以上であることを要求していました。
  • \\w* (変更後): 0個以上の単語文字にマッチします。これにより、レシーバ名が存在しない(0文字である)場合でも正規表現がマッチするようになり、func (*T) ProtoMessage() {} のような形式のメソッドも正しく認識されるようになりました。

この小さな変更により、Notepad++ の Go 言語の関数リスト機能が、Go 言語のメソッド定義の柔軟な構文(レシーバ名の省略)に完全に対応できるようになりました。

関連リンク

  • Go 言語のメソッドに関する公式ドキュメント: https://go.dev/tour/methods/1 (Go Tour のメソッドのセクション)
  • Notepad++ の Function List 機能に関する情報: Notepad++ の公式ドキュメントやコミュニティフォーラムで functionList.xml について検索すると、より詳細な情報が見つかります。

参考にした情報源リンク