自定义静态分析
静态分析允许你在执行单行代码之前发现问题。这是一个用于防止错误并确保代码符合样式指南的强大工具。
借助分析器,你可以找到简单的错别字。例如,一个意外的分号可能进入了 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 分析服务器和其他工具使用 analyzer 包 来执行静态分析。
你可以自定义静态分析以查找各种潜在问题,包括 Dart 语言规范 中指定的错误和警告。你还可以配置 linter 规则,以确保你的代码符合 Dart 样式指南 和 Effective Dart 中的其他建议指南。诸如 dart analyze
、flutter analyze
和 IDE 和编辑器 等工具使用 analyzer 包来评估你的代码。
本文档说明了如何使用分析选项文件或 Dart 源代码中的注释来自定义分析器的行为。如果你想将静态分析添加到你的工具,请参阅 analyzer 包 文档和 分析服务器 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 规则 可用。Linters 往往是非教派的——规则不必相互同意。例如,某些规则更适用于常规 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
- cancel_subscriptions
- close_sinks
- combinators_ordering
- comment_references
- invalid_case_patterns
- library_annotations
- one_member_abstracts
- only_throw_errors
禁用单个规则
#如果您包含 lints
中的分析选项文件,您可能希望禁用一些包含的规则。禁用单个规则与启用规则类似,但需要使用映射而不是列表作为 rules:
条目的值,因此每行应包含规则名称,后跟 : false
或 : true
。
以下是一个分析选项文件的示例,它使用了 lints
中除 avoid_shadowing_type_parameters
之外的所有推荐规则。它还启用了 lint await_only_futures
include: package:lints/recommended.yaml
linter:
rules:
avoid_shadowing_type_parameters: false
await_only_futures: true
启用分析器插件(实验性)
#分析器对插件有实验性支持。这些插件与分析器集成以添加功能,例如新诊断、快速修复和自定义代码完成。您只能为每个 analysis_options.yaml
文件启用一个插件。启用分析器插件会增加分析器使用的内存量。
如果您的情况满足以下任一条件,请不要使用分析器插件
- 您使用内存小于 16 GB 的开发机器。
- 您使用具有超过 10 个
pubspec.yaml
和analysis_options.yaml
文件的单一存储库。
您可以在 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;
或者,将忽略注释附加到其适用的行
int x = ''; // ignore: invalid_assignment
禁止对 pubspec 文件进行诊断
#如果您需要在 pubspec.yaml
文件中禁止分析器中的非错误诊断,请在受影响的行上方添加 ignore
注释。
以下示例忽略了 sort_pub_dependencies
lint,因为它想首先放置 flutter
依赖项
dependencies:
flutter:
sdk: flutter
# ignore: sort_pub_dependencies
collection: ^1.18.0
自定义分析规则
#每个 分析器诊断 和 linter 规则 都具有默认严重性。您可以使用分析选项文件更改各个规则的严重性,或始终忽略某些规则。
分析器支持三个严重性级别
info
- 不会导致分析失败的信息性消息。示例:
dead_code
warning
- 不会导致分析失败的警告,除非将分析器配置为将警告视为错误。示例:
invalid_null_aware_operator
error
- 导致分析失败的错误。示例:
invalid_assignment
忽略规则
#您可以使用 errors:
字段忽略特定的 分析器诊断 和 linter 规则。列出规则,后跟 : ignore
。例如,以下分析选项文件指示分析工具忽略 TODO 规则
analyzer:
errors:
todo: ignore
更改规则的严重性
#您可以全局更改特定规则的严重性。此技术适用于常规分析问题以及 lint。例如,以下分析选项文件指示分析工具将无效赋值视为警告,将缺少的返回视为错误,并提供有关死代码的信息(但不是警告或错误)
analyzer:
errors:
invalid_assignment: warning
missing_return: error
dead_code: info
资源
#使用以下资源详细了解 Dart 中的静态分析