js-control-flow-analyzer
Code Path Analysis Details - ESLint - Pluggable JavaScript linter
以下、ESLint の Code Path Analysis
の説明をする際にはこのページを大いに参考にしています。画像もそのまま掲載しているものがあります。
Copyright JS Foundation and other contributors, https://js.foundation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
ESLint互換の Control Flow Analyzerを作る計画
ESLint Code path analysis に存在するオブジェクト
CodePath
- id
- initialSegment
- finalSegments
- returnedSegments
- thrownSegments
- currentSegments
- upper
- childCodePaths
をプロパティにもつオブジェクト。1つのfunction、あるいはグローバルが1つの CodePath
に対応する。
CodePath
中の最初のセグメント(常に単一)と最後のセグメント(複数ある場合もある)への参照をもっている。
CodePathSegment
- id
- nextSegments
- prevSegments
- reachable
をプロパティにもつオブジェクト。上で「セグメント」と表現していたものはこれのこと。
CodePathSegment
同士が連なりあって、Doubly Linked Listのような構造をしている。ただし、通常の双方向連結リストとは異なり、前後のノードが複数個ある場合があることに注意が必要(例えば、if によって分岐する場合には next が複数に枝分かれする)。
このリストが CodePath
に含まれることで、制御フローを表現する。
この図で言うと、全体が CodePath
で個々のブロックが CodePathSegment
を表している。もとのソースコードは以下
if (a && b) {
foo();
}
bar();
一般的な(?)制御フローグラフとの用語の対応
「コンパイラの構成と最適化」(中田育男著)によれば、CodePathSegment
におよそ対応する用語として「基本ブロック」というものが出てきている。
制御フローグラフは、(中略)分岐も合流もない部分(これは基本ブロックを呼ばれる)を節点(node)として、それらの間を分岐や合流を表す有向辺(edge)で結んだ有向グラフである。
分岐も合流もない部分が基本ブロックになる、という事実が重要で、実際上の図を見直してみると、最初の基本ブロック (CodePathSegment
)には、プログラムの始まりから Identifier (a)
までが含まれている。これはつまり、Identifier (a)
までは分岐も合流もなく、一本道で処理が進む、ということを示している。
deno_lint の ControlFlow に求められる仕様
deno_lint は現状、
- no-fallthrough
- no-unreachable
- getter-return
以上3つのルールを実装するために使用されている。
そして、これらのルールを作るために求められる制御グラフフローの機能を洗い出してみると、以下になる。
- 任意の statement の位置(Span)をクエリとして、その statement が
- unreachable か否かを返す
- 同一スコープにあるそれより後ろの文の実行をスキップさせるのか否かを返す(unreachable 判定でまかなえるかも)
これを制御フローグラフで実現するためには、追加で
- statement の位置をクエリとして、それがどの
CodePath
(~= スコープ?)に属しているのかを求めて、そのCodePath
を返す
といったインターフェースも必要になりそう