Skip to content

Path skips for post rectors (NameImportingPostRector) are ignored since 2.8.0 #9941

Closed
rectorphp/rector-src
#8884

Description

@ker0x

Bug Report

Subject Details
Rector version 2.8.1 (also 2.8.0; works in 2.7.0)

Since 2.8.0, skipping a post rector for some paths has no effect. A NameImportingPostRector path skip in withSkip() is ignored and names are still imported in the skipped files.

This looks like it comes from rectorphp/rector-src#8602: it removed the generic path check from PostFileProcessor::shouldSkipPostRector() right after #8598 narrowed Skipper::shouldSkipRectorAndFile() to Rector objects (post rectors are not):

     private function shouldSkipPostRector(PostRectorInterface $postRector, string $filePath, array $stmts): bool
     {
-        if ($this->skipper->shouldSkipRectorAndFile($postRector, $filePath)) {
-            return true;
-        }
-
         // skip renaming if rename class rector is skipped

Only ClassRenamingPostRector still checks the skipper (through RenameClassRector), so path skips for NameImportingPostRector, DocblockNameImportingPostRector, UseAddingPostRector and UnusedImportRemovingPostRector no longer apply.

Minimal PHP Code Causing Issue

The demo can't take a path skip, so here is a local reproduction.

rector.php:

<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
use Rector\Php80\Rector\Class_\StringableForToStringRector;
use Rector\PostRector\Rector\NameImportingPostRector;

return RectorConfig::configure()
    ->withPaths([__DIR__ . '/src'])
    ->withRules([StringableForToStringRector::class])
    ->withImportNames()
    ->withSkip([
        NameImportingPostRector::class => [__DIR__ . '/src/Foo.php'],
    ]);

src/Foo.php:

<?php

declare(strict_types=1);

namespace App;

final class Foo
{
    public function now(): \DateTimeImmutable
    {
        return new \DateTimeImmutable();
    }
}

vendor/bin/rector process --dry-run on 2.8.1:

 namespace App;
+use DateTimeImmutable;
+
 final class Foo
 {
-    public function now(): \DateTimeImmutable
+    public function now(): DateTimeImmutable
     {
-        return new \DateTimeImmutable();
+        return new DateTimeImmutable();
     }
 }

Expected Behaviour

src/Foo.php is skipped by NameImportingPostRector, so Rector reports no change, as in 2.7.0. Skipping name importing per path is the documented way to keep namespace-prefixed names (e.g. Field\TextField, Query\Parameter) in some files while importing names elsewhere.

Activity

  1. TomasVotruba commented on Oct 27, 2026

    @TomasVotruba
    Member

    The change is on purpose. This is a correction of previously leaking API.
    The skip shouldn't ever handle internal post rules that can change. Either use imports or not.

    What real issue you're trying to solve by this skip?

  2. ker0x commented on Oct 27, 2026

    @ker0x
    Author

    Thanks for the explanation. The use case is readability with libraries that group many short class names by namespace. In our search index schemas we write new Field\TextField(...), new Field\IntegerField(...), and in repositories and search builders new Query\Parameter(...) and new Condition\EqualCondition(...). The prefix shows at a glance which kind of class each one is, and TextField or Parameter alone is ambiguous next to other imports. We import names everywhere else.

    Is there a supported way to keep a partially qualified name like Field\TextField (imported namespace plus short name) instead of importing the class itself? Something like an option to leave names that already go through an imported namespace alias as they are would cover it without exposing post rectors to skips.

  3. TomasVotruba commented on Oct 27, 2026

    @TomasVotruba
    Member

    This would be useful feature for the class name import 👌
    E.g. ORM and Assert would benefit here too.

    Care to kick of PR? Could be a new ->withImportNames() method argument.

  4. ker0x commented on Oct 28, 2026

    @ker0x
    Author

    Opened rectorphp/rector-src#8884, which adds the withImportNames(importPartiallyQualifiedNames: false) argument you suggested. It keeps names like Field\TextField or ORM\Column as written.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions