ResponseStatusCodeRector crashes on first-class callable of a method named assert*

クローズ 初心者向け
#9,954 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

関連するプルリクエストがすでにマージされています。

  • #1103 @TomasVotruba による — マージ済み

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
85/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
php, symfony
領域
tooling

調査の方向性

クラッシュは rules/CodeQuality/Rector/BinaryOp/ResponseStatusCodeRector.php で発生します。processMethodCall() は、assert で始まるすべてのメソッド名を processAssertMethodCall() に渡し、そこでは第一級 callable に対して getArgs() が呼び出されます。まずこの2つのメソッドを読み、その後、第一級 callable に対する早期リターンを追加してください。php -d zend.assertions=1 で issue 内の再現ファイルがエラーなくスキップされ、それをカバーするルールテスト用 fixture がある状態になれば完了です。

索引モデルが issue の本文から書いたものです。

説明

Bug Report

Subject Details
Rector version Rector 2.8.3 (also 2.5.7)

ResponseStatusCodeRector crashes when it visits a first-class callable whose method name starts with assert, for example $validator->assert(...). This is a common pattern with validation libraries such as PSL (Psl\Type\string()->assert(...)).

processMethodCall() sends every method call whose name starts with assert to processAssertMethodCall():

https://github.com/rectorphp/rector-symfony/blob/5e4e27ac2f9beb1ecdb268dddf5e7e5a3954cc0d/rules/CodeQuality/Rector/BinaryOp/ResponseStatusCodeRector.php#L107-L108

processAssertMethodCall() then calls getArgs() without a first-class callable check, and the php-parser assertion fails:

https://github.com/rectorphp/rector-symfony/blob/5e4e27ac2f9beb1ecdb268dddf5e7e5a3954cc0d/rules/CodeQuality/Rector/BinaryOp/ResponseStatusCodeRector.php#L179

[ERROR] Could not process "src/Example.php" file, due to:
        "System error: "assert(!$this->isPartialFunctionApplication())"

        Stack trace:
        #0 vendor/rector/rector/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php(50): assert()
        #1 vendor/rector/rector/vendor/rector/rector-symfony/rules/CodeQuality/Rector/BinaryOp/ResponseStatusCodeRector.php(155): PhpParser\Node\Expr\CallLike->getArgs()
        #2 vendor/rector/rector/vendor/rector/rector-symfony/rules/CodeQuality/Rector/BinaryOp/ResponseStatusCodeRector.php(105): Rector\Symfony\CodeQuality\Rector\BinaryOp\ResponseStatusCodeRector->processAssertMethodCall()
        #3 vendor/rector/rector/vendor/rector/rector-symfony/rules/CodeQuality/Rector/BinaryOp/ResponseStatusCodeRector.php(94): Rector\Symfony\CodeQuality\Rector\BinaryOp\ResponseStatusCodeRector->processMethodCall()

In Rector 2.5.7 the message is assert(!$this->isFirstClassCallable()). The crash needs zend.assertions = 1, which is the PHP CLI default in development setups.

Minimal PHP Code Causing Issue

<?php

final class Validator
{
    public function assert(mixed $value): string
    {
        return (string) $value;
    }
}

$validator = new Validator();
$values = array_map($validator->assert(...), ['a', 'b']);
<?php

use Rector\Config\RectorConfig;
use Rector\Symfony\CodeQuality\Rector\BinaryOp\ResponseStatusCodeRector;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/src'])
    ->withRules([ResponseStatusCodeRector::class]);

Run: php -d zend.assertions=1 vendor/bin/rector process --dry-run

Expected Behaviour

Rector should skip the node. A first-class callable has no arguments to inspect. A guard at the start of processMethodCall() would fix it. isPartialFunctionApplication() also covers first-class callables in the php-parser version that Rector 2.8.3 bundles:

if ($methodCall->isPartialFunctionApplication()) {
    return null;
}
主要言語
PHP
スター
10.5k
フォーク
742
PR マージ指標
30日以内にマージされた PR はありません

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

rectorphp/rector のほかの issue

rectorphp/rector の issue をすべて見る

似ている issue

PHP の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。