Skip to content

Commit

Permalink
Child constructors should be disallowed when parent constructor or an…
Browse files Browse the repository at this point in the history
… interface is disallowed (#147)

Have to check parents and interfaces too

Close #146
  • Loading branch information
spaze authored Dec 26, 2022
2 parents 53c2903 + d55780c commit f1f319b
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 6 deletions.
41 changes: 35 additions & 6 deletions src/Calls/NewCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\ConstantScalarType;
use PHPStan\Type\Constant\ConstantStringType;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
use Spaze\PHPStan\Rules\Disallowed\DisallowedHelper;
Expand All @@ -24,6 +24,7 @@
*/
class NewCalls implements Rule
{
private const CONSTRUCT = '::__construct';

/** @var DisallowedHelper */
private $disallowedHelper;
Expand Down Expand Up @@ -61,13 +62,41 @@ public function getNodeType(): string
public function processNode(Node $node, Scope $scope): array
{
if ($node->class instanceof Name) {
$name = "{$node->class}::__construct";
} elseif ($node->class instanceof Expr && $scope->getType($node->class) instanceof ConstantScalarType) {
$name = $scope->getType($node->class)->getValue() . '::__construct';
} else {
$className = $node->class;
} elseif ($node->class instanceof Expr) {
$type = $scope->getType($node->class);
if ($type instanceof ConstantStringType) {
$className = new Name($type->getValue());
}
}
if (!isset($className)) {
return [];
}
return $this->disallowedHelper->getDisallowedMessage($node, $scope, $name, $name, $this->disallowedCalls);

$type = $scope->resolveTypeByName($className);
$names = [
$type->getClassName(),
];
$reflection = $type->getClassReflection();
if ($reflection) {
foreach ($reflection->getParents() as $parent) {
$names[] = $parent->getName();
}
foreach ($reflection->getInterfaces() as $interface) {
$names[] = $interface->getName();
}
}

$errors = [];
foreach ($names as $name) {
$name .= self::CONSTRUCT;
$errors = array_merge(
$errors,
$this->disallowedHelper->getDisallowedMessage($node, $scope, $name, $type->getClassName() . self::CONSTRUCT, $this->disallowedCalls)
);
}

return $errors;
}

}
12 changes: 12 additions & 0 deletions tests/Calls/NewCallsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ protected function getRule(): Rule
'../src/*-allow/*.*',
],
],
[
'method' => 'Inheritance\Base::__construct()',
'message' => 'all your base are belong to us',
'allowIn' => [
'../src/disallowed-allowed/*.php',
'../src/*-allow/*.*',
],
],
[
'function' => 'DateTime::__construct()',
'message' => 'no future',
Expand All @@ -55,6 +63,10 @@ public function testRule(): void
{
// Based on the configuration above, in this file:
$this->analyse([__DIR__ . '/../src/disallowed/methodCalls.php'], [
[
'Calling Inheritance\Base::__construct() (as Inheritance\Sub::__construct()) is forbidden, all your base are belong to us',
19,
],
[
'Calling Constructor\ClassWithConstructor::__construct() is forbidden, class ClassWithConstructor should not be created',
32,
Expand Down

0 comments on commit f1f319b

Please sign in to comment.