1: <?php
2:
3: declare(strict_types=1);
4:
5: /**
6: * This file is part of the Nexus framework.
7: *
8: * (c) John Paul E. Balandan, CPA <paulbalandan@gmail.com>
9: *
10: * For the full copyright and license information, please view
11: * the LICENSE file that was distributed with this source code.
12: */
13:
14: namespace Nexus\PHPStan\Rules\CleanCode;
15:
16: use PhpParser\Node;
17: use PHPStan\Analyser\Scope;
18: use PHPStan\Rules\IdentifierRuleError;
19: use PHPStan\Rules\Rule;
20: use PHPStan\Rules\RuleErrorBuilder;
21:
22: /**
23: * @implements Rule<Node\Stmt>
24: */
25: final class AssignExprInCondRule implements Rule
26: {
27: #[\Override]
28: public function getNodeType(): string
29: {
30: return Node\Stmt::class;
31: }
32:
33: #[\Override]
34: public function processNode(Node $node, Scope $scope): array
35: {
36: if ($node instanceof Node\Stmt\If_) {
37: return self::processExprCond($node->cond, 'an if');
38: }
39:
40: if ($node instanceof Node\Stmt\ElseIf_) {
41: return self::processExprCond($node->cond, 'an elseif');
42: }
43:
44: if ($node instanceof Node\Stmt\While_) {
45: return self::processExprCond($node->cond, 'a while');
46: }
47:
48: if ($node instanceof Node\Stmt\Do_) {
49: return self::processExprCond($node->cond, 'a do-while');
50: }
51:
52: return [];
53: }
54:
55: /**
56: * @return list<IdentifierRuleError>
57: */
58: private static function processExprCond(Node\Expr $cond, string $stmt): array
59: {
60: if ($cond instanceof Node\Expr\Assign) {
61: return [
62: RuleErrorBuilder::message(\sprintf(
63: 'Assignment inside %s condition is not allowed.',
64: $stmt,
65: ))
66: ->identifier('nexus.assignInCond')
67: ->line($cond->getStartLine())
68: ->build(),
69: ];
70: }
71:
72: if ($cond instanceof Node\Expr\AssignRef) {
73: return [
74: RuleErrorBuilder::message(\sprintf(
75: 'Assignment by reference inside %s condition is not allowed.',
76: $stmt,
77: ))
78: ->identifier('nexus.assignRefInCond')
79: ->line($cond->getStartLine())
80: ->build(),
81: ];
82: }
83:
84: if ($cond instanceof Node\Expr\AssignOp) {
85: if (
86: $cond instanceof Node\Expr\AssignOp\BitwiseAnd
87: || $cond instanceof Node\Expr\AssignOp\BitwiseOr
88: || $cond instanceof Node\Expr\AssignOp\BitwiseXor
89: || $cond instanceof Node\Expr\AssignOp\ShiftLeft
90: || $cond instanceof Node\Expr\AssignOp\ShiftRight
91: ) {
92: return [
93: RuleErrorBuilder::message(\sprintf(
94: 'Bitwise assignment inside %s condition is not allowed.',
95: $stmt,
96: ))
97: ->identifier('nexus.bitwiseAssignInCond')
98: ->line($cond->getStartLine())
99: ->build(),
100: ];
101: }
102:
103: if ($cond instanceof Node\Expr\AssignOp\Coalesce) {
104: return [
105: RuleErrorBuilder::message(\sprintf(
106: 'Null-coalesce assignment inside %s condition is not allowed.',
107: $stmt,
108: ))
109: ->identifier('nexus.nullCoalesceAssignInCond')
110: ->line($cond->getStartLine())
111: ->build(),
112: ];
113: }
114:
115: if ($cond instanceof Node\Expr\AssignOp\Concat) {
116: return [
117: RuleErrorBuilder::message(\sprintf(
118: 'Concatenation assignment inside %s condition is not allowed.',
119: $stmt,
120: ))
121: ->identifier('nexus.concatenationAssignInCond')
122: ->line($cond->getStartLine())
123: ->build(),
124: ];
125: }
126:
127: return [
128: RuleErrorBuilder::message(\sprintf(
129: 'Arithmetic assignment inside %s condition is not allowed.',
130: $stmt,
131: ))
132: ->identifier('nexus.arithmeticAssignInCond')
133: ->line($cond->getStartLine())
134: ->build(),
135: ];
136: }
137:
138: return [];
139: }
140: }
141: