Skip to content

Commit

Permalink
Remove instanceof *Type checks
Browse files Browse the repository at this point in the history
  • Loading branch information
spaze committed Mar 5, 2023
1 parent 316a54a commit 3666e16
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 49 deletions.
47 changes: 23 additions & 24 deletions src/Calls/NewCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\Constant\ConstantStringType;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
use Spaze\PHPStan\Rules\Disallowed\RuleErrors\DisallowedRuleErrors;
Expand Down Expand Up @@ -62,39 +61,39 @@ public function getNodeType(): string
*/
public function processNode(Node $node, Scope $scope): array
{
$classNames = $names = $errors = [];
if ($node->class instanceof Name) {
$className = $node->class;
$classNames[] = $node->class;
} elseif ($node->class instanceof Expr) {
$type = $scope->getType($node->class);
if ($type instanceof ConstantStringType) {
$className = new Name($type->getValue());
foreach ($type->getConstantStrings() as $constantString) {
$classNames[] = new Name($constantString->getValue());
}
}
if (!isset($className)) {
if ($classNames === []) {
return [];
}

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

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

return $errors;
Expand Down
22 changes: 16 additions & 6 deletions src/Params/DisallowedCallParamValueCaseInsensitiveExcept.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

namespace Spaze\PHPStan\Rules\Disallowed\Params;

use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\ConstantScalarType;
use PHPStan\Type\Type;
use Spaze\PHPStan\Rules\Disallowed\Exceptions\UnsupportedParamTypeException;

Expand All @@ -19,12 +17,24 @@ class DisallowedCallParamValueCaseInsensitiveExcept extends DisallowedCallParamV
*/
public function matches(Type $type): bool
{
if (!$type instanceof ConstantScalarType) {
if (!$type->isConstantScalarValue()->yes()) {
throw new UnsupportedParamTypeException();
}
$a = is_string($this->getValue()) ? strtolower($this->getValue()) : $this->getValue();
$b = $type instanceof ConstantStringType ? strtolower($type->getValue()) : $type->getValue();
return $a !== $b;
$values = [];
foreach ($type->getConstantScalarValues() as $value) {
$values[] = $this->getLowercaseValue($value);
}
return !in_array($this->getLowercaseValue($this->getValue()), $values, true);
}


/**
* @param mixed $value
* @return mixed
*/
private function getLowercaseValue($value)
{
return is_string($value) ? strtolower($value) : $value;
}

}
5 changes: 2 additions & 3 deletions src/Params/DisallowedCallParamValueExcept.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

namespace Spaze\PHPStan\Rules\Disallowed\Params;

use PHPStan\Type\ConstantScalarType;
use PHPStan\Type\Type;
use Spaze\PHPStan\Rules\Disallowed\Exceptions\UnsupportedParamTypeException;

Expand All @@ -18,10 +17,10 @@ class DisallowedCallParamValueExcept extends DisallowedCallParamValue
*/
public function matches(Type $type): bool
{
if (!$type instanceof ConstantScalarType) {
if (!$type->isConstantScalarValue()->yes()) {
throw new UnsupportedParamTypeException();
}
return $this->getValue() !== $type->getValue();
return !in_array($this->getValue(), $type->getConstantScalarValues(), true);
}

}
5 changes: 2 additions & 3 deletions src/Params/DisallowedCallParamValueSpecific.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

namespace Spaze\PHPStan\Rules\Disallowed\Params;

use PHPStan\Type\ConstantScalarType;
use PHPStan\Type\Type;
use Spaze\PHPStan\Rules\Disallowed\Exceptions\UnsupportedParamTypeException;

Expand All @@ -18,10 +17,10 @@ class DisallowedCallParamValueSpecific extends DisallowedCallParamValue
*/
public function matches(Type $type): bool
{
if (!$type instanceof ConstantScalarType) {
if (!$type->isConstantScalarValue()->yes()) {
throw new UnsupportedParamTypeException();
}
return $this->getValue() === $type->getValue();
return [$this->getValue()] === $type->getConstantScalarValues();
}

}
10 changes: 8 additions & 2 deletions src/RuleErrors/DisallowedMethodRuleErrors.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use PHPStan\Analyser\Scope;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\TypeWithClassName;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\Type\TypeResolver;

Expand Down Expand Up @@ -50,7 +49,14 @@ public function get($class, CallLike $node, Scope $scope, array $disallowedCalls
$calledOnType = $this->typeResolver->getType($class, $scope);
if ($calledOnType->canCallMethods()->yes() && $calledOnType->hasMethod($node->name->name)->yes()) {
$method = $calledOnType->getMethod($node->name->name, $scope);
$calledAs = ($calledOnType instanceof TypeWithClassName ? $this->disallowedRuleErrors->getFullyQualified($calledOnType->getClassName(), $method) : null);
$classNames = $calledOnType->getObjectClassNames();
if (count($classNames) === 0) {
$calledAs = null;
} elseif (count($classNames) === 1) {
$calledAs = $this->disallowedRuleErrors->getFullyQualified($classNames[0], $method);
} else {
$calledAs = $this->disallowedRuleErrors->getFullyQualified('{' . implode(',', $classNames) . '}', $method);
}

foreach ($method->getDeclaringClass()->getTraits() as $trait) {
if ($trait->hasMethod($method->getName())) {
Expand Down
28 changes: 18 additions & 10 deletions src/Usages/ClassConstantUsages.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\TypeWithClassName;
use PHPStan\Type\VerbosityLevel;
use Spaze\PHPStan\Rules\Disallowed\DisallowedConstant;
use Spaze\PHPStan\Rules\Disallowed\DisallowedConstantFactory;
Expand Down Expand Up @@ -84,9 +83,14 @@ public function processNode(Node $node, Scope $scope): array
return [];
}

$displayName = ($usedOnType instanceof TypeWithClassName ? $this->getFullyQualified($usedOnType->getClassName(), $constant) : null);
if ($usedOnType instanceof ConstantStringType) {
$className = ltrim($usedOnType->getValue(), '\\');
$displayName = $usedOnType->getObjectClassNames() ? $this->getFullyQualified($usedOnType->getObjectClassNames(), $constant) : null;
if ($usedOnType->getConstantStrings()) {
$classNames = array_map(
function (ConstantStringType $constantString): string {
return ltrim($constantString->getValue(), '\\');
},
$usedOnType->getConstantStrings()
);
} else {
if ($usedOnType->hasConstant($constant)->no()) {
return [
Expand All @@ -97,18 +101,22 @@ public function processNode(Node $node, Scope $scope): array
))->build(),
];
} else {
$className = $usedOnType->getConstant($constant)->getDeclaringClass()->getDisplayName();
$classNames = [$usedOnType->getConstant($constant)->getDeclaringClass()->getDisplayName()];
}
}
$constant = $this->getFullyQualified($className, $constant);

return $this->disallowedConstantRuleErrors->get($constant, $scope, $displayName, $this->disallowedConstants);
return $this->disallowedConstantRuleErrors->get($this->getFullyQualified($classNames, $constant), $scope, $displayName, $this->disallowedConstants);
}


private function getFullyQualified(string $class, string $constant): string
/**
* @param non-empty-list<string> $classNames
* @param string $constant
* @return string
*/
private function getFullyQualified(array $classNames, string $constant): string
{
return "{$class}::{$constant}";
$className = count($classNames) === 1 ? $classNames[0] : '{' . implode(',', $classNames) . '}';
return $className . '::' . $constant;
}

}
2 changes: 1 addition & 1 deletion tests/Usages/ClassConstantUsagesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public function testRule(): void
23,
],
[
'Using PhpOption\Option::NAME is forbidden, no PhpOption',
'Using PhpOption\Option::NAME (as PhpOption\None::NAME) is forbidden, no PhpOption',
37,
],
]);
Expand Down

0 comments on commit 3666e16

Please sign in to comment.