hhast icon indicating copy to clipboard operation
hhast copied to clipboard

Add an optional lintMarkerAllowList

Open lexidor opened this issue 3 years ago • 12 comments

fixes #458

lexidor avatar Sep 17 '22 13:09 lexidor

Close and reopen to trigger CI

Atry avatar Sep 19 '22 16:09 Atry

Asking for feedback for HHClientLinter. This linter is special, because it is an amalgamation of hundreds of rules. The option "allow comments for HHClientLinter" could not be a simple binary toggle. I have added the lintMarkerAllowList option to HHClientLinter to allow for granular tuning.

I completely ignore the global lintMarkerAllowList in HHClientLinter. So when "lintMarkerAllowList": ["UnusedUseClause"] is configured HHClientLinter will still honor its own suppression comments.

I did this, because of the following confusing example.

{
  "roots": ["src/"],
  "lintMarkerAllowList": [],
  "linterConfigs": {
    "HHClientLinter": {
      "lintMarkerAllowList": [5555]
    }
  }
}

This is conflicting, because the global list says, no markers allowed, but HHClientLinter allows marker 5555. I would expect HHClientLinter to respect its own config here. But this means, if you want to disallow all markers, you need to set two empty lists. One for HHClientLinter and one at the global level.

I also considered to error out when HHClientLinter receives a lintMarkerAllowList in its own config when shouldAllowSuppressionComments() is false. But this requires you to repeat yourself. First add HHClientLinter linter to the global list and then fine-tune the HHClientLinter config.

Which of these two would be right for the hhast project? Which would be the least surprising?

lexidor avatar Sep 19 '22 16:09 lexidor

Do we really need the lintMarkerAllowList setting for HHClientLinter if there is such the lintMarkerAllowList global setting?

Atry avatar Sep 19 '22 17:09 Atry

Do we really need the lintMarkerAllowList setting for HHClientLinter if there is such the lintMarkerAllowList global setting?

The global list contains only classnames. HHClientLinter has many sublinters:

  • SketchyNullCheckLinter
  • BooleanExpressionAlwaysFalseLinter
  • DontUseTheCloneOperatorLinter
  • DontUseSafeMemberAccessOnNonnullLinter
  • DontImplicitlyConvertStringToBoolLinter

These are not classnames. The sublinters of HHClientLinter are unnamed. They can't be included in the global list.

lexidor avatar Sep 19 '22 17:09 lexidor

There is no "sublinter" concept in HHAST. A marker is for a lint error code, whose name could be either a class name without the -Linter suffix or an integer code. Given the setting name lintMarkerAllowList, I would expect it contains both class names without the -Linter suffix and integer codes.

Atry avatar Sep 19 '22 17:09 Atry

Given that the proposed setting is for markers, not linters, it would be straightforward to evaluate the allow list when parsing markers globally, instead of implementing the feature in each linter.

  • Parsing line based markers at https://github.com/hhvm/hhast/blob/5bc52f7af5df17b65a513227483e56d75fa7cafc/src/File.hack#L42
  • Parsing AST based markers at https://github.com/hhvm/hhast/blob/5bc52f7af5df17b65a513227483e56d75fa7cafc/src/Linters/suppress_ast_linter_error.hack#L19

Atry avatar Sep 19 '22 17:09 Atry

There is no "sublinter" concept in HHAST. A marker is for a lint error code, whose name could be either a class name or an integer code. Given the setting name lintMarkerAllowList, I would expect it contains both class names and integer codes.

That would be worth it. I'll type it as keyset<arraykey>.

lexidor avatar Sep 19 '22 18:09 lexidor

arraykey might be better. I typed it as string because it was string long before we introduced HHClientLinter and changing the type would break existing code.

Atry avatar Sep 19 '22 18:09 Atry

Given that the proposed setting is for markers, not linters, it would be straightforward to evaluate the allow list when parsing markers globally, instead of implementing the feature in each linter.

* Parsing line based markers at https://github.com/hhvm/hhast/blob/5bc52f7af5df17b65a513227483e56d75fa7cafc/src/File.hack#L42

* Parsing AST based markers at https://github.com/hhvm/hhast/blob/5bc52f7af5df17b65a513227483e56d75fa7cafc/src/Linters/suppress_ast_linter_error.hack#L19

I am assuming you are proposing to add a new function besides is_linter_error_suppressed that returns a tri-state.

enum SuppressionState : int {
  NOT_SUPPRESSED = 0;
  SUPPRESSED = 1;
  DISALLOWED_SUPPRESSION = 2;
}

I could then reimplement the is_linter_error_suppressed as get_suppression_state($linter, $node, $root, /*is suppression allowed*/ true) === SuppressionState::SUPPRESSED.

I am not so sure about how I would change the signature of erroCodesToSuppress. Any suggestions?

lexidor avatar Sep 19 '22 18:09 lexidor

I would create a new linter to raise lint errors for markers not in the allow list, and let all other linters simply ignore markers not in the allow list.

Atry avatar Sep 19 '22 18:09 Atry

I would create a new linter to raise lint errors for markers not in the allow list, and let all other linters simply ignore markers not in the allow list.

That is a very interesting approach I had not considered before. That is a great idea! Thanks for your input. I will rework my PR.

If that new linter would be impossible to suppress, we'd already be done. That could be done by automatically adding DontUseSuppressionMarkersThatAreNotDeclaredInLintMarkerAllowListLinter to the lintMarkerAllowList, because that would cause and infinite suppression regression.

Then we barely have to change anything about suppression comment logic. We just need to defang HHAST_IGNORE_ALL for DontUseSuppressionMarkersThatAreNotDeclaredInLintMarkerAllowList.

// We just need to defang this IGNORE_ALL, since this would suppress itself.
/*HHAST_IGNORE_ALL[DontUseSuppressionMarkersThatAreNotDeclaredInLintMarkerAllowList]*/

// After that...
/*HHAST_FIXME[DontUseSuppressionMarkersThatAreNotDeclaredInLintMarkerAllowList]
  Oh wait, I can't, since it is turtles all the way down. */
/*HHAST_FIXME[DontUseSuppressionMarkersThatAreNotDeclaredInLintMarkerAllowList]
  Suppressing the don't use markers linter*/
/*HHAST_FIXME[DontUseSuppressionMarkersThatAreNotDeclaredInLintMarkerAllowList]
  Suppressing the don't suppress MustUseBracesForControlFlow linter */
/*HHAST_FIXME[MustUseBracesForControlFlow]*/
if ($xyzzy) return;

lexidor avatar Sep 19 '22 19:09 lexidor

Converting to draft, will redo using a new linter. DontUseSuppressionMarkersThatAreNotDeclaredInLintMarkerAllowListLinter is a placeholder name btw.

lexidor avatar Sep 19 '22 19:09 lexidor

Parking this PR, the idea will be implemented as a new linter instead.

lexidor avatar May 24 '23 14:05 lexidor