hershel-theodore-layton/portable-hack-ast-linters

使用 portable-hack-ast 编写的 Hack 源代码代码检查器。

v0.0.6 2024-08-10 14:52 UTC

This package is auto-updated.

Last update: 2024-09-11 09:06:28 UTC


README

使用 portable-hack-ast 编写的 Hack 源代码代码检查器

如何检查我的代码

如果你之前使用过 HHAST,你可能期望可以直接将 hhast-lint.json 或类似的文件添加到你的仓库中以立即开始检查。PhaLinters 不是这样工作的。你必须添加一个执行检查的 Hack 源代码文件,并直接调用检查器。检查器位于 HTL\PhaLinters 命名空间中,所以可以自动完成。

此库会检查自身。你可以检查 lint.hack 并直接复制。此文件明确许可为 MIT-0 许可,而不是像此库的其他部分那样使用 MIT 许可。这意味着你可以做所有允许的 MIT 许可做的事情,而无需保持文件中的许可注释完整。此许可证的选择不会改变此项目其余部分的许可证。

包含哪些检查器?

要查看完整列表,请参阅 捆绑的检查器,几乎包含 HHAST 的所有检查器,还有一些以前从未见过的新检查器,仅在 portable-hack-ast-linters 中可用。

HHAST 中缺失的检查器

此库中不包含 HHAST 的一些检查器。

  • HHClientLinter.hack
    • 此检查器不使用 HHAST 框架。它是对 hh_client --lint 命令行的包装。由 hh_client 建议的检查非常高质量,并且可以/确实利用类型信息。HHAST 实现存在 严重的性能问题。可以开发一个单独的工具,因为它不需要 HHAST(或 Pha)中的任何东西。
  • DataProviderTypesLinter.hack
    • 这是一个试图使 <<DataProvider(...)>> 注释类型安全的良好意图的检查器。由于其本质,它是对类型检查器的粗糙启发式近似。它建议你做一些实际上有害的事情,比如滥用 nothing 类型。"真正的"解决方案是将 <<DataProvider>> 机制更改为补充 Hack 语言。
  • MustUseOverrideAttributeLinter.hack
    • 此检查器的输出不仅取决于参数,还取决于全局信息。父类中的更改将需要重新检查文件。以跨请求方式缓存检查结果将需要广泛的依赖跟踪。hh_client --lint 优于此检查器的功能,并且不依赖于 \ReflectionClass API。
  • StrictModeOnlyLinter.hack
    • 在 Hack 的早期阶段需要此检查器。文件曾经使用 .php.hh 扩展,模式由注释确定。<?hh 会将 .php 文件 "踢入" Hack 部分模式。你将显式启用 "严格模式",使用 <?hh // strict。自 hhvm 版本 4.0 发布以来,你可以使用 .hack 文件。

Fixme 指令

一些lint错误不能(也不应该)总是被修复。有时循环中的await并不表示虚假依赖,例如在sgml-stream的ConcurrentReusableRenderer中。

async function consider_the_following_code_async(): void {
  $awaitables = vec[];
  foreach ($snippets as $snippet) {
    $awaitables[] = $snippet->primeAsync($descendant_flow);
  }

  concurrent {
    // Race them all,...
    await AwaitAllWaitHandle::fromVec($awaitables);
    await async {
      foreach ($snippets as $snippet) {
        /* HHAST_IGNORE_ERROR[DontAwaitInALoop]
         * feedBytesToConsumer operates on the awaitables from the race.
         * There are no false dependencies here.
         * We just MUST collect bytes in order. */
        await $snippet->feedBytesToConsumerAsync($consumer, $successor_flow);
      }
    };
  }
}

$snippet->feedBytesToConsumerAsync(...)方法等待一个已在->primeAsync(...)中启动的Awaitable。内部,它也等待于$consumer->consumeAsync(...),这必须按顺序调用。这个循环中的await对于代码正确工作是必要的。为了通知hhast,添加了一个HHAST_IGNORE_ERROR[DontAwaitInALoop]注释。

这种注释抑制lint错误的方式一直让我有点困扰。我全心全意地赞同以下来自CppCoreGuidelines的引言。

Compilers don’t read comments ...
and neither do many programmers (consistently).

作为fixme注释的替代,PhaLinters使用pragma(...)指令和<<Pragmas(...)>>注释。以下代码片段表达了相同的目的。

/// hack
/* HHAST_FIXME_ERROR[DontAwaitInALoop] I'll get around to it. */
await $object->methodAsync();

// I'll get around to it.
pragma('PhaLinters', 'fixme:dont_await_in_a_loop');
await $object->methodAsync();