はじめに
Dart / Flutter の 静的解析の基礎を学びたい。
- Effective Dart: Style
- Customizing static analysis
- Introducing package:flutter_lints
- Analyzer plugins
- dart format
- Code formatting
- dart: The Dart command-line tool
静的解析(static analysis)
ソースコード、バイナリなどのプログラムを「実行せずに」解析すること。
バグやコーディングルール違反の検出のために実施される。
Diagnostic
静的解析を行うことは「診断」と表現され、診断結果は Diagnostic と表現される。
Dart Analysis Server や analyzer などのパッケージが Analyzer として様々なルールに基づいて Diagnostic(診断結果)を生成する。
Diagnostic は以下の仕組みによって出力されるエラー(error)、警告(warning)、情報(info)を表す。
error / warning / info は severity と言い、変更する ことができる。
Diagnostic は Analyzer が出力する診断結果の総称であるため、Lint や Plugin による指摘も Diagnostic の一種として扱われる。
また Diagnostic は 抑制 することもできる。
Diagnostic Message
Diagnostic から出力されるメッセージは Diagnostic messages にて一覧化されている。

https://dart.dev/tools/diagnostics
この一覧は
といった時に役立つ。
Linter rules
Lint ルールは Linter rules にて一覧を確認することができる。

https://dart.dev/tools/linter-rules
- 出力された Diagnostic について詳細を知りたい
-
ignoreしたい
といった時に役立つ。
YAML
YAML Ain't Markup Language
YAML ファイルを扱う上で、頭に入れておきたい注意点。
- インデントは「半角の空白」2 つ分
- タブによるインデントは不可
- 同じフィールドは 2 回記述できない
- 配列は
[]で表現する
glob
ファイルパスをまとめて指定するための簡易パターン記法。
Dart に限らず、
- Unix / Linux
- Git
- npm
- CI 設定
などでも広く使われる。
build/a.dart
build/b.dart
build/temp/c.dart
を設定値として使用したいとき、
build/**
という記法で簡略化することができる。
| 記号 | 意味 |
|---|---|
* |
任意の文字列 |
? |
任意の 1 文字 |
** |
任意の階層(再帰的) |
/ |
ディレクトリ区切り |
| glob の例 | 説明 |
|---|---|
lib/*.dart |
lib 配下の .dart ファイル |
lib/**/*.dart |
lib 配下の全ての .dart ファイル(サブディレクトリ内も含む) |
lib/** |
lib 配下の全てのファイル |
手動で静的解析を実行する
Dart SDK から $ dart analyze コマンドが提供されている。
$ dart analyze
$ dart analyze [<DIRECTORY> | <DART_FILE>]
Flutter SDK からは $ flutter analyze コマンドが提供されている。
$ flutter analyze
Diagnostic を抑制する
Diagnostic Message の name もしくは Linter rules の name を指定する。
int x = ''; // ignore: invalid_assignment
// ignore: invalid_assignment, const_initialized_with_non_constant_value
const x = y;
// ignore_for_file: unused_local_variable
// ignore_for_file: unused_local_variable, duplicate_ignore, dead_code
// ignore_for_file: type=lint
pubspec.yaml に関する解析の警告を抑制することもできる。
dependencies:
flutter:
sdk: flutter
# ignore: sort_pub_dependencies
collection: ^1.19.0
plugin の場合
// ignore: some_plugin/some_code
// ignore_for_file: some_plugin/some_code
analysis_options.yaml
静的解析をカスタマイズする際に利用するファイル。
include: package:lints/recommended.yaml
analyzer:
exclude: [build/**]
language:
strict-casts: true
strict-raw-types: true
linter:
rules:
- cancel_subscriptions
使用できるフィールドは Customizing static analysis に記載されている。
analysis_options.yaml は解析対象のディレクトリのルートに配置する。
下記の例では my_other_package と my_other_other_package で実行した静的解析は #1 を使用され、my_package で実行した静的解析は #2 が利用される。

https://dart.dev/tools/analysis
接頭語 package: を使用したパスと、相対パスが使用できるが、相対パスを使用する場合、analysis_options.yaml を配置したパスを起点とした相対パスを使用する。
include:
他の .yaml ファイルを引用するという設定。
include: <url>
include: package:flutter_lints/flutter.yaml
include:
- package:flutter_lints/recommended.yaml
- ../team_options.yaml
analyzer:
analyzer をカスタマイズするためのフィールド。
analyzer:
exclude:
- lib/client.dart
- lib/server/*.g.dart
- test/_data/**
language:
strict-casts: true
strict-raw-types: true
errors:
invalid_assignment: warning
missing_return: error
dead_code: info
exclude:
静的解析の対象外とするファイル。
analyzer:
exclude:
- lib/client.dart
- lib/server/*.g.dart
- test/_data/**
language:
型 check を強化するかどうかを true / false で設定する(デフォルト値は false)。
コーディングルールであるリントとは異なり、言語仕様レベルで許可もしくは禁止を強制することができる。
-
strict-casts-
dynamic型から特定の型への 「暗黙的な」キャストを許容しない
-
-
strict-inference- 「
dynamic型で宣言された後に、実際には特定の型として利用される変数」などの、型推測を許容しない
- 「
-
strict-raw-types- raw type(型引数を省略したジェネリクス)を許容しない
analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true
errors:
Diagnostic は「重大度(severity)」を持っていて、これは変更することができる。
-
ignore: 無視する -
info:$ dart analyze実行時の 終了ステータス が失敗扱いにならない -
warning: 終了ステータスが失敗扱いになる -
error: 終了ステータスが失敗扱いになる
analyzer:
errors:
todo: ignore
invalid_assignment: warning
missing_return: error
dead_code: info
linter:
リント ルールを設定するためのフィールド。
指定できるフィールド値は Linter rules に一覧がある。

https://dart.dev/tools/linter-rules
package として提供されるリントルールもある。

https://pub.dev/packages/lints
静的解析 とは異なり Lint にはコーディング規約、主観(好み)による判断があるため、誤検知が存在したり、静的解析の中では少し性質が異なる側面を持つことを理解して使用する必要がある。
pub.dev 上で公開される Dart / Flutter の package には score が付けられる。
linter:
rules:
- always_declare_return_types
- annotate_redeclares
- cancel_subscriptions
- close_sinks
- combinators_ordering
- comment_references
- invalid_case_patterns
- one_member_abstracts
- only_throw_errors
羅列するだけではなく、true / false を選択することができる。
Dart 言語のアップデートに伴って、過去のリントルールを明示的に無効化する場合などに利用する。
include: package:lints/recommended.yaml
linter:
rules:
avoid_shadowing_type_parameters: false
await_only_futures: true
ただしこの場合、YAML の制限により true / false 省略スタイルと混在させることができない に注意する。
公式で推奨されているリントルール
Flutter で Dart を利用する場合には lint package ではなく flutter_lints package の使用が推奨されている。
If you're working on Flutter code, then instead of using the
lintspackage, useflutter_lints, which provides a superset of the recommended rules.
https://dart.dev/tools/analysis#lints
include: package:lints/recommended.yaml
formatter:
フォーマット のルールをカスタマイズすることができる。
formatter:
page_width: 123
plugin:
カスタムリント、警告(warning)、エディタによる自動修正(quick fix として提案されるやつ)のカスタマイズを実現する。
pub.dev からダウンロードした plugin(package)を plugins フィールドに追加する。
plugins:
my_plugin: ^1.0.0
ローカル環境上の自前 plugin がある場合、ローカルのパスを記述しても良い。
plugins:
my_plugin:
path: /path/to/my_plugin
plugin で定義される「警告warning)」と「リント」はそれぞれデフォルトの挙動が異なる。
- 警告
- デフォルト:
true
- デフォルト:
- リント
- デフォルト:
false
- デフォルト:
plugins:
my_plugin:
path: /path/to/my_plugin
diagnostics:
rule_1: true
rule_2: true
rule_3: false
自前 plugin
自前の plugin を作成するには Plugin クラスを提供する analysis_server_plugin パッケージが必要。
Set up the plugin package で解説されている。
フォーマット
手動でフォーマットを実行する
Dart SDK から $ dart format コマンドが提供されている。
$ dart format <DIRECTORY|DART_FILE>
$ dart format <DIRECTORY>
$ dart format .
CI(continuous integration)上で、フォーマットが発生した場合に $ dart format を 終了ステータス と共に終了(exit)させることができる(Notify when changes occur)。
$ dart format -o none --set-exit-if-changed <DIRECTORY|DART_FILE>
※ -o none:変更があったファイルのみ表示する
自動でフォーマットを実行する(VSCode)
VSCode の settings.json に以下の設定を追加することで、ソースコードの保存時に自動的にフォーマットが実行されるようになる。
{
"[dart]": {
"editor.formatOnSave": true
}
}



