目錄
keyboard_arrow_down keyboard_arrow_up靜態分析讓你的程式碼問題能在執行前被發現,它在防止問題產生和程式碼風格指南的遵循上很有幫助。
在分析器的幫助下,你可以發現簡單的拼寫錯誤。例如,可能在 if
陳述式中不小心多打了一個分號:
void increment() { if (count < 10) ; count++; }
如果配置得當,分析器會指出這個分號的位置並輸出如下警告:
info - example.dart:9:19 - Avoid empty statements. - empty_statements
分析器也能幫你找出更多細節問題。例如,也許你忘記關閉一個 sink 了:
var controller = StreamController<String>();
info - Close instances of `dart.core.Sink`. - close_sinks
在 Dart 生態系統中,Dart 分析服務和其他相關工具使用了 analyzer 來提供靜態分析。
你可以自訂靜態分析以尋找各種潛在的問題,包括在 Dart 程式設計語言規範 中規定的錯誤和警告。你同樣能透過配置 linter ——分析器的一個外掛,來確保你的程式碼遵循 Dart 程式碼風格指南
和 高效 Dart 中其他建議的準則。諸如 Dart 編譯器 (dart compile
),
dart analyze
,
flutter analyze
,
和 JetBrains IDEs
等 Dart 工具都會使用 analyzer package 來評估你的程式碼。
這篇文件解釋瞭如何透過使用分析配置檔案,或在 Dart 原始碼中添加註釋來自訂分析器的行為。如果你想在工具中新增靜態分析規則,請參考 analyzer package 的文件和 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 不支援多個重複的 key,你只能引入最多一個檔案; -
使用
analyzer:
入口來自訂靜態分析: 啟用更嚴格的型別檢查, 排除檔案, 忽略特定規則, 改變規則的警告等級, or 開啟實驗性功能; -
使用
linter:
入口來配置 linter 規則。
如果分析器在 package 的根目錄下無法找到一個分析配置檔案,它將會往下查詢整個目錄樹。如果還是沒有可用的配置檔案,分析器則預設使用標準檢查規則。
對於如下所示的一個大型專案的目錄結構而言:
分析器使用 #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 程式碼在 List<String>
引數上傳遞了一個 jsonDecode
方法的返回值,實際是將返回的 dynamic
做了隱含向下轉換,在執行時可能導致錯誤。該模式會報告此類潛在的錯誤,要求你新增一個顯示的型別轉換或者調整你的程式碼。
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
,在該模式下會觸發推斷失敗的 hint 提示:
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
info - The type argument(s) of 'Map' can't be inferred - inference_failure_on_collection_literal
strict-raw-types: <bool>
設為 true
可確保當型別推理引擎,由於省略型別引數而無法確定靜態型別時,不再選擇dynamic
型別。下方合法 Dart 程式碼中有一個原始型別的 List
變數,導致在該模式下觸發了原始型別 hint 提示。
List numbers = [1, 2, 3]; // List with raw type
for (final n in numbers) {
print(n.length); // Runtime error
}
info - The generic type 'List<dynamic>' should have explicit type arguments but doesn't - strict_raw_type
啟用和停用 linter 規則
analyzer 包同樣提供一個程式碼 linter,幷包含一份廣泛多樣的 linter 規則。提示規則之間往往是無關聯性的,各種規則之間不必彼此遵守。例如,有些規則更合適支援庫,而另一些則是為 Flutter 應用設計的。注意,linter 規則可能會觸發誤報,靜態分析則不會。
啟用 Dart 團隊推薦的 linter 規則
Dart 團隊在 lints package 中提供了 2 個推薦的 linter 規則集合:
核心規則
幫助確認可能導致在執行或使用 Dart 程式碼時引發問題的關鍵事項。所有型別的程式碼都應該符合這些 linter 規則。被上傳至 pub.dev 的 package,會有一個部分基於透過這些規則的情況而產生的 package 評分。
推薦規則
幫助確認其他可能導致執行或使用 Dart 程式碼時引發問題的事項,並強制使用單一、慣用的程式碼風格和程式碼格式化。作為一個核心規則的超集,我們推薦所有的 Dart 程式碼使用它。
將 lints package 作為 dev dependency 新增,來啟用任意 lints 集合。
$ dart pub add --dev lints
然後編輯 analysis_options.yaml
檔案來引入你想要的規則集合:
include: package:lints/<RULE_SET>.yaml
例如,你可以像這樣引入推薦規則的集合:
include: package:lints/recommended.yaml
啟用單條規則
在分析配置檔案中新增最上層 key linter:
來啟用單條規則,緊跟著用 rules:
作為二級 key。在後續行中,以短橫槓為字首(YAML 列表的語法),指定你想要新增的規則。例如:
linter:
rules:
- always_declare_return_types
- cancel_subscriptions
- close_sinks
- comment_references
- one_member_abstracts
- only_throw_errors
- package_api_docs
- prefer_final_in_for_each
- prefer_single_quotes
停用單條規則
如果你引入了一個分析配置檔案(比如 lints
中的某一個),你可能會想要停用其中的一部分。停用單條規則和啟用單條規則是類似的,但要求使用鍵值對而不是列表來作為 rules:
的值。因此每一行應該包括規則的名字,後面跟上 : false
或者 : true
。
這裡是一個分析配置檔案的範例,其中使用了來自 lints
的所有推薦規則,除了 avoid_shadowing_type_parameters
被單獨停用。這裡同樣單獨啟用了 await_only_futures
這條 lint。
include: package:lints/recommended.yaml
linter:
rules:
avoid_shadowing_type_parameters: false
await_only_futures: true
從 analysis 中排除程式碼
有時候,部分程式碼可能允許包含分析出的警告和提示。例如,你也許依賴於某個不屬於你 package 所產生的程式碼,這些程式碼可以正常執行,但是在靜態檢查中會產生警告。或者某個 linter 規則可能會出現你想關掉的誤報。
有幾種方法可以從 analysis 中排除程式碼:
-
從 analysis 中排除整個檔案。
-
在單個檔案中停止特定的非錯誤規則的生效。
-
在單個檔案的某幾行中,停止特定的非錯誤規則的生效。
你同樣可以對所有檔案 停用特定的規則,或者 改變規則的警告等級。
排除檔案
使用分析器選項 exclude:
在靜態分析中排除檔案。你可以列出單獨的檔案,或者用 glob 語法:
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
新增 type=lint
以忽略所有的 linter 規則:
// ignore_for_file: type=lint
對一行程式碼忽略規則
透過在單行程式碼的上方新增 ignore
註釋,使得特定的非錯誤規則對該行程式碼忽略。這是一個忽略程式碼導致執行時錯誤的例子,你可能會在一個開發語言的測試上使用。
// ignore: invalid_assignment
int x = '';
使用逗號分隔的列表,可以忽略多條規則:
// ignore: invalid_assignment, const_initialized_with_non_constant_value
const x = y;
或者,將需要忽略的規則追加到相應的行後:
int x = ''; // ignore: invalid_assignment
自訂 analysis 規則
每個 分析器錯誤碼 和 linter 規則 都有一個預設的警告等級。你可以使用分析配置檔案來改變單個規則的警告等級,或者總是忽略某些規則。
分析器支援三種警告等級:
info
訊息,不會造成 analysis 驗證失敗。例如:dead_code
warning
警告,一般不會造成 analysis 驗證失敗,除非分析器被配置了對待警告與錯誤一致。例如:invalid_null_aware_operator
error
錯誤,會造成 analysis 驗證失敗。例如:invalid_assignment
忽略規則
你可以透過使用 errors:
欄位,來忽略特定的 分析器錯誤碼 and linter 規則。列出規則,在後面加上 : ignore
。例如下方的分析配置檔案,指示分析器工具忽略了 TODO 規則:
analyzer:
errors:
todo: ignore
修改規則的警告等級
你可以全域修改單個規則的警告等級。這項技術對於常規的 analysis 問題和 lints 問題都有效。例如下方的分析配置檔案,指示分析器工具把無效的賦值配置為警告,把缺少返回值配置為錯誤,而對於無法執行到的程式碼,僅提供並非警告和錯誤的資訊通知。
analyzer:
errors:
invalid_assignment: warning
missing_return: error
dead_code: info
更多資源
你還可以透過以下資源來深入瞭解 Dart 的靜態分析: