HHAST is a toolkit for for analyzing the structure of Hack files. It includes a linting and migration framework to find and automatically fix problems in your code. The lint errors and migration suggestions can be accessed from Hack API, command line interface or IDEs.

HHAST also ships with many built-in lint rules and migration rules. However, the HHAST built-in lint rules have limited access to the type checker, therefore, it is difficult to create a lint rule that needs to determine questions like “is this type a subtype of that type?” or “is this expression compatible with that function signature?”.

Recently, we released HHAST v4.139.0. The new version brings a proxy to run the linter from the Hack compiler written in OCaml, which includes more powerful lint rules that need the access to the type checker 1. Note that type checker based lint rules cannot be user-defined, as they must be written in OCaml, built in to the HHVM repository.

How to enable type checker based lint rules?

Firstly, follow the User Documentation to set up the linters for IDEs and command line tools.

The lint rules from the Hack compiler are not enabled by default, to enable them, put the following settings into your hhast-lint.json:

1
2
3
"extraLinters": [
  "Facebook\\HHAST\\HHClientLinter"
],

HHClientLinter is the special linter as a proxy to run linters from the Hack compiler. Similar to the Hack typing errors, these lint rules report lint errors with 4-digit numeric codes. To avoid conflicts, the 5xxx range is reserved for Hack compiler lint rules.

Run HHClientLinter for particular error codes

HHClientLinter can be configured to not report particular error codes by adding the following settings into your hhast-lint.json

1
2
3
4
5
"linterConfigs": {
  "Facebook\\HHAST\\HHClientLinter": {
    "ignore": [5624, 5639]
  }
}

or if you are interested in only particular error codes:

1
2
3
4
5
"linterConfigs": {
  "Facebook\\HHAST\\HHClientLinter": {
    "ignore_except": [5624, 5639]
  }
}

The definition of error codes can be found at lints_codes.ml.

Suppressing error codes in a file

Each lint error can be suppressed separately with the help of HHAST_IGNORE_ERROR markers.

For example, suppose you are generating a file including some unnecessary null checks, which triggers the error code 5611, putting the HHAST_IGNORE_ERROR[5611] marker at the previous line of each lint error position could prevent HHAST from reporting it.

1
2
3
4
5
6
7
8
9
10
11
class Diagnosis {
  public function __construct(shape('file' => string, 'position' => ?int, 'reason' => string) $data) {}

  public function hasFile(): bool {
    // HHAST_IGNORE_ERROR[5611]
    return $this->data['file'] is nonnull;
  }
  public function getFile(): string {
    return $this->data['file'];
  }
}

HHAST_IGNORE_ALL is also supported for suppressing an error code in the whole file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// HHAST_IGNORE_ALL[5611] because this file is generated.
// It is expected to include some correct but unnecessary null checks.
class Diagnosis {
  public function __construct(shape('file' => string, 'position' => ?int, 'reason' => string) $data) {}

  public function hasFile(): bool {
    return $this->data['file'] is nonnull;
  }
  public function getFile(): string {
    return $this->data['file'];
  }
  public function hasPosition(): bool {
    return $this->data['position'] is nonnull;
  }
  public function getPosition(): ?int {
    return $this->data['position'];
  }
  public function hasReason(): bool {
    return $this->data['reason'] is nonnull;
  }
  public function getReason(): string {
    return $this->data['reason'];
  }
}

HHAST_IGNORE_ALL is not encouraged because, unlike HHAST_IGNORE_ERROR, HHAST_IGNORE_ALL would silently skip newly introduced errors and you would miss the opportunity to review them.

References

  1. HHAST v4.139.0 requires HHVM 4.126 or newer version.