file_provider = new Provider\FakeFileProvider(); } /** * @dataProvider providerValidCodeParse * * @param array $methods_to_move * @param array $call_transforms * */ public function testValidCode( string $input_code, string $output_code, array $methods_to_move ): void { $test_name = $this->getTestName(); if (strpos($test_name, 'SKIPPED-') !== false) { $this->markTestSkipped('Skipped due to a bug.'); } $config = new TestConfig(); $this->project_analyzer = new \Psalm\Internal\Analyzer\ProjectAnalyzer( $config, new \Psalm\Internal\Provider\Providers( $this->file_provider, new Provider\FakeParserCacheProvider() ) ); $context = new Context(); $file_path = self::$src_dir_path . 'somefile.php'; $this->addFile( $file_path, $input_code ); $codebase = $this->project_analyzer->getCodebase(); $this->project_analyzer->refactorCodeAfterCompletion($methods_to_move); $this->analyzeFile($file_path, $context); $this->project_analyzer->prepareMigration(); $codebase->analyzer->updateFile($file_path, false); $this->project_analyzer->migrateCode(); $this->assertSame($output_code, $codebase->getFileContents($file_path)); } /** * @return array}> */ public function providerValidCodeParse(): array { return [ 'moveSimpleStaticMethodWithForeachIterator' => [ ' */ public static function Foo() { return new ArrayObject([1, 2, 3]); } } class B { public static function bar() : void { A::Foo(); foreach (A::Foo() as $f) {} } }', ' */ public static function Fe() { return new ArrayObject([1, 2, 3]); } }', [ 'Ns\A::Foo' => 'Ns\B::Fe', ], ], 'moveSimpleStaticMethodWithConstant' => [ ' 'Ns\B::Fe', ], ], 'moveSimpleStaticMethodWithProperty' => [ ' 'Ns\B::Fe', ], ], 'moveStaticMethodIntoNamespaceWithExistingUse' => [ ' 'Ns\A\B::Fedcba', ], ], 'moveEmptyStaticMethodOnly' => [ ' 'Ns\B::Fedcba', ], ], 'moveStaticMethodOnly' => [ ' $a3 * @return self */ public static function Foo(self $a1, ?self $a2, array $a3) : self { echo self::C; echo A::C; self::Bar(); A::Bar(); echo \Ns\B::D; new A(); /** @var self */ $a = new self(); new B(); return $a; } public static function Bar() : void {} } class B { const D = 5; }', ' $a3 * @return A */ public static function Fedbca(A $a1, ?A $a2, array $a3) : A { echo A::C; echo A::C; A::Bar(); A::Bar(); echo B::D; new A(); /** @var A */ $a = new A(); new B(); return $a; } }', [ 'Ns\A::Foo' => 'Ns\B::Fedbca', ], ], 'moveTwoStaticMethods' => [ ' $a3 * @return self */ public static function Foo(self $a1, ?self $a2, array $a3) : self { echo self::C; echo A::C; self::Bar(); A::Bar(); echo \Ns\B::D; new A(); /** @var self */ $a = new self(); new B(); return $a; } public static function Bar() : void {} } class B { const D = 5; }', ' $a3 * @return A */ public static function Fedbca(A $a1, ?A $a2, array $a3) : A { echo A::C; echo A::C; self::Blacksheep(); B::Blacksheep(); echo B::D; new A(); /** @var A */ $a = new A(); new B(); return $a; } public static function Blacksheep() : void {} }', [ 'Ns\A::Foo' => 'Ns\B::Fedbca', 'Ns\A::Bar' => 'Ns\B::Blacksheep', ], ], 'moveInstanceMethodIntoSubclassOnly' => [ ' $a3 * @return self */ public function Foo(self $a1, ?self $a2, array $a3) : self { echo self::C; echo A::C; $this->Bar(); A::Bar(); echo \Ns\AChild::D; new A(); /** @var self */ $a = new self(); new AChild(); return $a; } public function Bar() : void {} } class AChild extends A { const D = 5; }', ' $a3 * @return A */ public function Fedbca(A $a1, ?A $a2, array $a3) : A { echo A::C; echo A::C; $this->Bar(); A::Bar(); echo AChild::D; new A(); /** @var A */ $a = new A(); new AChild(); return $a; } }', [ 'Ns\A::Foo' => 'Ns\AChild::Fedbca', ], ], 'moveStaticMethodAndReferencesFromAbove' => [ ' 'Ns\B::Fe', ], ], 'moveStaticMethodAndReferencesFromBelow' => [ ' 'Ns\B::Fe', ], ], 'moveStaticMethodAndReferencesAcrossNamespaces' => [ ' 'Ns2\Ns3\B::Fe', ], ], 'moveStaticMethodAndReferencesAcrossNamespacesWithExistingUse' => [ ' 'Ns2\Ns3\B::Fedcba', ], ], 'renameInstanceMethod' => [ ' */ public function Foo() { return new ArrayObject([self::C]); } public function bat() { $this->foo(); } } class B extends A { public static function bar(A $a) : void { $a->Foo(); $this->foo(); parent::foo(); foreach ($a->Foo() as $f) {} } }', ' */ public function Fedcba() { return new ArrayObject([self::C]); } public function bat() { $this->Fedcba(); } } class B extends A { public static function bar(A $a) : void { $a->Fedcba(); $this->Fedcba(); parent::Fedcba(); foreach ($a->Fedcba() as $f) {} } }', [ 'Ns\A::foo' => 'Ns\A::Fedcba', ], ], ]; } }