自定义静态分析
静态分析允许你在执行任何一行代码之前发现问题。它是一个强大的工具,用于防止 bug 并确保代码符合风格指南。
借助分析器,你可以发现简单的拼写错误。例如,一个意外的分号可能进入了 if
语句
dartvoid increment() { if (count < 10) ; count++; }
如果配置得当,分析器会指向分号并产生以下警告
info - example.dart:9:19 - Unnecessary empty statement. Try removing the empty statement or restructuring the code. - empty_statements
分析器还可以帮助你发现更微妙的问题。例如,你可能忘记关闭一个 sink 方法
dartvar controller = StreamController<String>();
info - Unclosed instance of 'Sink'. Try invoking 'close' in the function in which the 'Sink' was created. - close_sinks
在 Dart 生态系统中,Dart Analysis Server 和其他工具使用 analyzer 包来执行静态分析。
你可以自定义静态分析以查找各种潜在问题,包括 Dart 语言规范中指定的错误和警告。你还可以配置 Linter 规则,以确保你的代码符合 Dart 风格指南和 Effective Dart 中建议的其他准则。像 dart analyze
、flutter analyze
以及 IDE 和编辑器这样的工具使用 analyzer 包来评估你的代码。
本文档解释了如何使用分析选项文件或 Dart 源代码中的注释来自定义分析器的行为。如果你想在你的工具中添加静态分析,请参阅 analyzer 包文档和 Analysis Server API 规范。
分析选项文件
#将分析选项文件 analysis_options.yaml
放在包的根目录,与 pubspec 文件位于同一目录。
这是一个分析选项文件的示例
include: package:lints/recommended.yaml
analyzer:
exclude: [build/**]
language:
strict-casts: true
strict-raw-types: true
linter:
rules:
- cancel_subscriptions
该示例说明了最常见的顶级条目
- 使用
include: url
引入指定 URL 中的选项——在此示例中,来自lints
包中的文件。由于 YAML 不允许重复键,你最多只能包含一个文件。 - 使用
analyzer:
条目自定义静态分析:启用更严格的类型检查、排除文件、忽略特定规则、更改规则的严重性或启用实验。 - 使用
linter:
条目配置Linter 规则。
如果分析器在包的根目录找不到分析选项文件,它会向上遍历目录树查找。如果找不到文件,分析器将默认为标准检查。
考虑一个大型项目的以下目录结构
分析器使用文件 #1 来分析 my_other_package
和 my_other_other_package
中的代码,并使用文件 #2 来分析 my_package
中的代码。
启用更严格的类型检查
#如果你希望进行比 Dart 类型系统要求的更严格的静态检查,请考虑启用 strict-casts
、strict-inference
和 strict-raw-types
语言模式
analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true
你可以将这些模式组合使用或单独使用;它们都默认为 false
。
strict-casts: <bool>
- 值为
true
可确保类型推断引擎永远不会从dynamic
隐式转换为更具体的类型。以下有效的 Dart 代码包含从jsonDecode
返回的dynamic
值到List<String>
的隐式向下转型,这可能在运行时失败。此模式会报告潜在错误,要求你添加显式转型或以其他方式调整代码。
void foo(List<String> lines) {
...
}
void bar(String jsonText) {
foo(jsonDecode(jsonText)); // Implicit cast
}
error - The argument type 'dynamic' can't be assigned to the parameter type 'List<String>'. - argument_type_not_assignable
strict-inference: <bool>
- 值为
true
可确保类型推断引擎在无法确定静态类型时不会选择dynamic
类型。以下有效的 Dart 代码创建了一个无法推断其类型参数的Map
,此模式会因此产生推断失败提示
final lines = {}; // Inference failure
lines['Dart'] = 10000;
lines['C++'] = 'one thousand';
lines['Go'] = 2000;
print('Lines: ${lines.values.reduce((a, b) => a + b)}'); // Runtime error
warning - The type argument(s) of 'Map' can't be inferred - inference_failure_on_collection_literal
strict-raw-types: <bool>
- 值为
true
可确保类型推断引擎在由于省略类型参数而无法确定静态类型时不会选择dynamic
类型。以下有效的 Dart 代码有一个具有原始类型的List
变量,此模式会因此产生原始类型提示
List numbers = [1, 2, 3]; // List with raw type
for (final n in numbers) {
print(n.length); // Runtime error
}
warning - The generic type 'List<dynamic>' should have explicit type arguments but doesn't - strict_raw_type
启用和禁用 Linter 规则
#analyzer 包还提供了一个代码 Linter。提供了各种各样的Linter 规则。Linter 往往是非宗派的——规则之间不必相互一致。例如,有些规则更适合常规 Dart 包,而另一些规则则专为 Flutter 应用设计。请注意,与静态分析不同,Linter 规则可能会产生误报。
启用 Dart 团队推荐的 Linter 规则
#Dart 团队在 lints 包中提供了两套推荐的 Linter 规则
- 核心规则
- 帮助识别在使用或运行 Dart 代码时可能导致问题的关键问题。所有代码都应通过这些 Linter 规则。上传到 pub.dev 的包会有一个包评分,该评分部分基于通过这些规则的情况。
- 推荐规则
- 帮助识别在使用或运行 Dart 代码时可能导致的其他问题,并强制执行单一、惯用的风格和格式。我们建议所有 Dart 代码都使用这些规则,它们是核心规则的超集。
要启用任一组 Lints,请将 lints 包添加为开发依赖项
dart pub add --dev lints
然后编辑你的 analysis_options.yaml
文件以包含你偏好的规则集
include: package:lints/<RULE_SET>.yaml
例如,你可以像这样包含推荐的规则集
include: package:lints/recommended.yaml
启用单个规则
#要启用单个 Linter 规则,请将 linter:
作为顶级键添加到分析选项文件中,后跟 rules:
作为二级键。在后续行中,指定要应用的规则,前面加上破折号(YAML 列表的语法)。例如
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
禁用单个规则
#如果你包含一个分析选项文件,例如 lints
中的文件,你可能想禁用一些包含的规则。禁用单个规则与启用它们类似,但需要使用映射而不是列表作为 rules:
条目的值,因此每行应包含规则名称,后跟 : false
或 : true
。
这是一个分析选项文件的示例,它使用了 lints
中除 avoid_shadowing_type_parameters
外的所有推荐规则。它还启用了 await_only_futures
规则
include: package:lints/recommended.yaml
linter:
rules:
avoid_shadowing_type_parameters: false
await_only_futures: true
包含共享选项
#分析选项文件可以包含在其他选项文件或甚至其他选项文件列表中指定的选项。你可以使用顶层 include:
字段来指定这些文件
include: package:flutter_lints/recommended.yaml
包含的选项文件可以通过 package:
路径或相对路径指定。可以在列表中指定多个分析选项文件
include:
- package:flutter_lints/recommended.yaml
- ../team_options.yaml
包含文件中的选项可以在包含文件中被覆盖,也可以被后续包含的文件覆盖。换句话说,分析选项文件指定的选项是通过首先按列表中出现的顺序应用每个包含文件(通过递归应用此算法)中指定的选项,然后用本地定义的任何选项覆盖它们来计算的。
例如,给定以下选项文件
include: two.yaml
# ...
以及一个包含这些选项文件的最终选项文件
include:
- one.yaml
- three.yaml
# ...
然后,通过依次应用 one.yaml
、two.yaml
、three.yaml
中找到的选项,最后应用 analysis_options.yaml
中的选项来计算组合的分析选项。
启用分析器插件 (实验性)
#分析器对插件提供实验性支持。这些插件与分析器集成,以添加新诊断、快速修复和自定义代码补全等功能。每个 analysis_options.yaml
文件只能启用一个插件。启用分析器插件会增加分析器使用的内存。
如果你的情况符合以下任一条件,请不要使用分析器插件
- 你的开发机器内存少于 16 GB。
- 你使用包含超过 10 个
pubspec.yaml
和analysis_options.yaml
文件的 mono-repo。
你可以在 pub.dev 上找到一些分析器插件。
要启用插件
将包含插件的包添加为开发依赖项。
dart pub add --dev <your_favorite_analyzer_plugin_package>
编辑你的
analysis_options.yaml
文件以启用插件。yamlanalyzer: plugins: - your_favorite_analyzer_plugin_package
要指定启用的特定插件功能,例如新诊断,可能需要额外的设置。
从分析中排除代码
#有时,某些代码未能通过分析是可以接受的。例如,你可能依赖于一个你未拥有的包生成的代码——生成的代码可以工作,但在静态分析期间会产生警告。或者 Linter 规则可能导致你想要抑制的误报。
你有几种方法可以从分析中排除代码
- 从分析中排除整个文件。
- 阻止特定的非错误规则应用于单个文件。
- 阻止特定的非错误规则应用于单个代码行。
你还可以禁用所有文件的特定规则或更改规则的严重性。
排除文件
#要从静态分析中排除文件,请使用 exclude:
分析器选项。你可以列出单个文件,或使用 glob 模式语法。所有 glob 模式的使用都应相对于包含 analysis_options.yaml
文件的目录。
analyzer:
exclude:
- lib/client.dart
- lib/server/*.g.dart
- test/_data/**
抑制文件的诊断
#要忽略特定文件的特定非错误诊断,请在文件中添加 ignore_for_file
注释
// ignore_for_file: unused_local_variable
这适用于整个文件,无论注释在前面还是后面,对于生成的代码特别有用。
要抑制多个诊断,请使用逗号分隔的列表
// ignore_for_file: unused_local_variable, duplicate_ignore, dead_code
要抑制所有 Linter 规则,请添加 type=lint
指定符
// ignore_for_file: type=lint
抑制代码行的诊断
#要抑制 Dart 代码特定行上的特定非错误诊断,请在该行代码上方放置 ignore
注释。这是一个忽略导致运行时错误的示例代码,你可以在语言测试中这样做
// ignore: invalid_assignment
int x = '';
要抑制多个诊断,请提供逗号分隔的列表
// ignore: invalid_assignment, const_initialized_with_non_constant_value
const x = y;
或者,将 ignore 注释附加到它应用的行
int x = ''; // ignore: invalid_assignment
抑制 pubspec 文件中的诊断
#如果你需要在 pubspec.yaml
文件中抑制分析器报告的非错误诊断,请在受影响的行上方添加 ignore
注释。
以下示例忽略了 sort_pub_dependencies
规则,因为它想把 flutter
依赖项放在首位
dependencies:
flutter:
sdk: flutter
# ignore: sort_pub_dependencies
collection: ^1.19.0
自定义分析规则
#每个分析器诊断和Linter 规则都有一个默认的严重性。你可以使用分析选项文件来更改单个规则的严重性,或始终忽略某些规则。
分析器支持三个严重性级别
info
- 不会导致分析失败的信息性消息。示例:
dead_code
warning
- 不会导致分析失败的警告,除非分析器被配置为将警告视为错误。示例:
invalid_null_aware_operator
error
- 导致分析失败的错误。示例:
invalid_assignment
忽略规则
#你可以使用 errors:
字段忽略特定的分析器诊断和Linter 规则。列出规则,后跟 : ignore
。例如,以下分析选项文件指示分析工具忽略 TODO 规则
analyzer:
errors:
todo: ignore
更改规则的严重性
#你可以全局更改特定规则的严重性。此技术适用于常规分析问题和 Lints。例如,以下分析选项文件指示分析工具将无效赋值视为警告,将缺少返回值视为错误,并提供关于死代码的信息(但不是警告或错误)
analyzer:
errors:
invalid_assignment: warning
missing_return: error
dead_code: info
配置 dart format
#你可以通过在分析选项文件中添加 formatter 部分并指定你偏好的 page_width
来配置 dart format
的行为。
有关更多信息,请阅读配置格式化程序页面宽度。
资源
#使用以下资源了解有关 Dart 中静态分析的更多信息