From 59dc239c891878cd7bdc176bee4c48e67ec7845f Mon Sep 17 00:00:00 2001 From: Matthew Brown Date: Sat, 17 Feb 2018 18:53:02 -0500 Subject: [PATCH] Fix #522 - prevent interface instantiation --- config.xsd | 1 + docs/issues.md | 9 +++++++++ .../Statements/Expression/Call/NewChecker.php | 17 ++++++++++++++++- tests/InterfaceTest.php | 6 ++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/config.xsd b/config.xsd index c8075b423..765a19cc0 100644 --- a/config.xsd +++ b/config.xsd @@ -107,6 +107,7 @@ + diff --git a/docs/issues.md b/docs/issues.md index a07557ad6..7c9cf513c 100644 --- a/docs/issues.md +++ b/docs/issues.md @@ -251,6 +251,15 @@ class A { echo (new A)->foo(); ``` +### InterfaceInstantiation + +Emitted when an attempt is made to instatiate an interface: + +```php +interface I {} +new I(); +``` + ### InaccessibleProperty Emitted when attempting to access a protected/private property from outside its available scope diff --git a/src/Psalm/Checker/Statements/Expression/Call/NewChecker.php b/src/Psalm/Checker/Statements/Expression/Call/NewChecker.php index e6d111ee6..2fbd33ca0 100644 --- a/src/Psalm/Checker/Statements/Expression/Call/NewChecker.php +++ b/src/Psalm/Checker/Statements/Expression/Call/NewChecker.php @@ -11,6 +11,7 @@ use Psalm\CodeLocation; use Psalm\Context; use Psalm\Issue\AbstractInstantiation; use Psalm\Issue\DeprecatedClass; +use Psalm\Issue\InterfaceInstantiation; use Psalm\Issue\TooManyArguments; use Psalm\IssueBuffer; use Psalm\Type; @@ -59,6 +60,20 @@ class NewChecker extends \Psalm\Checker\Statements\Expression\CallChecker ) === false) { return false; } + + if ($codebase->interfaceExists($fq_class_name)) { + if (IssueBuffer::accepts( + new InterfaceInstantiation( + 'Interface ' . $fq_class_name . ' cannot be instantiated', + new CodeLocation($statements_checker->getSource(), $stmt->class) + ), + $statements_checker->getSuppressedIssues() + )) { + return false; + } + + return null; + } } } else { switch ($stmt->class->parts[0]) { @@ -106,7 +121,7 @@ class NewChecker extends \Psalm\Checker\Statements\Expression\CallChecker if (strtolower($fq_class_name) !== 'stdclass' && $context->check_classes && - $codebase->classExists($fq_class_name) + $codebase->classlikes->classExists($fq_class_name) ) { $storage = $project_checker->classlike_storage_provider->get($fq_class_name); diff --git a/tests/InterfaceTest.php b/tests/InterfaceTest.php index 8da595bf1..00d05d905 100644 --- a/tests/InterfaceTest.php +++ b/tests/InterfaceTest.php @@ -574,6 +574,12 @@ class InterfaceTest extends TestCase }', 'error_message' => 'InvalidReturnType', ], + 'interfaceInstantiation' => [ + ' 'InterfaceInstantiation', + ], ]; } }