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: public function getNodeType(): string
28: {
29: return Node\Stmt::class;
30: }
31:
32: public function processNode(Node $node, Scope $scope): array
33: {
34: if ($node instanceof Node\Stmt\If_) {
35: return $this->processExprCond($node->cond, 'an if');
36: }
37:
38: if ($node instanceof Node\Stmt\ElseIf_) {
39: return $this->processExprCond($node->cond, 'an elseif');
40: }
41:
42: if ($node instanceof Node\Stmt\While_) {
43: return $this->processExprCond($node->cond, 'a while');
44: }
45:
46: if ($node instanceof Node\Stmt\Do_) {
47: return $this->processExprCond($node->cond, 'a do-while');
48: }
49:
50: return [];
51: }
52:
53: /**
54: * @return list<IdentifierRuleError>
55: */
56: private function processExprCond(Node\Expr $cond, string $stmt): array
57: {
58: if ($cond instanceof Node\Expr\Assign) {
59: return [
60: RuleErrorBuilder::message(\sprintf(
61: 'Assignment inside %s condition is not allowed.',
62: $stmt,
63: ))
64: ->identifier('nexus.assignInCond')
65: ->line($cond->getStartLine())
66: ->build(),
67: ];
68: }
69:
70: if ($cond instanceof Node\Expr\AssignRef) {
71: return [
72: RuleErrorBuilder::message(\sprintf(
73: 'Assignment by reference inside %s condition is not allowed.',
74: $stmt,
75: ))
76: ->identifier('nexus.assignRefInCond')
77: ->line($cond->getStartLine())
78: ->build(),
79: ];
80: }
81:
82: if ($cond instanceof Node\Expr\AssignOp) {
83: if (
84: $cond instanceof Node\Expr\AssignOp\BitwiseAnd
85: || $cond instanceof Node\Expr\AssignOp\BitwiseOr
86: || $cond instanceof Node\Expr\AssignOp\BitwiseXor
87: || $cond instanceof Node\Expr\AssignOp\ShiftLeft
88: || $cond instanceof Node\Expr\AssignOp\ShiftRight
89: ) {
90: return [
91: RuleErrorBuilder::message(\sprintf(
92: 'Bitwise assignment inside %s condition is not allowed.',
93: $stmt,
94: ))
95: ->identifier('nexus.bitwiseAssignInCond')
96: ->line($cond->getStartLine())
97: ->build(),
98: ];
99: }
100:
101: if ($cond instanceof Node\Expr\AssignOp\Coalesce) {
102: return [
103: RuleErrorBuilder::message(\sprintf(
104: 'Null-coalesce assignment inside %s condition is not allowed.',
105: $stmt,
106: ))
107: ->identifier('nexus.nullCoalesceAssignInCond')
108: ->line($cond->getStartLine())
109: ->build(),
110: ];
111: }
112:
113: if ($cond instanceof Node\Expr\AssignOp\Concat) {
114: return [
115: RuleErrorBuilder::message(\sprintf(
116: 'Concatenation assignment inside %s condition is not allowed.',
117: $stmt,
118: ))
119: ->identifier('nexus.concatenationAssignInCond')
120: ->line($cond->getStartLine())
121: ->build(),
122: ];
123: }
124:
125: return [
126: RuleErrorBuilder::message(\sprintf(
127: 'Arithmetic assignment inside %s condition is not allowed.',
128: $stmt,
129: ))
130: ->identifier('nexus.arithmeticAssignInCond')
131: ->line($cond->getStartLine())
132: ->build(),
133: ];
134: }
135:
136: return [];
137: }
138: }
139: