forked from hhvm/hhast
-
Notifications
You must be signed in to change notification settings - Fork 0
/
NoNewlineAtStartOfControlFlowBlockLinter.hack
71 lines (61 loc) · 2.05 KB
/
NoNewlineAtStartOfControlFlowBlockLinter.hack
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
/*
* 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;
use namespace HH\Lib\{C, Vec};
class NoNewlineAtStartOfControlFlowBlockLinter extends AutoFixingASTLinter {
const type TNode = IControlFlowStatement;
const type TContext = Script;
<<__Override>>
public function getLintErrorForNode(
Script $_context,
IControlFlowStatement $node,
): ?ASTLintError {
$body = control_flow_statement_get_body_like($node);
if (!$body is CompoundStatement) {
return null;
}
$left_brace = $body->getLeftBrace();
$next_token = $this->getAST()->getNextToken($left_brace);
if ($next_token is null) {
return null;
}
$next_leading = $next_token->getLeading()->toVec();
if (!C\first($next_leading) is EndOfLine) {
return null;
}
$seen_eol = C\last($left_brace->getTrailing()->toVec()) is EndOfLine;
// The AST tends to be structured in such a way that the trivia
// after the `{` including the newline is part of the `{`.
// If this were to change in the future,
// expect two newlines before the next token.
if ($seen_eol) {
return new ASTLintError(
$this,
"Don't start control flow blocks with a newline.",
$next_token,
() ==> self::stripLeadingEols($next_leading)
|> $next_token->withLeading(new NodeList($$)),
);
} else if (idx($next_leading, 1) is EndOfLine) {
return new ASTLintError(
$this,
"Don't start control flow blocks with a newline.",
$next_token,
() ==> self::stripLeadingEols($next_leading)
|> Vec\concat(vec[$next_leading[0]], $$)
|> $next_token->withLeading(new NodeList($$)),
);
}
return null;
}
private static function stripLeadingEols(vec<Trivia> $trivia): vec<Trivia> {
return C\find_key($trivia, $n ==> !$n is EndOfLine)
|> Vec\slice($trivia, $$ as nonnull);
}
}