forked from hhvm/hhast
-
Notifications
You must be signed in to change notification settings - Fork 0
/
suppress_ast_linter_error.php
130 lines (114 loc) · 3.21 KB
/
suppress_ast_linter_error.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<?hh // strict
/*
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
namespace Facebook\HHAST\Linters\SuppressASTLinter;
use type Facebook\HHAST\{
BreakStatement,
ContinueStatement,
EchoStatement,
EditableNode,
EditableToken,
GotoStatement,
IControlFlowStatement,
ReturnStatement,
ThrowStatement,
TryStatement,
UnsetStatement
};
use type Facebook\HHAST\Linters\{
BaseLinter,
LintError,
};
use namespace HH\Lib\{C, Str, Vec};
/**
* Allow users to suppress specific cases where a linter is used.
**/
function is_linter_error_suppressed(
BaseLinter $linter,
EditableNode $node,
vec<EditableNode> $parents,
LintError $_error,
): bool {
$token = $node->getFirstToken();
$fixme = $linter->getFixmeMarker();
$ignore = $linter->getIgnoreSingleErrorMarker();
return is_linter_suppressed_in_current_node($token, $fixme, $ignore) ||
is_linter_suppressed_in_sibling_node($parents, $fixme, $ignore) ||
is_linter_suppressed_up_to_statement($parents, $fixme, $ignore);
}
// Check the current token's leading trivia. For example a comment on the line before
function is_linter_suppressed_in_current_node(
?EditableToken $token,
string $fixme,
string $ignore,
): bool {
if ($token === null) {
return false;
}
$leading = $token->getLeading()->getCode();
return Str\contains($leading, $fixme) || Str\contains($leading, $ignore);
}
// Check sibling node as the comment might be attached there instead of on the current node
function is_linter_suppressed_in_sibling_node(
vec<EditableNode> $parents,
string $fixme,
string $ignore,
): bool {
$parent = C\last($parents);
if ($parent === null) {
return false;
}
$sibling = C\first($parent->getChildren());
if ($sibling === null) {
return false;
}
$token = $sibling->getLastToken();
if ($token !== null) {
$trailing = $token->getTrailing()->getCode();
if (Str\contains($trailing, $fixme) || Str\contains($trailing, $ignore)) {
return true;
}
$leading = $token->getLeading()->getCode();
if (Str\contains($leading, $fixme) || Str\contains($leading, $ignore)) {
return true;
}
}
return false;
}
// Walk up the parents and check the leading trivia until we hit a Statement type node.
function is_linter_suppressed_up_to_statement(
vec<EditableNode> $parents,
string $fixme,
string $ignore,
): bool {
$parents = Vec\reverse($parents);
foreach ($parents as $parent) {
if (
$parent instanceof IControlFlowStatement ||
$parent instanceof BreakStatement ||
$parent instanceof ContinueStatement ||
$parent instanceof EchoStatement ||
$parent instanceof GotoStatement ||
$parent instanceof ReturnStatement ||
$parent instanceof ThrowStatement ||
$parent instanceof TryStatement ||
$parent instanceof UnsetStatement
) {
return false;
}
$token = $parent->getFirstToken();
if ($token !== null) {
$leading = $token->getCode();
if (Str\contains($leading, $fixme) || Str\contains($leading, $ignore)) {
return true;
}
}
}
return false;
}