Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions rules/Php81/NodeManipulator/NullToStrictStringIntConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ public function convertIfNull(
return $funcCall;
}

// already cast to the target type on a previous run, re-casting would nest a redundant cast
if ($this->isAlreadyCastToTargetType($argValue, $targetType)) {
return null;
}

$wrapInParentheses = false;
if ($argValue instanceof Ternary && $argValue->cond instanceof CastString_) {
$wrapInParentheses = true;
Expand All @@ -118,6 +123,26 @@ public function convertIfNull(
return $funcCall;
}

/**
* Structural check (immune to stale resolved types on re-printed nodes): the value is already a
* cast/literal of the target type, or a ternary whose both branches are.
*/
private function isAlreadyCastToTargetType(Expr $expr, string $targetType): bool
{
if ($expr instanceof Ternary) {
// short ternary "A ?: B" keeps the left value in cond; full ternary uses if
$left = $expr->if ?? $expr->cond;
return $this->isAlreadyCastToTargetType($left, $targetType)
&& $this->isAlreadyCastToTargetType($expr->else, $targetType);
}

if ($targetType === 'string') {
return $expr instanceof CastString_ || $expr instanceof String_ || $expr instanceof InterpolatedString;
}

return $expr instanceof CastInt_ || $expr instanceof Int_;
}

private function shouldSkipValue(Expr $expr, Scope $scope, bool $isTrait, string $targetType): bool
{
// array dim fetch value is mixed, null is not known - skip to avoid wrong (string) cast
Expand Down
Loading