Skip to content

Commit

Permalink
Tip for Discovering Symbols on all "not found" messages
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Jun 14, 2020
1 parent 4a9c159 commit 75e6115
Show file tree
Hide file tree
Showing 44 changed files with 98 additions and 23 deletions.
4 changes: 2 additions & 2 deletions src/Analyser/FileAnalyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public function analyseFile(
$fileErrors[] = new Error($e->getMessage(), $file, $node->getLine(), false, null, null, $e->getTip());
continue;
} catch (IdentifierNotFound $e) {
$fileErrors[] = new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, $node->getLine(), false);
$fileErrors[] = new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, $node->getLine(), false, null, null, 'Learn more at https://phpstan.org/user-guide/discovering-symbols');
continue;
}

Expand Down Expand Up @@ -232,7 +232,7 @@ public function analyseFile(
} catch (\PHPStan\AnalysedCodeException $e) {
$fileErrors[] = new Error($e->getMessage(), $file, null, false, null, null, $e->getTip());
} catch (IdentifierNotFound $e) {
$fileErrors[] = new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, null, false);
$fileErrors[] = new Error(sprintf('Reflection error: %s not found.', $e->getIdentifier()->getName()), $file, null, false, null, null, 'Learn more at https://phpstan.org/user-guide/discovering-symbols');
}
} elseif (is_dir($file)) {
$fileErrors[] = new Error(sprintf('File %s is a directory.', $file), $file, null, false);
Expand Down
4 changes: 2 additions & 2 deletions src/Rules/Classes/ClassConstantRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ public function processNode(Node $node, Scope $scope): array

if (strtolower($constantName) === 'class') {
return [
RuleErrorBuilder::message(sprintf('Class %s not found.', $className))->build(),
RuleErrorBuilder::message(sprintf('Class %s not found.', $className))->discoveringSymbolsTip()->build(),
];
}

return [
RuleErrorBuilder::message(
sprintf('Access to constant %s on an unknown class %s.', $constantName, $className)
)->build(),
)->discoveringSymbolsTip()->build(),
];
} else {
$messages = $this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($className, $class)]);
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Classes/ExistingClassInClassExtendsRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function processNode(Node $node, Scope $scope): array
'%s extends unknown class %s.',
$currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class',
$extendedClassName
))->nonIgnorable()->build();
))->nonIgnorable()->discoveringSymbolsTip()->build();
}
} else {
$reflection = $this->reflectionProvider->getClass($extendedClassName);
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Classes/ExistingClassInInstanceOfRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public function processNode(Node $node, Scope $scope): array
}

return [
RuleErrorBuilder::message(sprintf('Class %s not found.', $name))->line($class->getLine())->build(),
RuleErrorBuilder::message(sprintf('Class %s not found.', $name))->line($class->getLine())->discoveringSymbolsTip()->build(),
];
} elseif ($this->checkClassCaseSensitivity) {
return $this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($name, $class)]);
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Classes/ExistingClassInTraitUseRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function processNode(Node $node, Scope $scope): array
foreach ($node->traits as $trait) {
$traitName = (string) $trait;
if (!$this->reflectionProvider->hasClass($traitName)) {
$messages[] = RuleErrorBuilder::message(sprintf('%s uses unknown trait %s.', $currentName, $traitName))->nonIgnorable()->build();
$messages[] = RuleErrorBuilder::message(sprintf('%s uses unknown trait %s.', $currentName, $traitName))->nonIgnorable()->discoveringSymbolsTip()->build();
} else {
$reflection = $this->reflectionProvider->getClass($traitName);
if ($reflection->isClass()) {
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Classes/ExistingClassesInClassImplementsRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function processNode(Node $node, Scope $scope): array
'%s implements unknown interface %s.',
$currentClassName !== null ? sprintf('Class %s', $currentClassName) : 'Anonymous class',
$implementedClassName
))->nonIgnorable()->build();
))->nonIgnorable()->discoveringSymbolsTip()->build();
}
} else {
$reflection = $this->reflectionProvider->getClass($implementedClassName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function processNode(Node $node, Scope $scope): array
'Interface %s extends unknown interface %s.',
$currentInterfaceName,
$extendedInterfaceName
))->nonIgnorable()->build();
))->nonIgnorable()->discoveringSymbolsTip()->build();
}
} else {
$reflection = $this->reflectionProvider->getClass($extendedInterfaceName);
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Classes/InstantiationRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ private function checkClassName(string $class, Node $node, Scope $scope): array
}

return [
RuleErrorBuilder::message(sprintf('Instantiated class %s not found.', $class))->build(),
RuleErrorBuilder::message(sprintf('Instantiated class %s not found.', $class))->discoveringSymbolsTip()->build(),
];
} else {
$messages = $this->classCaseSensitivityCheck->checkClassNames([
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Classes/MixinRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public function processNode(Node $node, Scope $scope): array

foreach ($type->getReferencedClasses() as $class) {
if (!$this->reflectionProvider->hasClass($class)) {
$errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @mixin contains unknown class %s.', $class))->build();
$errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @mixin contains unknown class %s.', $class))->discoveringSymbolsTip()->build();
} elseif ($this->reflectionProvider->getClass($class)->isTrait()) {
$errors[] = RuleErrorBuilder::message(sprintf('PHPDoc tag @mixin contains invalid type %s.', $class))->build();
} elseif ($this->checkClassCaseSensitivity) {
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Constants/ConstantRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public function processNode(Node $node, Scope $scope): array
RuleErrorBuilder::message(sprintf(
'Constant %s not found.',
(string) $node->name
))->build(),
))->discoveringSymbolsTip()->build(),
];
}

Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Exceptions/CaughtExceptionExistenceRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public function processNode(Node $node, Scope $scope): array
if ($scope->isInClassExists($className)) {
continue;
}
$errors[] = RuleErrorBuilder::message(sprintf('Caught class %s not found.', $className))->line($class->getLine())->build();
$errors[] = RuleErrorBuilder::message(sprintf('Caught class %s not found.', $className))->line($class->getLine())->discoveringSymbolsTip()->build();
continue;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Functions/CallToNonExistentFunctionRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function processNode(Node $node, Scope $scope): array

if (!$this->reflectionProvider->hasFunction($node->name, $scope)) {
return [
RuleErrorBuilder::message(sprintf('Function %s not found.', (string) $node->name))->build(),
RuleErrorBuilder::message(sprintf('Function %s not found.', (string) $node->name))->discoveringSymbolsTip()->build(),
];
}

Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Methods/CallStaticMethodsRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public function processNode(Node $node, Scope $scope): array
'Call to static method %s() on an unknown class %s.',
$methodName,
$className
))->build(),
))->discoveringSymbolsTip()->build(),
];
} else {
$errors = $this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($className, $class)]);
Expand Down
4 changes: 2 additions & 2 deletions src/Rules/Namespaces/ExistingNamesInGroupUseRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public function processNode(Node $node, Scope $scope): array
private function checkConstant(Node\Name $name): ?RuleError
{
if (!$this->reflectionProvider->hasConstant($name, null)) {
return RuleErrorBuilder::message(sprintf('Used constant %s not found.', (string) $name))->line($name->getLine())->build();
return RuleErrorBuilder::message(sprintf('Used constant %s not found.', (string) $name))->discoveringSymbolsTip()->line($name->getLine())->build();
}

return null;
Expand All @@ -85,7 +85,7 @@ private function checkConstant(Node\Name $name): ?RuleError
private function checkFunction(Node\Name $name): ?RuleError
{
if (!$this->reflectionProvider->hasFunction($name, null)) {
return RuleErrorBuilder::message(sprintf('Used function %s not found.', (string) $name))->line($name->getLine())->build();
return RuleErrorBuilder::message(sprintf('Used function %s not found.', (string) $name))->discoveringSymbolsTip()->line($name->getLine())->build();
}

if ($this->checkFunctionNameCase) {
Expand Down
4 changes: 2 additions & 2 deletions src/Rules/Namespaces/ExistingNamesInUseRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private function checkConstants(array $uses): array
continue;
}

$errors[] = RuleErrorBuilder::message(sprintf('Used constant %s not found.', (string) $use->name))->line($use->name->getLine())->build();
$errors[] = RuleErrorBuilder::message(sprintf('Used constant %s not found.', (string) $use->name))->line($use->name->getLine())->discoveringSymbolsTip()->build();
}

return $errors;
Expand All @@ -88,7 +88,7 @@ private function checkFunctions(array $uses): array
$errors = [];
foreach ($uses as $use) {
if (!$this->reflectionProvider->hasFunction($use->name, null)) {
$errors[] = RuleErrorBuilder::message(sprintf('Used function %s not found.', (string) $use->name))->line($use->name->getLine())->build();
$errors[] = RuleErrorBuilder::message(sprintf('Used function %s not found.', (string) $use->name))->line($use->name->getLine())->discoveringSymbolsTip()->build();
} elseif ($this->checkFunctionNameCase) {
$functionReflection = $this->reflectionProvider->getFunction($use->name, null);
$realName = $functionReflection->getName();
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/PhpDoc/InvalidPhpDocVarTagTypeRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public function processNode(Node $node, Scope $scope): array
$errors[] = RuleErrorBuilder::message(sprintf(
sprintf('%s contains unknown class %%s.', $identifier),
$referencedClass
))->build();
))->discoveringSymbolsTip()->build();
}

if (!$this->checkClassCaseSensitivity) {
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Properties/AccessStaticPropertiesRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public function processNode(Node $node, Scope $scope): array
'Access to static property $%s on an unknown class %s.',
$name,
$class
))->build(),
))->discoveringSymbolsTip()->build(),
];
} else {
$messages = $this->classCaseSensitivityCheck->checkClassNames([new ClassNameNodePair($class, $node->class)]);
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/Properties/ExistingClassesInPropertiesRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public function processNode(Node $node, Scope $scope): array
$propertyReflection->getDeclaringClass()->getDisplayName(),
$node->name->name,
$referencedClass
))->build();
))->discoveringSymbolsTip()->build();
}

if ($this->checkClassCaseSensitivity) {
Expand Down
5 changes: 5 additions & 0 deletions src/Rules/RuleErrorBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ public function tip(string $tip): self
return $this;
}

public function discoveringSymbolsTip(): self
{
return $this->tip('Learn more at https://phpstan.org/user-guide/discovering-symbols');
}

public function identifier(string $identifier): self
{
$this->properties['identifier'] = $identifier;
Expand Down
2 changes: 1 addition & 1 deletion src/Rules/RuleLevelHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public function findTypeToCheck(
continue;
}

$errors[] = RuleErrorBuilder::message(sprintf($unknownClassErrorPattern, $referencedClass))->line($var->getLine())->build();
$errors[] = RuleErrorBuilder::message(sprintf($unknownClassErrorPattern, $referencedClass))->line($var->getLine())->discoveringSymbolsTip()->build();
}

if (count($errors) > 0 || $hasClassExistsClass) {
Expand Down
1 change: 1 addition & 0 deletions tests/PHPStan/Rules/Arrays/IterableInForeachRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public function testCheckWithMaybes(): void
[
'Iterating over an object of an unknown class IterablesInForeach\Bar.',
47,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ public function testRule(): void
[
'Access to offset \'bar\' on an unknown class NonexistentOffset\Bar.',
101,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Access to an offset on an unknown class NonexistentOffset\Bar.',
102,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Offset 0 does not exist on array<string, string>.',
Expand Down
7 changes: 7 additions & 0 deletions tests/PHPStan/Rules/Classes/ClassConstantRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public function testClassConstant(): void
[
'Class ClassConstantNamespace\Bar not found.',
6,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Using self outside of class scope.',
Expand All @@ -53,6 +54,7 @@ public function testClassConstant(): void
[
'Access to constant FOO on an unknown class ClassConstantNamespace\UnknownClass.',
21,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Class ClassConstantNamespace\Foo referenced with incorrect case: ClassConstantNamespace\FOO.',
Expand Down Expand Up @@ -123,10 +125,12 @@ public function testClassConstantVisibility(): void
[
'Access to constant FOO on an unknown class ClassConstantVisibility\UnknownClassFirst.',
112,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Access to constant FOO on an unknown class ClassConstantVisibility\UnknownClassSecond.',
112,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Cannot access constant FOO on int|string.',
Expand All @@ -149,14 +153,17 @@ public function testClassExists(): void
[
'Class UnknownClass\Bar not found.',
24,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Class UnknownClass\Foo not found.',
26,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Class UnknownClass\Foo not found.',
29,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public function testRuleExtendsError(): void
[
'Class ExtendsError\Foo extends unknown class ExtendsError\Bar.',
5,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Class ExtendsError\Lorem extends interface ExtendsError\BazInterface.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public function testClassDoesNotExist(): void
[
'Class InstanceOfNamespace\Bar not found.',
7,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Using self outside of class scope.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public function testTraitUseError(): void
[
'Class TraitUseError\Foo uses unknown trait TraitUseError\FooTrait.',
8,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
/*[
'Trait TraitUseError\BarTrait uses class TraitUseError\Foo.',
Expand All @@ -56,6 +57,7 @@ public function testTraitUseError(): void
[
'Anonymous class uses unknown trait TraitUseError\FooTrait.',
27,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Anonymous class uses interface TraitUseError\Baz.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public function testRuleImplementsError(): void
[
'Class ImplementsError\Foo implements unknown interface ImplementsError\Bar.',
5,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Class ImplementsError\Lorem implements class ImplementsError\Foo.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public function testRuleExtendsError(): void
[
'Interface InterfaceExtendsError\Foo extends unknown interface InterfaceExtendsError\Bar.',
5,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Interface InterfaceExtendsError\Lorem extends class InterfaceExtendsError\BazClass.',
Expand Down
5 changes: 5 additions & 0 deletions tests/PHPStan/Rules/Classes/InstantiationRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public function testInstantiation(): void
[
'Instantiated class TestInstantiation\FooBarInstantiation not found.',
27,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Class TestInstantiation\BarInstantiation constructor invoked with 0 parameters, 1 required.',
Expand All @@ -61,6 +62,7 @@ public function testInstantiation(): void
[
'Instantiated class Test not found.',
33,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Class DatePeriod constructor invoked with 0 parameters, 1-4 required.',
Expand Down Expand Up @@ -153,14 +155,17 @@ public function testInstantiation(): void
[
'Instantiated class UndefinedClass1 not found.',
169,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Instantiated class UndefinedClass2 not found.',
172,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Instantiated class UndefinedClass3 not found.',
179,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Class TestInstantiation\FinalClass does not have a constructor and must be instantiated without any parameters.',
Expand Down
2 changes: 2 additions & 0 deletions tests/PHPStan/Rules/Classes/MixinRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public function testRule(): void
[
'PHPDoc tag @mixin contains unknown class MixinRule\UnknownestClass.',
50,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'PHPDoc tag @mixin contains invalid type MixinRule\FooTrait.',
Expand All @@ -68,6 +69,7 @@ public function testRule(): void
[
'PHPDoc tag @mixin contains unknown class MixinRule\U.',
59,
'Learn more at https://phpstan.org/user-guide/discovering-symbols',
],
[
'Generic type MixinRule\Consecteur<MixinRule\Foo> in PHPDoc tag @mixin does not specify all template types of class MixinRule\Consecteur: T, U',
Expand Down

0 comments on commit 75e6115

Please sign in to comment.