Skip to content

Commit

Permalink
Add PHPStan bleeding edge compatibility (#98)
Browse files Browse the repository at this point in the history
Co-authored-by: Viktor Szépe <[email protected]>
Co-authored-by: Martin Herndl <[email protected]>
  • Loading branch information
3 people authored May 2, 2022
1 parent 056b058 commit 37eaf7e
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 43 deletions.
11 changes: 10 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@ dist: "bionic"
php:
- "8.0"
- "7.4"
- "7.1"
- "7.2"

jobs:
include:
- php: "8.1"
script:
- "composer test:syntax -- --no-progress"
- "composer test:phpunit -- --verbose"
# - "composer test:cs -- -s"
- "composer test:phpstan -- --ansi --memory-limit=1G --no-progress"

cache:
directories:
Expand Down
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@
"phpstan"
],
"require": {
"php": "^7.1 || ^8.0",
"php": "^7.2 || ^8.0",
"php-stubs/wordpress-stubs": "^4.7 || ^5.0",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan": "^1.6",
"symfony/polyfill-php73": "^1.12.0"
},
"require-dev": {
"composer/composer": "^2.1.12",
"composer/composer": "^2.1.14",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7",
"php-parallel-lint/php-parallel-lint": "^1.1",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^7 || ^9",
"phpstan/phpstan-strict-rules": "^1.2",
"phpunit/phpunit": "^8 || ^9",
"szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^0.6"
},
"autoload": {
Expand Down
4 changes: 4 additions & 0 deletions extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ services:
class: SzepeViktor\PHPStan\WordPress\TermExistsDynamicFunctionReturnTypeExtension
tags:
- phpstan.broker.dynamicFunctionReturnTypeExtension
-
class: SzepeViktor\PHPStan\WordPress\HookDocsVisitor
tags:
- phpstan.parser.richParserNodeVisitor
rules:
- SzepeViktor\PHPStan\WordPress\HookDocsRule
- SzepeViktor\PHPStan\WordPress\IsWpErrorRule
Expand Down
17 changes: 2 additions & 15 deletions src/HookDocBlock.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,7 @@ public function getNullableHookDocBlock(FuncCall $functionCall, Scope $scope): ?

private static function getNullableNodeComment(FuncCall $node): ?\PhpParser\Comment\Doc
{
$startLine = $node->getStartLine();

while ($node !== null && $node->getStartLine() === $startLine) {
// Fetch the docblock from the node.
$comment = $node->getDocComment();

if ($comment !== null) {
return $comment;
}

/** @var \PhpParser\Node|null */
$node = $node->getAttribute('parent');
}

return null;
/** @var \PhpParser\Comment\Doc|null */
return $node->getAttribute('latestDocComment');
}
}
48 changes: 48 additions & 0 deletions src/HookDocsVisitor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

/**
* Custom node visitor to fetch the docblock for a function call.
*/

declare(strict_types=1);

namespace SzepeViktor\PHPStan\WordPress;

use PhpParser\Node;

final class HookDocsVisitor extends \PhpParser\NodeVisitorAbstract
{
/** @var int|null */
protected $latestStartLine = null;

/** @var \PhpParser\Comment\Doc|null */
protected $latestDocComment = null;

// phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter
public function beforeTraverse(array $nodes): ?array
{
$this->latestStartLine = null;
$this->latestDocComment = null;

return null;
}

public function enterNode(Node $node): ?Node
{
if ($node->getStartLine() !== $this->latestStartLine) {
$this->latestDocComment = null;
}

$this->latestStartLine = $node->getStartLine();

$doc = $node->getDocComment();

if ($doc !== null) {
$this->latestDocComment = $doc;
}

$node->setAttribute('latestDocComment', $this->latestDocComment);

return null;
}
}
32 changes: 21 additions & 11 deletions tests/HookDocsRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,45 +38,55 @@ public function testRule(): void
[
[
'Expected 2 @param tags, found 1.',
22,
19,
],
[
'Expected 2 @param tags, found 3.',
31,
28,
],
[
'@param string $one does not accept actual type of parameter: int|string.',
43,
40,
],
[
'@param string $one does not accept actual type of parameter: int.',
53,
50,
],
[
'@param tag must not be named $this. Choose a descriptive alias, for example $instance.',
82,
79,
],
[
'Expected 2 @param tags, found 1.',
97,
94,
],
[
'@param ChildTestClass $one does not accept actual type of parameter: ParentTestClass.',
134,
'@param SzepeViktor\PHPStan\WordPress\Tests\ChildTestClass $one does not accept actual type of parameter: SzepeViktor\PHPStan\WordPress\Tests\ParentTestClass.',
131,
],
[
'@param string $one does not accept actual type of parameter: string|null.',
155,
152,
],
[
'One or more @param tags has an invalid name or invalid syntax.',
170,
167,
],
[
'One or more @param tags has an invalid name or invalid syntax.',
206,
203,
],
[
'Expected 2 @param tags, found 1.',
214,
],
]
);
}

