file_provider = new Provider\FakeFileProvider(); } /** * @param Config $config * * @return \Psalm\Internal\Analyzer\ProjectAnalyzer */ private function getProjectAnalyzerWithConfig(Config $config) { $project_analyzer = new \Psalm\Internal\Analyzer\ProjectAnalyzer( $config, new \Psalm\Internal\Provider\Providers( $this->file_provider, new Provider\FakeParserCacheProvider() ) ); $project_analyzer->setPhpVersion('7.3'); $config->setIncludeCollector(new IncludeCollector()); $config->visitComposerAutoloadFiles($project_analyzer, null); return $project_analyzer; } /** * @return void */ public function testNonexistentStubFile() { $this->expectException(\Psalm\Exception\ConfigException::class); $this->expectExceptionMessage('Cannot resolve stubfile path'); $this->project_analyzer = $this->getProjectAnalyzerWithConfig( Config::loadFromXML( dirname(__DIR__), ' ' ) ); } /** * @return void */ public function testStubFileClass() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'foo(5, "hello"); $c = \SystemClass::bar(5, "hello"); echo \SystemClass::HELLO;' ); $this->analyzeFile($file_path, new Context()); } /** * @param string $file * * @return string * * @psalm-pure */ private function getOperatingSystemStyledPath(string $file): string { return implode(DIRECTORY_SEPARATOR, explode('/', $file)); } /** * @return void */ public function testLoadStubFileWithRelativePath() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $path = $this->getOperatingSystemStyledPath('tests/fixtures/stubs/systemclass.php'); $stub_files = $this->project_analyzer->getConfig()->getStubFiles(); $this->assertStringContainsString($path, \reset($stub_files)); } /** * @return void */ public function testLoadStubFileWithAbsolutePath() { $runDir = dirname(__DIR__); $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( $runDir, ' ' ) ); $path = $this->getOperatingSystemStyledPath('tests/fixtures/stubs/systemclass.php'); $stub_files = $this->project_analyzer->getConfig()->getStubFiles(); $this->assertStringContainsString($path, \reset($stub_files)); } /** * @return void */ public function testStubFileConstant() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testPhpStormMetaParsingFile() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'creAte("object"); $a2 = (new \Ns\MyClass)->creaTe("exception"); $b1 = \Create("object"); $b2 = \cReate("exception"); $e2 = \creAte(\LogicException::class); $c1 = (new \Ns\MyClass)->foo(5); $c2 = (new \Ns\MyClass)->bar(["hello"]); $d1 = \foO(5); $d2 = \baR(["hello"]); }' ); $context = new Context(); $this->analyzeFile($file_path, $context); } /** * @return void */ public function testNamespacedStubClass() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'foo(5, "hello"); $c = Foo\SystemClass::bar(5, "hello"); echo Foo\BAR;' ); $this->analyzeFile($file_path, new Context()); } /** * @return void */ public function testStubRegularFunction() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testStubVariadicFunction() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testStubVariadicFunctionWrongArgType() { $this->expectExceptionMessage('InvalidScalarArgument'); $this->expectException(\Psalm\Exception\CodeException::class); $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testUserVariadicWithFalseVariadic() { $this->expectExceptionMessage('TooManyArguments'); $this->expectException(\Psalm\Exception\CodeException::class); $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void * @runInSeparateProcess */ public function testPolyfilledFunction() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void * @runInSeparateProcess */ public function testConditionalConstantDefined() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void * @runInSeparateProcess */ public function testClassAlias() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'foo; echo $a->bar("hello"); function f(): A { return new A; } function getAliased(): B { return f(); } $d = new D(); D::bat(); $d::bat(); class E implements IAlias {}' ); $this->analyzeFile($file_path, new Context()); } /** * @return void */ public function testStubFunctionWithFunctionExists() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testNamespacedStubFunctionWithFunctionExists() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testNoStubFunction() { $this->expectExceptionMessage('UndefinedFunction - /src/somefile.php:2:22 - Function barBar does not exist'); $this->expectException(\Psalm\Exception\CodeException::class); $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testNamespacedStubFunction() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testConditionalNamespacedStubFunction() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testConditionallyExtendingInterface() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'getMessage(); } function bar(I6 $d) : void { $d->getMessage(); } function bat(I7 $d) : void { $d->getMessage(); } function baz(I8 $d) : void { $d->getMessage(); }' ); $this->analyzeFile($file_path, new Context()); } /** * @return void */ public function testStubFileWithExistingClassDefinition() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testStubFileWithPartialClassDefinitionWithMoreMethods() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'foo(A::class); (new PartiallyStubbedClass())->bar(5);' ); $this->analyzeFile($file_path, new Context()); } /** * @return void */ public function testExtendOnlyStubbedClass() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'foo(A::class);' ); $this->analyzeFile($file_path, new Context()); } /** * @return void */ public function testStubFileWithExtendedStubbedClass() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testStubFileWithPartialClassDefinitionWithCoercion() { $this->expectExceptionMessage('TypeCoercion'); $this->expectException(\Psalm\Exception\CodeException::class); $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'foo("dasda");' ); $this->analyzeFile($file_path, new Context()); } /** * @return void */ public function testStubFileWithPartialClassDefinitionGeneralReturnType() { $this->expectExceptionMessage('InvalidReturnStatement'); $this->expectException(\Psalm\Exception\CodeException::class); $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } /** * @return void */ public function testStubFileWithTemplatedClassDefinitionAndMagicMethodOverride() { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context()); } public function testInheritedMethodUsedInStub() : void { $this->project_analyzer = $this->getProjectAnalyzerWithConfig( TestConfig::loadFromXML( dirname(__DIR__), ' ' ) ); $this->project_analyzer->getCodebase()->reportUnusedCode(); $vendor_file_path = getcwd() . '/vendor/vendor_class.php'; $this->addFile( $vendor_file_path, 'foo(); } }' ); $file_path = getcwd() . '/src/somefile.php'; $this->addFile( $file_path, 'analyzeFile($file_path, new Context(), false); $this->project_analyzer->consolidateAnalyzedData(); } }