A rule's output for file A can depend on the contents of file B (AddOverrideAttributeToOverriddenMethodsRector reads the parent, AddReturnTypeDeclarationBasedOnParentClassMethodRector and ReturnTypeFromStrictTypedCallRector read declarations in other files).
The cache stores A's verdict under a hash of A's own contents, so a change in B leaves the entry looking valid.
Reproduction, with AddOverrideAttributeToOverriddenMethodsRector alone:
class Base without foo(), class Child extends Base with foo().
- Run once - nothing to change, both files cached.
- Add
foo() to Base. Do not touch Child.
- Run again.
warm cache: [OK] Rector is done!
cold cache: + #[\Override] -> 1 file would have been changed
Same files on disk; the only difference is the cache. src/Caching holds no per-file dependency information, so nothing invalidates Child. The run is green, which makes this a silent false negative rather than a visible miss.
A rule's output for file A can depend on the contents of file B (
AddOverrideAttributeToOverriddenMethodsRectorreads the parent,AddReturnTypeDeclarationBasedOnParentClassMethodRectorandReturnTypeFromStrictTypedCallRectorread declarations in other files).The cache stores A's verdict under a hash of A's own contents, so a change in B leaves the entry looking valid.
Reproduction, with
AddOverrideAttributeToOverriddenMethodsRectoralone:class Basewithoutfoo(),class Child extends Basewithfoo().foo()toBase. Do not touchChild.warm cache: [OK] Rector is done!
cold cache:
+ #[\Override]-> 1 file would have been changedSame files on disk; the only difference is the cache.
src/Cachingholds no per-file dependency information, so nothing invalidatesChild. The run is green, which makes this a silent false negative rather than a visible miss.