diff --git a/README.md b/README.md
index 817eba359dcd..c09866bd1d6c 100644
--- a/README.md
+++ b/README.md
@@ -65,11 +65,9 @@ It supports all versions of PHP from 5.2 and many open-source projects:
## How to Apply Coding Standards?
-The AST libraries that Rector uses aren't well-suited for coding standards, so it's better to let coding standard tools do that.
+Rector uses [nikic/php-parser](https://github.com/nikic/PHP-Parser/), that build on technology called *abstract syntax tree*) technology* (AST). AST doesn't care about spaces and produces mall-formatted code. That's why your project needs to have coding standard tool and set of rules, so it can make refactored nice and shiny again.
-Don't have a coding standard tool for your project? Consider adding [EasyCodingStandard](https://github.com/Symplify/EasyCodingStandard), [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) or [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer).
-
-*Tip: If you have EasyCodingStandard, you can start your set with [`ecs-after-rector.yaml`](/ecs-after-rector.yaml).*
+Don't have any coding standard tool? Add [EasyCodingStandard](https://github.com/Symplify/EasyCodingStandard) and use prepared [`ecs-after-rector.yaml`](/ecs-after-rector.yaml) set.
## Install
diff --git a/phpstan.neon b/phpstan.neon
index 8c5584530577..c98a76e222df 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -252,3 +252,8 @@ parameters:
- '#Class (.*?) should be written with \:\:class notation, string found#'
- '#Parameter \#2 \$key of method Rector\\BetterPhpDocParser\\PhpDocNode\\AbstractTagValueNode\:\:printArrayItem\(\) expects string\|null, int\|string given#'
- '#Method Rector\\Naming\\Naming\\PropertyNaming\:\:resolveShortClassName\(\) should return string but returns string\|null#'
+
+ -
+ message: "#^Class \"Rector\\\\PSR4\\\\Rector\\\\Namespace_\\\\NormalizeNamespaceByPSR4ComposerAutoloadRector\" is missing @see annotation with test case class reference$#"
+ count: 1
+ path: rules/psr4/src/Rector/Namespace_/NormalizeNamespaceByPSR4ComposerAutoloadRector.php
diff --git a/phpunit.xml b/phpunit.xml
index 9e8a7f538349..07cc31ff3005 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -13,6 +13,7 @@
rules/*/tests
packages/*/tests
tests
+ utils/*/tests
diff --git a/rules/nette-tester-to-phpunit/src/Rector/StaticCall/NetteAssertToPHPUnitAssertRector.php b/rules/nette-tester-to-phpunit/src/Rector/StaticCall/NetteAssertToPHPUnitAssertRector.php
index 13e098ad73a0..a64119ff59f4 100644
--- a/rules/nette-tester-to-phpunit/src/Rector/StaticCall/NetteAssertToPHPUnitAssertRector.php
+++ b/rules/nette-tester-to-phpunit/src/Rector/StaticCall/NetteAssertToPHPUnitAssertRector.php
@@ -11,6 +11,9 @@
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\NetteTesterToPHPUnit\AssertManipulator;
+/**
+ * @see \Rector\NetteTesterToPHPUnit\Tests\Rector\Class_\NetteTesterClassToPHPUnitClassRector\NetteTesterPHPUnitRectorTest
+ */
final class NetteAssertToPHPUnitAssertRector extends AbstractRector
{
/**
diff --git a/rules/oxid/src/Rector/FuncCall/OxidReplaceBackwardsCompatabilityClassRector.php b/rules/oxid/src/Rector/FuncCall/OxidReplaceBackwardsCompatabilityClassRector.php
index 039b86c99a23..d610476a5bd1 100644
--- a/rules/oxid/src/Rector/FuncCall/OxidReplaceBackwardsCompatabilityClassRector.php
+++ b/rules/oxid/src/Rector/FuncCall/OxidReplaceBackwardsCompatabilityClassRector.php
@@ -15,6 +15,9 @@
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
+/**
+ * @see \Rector\Oxid\Tests\Rector\FuncCall\OxidReplaceBackwardsCompatabilityClassRector\OxidReplaceBackwardsCompatabilityClassRectorTest
+ */
final class OxidReplaceBackwardsCompatabilityClassRector extends AbstractRector
{
/**
diff --git a/rules/php72/src/Rector/Each/ListEachRector.php b/rules/php72/src/Rector/Each/ListEachRector.php
index 4d8ff51cd5aa..94bea7a46027 100644
--- a/rules/php72/src/Rector/Each/ListEachRector.php
+++ b/rules/php72/src/Rector/Each/ListEachRector.php
@@ -18,6 +18,8 @@
/**
* @source https://wiki.php.net/rfc/deprecations_php_7_2#each
+ *
+ * @see \Rector\Php72\Tests\Rector\Each\EachRectorTest
*/
final class ListEachRector extends AbstractRector
{
diff --git a/rules/php72/src/Rector/Each/WhileEachToForeachRector.php b/rules/php72/src/Rector/Each/WhileEachToForeachRector.php
index 4fc0dca3d5d8..1d83032d33d6 100644
--- a/rules/php72/src/Rector/Each/WhileEachToForeachRector.php
+++ b/rules/php72/src/Rector/Each/WhileEachToForeachRector.php
@@ -18,6 +18,8 @@
/**
* @source https://wiki.php.net/rfc/deprecations_php_7_2#each
+ *
+ * @see \Rector\Php72\Tests\Rector\Each\EachRectorTest
*/
final class WhileEachToForeachRector extends AbstractRector
{
diff --git a/rules/psr4/config/config.yaml b/rules/psr4/config/config.yaml
index d8fb38901f0b..6300c1432bec 100644
--- a/rules/psr4/config/config.yaml
+++ b/rules/psr4/config/config.yaml
@@ -2,6 +2,7 @@ services:
_defaults:
public: true
autowire: true
+ autoconfigure: true
Rector\PSR4\:
resource: '../src'
diff --git a/rules/sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php b/rules/sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php
index d82b682a46d5..37a160e6a3f3 100644
--- a/rules/sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php
+++ b/rules/sensio/src/Rector/FrameworkExtraBundle/TemplateAnnotationRector.php
@@ -23,6 +23,10 @@
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
+/**
+ * @see \Rector\Sensio\Tests\Rector\FrameworkExtraBundle\TemplateAnnotationRector\TemplateAnnotationVersion3RectorTest
+ * @see \Rector\Sensio\Tests\Rector\FrameworkExtraBundle\TemplateAnnotationRector\TemplateAnnotationVersion5RectorTest
+ */
final class TemplateAnnotationRector extends AbstractRector
{
/**
@@ -139,6 +143,7 @@ private function classHasTemplateAnnotations(Class_ $node): bool
private function getSensioTemplateTagValueNode(ClassMethod $classMethod): ?SensioTemplateTagValueNode
{
+ /** @var PhpDocInfo|null $phpDocInfo */
$phpDocInfo = $classMethod->getAttribute(AttributeKey::PHP_DOC_INFO);
if ($phpDocInfo === null) {
return null;
diff --git a/src/Rector/Architecture/DependencyInjection/ReplaceVariableByPropertyFetchRector.php b/src/Rector/Architecture/DependencyInjection/ReplaceVariableByPropertyFetchRector.php
index 489a446c877b..04003dc54ba5 100644
--- a/src/Rector/Architecture/DependencyInjection/ReplaceVariableByPropertyFetchRector.php
+++ b/src/Rector/Architecture/DependencyInjection/ReplaceVariableByPropertyFetchRector.php
@@ -15,6 +15,9 @@
use Rector\Core\RectorDefinition\RectorDefinition;
use Rector\NodeTypeResolver\Node\AttributeKey;
+/**
+ * @see \Rector\Core\Tests\Rector\Architecture\DependencyInjection\ActionInjectionToConstructorInjectionRector\ActionInjectionToConstructorInjectionRectorTest
+ */
final class ReplaceVariableByPropertyFetchRector extends AbstractRector
{
/**
diff --git a/utils/phpstan-extensions/config/phpstan-extensions.neon b/utils/phpstan-extensions/config/phpstan-extensions.neon
index 65525e48d0b3..27ce597c6674 100644
--- a/utils/phpstan-extensions/config/phpstan-extensions.neon
+++ b/utils/phpstan-extensions/config/phpstan-extensions.neon
@@ -1,6 +1,15 @@
services:
- - { class: Rector\PHPStanExtensions\Rule\ClassMethod\PreventParentMethodVisibilityOverrideRule, tags: [phpstan.rules.rule] }
- - { class: Rector\PHPStanExtensions\Rule\ClassLike\KeepRectorNamespaceForRectorRule, tags: [phpstan.rules.rule] }
+ -
+ class: Rector\PHPStanExtensions\Rule\SeeAnnotationToTestRule
+ tags: [phpstan.rules.rule]
+
+ -
+ class: Rector\PHPStanExtensions\Rule\ClassMethod\PreventParentMethodVisibilityOverrideRule
+ tags: [phpstan.rules.rule]
+
+ -
+ class: Rector\PHPStanExtensions\Rule\ClassLike\KeepRectorNamespaceForRectorRule
+ tags: [phpstan.rules.rule]
- Rector\PHPStanExtensions\Utils\PHPStanValueResolver
diff --git a/utils/phpstan-extensions/src/Rule/ClassLike/KeepRectorNamespaceForRectorRule.php b/utils/phpstan-extensions/src/Rule/ClassLike/KeepRectorNamespaceForRectorRule.php
index e1469d9983e5..91b3f2428b33 100644
--- a/utils/phpstan-extensions/src/Rule/ClassLike/KeepRectorNamespaceForRectorRule.php
+++ b/utils/phpstan-extensions/src/Rule/ClassLike/KeepRectorNamespaceForRectorRule.php
@@ -9,11 +9,17 @@
use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
-use PHPStan\Rules\RuleError;
-use PHPStan\Rules\RuleErrorBuilder;
+/**
+ * @see \Rector\PHPStanExtensions\Tests\Rule\ClassLike\KeepRectorNamespaceForRectorRuleTest
+ */
final class KeepRectorNamespaceForRectorRule implements Rule
{
+ /**
+ * @var string
+ */
+ public const ERROR_MESSAGE = 'Change namespace for "%s". It cannot be in "Rector" namespace, unless Rector rule.';
+
public function getNodeType(): string
{
return ClassLike::class;
@@ -21,7 +27,7 @@ public function getNodeType(): string
/**
* @param ClassLike $node
- * @return RuleError[]
+ * @return string[]
*/
public function processNode(Node $node, Scope $scope): array
{
@@ -32,20 +38,23 @@ public function processNode(Node $node, Scope $scope): array
/** @var string $classLikeName */
$classLikeName = $node->name->toString();
- $ruleError = $this->createRuleError($node, $scope, $classLikeName);
+ $errorMessage = sprintf(self::ERROR_MESSAGE, $classLikeName);
- return [$ruleError];
+ return [$errorMessage];
}
- private function shouldSkip(Node $node, Scope $scope): bool
+ private function shouldSkip(ClassLike $classLike, Scope $scope): bool
{
$namespace = $scope->getNamespace();
if ($namespace === null) {
return true;
}
- // skip interface and tests
- if (Strings::match($namespace, '#\\\\(Contract|Exception|Tests)\\\\#')) {
+ // skip interface and tests, except tests here
+ if (Strings::match($namespace, '#\\\\(Contract|Exception|Tests)\\\\#') && ! Strings::contains(
+ $namespace,
+ 'PHPStanExtensions'
+ )) {
return true;
}
@@ -53,7 +62,7 @@ private function shouldSkip(Node $node, Scope $scope): bool
return true;
}
- $name = $node->name;
+ $name = $classLike->name;
if ($name === null) {
return true;
}
@@ -63,18 +72,4 @@ private function shouldSkip(Node $node, Scope $scope): bool
return (bool) Strings::match($classLikeName, '#(Rector|Test|Trait)$#');
}
-
- private function createRuleError(Node $node, Scope $scope, string $classLikeName): RuleError
- {
- $message = sprintf(
- 'Change namespace for "%s". It cannot be in "Rector" namespace, unless Rector rule.',
- $classLikeName
- );
-
- $ruleErrorBuilder = RuleErrorBuilder::message($message);
- $ruleErrorBuilder->line($node->getLine());
- $ruleErrorBuilder->file($scope->getFile());
-
- return $ruleErrorBuilder->build();
- }
}
diff --git a/utils/phpstan-extensions/src/Rule/ClassMethod/PreventParentMethodVisibilityOverrideRule.php b/utils/phpstan-extensions/src/Rule/ClassMethod/PreventParentMethodVisibilityOverrideRule.php
index f792523da4c9..d3a9bf8a8ad4 100644
--- a/utils/phpstan-extensions/src/Rule/ClassMethod/PreventParentMethodVisibilityOverrideRule.php
+++ b/utils/phpstan-extensions/src/Rule/ClassMethod/PreventParentMethodVisibilityOverrideRule.php
@@ -8,13 +8,19 @@
use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
-use PHPStan\Rules\RuleError;
-use PHPStan\Rules\RuleErrorBuilder;
use Rector\Core\Exception\NotImplementedException;
use ReflectionMethod;
+/**
+ * @see \Rector\PHPStanExtensions\Tests\Rule\ClassMethod\PreventParentMethodVisibilityOverrideRuleTest
+ */
final class PreventParentMethodVisibilityOverrideRule implements Rule
{
+ /**
+ * @var string
+ */
+ public const ERROR_MESSAGE = 'Change "%s()" method visibility to "%s" to respect parent method visibility.';
+
public function getNodeType(): string
{
return ClassMethod::class;
@@ -22,7 +28,7 @@ public function getNodeType(): string
/**
* @param ClassMethod $node
- * @return RuleError[]
+ * @return string[]
*/
public function processNode(Node $node, Scope $scope): array
{
@@ -49,8 +55,8 @@ public function processNode(Node $node, Scope $scope): array
$methodVisibility = $this->resolveReflectionMethodVisibilityAsStrings($parentReflectionMethod);
- $ruleError = $this->createRuleError($node, $scope, $methodName, $methodVisibility);
- return [$ruleError];
+ $errorMessage = sprintf(self::ERROR_MESSAGE, $methodName, $methodVisibility);
+ return [$errorMessage];
}
return [];
@@ -87,19 +93,4 @@ private function resolveReflectionMethodVisibilityAsStrings(ReflectionMethod $re
throw new NotImplementedException();
}
-
- private function createRuleError(Node $node, Scope $scope, string $methodName, string $methodVisibility): RuleError
- {
- $message = sprintf(
- 'Change "%s()" method visibility to "%s" to respect parent method visibility.',
- $methodName,
- $methodVisibility
- );
-
- $ruleErrorBuilder = RuleErrorBuilder::message($message);
- $ruleErrorBuilder->line($node->getLine());
- $ruleErrorBuilder->file($scope->getFile());
-
- return $ruleErrorBuilder->build();
- }
}
diff --git a/utils/phpstan-extensions/src/Rule/SeeAnnotationToTestRule.php b/utils/phpstan-extensions/src/Rule/SeeAnnotationToTestRule.php
new file mode 100644
index 000000000000..ddc303ffa893
--- /dev/null
+++ b/utils/phpstan-extensions/src/Rule/SeeAnnotationToTestRule.php
@@ -0,0 +1,142 @@
+fileTypeMapper = $fileTypeMapper;
+ $this->broker = $broker;
+ }
+
+ public function getNodeType(): string
+ {
+ return Class_::class;
+ }
+
+ /**
+ * @param Class_ $node
+ * @return string[]
+ */
+ public function processNode(Node $node, Scope $scope): array
+ {
+ $classReflection = $this->matchClassReflection($node);
+ if ($classReflection === null) {
+ return [];
+ }
+
+ if ($this->shouldSkipClassReflection($classReflection)) {
+ return [];
+ }
+
+ $docComment = $node->getDocComment();
+ if ($docComment === null) {
+ return [sprintf(self::ERROR_MESSAGE, $classReflection->getName())];
+ }
+
+ $resolvedPhpDoc = $this->resolvePhpDoc($scope, $classReflection, $docComment);
+
+ $seeTags = $resolvedPhpDoc->getPhpDocNode()->getTagsByName('@see');
+
+ // @todo validate to refer a TestCase class
+ if ($seeTags !== []) {
+ return [];
+ }
+
+ return [sprintf(self::ERROR_MESSAGE, $classReflection->getName())];
+ }
+
+ private function isClassMatch(string $className): bool
+ {
+ foreach (self::CLASS_SUFFIXES as $classSuffix) {
+ if (Strings::endsWith($className, $classSuffix)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private function shouldSkipClassReflection(ClassReflection $classReflection): bool
+ {
+ if (! $this->isClassMatch($classReflection->getName())) {
+ return true;
+ }
+
+ if ($classReflection->isAbstract()) {
+ return true;
+ }
+
+ // meta-Rector
+ if ($classReflection->isSubclassOf(PostRectorInterface::class)) {
+ return true;
+ }
+
+ // skip filesystem for now
+ return ! $classReflection->isSubclassOf(PhpRectorInterface::class);
+ }
+
+ private function matchClassReflection(Class_ $node): ?ClassReflection
+ {
+ if ($node->name === null) {
+ return null;
+ }
+
+ $className = (string) $node->namespacedName;
+ if (! class_exists($className)) {
+ return null;
+ }
+
+ return $this->broker->getClass($className);
+ }
+
+ private function resolvePhpDoc(Scope $scope, ClassReflection $classReflection, Doc $doc): ResolvedPhpDocBlock
+ {
+ return $this->fileTypeMapper->getResolvedPhpDoc(
+ $scope->getFile(),
+ $classReflection->getName(),
+ null,
+ null,
+ $doc->getText()
+ );
+ }
+}
diff --git a/utils/phpstan-extensions/tests/AbstractServiceAwareRuleTestCase.php b/utils/phpstan-extensions/tests/AbstractServiceAwareRuleTestCase.php
new file mode 100644
index 000000000000..c3b6515e314f
--- /dev/null
+++ b/utils/phpstan-extensions/tests/AbstractServiceAwareRuleTestCase.php
@@ -0,0 +1,35 @@
+createContainer([$config]);
+ return $container->getByType($ruleClass);
+ }
+
+ /**
+ * @param string[] $configs
+ */
+ private function createContainer(array $configs): Container
+ {
+ $containerFactory = new ContainerFactory(getcwd());
+ // random for tests cache invalidation in case the container changes
+ $tempDirectory = sys_get_temp_dir() . '/_phpstan_rector/id_' . random_int(0, 1000);
+
+ return $containerFactory->create($tempDirectory, $configs, [], []);
+ }
+}
diff --git a/utils/phpstan-extensions/tests/Rule/ClassLike/KeepRectorNamespaceForRectorRuleTest.php b/utils/phpstan-extensions/tests/Rule/ClassLike/KeepRectorNamespaceForRectorRuleTest.php
index 71c1594820bc..21717554f59e 100644
--- a/utils/phpstan-extensions/tests/Rule/ClassLike/KeepRectorNamespaceForRectorRuleTest.php
+++ b/utils/phpstan-extensions/tests/Rule/ClassLike/KeepRectorNamespaceForRectorRuleTest.php
@@ -12,21 +12,19 @@
final class KeepRectorNamespaceForRectorRuleTest extends RuleTestCase
{
/**
- * @param array $expectedErrorsWithLines
* @dataProvider provideData()
*/
public function testRule(string $filePath, array $expectedErrorsWithLines): void
{
- $this->analyse([$filePath], [$expectedErrorsWithLines]);
+ $this->analyse([$filePath], $expectedErrorsWithLines);
}
public function provideData(): Iterator
{
yield [__DIR__ . '/Source/Rector/ClassInCorrectNamespaceRector.php', []];
- yield [
- __DIR__ . '/Source/Rector/WrongClass.php',
- ['Change namespace for "WrongClass". It cannot be in Rector namespace, unless Rector rule.', 8],
- ];
+
+ $errorMessage = sprintf(KeepRectorNamespaceForRectorRule::ERROR_MESSAGE, 'WrongClass', 'Rector');
+ yield [__DIR__ . '/Source/Rector/WrongClass.php', [[$errorMessage, 7]]];
}
protected function getRule(): Rule
diff --git a/utils/phpstan-extensions/tests/Rule/ClassLike/Source/Rector/WrongClass.php b/utils/phpstan-extensions/tests/Rule/ClassLike/Source/Rector/WrongClass.php
index d7a878cb4088..3eeedebed357 100644
--- a/utils/phpstan-extensions/tests/Rule/ClassLike/Source/Rector/WrongClass.php
+++ b/utils/phpstan-extensions/tests/Rule/ClassLike/Source/Rector/WrongClass.php
@@ -2,7 +2,6 @@
declare(strict_types=1);
-
namespace Rector\PHPStanExtensions\Tests\Rule\ClassLike\Source\Rector;
final class WrongClass
diff --git a/utils/phpstan-extensions/tests/Rule/ClassMethod/PreventParentMethodVisibilityOverrideRuleTest.php b/utils/phpstan-extensions/tests/Rule/ClassMethod/PreventParentMethodVisibilityOverrideRuleTest.php
index 82d552ef5732..7202c58860a4 100644
--- a/utils/phpstan-extensions/tests/Rule/ClassMethod/PreventParentMethodVisibilityOverrideRuleTest.php
+++ b/utils/phpstan-extensions/tests/Rule/ClassMethod/PreventParentMethodVisibilityOverrideRuleTest.php
@@ -4,18 +4,25 @@
namespace Rector\PHPStanExtensions\Tests\Rule\ClassMethod;
+use Iterator;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use Rector\PHPStanExtensions\Rule\ClassMethod\PreventParentMethodVisibilityOverrideRule;
final class PreventParentMethodVisibilityOverrideRuleTest extends RuleTestCase
{
- public function testRule(): void
+ /**
+ * @dataProvider provideData()
+ */
+ public function testRule(string $filePath, array $expectedErrorsWithLines): void
{
- $this->analyse(
- [__DIR__ . '/Source/ClassWithOverridingVisibility.php'],
- [['Change "run()" method visibility to "protected" to respect parent method visibility.', 10]]
- );
+ $this->analyse([$filePath], $expectedErrorsWithLines);
+ }
+
+ public function provideData(): Iterator
+ {
+ $errorMessage = sprintf(PreventParentMethodVisibilityOverrideRule::ERROR_MESSAGE, 'run', 'protected');
+ yield [__DIR__ . '/Source/ClassWithOverridingVisibility.php', [[$errorMessage, 9]]];
}
protected function getRule(): Rule
diff --git a/utils/phpstan-extensions/tests/Rule/ClassMethod/Source/ClassWithOverridingVisibility.php b/utils/phpstan-extensions/tests/Rule/ClassMethod/Source/ClassWithOverridingVisibility.php
index 8b012f86285c..0c9cf41b2d79 100644
--- a/utils/phpstan-extensions/tests/Rule/ClassMethod/Source/ClassWithOverridingVisibility.php
+++ b/utils/phpstan-extensions/tests/Rule/ClassMethod/Source/ClassWithOverridingVisibility.php
@@ -2,7 +2,6 @@
declare(strict_types=1);
-
namespace Rector\PHPStanExtensions\Tests\Rule\ClassMethod\Source;
final class ClassWithOverridingVisibility extends GoodVisibility
@@ -11,11 +10,3 @@ public function run()
{
}
}
-
-abstract class GoodVisibility
-{
- protected function run()
- {
-
- }
-}
diff --git a/utils/phpstan-extensions/tests/Rule/ClassMethod/Source/GoodVisibility.php b/utils/phpstan-extensions/tests/Rule/ClassMethod/Source/GoodVisibility.php
new file mode 100644
index 000000000000..f5f14f603aec
--- /dev/null
+++ b/utils/phpstan-extensions/tests/Rule/ClassMethod/Source/GoodVisibility.php
@@ -0,0 +1,13 @@
+analyse([$filePath], $expectedErrorsWithLines);
+ }
+
+ public function provideData(): Iterator
+ {
+ $errorMessage = sprintf(SeeAnnotationToTestRule::ERROR_MESSAGE, ClassMissingDocBlockRector::class);
+ yield [__DIR__ . '/Fixture/ClassMissingDocBlockRector.php', [[$errorMessage, 12]]];
+
+ $errorMessage = sprintf(SeeAnnotationToTestRule::ERROR_MESSAGE, ClassMissingSeeAnnotationRector::class);
+ yield [__DIR__ . '/Fixture/ClassMissingSeeAnnotationRector.php', [[$errorMessage, 15]]];
+ }
+
+ protected function getRule(): Rule
+ {
+ return $this->getRuleFromConfig(
+ SeeAnnotationToTestRule::class,
+ __DIR__ . '/../../../config/phpstan-extensions.neon'
+ );
+ }
+}