Skip to content

Commit

Permalink
Init
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed May 27, 2024
1 parent 79c1569 commit cae46a1
Show file tree
Hide file tree
Showing 18 changed files with 115 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/code_analysis.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
# see https://github.com/shivammathur/setup-php
- uses: shivammathur/setup-php@v2
with:
php-version: 8.1
php-version: 8.2
coverage: none

# composer install cache - https://github.com/ramsey/composer-install
Expand Down
17 changes: 11 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
# Type Perfect

[![Downloads](https://img.shields.io/packagist/dt/tomasvotruba/type-perfect.svg?style=flat-square)](https://packagist.org/packages/tomasvotruba/type-perfect/stats)
[![Downloads](https://img.shields.io/packagist/dt/rector/type-perfect.svg?style=flat-square)](https://packagist.org/packages/rector/type-perfect/stats)

Set of rules for PHPStan used by Symplify projects

- See [Rules Overview](docs/rules_overview.md)
Next level type declaration check PHPStan rules.

<br>

## Install

```bash
composer requiretomasvotruba/type-perfect --dev
composer require rector/type-perfect --dev
```

*Note: Make sure you use [`phpstan/extension-installer`](https://github.com/phpstan/extension-installer#usage) to load necessary service configs.*

<br>

@todo enable by configuration
one at a time :) levels?

```yaml
parameters:
type_coverage:
narrow: false
no_mixed: false
no_falsy_return: false
```
Add sets one by one, fix what you find useful and ignore the rest.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ jobs:
- run: composer config --no-plugins allow-plugins.phpstan/extension-installer true

- run: composer require phpstan/phpstan phpstan/extension-installer --dev
- run: composer require tomasvotruba/type-perfect:dev-main --dev
- run: composer require rector/type-perfect:dev-main --dev


4 changes: 2 additions & 2 deletions build/target-repository/composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "tomasvotruba/type-perfect",
"name": "rector/type-perfect",
"type": "phpstan-extension",
"description": "Next level type declaration checks",
"license": "MIT",
Expand All @@ -16,7 +16,7 @@
"extra": {
"phpstan": {
"includes": [
"config/services.neon",
"config/extension.neon",
"config/rules.neon"
]
}
Expand Down
2 changes: 1 addition & 1 deletion build/target-repository/phpstan-for-tests.neon
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# this config is only for tests, it verifies all the rules are runnable
includes:
- vendor/tomasvotruba/type-perfect/config/rules.neon
- vendor/rector/type-perfect/config/rules.neon

parameters:
level: 4
Expand Down
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"name": "tomasvotruba/type-perfect",
"name": "rector/type-perfect",
"type": "phpstan-extension",
"description": "Next level type declaration checks",
"license": "MIT",
"require": {
"php": "^7.2|^8.0",
"php": "^8.2",
"phpstan/phpstan": "^1.11",
"webmozart/assert": "^1.11"
"webmozart/assert": "^1.11",
"nette/utils": "^4.0"
},
"require-dev": {
"nikic/php-parser": "^4.19",
Expand All @@ -31,7 +32,7 @@
"extra": {
"phpstan": {
"includes": [
"config/services.neon",
"config/extension.neon",
"config/rules.neon"
]
}
Expand Down
20 changes: 20 additions & 0 deletions config/services.neon → config/extension.neon
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
parametersSchema:
# see https://doc.nette.org/en/schema for configuration
type_perfect: structure([
narrow: bool()
no_mixed: bool()
no_falsy_return: bool()
])

# default parameters
parameters:
type_perfect:
narrow: false
no_mixed: false
no_falsy_return: false

services:
-
factory: Rector\TypePerfect\Configuration
arguments:
- %type_perfect%

- Rector\TypePerfect\NodeTraverser\SimpleCallableNodeTraverser
- Rector\TypePerfect\NodeFinder\ClassMethodNodeFinder
- Rector\TypePerfect\NodeFinder\MethodCallNodeFinder
Expand Down
1 change: 0 additions & 1 deletion config/rules.neon
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ rules:
- Rector\TypePerfect\Rules\NoArrayAccessOnObjectRule
- Rector\TypePerfect\Rules\NoIssetOnObjectRule


services:
# for NarrowPublicClassMethodParamTypeByCallerTypeRule
-
Expand Down
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
includes:
- config/services.neon
- config/extension.neon
- config/rules.neon

parameters:
Expand Down
31 changes: 31 additions & 0 deletions src/Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Rector\TypePerfect;

final readonly class Configuration
{
/**
* @param array<string, mixed> $parameters
*/
public function __construct(
private array $parameters
) {
}

public function isNarrowEnabled(): bool
{
return $this->parameters['narrow'] ?? false;
}

public function isNoMixedEnabled(): bool
{
return $this->parameters['no_mixed'] ?? false;
}

public function isNoFalsyReturnEnabled(): bool
{
return $this->parameters['no_falsy_return'] ?? false;
}
}
2 changes: 1 addition & 1 deletion src/Matcher/Collector/PublicClassMethodMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
final class PublicClassMethodMatcher
{
/**
* @var array<class-string>
* @var string[]
*/
private const SKIPPED_TYPES = ['PHPUnit\Framework\TestCase', 'Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator'];

Expand Down
2 changes: 1 addition & 1 deletion src/NodeFinder/MethodCallNodeFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

final class MethodCallNodeFinder
{
private NodeFinder $nodeFinder;
private readonly NodeFinder $nodeFinder;

public function __construct(
private readonly ReflectionParser $reflectionParser,
Expand Down
6 changes: 6 additions & 0 deletions src/Rules/NarrowPrivateClassMethodParamTypeRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use PHPStan\Type\Type;
use PHPStan\Type\UnionType;
use PHPStan\Type\VerbosityLevel;
use Rector\TypePerfect\Configuration;
use Rector\TypePerfect\NodeFinder\ClassMethodNodeFinder;
use Rector\TypePerfect\NodeFinder\MethodCallNodeFinder;

Expand All @@ -39,6 +40,7 @@ final class NarrowPrivateClassMethodParamTypeRule implements Rule
public const ERROR_MESSAGE = 'Parameter %d should use "%s" type as the only type passed to this method';

public function __construct(
private readonly Configuration $configuration,
private readonly MethodCallNodeFinder $methodCallNodeFinder,
private readonly ClassMethodNodeFinder $classMethodNodeFinder
) {
Expand All @@ -58,6 +60,10 @@ public function getNodeType(): string
*/
public function processNode(Node $node, Scope $scope): array
{
if (! $this->configuration->isNarrowEnabled()) {
return [];
}

$args = $node->getArgs();
if ($args === []) {
return [];
Expand Down
12 changes: 11 additions & 1 deletion src/Rules/NarrowPublicClassMethodParamTypeRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
use Rector\TypePerfect\Collector\ClassMethod\PublicClassMethodParamTypesCollector;
use Rector\TypePerfect\Collector\MethodCall\MethodCallArgTypesCollector;
use Rector\TypePerfect\Collector\MethodCallableNode\MethodCallableCollector;
use Rector\TypePerfect\Configuration;
use Rector\TypePerfect\Enum\Types\ResolvedTypes;

/**
* @see \Rector\TypePerfect\Tests\Rules\NarrowPublicClassMethodParamTypeByCallerTypeRule\NarrowPublicClassMethodParamTypeByCallerTypeRuleTest
* @see \Rector\TypePerfect\Tests\Rules\NarrowPublicClassMethodParamTypeRule\NarrowPublicClassMethodParamTypeRuleTest
*
* @implements Rule<CollectedDataNode>
*/
Expand All @@ -28,6 +29,11 @@ final class NarrowPublicClassMethodParamTypeRule implements Rule
*/
public const ERROR_MESSAGE = 'Parameters should have "%s" types as the only types passed to this method';

public function __construct(
private readonly Configuration $configuration
) {
}

/**
* @return class-string<Node>
*/
Expand All @@ -42,6 +48,10 @@ public function getNodeType(): string
*/
public function processNode(Node $node, Scope $scope): array
{
if (! $this->configuration->isNarrowEnabled()) {
return [];
}

$publicClassMethodCollector = $node->get(PublicClassMethodParamTypesCollector::class);

$classMethodReferenceToArgTypes = $this->resolveClassMethodReferenceToArgTypes($node);
Expand Down
8 changes: 7 additions & 1 deletion src/Rules/NoMixedMethodCallerRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\ErrorType;
use PHPStan\Type\MixedType;
use Rector\TypePerfect\Configuration;

/**
* @see \Rector\TypePerfect\Tests\Rules\NoMixedMethodCallerRule\NoMixedMethodCallerRuleTest
Expand All @@ -22,10 +23,11 @@ final class NoMixedMethodCallerRule implements Rule
/**
* @var string
*/
public const ERROR_MESSAGE = 'Mixed variable in a `%s->...()` method call can lead to false dead methods. Make sure the variable type is known';
public const ERROR_MESSAGE = 'Mixed variable in a `%s->...()` can skip important errors. Make sure the type is known';

public function __construct(
private readonly Standard $printerStandard,
private readonly Configuration $configuration,
) {
}

Expand All @@ -43,6 +45,10 @@ public function getNodeType(): string
*/
public function processNode(Node $node, Scope $scope): array
{
if (! $this->configuration->isNoMixedEnabled()) {
return [];
}

$callerType = $scope->getType($node->var);
if (! $callerType instanceof MixedType) {
return [];
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/NoMixedPropertyFetcherRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ final class NoMixedPropertyFetcherRule implements Rule
/**
* @var string
*/
public const ERROR_MESSAGE = 'Anonymous variables in a "%s->..." property fetch can lead to false dead property. Make sure the variable type is known';
public const ERROR_MESSAGE = 'Mixed property fetch in a "%s->..." can skip important errors. Make sure the type is known';

public function __construct(
private readonly Standard $standard,
Expand Down
16 changes: 14 additions & 2 deletions src/Rules/NoReturnFalseInNonBoolClassMethodRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
use PhpParser\NodeFinder;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\Constant\ConstantBooleanType;
use Rector\TypePerfect\Configuration;

/**
* @implements Rule<ClassMethod>
Expand All @@ -27,6 +29,7 @@ final class NoReturnFalseInNonBoolClassMethodRule implements Rule
private readonly NodeFinder $nodeFinder;

public function __construct(
private readonly Configuration $configuration,
) {
$this->nodeFinder = new NodeFinder();
}
Expand All @@ -41,10 +44,14 @@ public function getNodeType(): string

/**
* @param ClassMethod $node
* @retur string[]
* @retur RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
if (! $this->configuration->isNoMixedEnabled()) {
return [];
}

if ($node->stmts === null) {
return [];
}
Expand All @@ -70,7 +77,12 @@ public function processNode(Node $node, Scope $scope): array
continue;
}

return [self::ERROR_MESSAGE];
$ruleError = RuleErrorBuilder::message(self::ERROR_MESSAGE)
->line($return->getEndLine())
->identifier('type_perfect.no_return_false')
->build();

return [$ruleError];
}

return [];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
includes:
- ../../../../config/services.neon
- ../../../../config/extension.neon

rules:
- Rector\TypePerfect\Rules\NoMixedMethodCallerRule

0 comments on commit cae46a1

Please sign in to comment.