Skip to content

[CodingStyle] Keep trait use adaptations in SeparateMultiUseImportsRector - #8510

Merged
TomasVotruba merged 1 commit into
rectorphp:mainfrom
calebdw:calebdw/separate-multi-use-imports-adaptations
Sep 21, 2026
Merged

TomasVotruba merged 1 commit into
rectorphp:mainfrom
calebdw:calebdw/separate-multi-use-imports-adaptations

Conversation

@calebdw

@calebdw calebdw commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

SeparateMultiUseImportsRector only carries Alias adaptations onto the split
statements, so every other adaptation is dropped together with the grouped
statement it sat on.

The one that hurts is insteadof:

class SomeClass
{
    use A, B {
        A::collide insteadof B;
    }
}

becomes

class SomeClass
{
    use A;
    use B;
}

Nothing is left to resolve the conflict, so the class no longer loads:

Trait method A::collide has not been applied as SomeClass::collide, because of collision with B::collide

An Alias that names no trait (exec as renamed;) is dropped just as silently,
taking the aliased method with it.

Fix

A Precedence adaptation now follows the trait it names, the same way an alias
already did — PHP accepts the adaptation on the winning trait's own statement:

use A {
    A::collide insteadof B;
}
use B;

Two kinds cannot follow a single trait, and for those the statement is left
alone rather than rewritten:

  • an adaptation naming no trait applies to all of the used traits
  • an adaptation naming a trait used in a different statement belongs to none
    of the ones being split, e.g. use A; use B, C { A::exec insteadof B; }

Tests

  • with_trait_use_precedence — the insteadof case above
  • skip_unqualified_trait_use_adaptation — adaptation naming no trait
  • skip_trait_use_adaptation_of_other_statement — adaptation naming a trait from another statement

The existing alias fixtures are unchanged.

…sRector

Splitting a grouped trait use only carried Alias adaptations across, so an
insteadof was dropped along with the statement it sat on:

    use A, B {
        A::collide insteadof B;
    }

became two plain uses with nothing left to resolve the conflict, and the
class could no longer be loaded at all. An alias naming no trait was
dropped just as silently, taking the aliased method with it.

Precedence adaptations now follow the trait they name, the same way an
alias already did. The two that cannot follow a single trait leave the
statement alone instead: one that names no trait applies to all of them,
and one that names a trait used in another statement belongs to none of
the ones being split.
@TomasVotruba

Copy link
Copy Markdown
Member

LGTM, thanks

@TomasVotruba
TomasVotruba merged commit 67fb3a0 into rectorphp:main Sep 21, 2026
45 checks passed
@calebdw
calebdw deleted the calebdw/separate-multi-use-imports-adaptations branch September 21, 2026 12:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants