RAKUS Developers Blog | ラクス エンジニアブログ

株式会社ラクスのITエンジニアによる技術ブログです。

Flutterの静的解析入門

こんにちは、株式会社ラクスで先行技術検証を行っている技術推進課の@t_okkanです。
今回はFlutterの静的解析を紹介します。

FlutterはDartで実装しているため、静的解析もDartの仕組みを利用します。
Dartは静的型付け言語と動的型付け言語のどちらにも対応しているため、型チェックが比較的ゆるいプログラミング言語です。
そのため、静的解析のルールを定めることで型チェックを厳密にしたり、コードのバグを未然に防ぐことが必要になります。
また、ソースコードに強制的に統一されたコーディングスタイルを適用できます。
Flutterの静的解析の仕組みからできることを紹介しています。

Flutterの静的解析の構成要素

Flutterの実装言語であるDartの静的解析はAnalyzerとLinterから構成されます。

FlutterではこのDartの静的解析の仕組みを利用して、ソースコードの静的解析を行います。

静的解析の導入

Flutterのプロジェクトに静的解析を導入するには、analysis_optins.yamlファイルをpubsepc.yamlファイルと同じディレクトリに配置します。

./ sample
    |- android
    |- ios
    |- lib
    |    |- main.dart
    |- analysis_options.yaml  ← ファイルを追加
    |- pubspec.yaml

Flutterの新規プロジェクトを作成した時に、プロジェクトのルートにanalysis_options.yamlファイルを追加することをお勧めします。 analysis_options.yamlは以下のような実装になります。

include: package:pedantic/analysis_options.yaml

analyzer:
  exclude: [build/**]
  strong-mode:
    implicit-casts: false

linter:
  rules:
    - camel_case_types

analysis_options.yamlでは以下の設定が可能です。

  • inculde

    他のanalysis_options.yamlファイルを取り込むことで、定義されている静的解析のルールを取り込む。

  • analyzer

    Analyzerや静的解析全体のカスタマイズを設定する。

  • linter

    Linterのルールをカスタマイズを設定する。

それぞれの設定でできることを詳しく説明していきます。

includeの設定

includeにはすでに定義済みの外部のanalysis_options.yamlファイルをプロジェクトに取り込むことができます。
これにより静的解析を手軽に導入することができます。
また、analyzerlinterを独自で設定して1から静的解析のルールを構築することも可能ですが、Flutterのプラグインとして定義済みのルールを適用することができます。
主なプラグインには以下のようなものがあります。

  • effective_dart

    Dartを効率的に実装するために定めたルールであるEffective Dartに準拠したLinterのルールを適用できる。

pub.dev

  • lint

    effective_dartプラグインと同様にEffective Dartに準拠したLinterのルールを適用できる。

pub.dev

  • pedantic

    Googleが内部で使用している静的解析のルールを取り込むことができる。Flutter SDKを実装するプロジェクトで利用されているルール。Effective Dartよりもより厳密なルールが設定がされている。

pub.dev

それぞれのプラグインリポジトリanalysis_options.yamlから、どのようなルールが設定されているのか確認できます。
静的解析のプラグインを導入する場合は、pubspec.yamlプラグインを追加し、analysis_options.yamlincludeプラグインで定義されているanalysis_options.yamlを設定します。
例えば、pedanticを導入する場合は以下のようになります。

dev_dependencies:
  flutter_test:
    sdk: flutter
  # プラグインを追加  
  pedantic: ^1.11.0
  • analysis_options.yaml
# pedanticのanalysis_options.yamlを設定
include: package:pedantic/analysis_options.yaml

analyzerの設定

analyzerではDartの型システムのカスタマイズや、静的解析を適用する範囲の設定などができます。

厳密な型チェックを有効にする

Dartは部分的に動的片付け言語になるため、デフォルトでは暗黙的型変換が有効であったり、比較的ゆるめの型チェックになります。
Dartのデフォルトの型チェックよりも厳密な型チェックが必要な場合は、analyzerのオプションでstrong-modeを指定することで有効にできます。strong-modeでは以下のような設定が可能です。

  • implicit-casts

    falseにすることで暗黙的型変換の実装を禁止できます。

  • implicit-dynamic

    falseにすることで動的な型宣言で使用するdynamic型の使用を禁止できます。

analysis_options.yamlは以下のように設定します。

analyzer:
  strong-mode:
    implicit-casts: false
    implicit-dynamic: false

コンパイル時の型チェックが厳密になり、より堅牢なコードになるので、できるだけ厳密な型チェックは有効にすることをおすすめします。

一部のファイルを解析の対象から除外する

Flutterの実装をしていると、immutableなクラスを自動生成するfreezedパッケージなどで自動生成されたファイルは、静的解析の対象から除外したい場合があります。
また、一部のファイルを解析から除外したい場合は、analyzerのオプションのexcludeに除外するファイルを設定できます。
以下にanalysis_options.yamlの設定の一例を載せておきます。

analyzer:
    exclude:
        # ファイルを直接指定
        - lib/client.dart
        # フォルダ内の特定の拡張子を指定
        - lib/data/model/*.freezed.dart
        # フォルダ内の全てのファイルを指定
        - test/_data/**

特定のルールをプロジェクトで無効にする

前述した静的解析用のプラグインを導入した際に、特定のルールだけは無効にしたい場合があります。
特定のルールをプロジェクトで無効にするには、analyzerのオプションのerrorsに設定し、errorsのオプションに無視したいルール名、ignoreを設定すると、プロジェクト全体で指定したルールを無効にできます。
なお、AnalyzerとLinterのどちらのルールも無効にできます。
参考として、以下にanalysis_options.yaml設定の一例を載せておきます。

analyzer:
    errors:
        # ルール名:ignore
        # Analyzerの無効化:TODO表記を無視する
        todo: ignore
        # Linterの無効化
        avoid_empty_else: ignore

解析のルールの重要度を変更する

Flutterの静的解析にはinfowarningerrorの3種類の重要度があります。

  • infowarning:静的解析には失敗しないが、警告されるレベル
  • error:違反していると静的解析が失敗するレベル

Flutterの静的解析では、特定の解析ルールの重要度をプロジェクト全体で変更することができます。
例えば、Linterルールはデフォルトでinfoレベルに設定されていますが、warningerrorレベルに引き上げることが可能です。
重要度を変更するにはanalyzererrorsオプションに、変更したいルール名と重要度(infowarningerror)を設定します。
以下に、analysis_options.yaml設定の一例を載せておきます。

analyzer:
    errors:
        # ルール名:重要度(info、warning、error)
        # Analyzerの変更:returnの省略を警告する
        missing_return: warning
        # Linterの変更
        prefer_contains: error

linterの設定

プラグインであるpedanticeffective_dartを導入することで、Linterを手軽に設定できましたが、もちろん開発者が個別でLinterをカスタマイズすることも可能です。
カスタマイズする項目をlinterrulesに設定します。
Linterで設定できるルールの一覧は、以下で公開されています。

dart-lang.github.io

pedanticeffective_dart、Flutterでデフォルトで適用されている設定はそれぞれマークされており、設定されているルールを上書きして無効にすることもできます。
例えば、ローカル変数で型推論を使用するようにします。
omit_local_variable_typesを無効にする場合は、以下のようにfalseを設定します。

include: package:pedantic/analysis_options.yaml

linter:
  rules:
    omit_local_variable_types: false

ファイルや特定のコードを静的解析の対象から除外する

analyzerの設定で、特定のファイルを静的解析の対象から除外することができました。
それに加え、ソースコードの特定の1行だけ特別に静的解析の対象から除外することができます。
また、ファイル内にそのファイルを静的解析の対象から除外する設定ができます。

  • 1行のコードで特定のルールを除外する

    特定の1行のコードでルールを除外するにはコードの1行上にignore: linterのルールコメントアウトで追加します。複数のルールを除外する場合はコンマ区切りで指定します。

// ignore: linterのルール名
// 以下実装例
class Point {
    int x, y;
    // ignore: empty_constructor_bodies
    Point(this.x, this.y) {} // 空のコンストラクタが警告されない
}
  • ファイル内で特定のルールを除外する

    ファイル内で特定のルールが適用されないように設定できます。ファイルのどこか(できればパッケージのimportの直下)にignore_for_file: linterのルールコメントアウトで追加します。複数のルールを除外する場合はコンマ区切りで指定します。

// ignore_for_file: linterのルール名
// 以下実装例
// ignore_for_file: omit_local_variable_types, empty_constructor_bodies
class Point {
    int x, y;
    Point(this.x, this.y) {} // 空のコンストラクタが警告されない
}

静的解析の実行

静的解析を実行する方法には、エディタで実行する方法と、コマンドラインで実行する方法があります。
静的解析の実行については、FlutterのリポジトリWikiに詳しく記載されていますので、合わせてご確認ください。

github.com

エディタで静的解析を有効にする

Flutterの開発に対応しているエディタやIDEを使用している場合、各環境のFlutterとDartの拡張プラグインをインストールしていればプロジェクトのanalysis_options.yamlを認識して、ファイル保存時などおいて、自動で静的解析を実行します。
各エディタのセットアップ方法は、以下に紹介されています。
手順に沿って拡張プラグインをインストールしてください。

flutter.dev

コマンドラインで静的解析を実行する

コマンドラインからでも静的解析を実行できます。
プロジェクトのルートでflutter analyzeを実行します。

$ flutter analyze
Analyzing flutter_analyzer...                                           

  info • Avoid types as parameter names • lib/main.dart:39:16 • avoid_types_as_parameter_names

1 issue found. (ran in 4.2s)

まとめ

Flutterの静的解析についてまとめました。

Lintルールなど設定値が多く、いきなり一つ一つを自分で設定するのハードルが高いかと思います。
ですのでまずは、pedanticeffective_dartなどのプラグインを導入することをお勧めします。

また、別の方法としてはFlutterのリポジトリにあるanalysis_options.yamlファイルをコピーする方法もお勧めです。
あとは、Effective Dartをしっかり読み、Flutterの実装を進めて気になることがあれば個別でルールを追加していくと良いかと思います。
そして、ある程度ルールが固まってきたらテンプレート化し、複数のプロジェクトで使いまわせるようになるかと思います。


◆TECH PLAY
techplay.jp

◆connpass
rakus.connpass.com

Copyright © RAKUS Co., Ltd. All rights reserved.