-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unused schema properties #42
Open
michal-efabrica
wants to merge
10
commits into
efabrica-team:main
Choose a base branch
from
michal-efabrica:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+493
−7
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
467d32d
Unused schema properties
michal-efabrica bff47aa
Unused schema properties
michal-efabrica 869a2ab
Unused schema properties
michal-efabrica 2f2991d
Unused schema properties
michal-efabrica 3eddea1
Unused schema properties
michal-efabrica 6d8a395
Unused schema properties
michal-efabrica c0adca3
Unused schema properties
michal-efabrica 3583926
Unused schema properties
michal-efabrica fb05200
Unused schema properties
michal-efabrica f5600e3
Unused schema properties
michal-efabrica File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Efabrica\PHPStanRules\Collector\Schema; | ||
|
||
use PhpParser\Node; | ||
use PhpParser\Node\Stmt\Class_; | ||
use PHPStan\Analyser\Scope; | ||
use PHPStan\Collectors\Collector; | ||
use ReflectionClass; | ||
use ReflectionMethod; | ||
|
||
/** | ||
* @implements Collector<Class_, array{string, bool, string, int}> | ||
*/ | ||
final class SchemaDefinitions implements Collector | ||
{ | ||
public function getNodeType(): string | ||
{ | ||
return Class_::class; | ||
} | ||
|
||
public function processNode(Node $node, Scope $scope): ?array | ||
{ | ||
if (!$node instanceof Class_) { | ||
return null; | ||
} | ||
|
||
/** @var class-string */ | ||
$className = !is_null($node->namespacedName) ? $node->namespacedName->toString() : ''; | ||
if (strpos($className, '\\Schema\\') !== false) { | ||
return null; | ||
} | ||
$reflectionClass = new ReflectionClass($className); | ||
$reflectionConstructor = $reflectionClass->hasMethod('__construct') ? $reflectionClass->getMethod('__construct') : null; | ||
$reflectionConstructorParameters = ($reflectionConstructor instanceof ReflectionMethod) ? $reflectionConstructor->getParameters() : null; | ||
|
||
$params = []; | ||
if (is_array($reflectionConstructorParameters) && count($reflectionConstructorParameters) > 0) { | ||
foreach ($reflectionConstructorParameters as $arg) { | ||
$tmp = []; | ||
$tmp['name'] = $arg->getName(); | ||
$tmp['type'] = (string) $arg->getType(); | ||
$tmp['key'] = $arg->getPosition(); | ||
|
||
$params[] = $tmp; | ||
} | ||
} | ||
if (empty($params)) { | ||
return null; | ||
} | ||
return [$className, $reflectionClass->isAbstract(), (string)json_encode($params), $node->getLine()]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Efabrica\PHPStanRules\Collector\Schema; | ||
|
||
use PhpParser\Node; | ||
use PhpParser\Node\Expr\Array_; | ||
use PhpParser\Node\Expr\New_; | ||
use PhpParser\Node\Name; | ||
use PHPStan\Analyser\Scope; | ||
use PHPStan\Collectors\Collector; | ||
|
||
/** | ||
* @implements Collector<New_, array{string, string, int}> | ||
*/ | ||
final class SchemaUsage implements Collector | ||
{ | ||
public function getNodeType(): string | ||
{ | ||
return New_::class; | ||
} | ||
|
||
public function processNode(Node $node, Scope $scope) | ||
{ | ||
if (!$node->class instanceof Name) { | ||
return null; | ||
} | ||
$className = $node->class->toCodeString(); | ||
if (strpos($className, '\\Schema\\') === false) { | ||
return null; | ||
} | ||
|
||
$params = []; | ||
foreach ($node->getArgs() as $key => $arg) { | ||
$tmp = []; | ||
if (!empty($arg->name)) { | ||
$tmp['name'] = $arg->name->name; | ||
} | ||
$tmp['key'] = $key; | ||
$tmp['type'] = get_class($arg->value); | ||
if ($arg->value instanceof Array_) { | ||
$tmp['aditional'] = count($arg->value->items); | ||
} | ||
if (strpos($tmp['type'], 'Scalar') !== false && property_exists($arg->value, 'value') && (is_numeric($arg->value->value) || is_string($arg->value->value))) { | ||
$tmp['aditional'] = $arg->value->value; | ||
} | ||
|
||
$params[] = $tmp; | ||
} | ||
if (empty($params)) { | ||
return null; | ||
} | ||
return [$node->class->toCodeString(), (string) json_encode($params), $node->getLine()]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Efabrica\PHPStanRules\Rule\Schema; | ||
|
||
use Efabrica\PHPStanRules\Collector\Schema\SchemaDefinitions; | ||
use Efabrica\PHPStanRules\Collector\Schema\SchemaUsage; | ||
use PhpParser\Node; | ||
use PHPStan\Analyser\Scope; | ||
use PHPStan\Node\CollectedDataNode; | ||
use PHPStan\Rules\Rule; | ||
use PHPStan\Rules\RuleErrorBuilder; | ||
|
||
/** | ||
* @implements Rule<CollectedDataNode> | ||
*/ | ||
final class NeverUsedProperties implements Rule | ||
{ | ||
/** | ||
* @var array<string, array{ | ||
* 0: string, | ||
* 1: bool, | ||
* 2: string, | ||
* 3: int, | ||
* attributes: array<int, string>, | ||
* file: string | ||
* }> | ||
*/ | ||
private array $schemaDefinitions = []; | ||
|
||
public function getNodeType(): string | ||
{ | ||
return CollectedDataNode::class; | ||
} | ||
|
||
public function processNode(Node $node, Scope $scope): array | ||
{ | ||
if (!$node instanceof CollectedDataNode) { | ||
return []; | ||
} | ||
$schemaUsage = $node->get(SchemaUsage::class); | ||
$this->schemaDefinitions = $this->convertSchemaDefinitions($node->get(SchemaDefinitions::class)); | ||
|
||
$warnings = []; | ||
foreach ($this->schemaDefinitions as $schemaName => $schemaData) { | ||
$schemaUse = $this->getSchemasUse($schemaUsage, $schemaName); | ||
$unusedProperties = $this->getUnusedProperties($schemaUse, $schemaName); | ||
if (count($unusedProperties) > 0) { | ||
$warnings[] = RuleErrorBuilder::message(sprintf( | ||
'Class "%s" contains never used properties "%s".', | ||
$schemaName, | ||
implode(',', $unusedProperties), | ||
)) | ||
->file($this->schemaDefinitions[trim($schemaName, '\\')]['file'])->line($this->schemaDefinitions[trim($schemaName, '\\')][3])->build(); | ||
} | ||
} | ||
|
||
return $warnings; | ||
} | ||
|
||
/** | ||
* @param array<string, array<int, array{0: string, 1: bool, 2: string, 3: int}>> $schemaDefinitions | ||
* | ||
* @return array<string, array{ | ||
* 0: string, | ||
* 1: bool, | ||
* 2: string, | ||
* 3: int, | ||
* attributes: array<int, string>, | ||
* file: string | ||
* }> | ||
*/ | ||
private function convertSchemaDefinitions(array $schemaDefinitions): array | ||
{ | ||
$result = []; | ||
foreach ($schemaDefinitions as $key => $value) { | ||
$tmp = $value[0]; | ||
$attributes = json_decode($tmp[2], true); | ||
$tmp['attributes'] = []; | ||
if (is_array($attributes)) { | ||
foreach ($attributes as $attribute) { | ||
$tmp['attributes'][(int) $attribute['key']] = (string) $attribute['name']; | ||
} | ||
} | ||
$tmp['file'] = $key; | ||
$result[$tmp[0]] = $tmp; | ||
} | ||
return $result; | ||
} | ||
|
||
/** | ||
* @param array<string, array<int, array{ | ||
* 0: string, | ||
* 1: string, | ||
* 2: int | ||
* }>> $schemaUsage | ||
* | ||
* @return array<int, array{ | ||
* 0: string, | ||
* 1: string, | ||
* 2: int | ||
* }> | ||
*/ | ||
private function getSchemasUse(array $schemaUsage, string $schemaName): array | ||
{ | ||
$tmp = []; | ||
foreach ($schemaUsage as $schemaArray) { | ||
foreach ($schemaArray as $schema) { | ||
if (trim($schema[0], '\\') === $schemaName) { | ||
$tmp[] = $schema; | ||
} | ||
} | ||
} | ||
return $tmp; | ||
} | ||
|
||
/** | ||
* @param array<int, array{ | ||
* 0: string, | ||
* 1: string, | ||
* 2: int | ||
* }> $schemas | ||
* | ||
* @return array<int, string> | ||
*/ | ||
private function getUnusedProperties(array $schemas, string $schemaName): array | ||
{ | ||
if (empty($schemas)) { | ||
return []; | ||
} | ||
$attributesArray = []; | ||
$result = []; | ||
foreach ($schemas as $schema) { | ||
$attributesArray[] = json_decode($schema[1], true); | ||
} | ||
|
||
foreach ($attributesArray as $attributes) { | ||
if (is_array($attributes)) { | ||
foreach ($attributes as $attribute) { | ||
$result[$attribute['key']] = true; | ||
} | ||
} | ||
} | ||
|
||
$return = []; | ||
foreach ($this->schemaDefinitions[trim($schemaName, '\\')]['attributes'] as $k => $r) { | ||
if (!isset($result[$k])) { | ||
$return[] = $r; | ||
} | ||
} | ||
return $return; | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pouzivas tu ext-random na nieco? plus pls prehod ext pod "php" a za to balicek phpstan
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tu random mi tam kázalo dat toto tu. Upravím to bez toho.