Skip to content

Check whether method parameter/return has typehint #16

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

Merged
merged 2 commits into from
May 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions src/Rules/Methods/MissingMethodParameterTypehintRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Methods;

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Type\MixedType;

final class MissingMethodParameterTypehintRule implements \PHPStan\Rules\Rule
{

/**
* @return string Class implementing \PhpParser\Node
*/
public function getNodeType(): string
{
return \PhpParser\Node\Stmt\ClassMethod::class;
}

/**
* @param \PhpParser\Node\Stmt\ClassMethod $node
* @param \PHPStan\Analyser\Scope $scope
*
* @return string[] errors
*/
public function processNode(Node $node, Scope $scope): array
{
if (!$scope->isInClass()) {
throw new \PHPStan\ShouldNotHappenException();
}

$methodReflection = $scope->getClassReflection()->getNativeMethod($node->name);

$messages = [];

foreach ($methodReflection->getParameters() as $parameterReflection) {
$message = $this->checkMethodParameter($methodReflection, $parameterReflection);
if ($message === null) {
continue;
}

$messages[] = $message;
}

return $messages;
}

private function checkMethodParameter(MethodReflection $methodReflection, ParameterReflection $parameterReflection): ?string
{
$parameterType = $parameterReflection->getType();

if ($parameterType instanceof MixedType && !$parameterType->isExplicitMixed()) {
return sprintf(
'Method %s::%s() has parameter $%s with no typehint specified',
$methodReflection->getDeclaringClass()->getName(),
$methodReflection->getName(),
$parameterReflection->getName()
);
}

return null;
}

}
60 changes: 60 additions & 0 deletions src/Rules/Methods/MissingMethodReturnTypehintRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Methods;

use PhpParser\Node;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\MixedType;

final class MissingMethodReturnTypehintRule implements \PHPStan\Rules\Rule
{

/**
* @return string Class implementing \PhpParser\Node
*/
public function getNodeType(): string
{
return \PhpParser\Node\Stmt\ClassMethod::class;
}

/**
* @param \PhpParser\Node\Stmt\ClassMethod $node
* @param \PHPStan\Analyser\Scope $scope
*
* @return string[] errors
*/
public function processNode(Node $node, Scope $scope): array
{
if (!$scope->isInClass()) {
throw new \PHPStan\ShouldNotHappenException();
}

$methodReflection = $scope->getClassReflection()->getNativeMethod($node->name);

$messages = [];

$message = $this->checkMethodReturnType($methodReflection);
if ($message !== null) {
$messages[] = $message;
}

return $messages;
}

private function checkMethodReturnType(MethodReflection $methodReflection): ?string
{
$returnType = $methodReflection->getReturnType();

if ($returnType instanceof MixedType && !$returnType->isExplicitMixed()) {
return sprintf(
'Method %s::%s() has no return typehint specified',
$methodReflection->getDeclaringClass()->getName(),
$methodReflection->getName()
);
}

return null;
}

}
39 changes: 39 additions & 0 deletions tests/Rules/Methods/MissingMethodParameterTypehintRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Methods;

class MissingMethodParameterTypehintRuleTest extends \PHPStan\Testing\RuleTestCase
{

protected function getRule(): \PHPStan\Rules\Rule
{
return new MissingMethodParameterTypehintRule();
}

public function testRule(): void
{
$this->analyse([__DIR__ . '/data/missing-method-parameter-typehint.php'], [
[
'Method MissingMethodParameterTypehint\FooInterface::getFoo() has parameter $p1 with no typehint specified',
8,
],
[
'Method MissingMethodParameterTypehint\FooParent::getBar() has parameter $p2 with no typehint specified',
15,
],
[
'Method MissingMethodParameterTypehint\Foo::getFoo() has parameter $p1 with no typehint specified',
25,
],
[
'Method MissingMethodParameterTypehint\Foo::getBar() has parameter $p2 with no typehint specified',
33,
],
[
'Method MissingMethodParameterTypehint\Foo::getBaz() has parameter $p3 with no typehint specified',
42,
],
]);
}

}
35 changes: 35 additions & 0 deletions tests/Rules/Methods/MissingMethodReturnTypehintRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Methods;

class MissingMethodReturnTypehintRuleTest extends \PHPStan\Testing\RuleTestCase
{

protected function getRule(): \PHPStan\Rules\Rule
{
return new MissingMethodReturnTypehintRule();
}

public function testRule(): void
{
$this->analyse([__DIR__ . '/data/missing-method-return-typehint.php'], [
[
'Method MissingMethodReturnTypehint\FooInterface::getFoo() has no return typehint specified',
8,
],
[
'Method MissingMethodReturnTypehint\FooParent::getBar() has no return typehint specified',
15,
],
[
'Method MissingMethodReturnTypehint\Foo::getFoo() has no return typehint specified',
25,
],
[
'Method MissingMethodReturnTypehint\Foo::getBar() has no return typehint specified',
33,
],
]);
}

}
55 changes: 55 additions & 0 deletions tests/Rules/Methods/data/missing-method-parameter-typehint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace MissingMethodParameterTypehint;

interface FooInterface
{

public function getFoo($p1): void;

}

class FooParent
{

public function getBar($p2)
{

}

}

class Foo extends FooParent implements FooInterface
{

public function getFoo($p1): void
{

}

/**
* @param $p2
*/
public function getBar($p2)
{

}

/**
* @param $p3
* @param int $p4
*/
public function getBaz($p3, $p4): bool
{
return false;
}

/**
* @param mixed $p5
*/
public function getFooBar($p5): bool
{
return false;
}

}
43 changes: 43 additions & 0 deletions tests/Rules/Methods/data/missing-method-return-typehint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

namespace MissingMethodReturnTypehint;

interface FooInterface
{

public function getFoo($p1);

}

class FooParent
{

public function getBar($p2)
{

}

}

class Foo extends FooParent implements FooInterface
{

public function getFoo($p1)
{

}

/**
* @param $p2
*/
public function getBar($p2)
{

}

public function getBaz(): bool
{
return false;
}

}