file_provider = new Provider\FakeFileProvider(); } /** * @dataProvider providerFileCheckerValidCodeParse * * @param string $input_code * @param string $output_code * @param string $php_version * @param string[] $issues_to_fix * @param bool $safe_types * * @return void */ public function testValidCode($input_code, $output_code, $php_version, array $issues_to_fix, $safe_types) { $test_name = $this->getName(); if (strpos($test_name, 'PHP7-') !== false) { if (version_compare(PHP_VERSION, '7.0.0dev', '<')) { $this->markTestSkipped('Test case requires PHP 7.'); return; } } elseif (strpos($test_name, 'SKIPPED-') !== false) { $this->markTestSkipped('Skipped due to a bug.'); } $config = new TestConfig(); if (empty($issues_to_fix)) { $config->addPluginPath('examples/ClassUnqualifier.php'); } $this->project_checker = new \Psalm\Checker\ProjectChecker( $config, $this->file_provider, new Provider\FakeParserCacheProvider(), new \Psalm\Provider\NoCache\NoFileStorageCacheProvider(), new \Psalm\Provider\NoCache\NoClassLikeStorageCacheProvider() ); $context = new Context(); $file_path = self::$src_dir_path . 'somefile.php'; $this->addFile( $file_path, $input_code ); list($php_major_version, $php_minor_version) = explode('.', $php_version); $keyed_issues_to_fix = []; foreach ($issues_to_fix as $issue) { $keyed_issues_to_fix[$issue] = true; } $this->project_checker->setIssuesToFix($keyed_issues_to_fix); $this->project_checker->alterCodeAfterCompletion( (int) $php_major_version, (int) $php_minor_version, false, $safe_types ); $this->analyzeFile($file_path, $context); $this->project_checker->getCodebase()->analyzer->updateFile($file_path, false); $this->assertSame($output_code, $this->project_checker->getCodebase()->getFileContents($file_path)); } /** * @return array */ public function providerFileCheckerValidCodeParse() { return [ 'addMissingVoidReturnType56' => [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' "hello"] : ["a" => "goodbye", "b" => "hello again"]; }', ' "hello"] : ["a" => "goodbye", "b" => "hello again"]; }', '7.0', ['MissingReturnType'], true, ], 'addMissingObjectLikeReturnTypeSeparateStatements70' => [ ' "hello", "b" => "hello again"]; } if (rand(0, 1)) { return ["a" => "hello", "b" => "hello again"]; } return ["a" => "goodbye"]; }', ' "hello", "b" => "hello again"]; } if (rand(0, 1)) { return ["a" => "hello", "b" => "hello again"]; } return ["a" => "goodbye"]; }', '7.0', ['MissingReturnType'], true, ], 'addMissingStringArrayReturnTypeFromCall71' => [ ' */ function bar(): array { return foo(); }', '7.1', ['MissingReturnType'], true, ], 'addMissingDocblockStringArrayReturnTypeFromCall71' => [ ' */ function bar() { return foo(); }', '7.1', ['MissingReturnType'], true, ], 'addMissingNullableStringReturnType71' => [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ ' [ '