hershel-theodore-layton / portable-hack-ast-linters
使用 portable-hack-ast 编写的 Hack 源代码代码检查器。
Requires
- hhvm: ^4.102
- hershel-theodore-layton/portable-hack-ast: dev-master || <1
- hershel-theodore-layton/portable-hack-ast-extras: dev-master || <1
- hershel-theodore-layton/pragma: <1
Requires (Dev)
- hhvm/hhvm-autoload: ^3.2
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)中的任何东西。
- 此检查器不使用 HHAST 框架。它是对
- 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
文件。
- 在 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();