This repository was archived by the owner on Dec 1, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathDontDiscardNewExpressionsLinter.hack
69 lines (57 loc) · 1.98 KB
/
DontDiscardNewExpressionsLinter.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
/*
* 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, Str};
final class DontDiscardNewExpressionsLinter extends ASTLinter {
const type TConfig = shape(?'exceptionSuffixes' => vec<string>);
const type TContext = Script;
const type TNode = ExpressionStatement;
const string BASE_MESSAGE = <<<'TEXT'
You are discarding the result of a `new` expression.
If you are intentionally discarding the newly created object,
consider assigning it to `$_` to communicate with your readers.
TEXT;
const string UNTHROWN_EXCEPTION =
'It looks like you are constructing an Exception. Did you intend to throw it?';
const string SIDE_EFFECTS_IN_CONSTRUCTOR_SMELL = <<<'TEXT'
If you are running this constructor for its side-effects,
consider restructuring that class / constructor.
A constructor is meant for creating objects, not for causing effects.
TEXT;
<<__Override>>
public function getLintErrorForNode(
Script $_context,
this::TNode $node,
): ?ASTLintError {
$expression = $node->getExpression();
if (!$expression is ObjectCreationExpression) {
return null;
}
$message = static::BASE_MESSAGE.
(
$this->isConstructingAnException($expression)
? static::UNTHROWN_EXCEPTION
: static::SIDE_EFFECTS_IN_CONSTRUCTOR_SMELL
);
return new ASTLintError($this, $message, $node);
}
private function isConstructingAnException(
ObjectCreationExpression $expression,
): bool {
$cls = $expression->getObject()->getType()->getLastToken()?->getText();
return $cls is nonnull &&
C\any(
$this->getExceptionSuffixes(),
$suffix ==> Str\ends_with($cls, $suffix),
);
}
private function getExceptionSuffixes(): vec<string> {
return $this->getConfig()['exceptionSuffixes'] ?? vec['Exception'];
}
}