public static function getAdditionalConfigFiles(): array
{
// Path to your project's phpstan.neon, or extension.neon in case of custom extension packages.
return [dirname(__DIR__) . '/extension.neon'];
}
}
6 changes: 6 additions & 0 deletions tests/IsWpErrorRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,10 @@ public function testRule(): void
]
);
}

public static function getAdditionalConfigFiles(): array
{
// Path to your project's phpstan.neon, or extension.neon in case of custom extension packages.
return [dirname(__DIR__) . '/extension.neon'];
}
}
1 change: 0 additions & 1 deletion tests/data/apply_filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

use function PHPStan\Testing\assertType;
use function apply_filters;
use function returnValue;

$value = apply_filters('filter', 'Hello, World');
assertType('mixed', $value);
Expand Down
31 changes: 23 additions & 8 deletions tests/data/hook-docs.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@

namespace SzepeViktor\PHPStan\WordPress\Tests;

use ChildTestClass;
use ParentTestClass;

// phpcs:disable Squiz.NamingConventions.ValidFunctionName.NotCamelCaps,Squiz.NamingConventions.ValidVariableName.NotCamelCaps,Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps

$one = 1;
Expand Down Expand Up @@ -87,7 +84,7 @@ function wide_param_type(string $one)
* @param \stdClass $instance Instance.
* @param array $args Args
*/
do_action('action', $this, $args);
do_action('action', $this, []);

/**
* This param tag renames the `$this` variable, which is fine, but still has a missing param tag.
Expand All @@ -109,7 +106,7 @@ function correct_inherited_param_type(ChildTestClass $one)
/**
* This param tag is for a super class of the variable, which is fine.
*
* @param \ParentTestClass $one First parameter.
* @param ParentTestClass $one First parameter.
*/
$args = apply_filters('filter', $one);
}
Expand All @@ -119,7 +116,7 @@ function correct_interface_param_type(ChildTestClass $one)
/**
* This param tag is for the interface of the variable, which is fine.
*
* @param \TestInterface $one First parameter.
* @param TestInterface $one First parameter.
*/
$args = apply_filters('filter', $one);
}
Expand All @@ -129,7 +126,7 @@ function incorrect_inherited_param_type(ParentTestClass $one)
/**
* This param tag is for a child class of the variable. Oh no.
*
* @param \ChildTestClass $one First parameter.
* @param ChildTestClass $one First parameter.
*/
$args = apply_filters('filter', $one);
}
Expand Down Expand Up @@ -203,8 +200,26 @@ function incorrect_nullable_param_type(?string $one = null)
* @param bool has_site_pending_automated_transfer( $this->blog_id )
* @param int $blog_id Blog identifier.
*/
return apply_filters(
$value = apply_filters(
'filter',
false,
$this->blog_id
);

/**
* This filter is wrapped inside another function call, which is weird but ok. Its param count is incorrect.
*
* @param int $number
*/
$value = intval(apply_filters('filter', 123, $foo));

/**
* This is a docblock for an unrelated function.
*
* It exists to ensure the undocumented filter below does not have its docblock inherited from this function.
*
* @param bool $yes
*/
function foo( bool $yes ) {}

$value = apply_filters('filter', 123, $foo);
6 changes: 4 additions & 2 deletions tests/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

declare(strict_types=1);

namespace SzepeViktor\PHPStan\WordPress\Tests;

/**
* Returns the passed value.
*
Expand All @@ -18,10 +20,10 @@ interface TestInterface
{
}

class ParentTestClass implements \TestInterface
class ParentTestClass implements TestInterface
{
}

class ChildTestClass extends \ParentTestClass
class ChildTestClass extends ParentTestClass
{
}

0 comments on commit 37eaf7e

Please sign in to comment.