概览

有多种工具可供 Fuchsia 开发者使用,用于对代码执行 lint 请求和设置代码格式。本文概述了各种语言中的这些工具,并说明了应如何添加其他 lint 检查,以及应遵循哪些准确性标准。

请注意,这并未尝试解释每个 linter 和格式化程序的具体语言配置。虽然执行 lint 请求和设置格式的目的是鼓励并强制执行有关样式和最佳做法的建议,但每种相关语言都有自己的指南,用于说明做出的决策和启用的配置。

工具集成

Fuchsia 团队提供了两种设置代码格式和执行 lint 代码的方法:开发者端 fx 工具中的子命令,以及对上传的更改进行集成的 Tricium 分析。此外,格式设置和执行 lint 检查的一部分可以直接包含在 build 中,但在准确性方面有严格的限制。

开发者工具(IDE 和 fx)

主要开发者工具套件是 fx 命令及其子命令。它提供了两个与此处相关的子命令:fx 格式代码和 fx lint。每个函数都会对一个文件列表运行相关工具,并将输出结果输出到终端的 stdout/stderr。运行 fx lint 会假定开发者已经运行 fx build;否则,许多 linter 都会生成与 build 所创建的缺失文件相关的错误。

可以通过以下三种方式之一指定文件列表:

  • 自第二次 Git 提交以来发生更改的文件列表,包括已提交、已修改和已缓存的文件(这是默认行为)
  • 以逗号分隔列表传递给 --files 标志的文件列表
  • GN 目标的来源中传递给 --target 标志的文件列表

格式设置是就地完成的。linting 在默认情况下只处于警告状态,但用户可以将 --Fix 标志传递给 fx lint,以自动修正这些工具提供修复的错误。

大多数编辑器还会集成格式设置工具和 linter,让开发者能够在保存时自动设置格式或在按键绑定时自动设置格式。在大多数情况下,设置(如果有)包括将 IDE 指向相关配置文件和 Fuchsia 分发的工具二进制文件。

集成工具 (Tricium)

Tricium 服务与 Gerrit 代码审核系统相集成,能以不会阻止提交的方式显示相关警告。它在对 Fuchsia 代码库具有提交权限的用户上传的每个补丁集上触发,并运行两套工具分析套件。

格式设置工具分析会进行最低限度的检出(没有 third_party、没有预构建文件),并从补丁提交中提取已更改文件的列表。它根据每个文件的文件扩展名运行相关的格式设置工具。如果生成的格式化文件与所上传补丁中的文件内容不同,Tricium 会在补丁上发布注释,说明如何对文件运行适当的格式化程序。

linter 分析会执行完整检出,并执行最低限度的构建(以生成必要的配置文件和头文件)。该工具会从补丁提交中提取已更改文件的列表,然后根据文件扩展名运行相关的 linter。linter 会请求机器可读的输出内容,如果生成了警告,则会解析输出结果并将其收集到注释表单中。然后,Tricium 会在包含 linter 警告的相应行中添加备注。

在可能的情况下,Tricium 仅在提交中已更改的代码行上运行工具,但并非所有 linter 都支持此行为。对于会更改的 lint,这样可确保现有但不相关的 lint 错误不会分散对更改本身的注意力,而是只显示直接相关的 lint。

分析结果通常基于启发法。因此,它们偶尔会产生假正例。Fuchsia 旨在为这些分析器设置较高的标准,根据由 Tricium 服务生成的指标测得的错误率高于 10% 的任何分析器都将被停用。

通常,新的 linter 应添加到现有的 Tricium 方案。到目前为止,这些 build 的结账/构建时间成本最高(分析本身最多只需几秒钟,最差几分钟,而签出和/o build 可能需要更长的时间),因此从时间和基础架构资源的角度来看,仅扩展现有构建器会更加高效。选择扩展哪个配方时,应根据所需信息量来选择,例如,如果运行分析不需要预构建/第三方代码,则应使用最低的结账配方。

构建集成

提供零误报率的 linter 检查的另一种方法是将其纳入 build 中。 不建议对此类别进行额外的检查,除非确定这些检查不会触发误报。

这些检查直接在 build 中实现(通常作为运行相关脚本的操作),因此如果发现错误,会导致整个构建失败。它们还会延长构建时间,因此只应在向开发者提供有价值的正确信息的情况下使用。

标准

格式化程序

格式化程序应遵循相关的样式指南,但格式指南的输出是否是样式指南的可信来源则由语言及其样式仲裁器决定。当上游社区中的格式化程序更改时(例如,当 Rust 社区更改了 rustfmt 时),更新后的格式化程序将随工具链一起滚动至 Fuchsia。这种情况不会经常发生,但在开发者更新以使用新的工具链之前,可能会导致 Tricium 和本地工具之间的格式冲突。

通常,Fuchsia 是否支持格式化程序取决于运行格式化命令的开发者。唯一的自动化来自 Tricium,它会在文件与格式化程序的输出不同时发出警告,但不会阻止 CL 的提交。

Linter

linter 通常应该向开发者提供实用且可操作的评论。由于它们通常基于启发法,因此可能会产生假正例,但应停用超过 10% 的假正例率的 linter。添加 linter 检查的过程是提交一个 bug,请求新检查,并概述其值和预期的假正例率。若要移除 linter 检查,请提交 bug 或提交包含所请求配置更改的补丁。

只有保证不会产生误报的 linter 才能在 build 本身中实现。这些规范应由本地 build 和 CQ 强制执行,以确保开发者尝试提交代码时不会出现意外。

语言工具

每种受支持的语言都提供了一个格式化程序和可选的 linter。本部分介绍如何将这些工具集成到 Fuchsia 工作流中。虽然格式化程序往往很简单,但该工具的集成方式有点复杂。在大多数情况下,开发者不需要了解 fx 和 Tricium 的内部原理。

假定所有命令都从 Fuchsia 检出的根目录运行。

C/C++

C/C++ 代码使用 clang-formatclang-tidy。这些依赖项以预构建形式从 Clang 工具链进行分发。两者都使用根级配置文件(分别是 .clang-format.clang-tidy)。开发者不应在较低级别创建额外的配置文件,否则会导致树中出现不一致。

clang-format 在源文件上运行,如下所示:

prebuilt/third_party/clang/$HOST_PLATFORM/bin/clang-format \
-i \
-style=file \
-fallback-style=Google \
-sort-includes \
$FILES

在运行 clang-tidy 之前,您必须:

  • 构建生成的头文件。clang-tidy 工具会编译部分源代码,并且 Fuchsia 中的大多数 C 和 C++ 代码包括在 build 中生成的头文件。

出现编译数据库和生成的头文件后,您便可以运行 run-clang-tidy.py 脚本来启动 clang-tidy 工具。该脚本会处理错误并行化和重复信息删除,当多个源文件中包含同一标头时,必须这样做。使用此脚本时,您还必须传递分布式 Fuchsia 工具链中的 clang-tidyclang-apply-replacements 二进制文件,以确保使用正确的二进制文件。

export CLANG_TOOLCHAIN_PREFIX=prebuilt/third_party/clang/$HOST_PLATFORM
$CLANG_TOOLCHAIN_PREFIX/share/clang/run-clang-tidy.py \
  -clang-tidy-binary $CLANG_TOOLCHAIN_PREFIX/bin/clang-tidy \
  -clang-apply-replacements-binary $CLANG_TOOLCHAIN_PREFIX/bin/clang-apply-replacements \
  $FILES

可以添加可选的 -fix 标志来自动应用修正。此操作可通过开发者端工具获取。

Rust

Rust 代码使用 rustfmtclippy。它们以预构建形式从 Rust 工具链进行分发。格式化程序具有根级配置文件 (rustfmt.toml)。

rustfmt 在源文件上运行,如下所示:

prebuilt/third_party/rust/${HOST_PLATFORM}/bin/rustfmt \
--config-path=rustfmt.toml \
--unstable-features \
--skip-children \
$FILES

默认情况下,clippyfx build 在所有 Rust 目标上运行。在提交前,clippy 警告被视为构建错误。

如果您只想运行 linter,也可以使用我们的 fx 帮助程序脚本在 GN 目标上本地调用它:

fx clippy TARGET
fx clippy --files FILE1 FILE2 # Filters lints for a list of specific files
fx lint # Same as --files but implicitly runs on locally changed files

启用 Clippy lint

要查看目标的 lint,您需要通过以下某种方式启用它们:

  • 通过添加 configs += [ "//build/config/rust/lints:clippy_warn_all" ] 配置,在特定目标上启用默认的 Clippy lint 集。
  • 使用以下 gn 参数:fx set core.x64 --args clippy_warn_all=true 在本地将 clippy lint 作为警告启用。这对于在为 crate 启用 lint 之前查明哪些 lint 是常见的,或者收集整个项目 lint 频率等统计信息非常有用。

点此可查看所有可用的 Clippy lint 及其名称。

针对特定代码停用 clippy lint

#[allow(clippy::LINT_NAME)] 添加到您想要忽略特定 lint 的任何 Rust 代码。请注意,属性无法应用于所有表达式,并且可能需要将属性应用于所属语法元素。

Go

Go 代码使用 gofmtgo vet。这些依赖项是作为 Go 工具链 build 的一部分构建的,还会在 Go 主机工具链预构建版本中分发。

gofmt 在源文件上运行,如下所示:

prebuilt/third_party/go/$HOST_PLATFORM/bin/gofmt -s -w $FILES

TODO(https://fxbug.dev/42101826):最终确定实现细节后,对其进行审查。

FIDL

FIDL 代码使用 fidl-formatfidl-lint 工具。它们是从树内构建为主机工具的。在运行 zircon/tools 目标之前,必须先构建使二进制文件存在。

fidl-format 在源文件上运行,如下所示:

$ZIRCON_BUILD_DIR/tools/fidl-format -i $FILES

fidl-lint 在源文件上运行,如下所示:

$ZIRCON_BUILD_DIR/tools/fidl-lint $FILES

GN

GN 文件使用 gn format 子命令。没有 linter。该软件包会作为 GN 预构建版本的一部分进行分发。

它在源文件上运行,如下所示:

prebuilt/third_party/gn/$HOST_PLATFORM/gn format <files>