From f660ff4f830224e836abb853466c678e09ca4e89 Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Sun, 31 Oct 2021 02:43:17 +0300 Subject: [PATCH 1/2] Move ForbiddenCode-related tests to the corresponding test file --- tests/Config/ConfigTest.php | 196 -------------------------------- tests/ForbiddenCodeTest.php | 219 ++++++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+), 196 deletions(-) diff --git a/tests/Config/ConfigTest.php b/tests/Config/ConfigTest.php index 8a948b499..14048db22 100644 --- a/tests/Config/ConfigTest.php +++ b/tests/Config/ConfigTest.php @@ -929,202 +929,6 @@ class ConfigTest extends \Psalm\Tests\TestCase $this->analyzeFile($file_path, new Context()); } - public function testAllowedEchoFunction(): void - { - $this->project_analyzer = $this->getProjectAnalyzerWithConfig( - TestConfig::loadFromXML( - dirname(__DIR__, 2), - ' - ' - ) - ); - - $file_path = getcwd() . '/src/somefile.php'; - - $this->addFile( - $file_path, - 'analyzeFile($file_path, new Context()); - } - - public function testForbiddenEchoFunctionViaFunctions(): void - { - $this->expectExceptionMessage('ForbiddenCode'); - $this->expectException(\Psalm\Exception\CodeException::class); - $this->project_analyzer = $this->getProjectAnalyzerWithConfig( - TestConfig::loadFromXML( - dirname(__DIR__, 2), - ' - - - - - ' - ) - ); - - $file_path = getcwd() . '/src/somefile.php'; - - $this->addFile( - $file_path, - 'analyzeFile($file_path, new Context()); - } - - public function testForbiddenEchoFunctionViaFlag(): void - { - $this->expectExceptionMessage('ForbiddenEcho'); - $this->expectException(\Psalm\Exception\CodeException::class); - $this->project_analyzer = $this->getProjectAnalyzerWithConfig( - TestConfig::loadFromXML( - dirname(__DIR__, 2), - ' - ' - ) - ); - - $file_path = getcwd() . '/src/somefile.php'; - - $this->addFile( - $file_path, - 'analyzeFile($file_path, new Context()); - } - - public function testAllowedPrintFunction(): void - { - $this->project_analyzer = $this->getProjectAnalyzerWithConfig( - TestConfig::loadFromXML( - dirname(__DIR__, 2), - ' - ' - ) - ); - - $file_path = getcwd() . '/src/somefile.php'; - - $this->addFile( - $file_path, - 'analyzeFile($file_path, new Context()); - } - - public function testForbiddenPrintFunction(): void - { - $this->expectExceptionMessage('ForbiddenCode'); - $this->expectException(\Psalm\Exception\CodeException::class); - $this->project_analyzer = $this->getProjectAnalyzerWithConfig( - TestConfig::loadFromXML( - dirname(__DIR__, 2), - ' - - - - - ' - ) - ); - - $file_path = getcwd() . '/src/somefile.php'; - - $this->addFile( - $file_path, - 'analyzeFile($file_path, new Context()); - } - - public function testAllowedVarExportFunction(): void - { - $this->project_analyzer = $this->getProjectAnalyzerWithConfig( - TestConfig::loadFromXML( - dirname(__DIR__, 2), - ' - ' - ) - ); - - $file_path = getcwd() . '/src/somefile.php'; - - $this->addFile( - $file_path, - 'analyzeFile($file_path, new Context()); - } - - public function testForbiddenVarExportFunction(): void - { - $this->expectExceptionMessage('ForbiddenCode'); - $this->expectException(\Psalm\Exception\CodeException::class); - $this->project_analyzer = $this->getProjectAnalyzerWithConfig( - TestConfig::loadFromXML( - dirname(__DIR__, 2), - ' - - - - - ' - ) - ); - - $file_path = getcwd() . '/src/somefile.php'; - - $this->addFile( - $file_path, - 'analyzeFile($file_path, new Context()); - } - - public function testForbiddenEmptyFunction(): void - { - $this->expectExceptionMessage('ForbiddenCode'); - $this->expectException(\Psalm\Exception\CodeException::class); - $this->project_analyzer = $this->getProjectAnalyzerWithConfig( - TestConfig::loadFromXML( - dirname(__DIR__, 2), - ' - - - - - ' - ) - ); - - $file_path = getcwd() . '/src/somefile.php'; - - $this->addFile( - $file_path, - 'analyzeFile($file_path, new Context()); - } - public function testValidThrowInvalidCatch(): void { $this->expectExceptionMessage('InvalidCatch'); diff --git a/tests/ForbiddenCodeTest.php b/tests/ForbiddenCodeTest.php index fca90a5fc..01e4dc86e 100644 --- a/tests/ForbiddenCodeTest.php +++ b/tests/ForbiddenCodeTest.php @@ -1,6 +1,14 @@ project_analyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__, 2), + ' + ' + ) + ); + + $file_path = getcwd() . '/src/somefile.php'; + + $this->addFile( + $file_path, + 'analyzeFile($file_path, new Context()); + } + + public function testForbiddenEchoFunctionViaFunctions(): void + { + $this->expectExceptionMessage('ForbiddenCode'); + $this->expectException(\Psalm\Exception\CodeException::class); + $this->project_analyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__, 2), + ' + + + + + ' + ) + ); + + $file_path = getcwd() . '/src/somefile.php'; + + $this->addFile( + $file_path, + 'analyzeFile($file_path, new Context()); + } + + public function testForbiddenEchoFunctionViaFlag(): void + { + $this->expectExceptionMessage('ForbiddenEcho'); + $this->expectException(\Psalm\Exception\CodeException::class); + $this->project_analyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__, 2), + ' + ' + ) + ); + + $file_path = getcwd() . '/src/somefile.php'; + + $this->addFile( + $file_path, + 'analyzeFile($file_path, new Context()); + } + + public function testAllowedPrintFunction(): void + { + $this->project_analyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__, 2), + ' + ' + ) + ); + + $file_path = getcwd() . '/src/somefile.php'; + + $this->addFile( + $file_path, + 'analyzeFile($file_path, new Context()); + } + + public function testForbiddenPrintFunction(): void + { + $this->expectExceptionMessage('ForbiddenCode'); + $this->expectException(\Psalm\Exception\CodeException::class); + $this->project_analyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__, 2), + ' + + + + + ' + ) + ); + + $file_path = getcwd() . '/src/somefile.php'; + + $this->addFile( + $file_path, + 'analyzeFile($file_path, new Context()); + } + + public function testAllowedVarExportFunction(): void + { + $this->project_analyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__, 2), + ' + ' + ) + ); + + $file_path = getcwd() . '/src/somefile.php'; + + $this->addFile( + $file_path, + 'analyzeFile($file_path, new Context()); + } + + public function testForbiddenVarExportFunction(): void + { + $this->expectExceptionMessage('ForbiddenCode'); + $this->expectException(\Psalm\Exception\CodeException::class); + $this->project_analyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__, 2), + ' + + + + + ' + ) + ); + + $file_path = getcwd() . '/src/somefile.php'; + + $this->addFile( + $file_path, + 'analyzeFile($file_path, new Context()); + } + + public function testForbiddenEmptyFunction(): void + { + $this->expectExceptionMessage('ForbiddenCode'); + $this->expectException(\Psalm\Exception\CodeException::class); + $this->project_analyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__, 2), + ' + + + + + ' + ) + ); + + $file_path = getcwd() . '/src/somefile.php'; + + $this->addFile( + $file_path, + 'analyzeFile($file_path, new Context()); + } + + private function getProjectAnalyzerWithConfig(Config $config): \Psalm\Internal\Analyzer\ProjectAnalyzer + { + $p = new \Psalm\Internal\Analyzer\ProjectAnalyzer( + $config, + new \Psalm\Internal\Provider\Providers( + $this->file_provider, + new Provider\FakeParserCacheProvider() + ) + ); + + $p->setPhpVersion('7.4'); + + return $p; + } } From ac098a52da7d54437d1dba468ecc4488fd454664 Mon Sep 17 00:00:00 2001 From: Bruce Weirdan Date: Sun, 31 Oct 2021 03:02:16 +0300 Subject: [PATCH 2/2] Allow to forbid `exit()` and `die()` --- .../Statements/Expression/ExitAnalyzer.php | 33 ++++++++++- tests/ForbiddenCodeTest.php | 57 +++++++++++++++++++ 2 files changed, 87 insertions(+), 3 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/ExitAnalyzer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/ExitAnalyzer.php index 4f442c7b6..a9cf6f617 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/ExitAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/ExitAnalyzer.php @@ -1,7 +1,7 @@ getProjectAnalyzer()->getConfig(); + + $forbidden = null; + + if (isset($config->forbidden_functions['exit']) + && $stmt->getAttribute('kind') === Exit_::KIND_EXIT + ) { + $forbidden = 'exit'; + } elseif (isset($config->forbidden_functions['die']) + && $stmt->getAttribute('kind') === Exit_::KIND_DIE + ) { + $forbidden = 'die'; + } + + if ($forbidden) { + if (IssueBuffer::accepts( + new ForbiddenCode( + 'You have forbidden the use of ' . $forbidden, + new CodeLocation($statements_analyzer, $stmt) + ), + $statements_analyzer->getSuppressedIssues() + )) { + // fall through + } + } + if ($stmt->expr) { $context->inside_call = true; @@ -91,7 +118,7 @@ class ExitAnalyzer && !$context->collect_initializations ) { if ($context->mutation_free || $context->external_mutation_free) { - $function_name = $stmt->getAttribute('kind') === PhpParser\Node\Expr\Exit_::KIND_DIE ? 'die' : 'exit'; + $function_name = $stmt->getAttribute('kind') === Exit_::KIND_DIE ? 'die' : 'exit'; if (IssueBuffer::accepts( new ImpureFunctionCall( diff --git a/tests/ForbiddenCodeTest.php b/tests/ForbiddenCodeTest.php index 01e4dc86e..a127b01f9 100644 --- a/tests/ForbiddenCodeTest.php +++ b/tests/ForbiddenCodeTest.php @@ -267,6 +267,63 @@ class ForbiddenCodeTest extends TestCase $this->analyzeFile($file_path, new Context()); } + public function testForbiddenExitFunction(): void + { + $this->expectExceptionMessage('ForbiddenCode'); + $this->expectException(\Psalm\Exception\CodeException::class); + $this->project_analyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__, 2), + ' + + + + + ' + ) + ); + + $file_path = getcwd() . '/src/somefile.php'; + + $this->addFile( + $file_path, + 'analyzeFile($file_path, new Context()); + } + + public function testForbiddenDieFunction(): void + { + $this->expectExceptionMessage('ForbiddenCode'); + $this->expectException(\Psalm\Exception\CodeException::class); + $this->project_analyzer = $this->getProjectAnalyzerWithConfig( + TestConfig::loadFromXML( + dirname(__DIR__, 2), + ' + + + + + ' + ) + ); + + $file_path = getcwd() . '/src/somefile.php'; + + $this->addFile( + $file_path, + 'analyzeFile($file_path, new Context()); + } + + private function getProjectAnalyzerWithConfig(Config $config): \Psalm\Internal\Analyzer\ProjectAnalyzer { $p = new \Psalm\Internal\Analyzer\ProjectAnalyzer(