Skip to content

Commit 143cebb

Browse files
authored
Merge pull request #1 from sasezaki/initial-setup
initial setups
2 parents 3a49301 + 16b55ef commit 143cebb

13 files changed

+185
-61
lines changed

composer-require-checker.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
"PHPStan\\Type\\ArrayType",
1717
"PHPStan\\Type\\Constant\\ConstantStringType",
1818
"PHPStan\\Type\\ObjectType",
19-
"PHPStan\\Type\\Type"
19+
"PHPStan\\Type\\Type",
20+
"PhpParser\\Node\\Expr\\FuncCall",
21+
"PhpParser\\Node\\Name"
2022
]
2123
}

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "struggle-for-php/sfp-phpstan-dont-operation-inside-constructor",
3-
"description": "Extra strict and opinionated resource operation rules.neon for PHPStan",
3+
"description": "Extra strict and opinionated resource operation rules for PHPStan",
44
"type": "phpstan-extension",
55
"keywords": ["phpstan", "static analysis", "constructor", "operation", "resource"],
66
"license": [
@@ -9,7 +9,7 @@
99
"require": {
1010
"php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0",
1111
"phpstan/phpstan": "^1.10",
12-
"struggle-for-php/resource-operations": "^4.0.1"
12+
"struggle-for-php/resource-operations": "^4.0.2"
1313
},
1414
"require-dev": {
1515
"laminas/laminas-coding-standard": "^2.0.0",

example/example.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
<?php
22
namespace SfpExample\PHPStan\DontOperationInsideConstructor;
33

4+
use function fopen;
5+
46
class Example
57
{
68
public function __construct()
79
{
810
$fileInfo = new \SplFileInfo('test');
911
$fileInfo->openFile('r');
12+
13+
fopen('test', 'r');
1014
}
1115

1216
public static function factory() : self

phpstan.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ parameters:
77
- test/Rules/data/*
88

99
includes:
10-
# - vendor/phpstan/phpstan-phpunit/extension.neon
10+
- vendor/phpstan/phpstan-phpunit/extension.neon
1111
- vendor/phpstan/phpstan-phpunit/rules.neon

rules.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
rules:
22
- Sfp\PHPStan\DontOperationInsideConstructor\Rules\ResourceOperationMethodCallRule
3+
- Sfp\PHPStan\DontOperationInsideConstructor\Rules\ResourceOperationFuncCallRule
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sfp\PHPStan\DontOperationInsideConstructor\Rules;
6+
7+
use PhpParser\Node;
8+
use PhpParser\Node\Name;
9+
use PHPStan\Analyser\Scope;
10+
use PHPStan\Rules\Rule;
11+
use PHPStan\Rules\RuleErrorBuilder;
12+
use Sfp\ResourceOperations\ResourceOperations;
13+
14+
use function in_array;
15+
use function sprintf;
16+
17+
/**
18+
* @implements Rule<Node\Expr\FuncCall>
19+
*/
20+
final class ResourceOperationFuncCallRule implements Rule
21+
{
22+
public function getNodeType(): string
23+
{
24+
return Node\Expr\FuncCall::class;
25+
}
26+
27+
public function processNode(Node $node, Scope $scope): array
28+
{
29+
if ($scope->getFunctionName() !== '__construct') {
30+
return [];
31+
}
32+
33+
if (! $node->name instanceof Name) {
34+
return [];
35+
}
36+
37+
$errors = [];
38+
if (in_array($node->name->toString(), ResourceOperations::getFunctions(), true)) {
39+
$errors[] = RuleErrorBuilder::message(
40+
sprintf("Don't resource operation inside constructor. function %s() is called.", $node->name->toString())
41+
)->identifier('sfp-dont-operation.resourceOperationFuncCall')->build();
42+
}
43+
44+
return $errors;
45+
}
46+
}

src/Rules/ResourceOperationMethodCallRule.php

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,43 +10,47 @@
1010
use PHPStan\Rules\RuleErrorBuilder;
1111
use Sfp\ResourceOperations\ResourceOperations;
1212

13+
use function in_array;
14+
use function sprintf;
15+
use function strtolower;
16+
1317
/**
1418
* @implements Rule<Node\Expr\MethodCall>
1519
*/
1620
final class ResourceOperationMethodCallRule implements Rule
1721
{
18-
public function getNodeType(): string
19-
{
20-
return Node\Expr\MethodCall::class;
21-
}
22-
23-
public function processNode(Node $node, Scope $scope): array
24-
{
25-
if (! $node->name instanceof Node\Identifier) {
26-
// @codeCoverageIgnoreStart
27-
return []; // @codeCoverageIgnoreEnd
28-
}
29-
30-
if ($scope->getFunctionName() !== '__construct') {
31-
return [];
32-
}
33-
34-
$calledOnType = $scope->getType($node->var);
35-
36-
$methodNames = [];
37-
foreach ($calledOnType->getObjectClassNames() as $objectClassName) {
38-
$methodNames [] = $objectClassName . '::' .strtolower($node->name->name);
39-
}
40-
41-
$errors = [];
42-
foreach ($methodNames as $methodName) {
43-
if (in_array($methodName, ResourceOperations::getMethods(), true)) {
44-
$errors[] = RuleErrorBuilder::message(
45-
sprintf("Don't resource operation inside constructor. Method %s() is called.", $methodName)
46-
)->identifier('sfp-dont-operation.resourceOperationMethodCall')->build();
47-
}
48-
}
49-
50-
return $errors;
51-
}
22+
public function getNodeType(): string
23+
{
24+
return Node\Expr\MethodCall::class;
25+
}
26+
27+
public function processNode(Node $node, Scope $scope): array
28+
{
29+
if (! $node->name instanceof Node\Identifier) {
30+
// @codeCoverageIgnoreStart
31+
return []; // @codeCoverageIgnoreEnd
32+
}
33+
34+
if ($scope->getFunctionName() !== '__construct') {
35+
return [];
36+
}
37+
38+
$calledOnType = $scope->getType($node->var);
39+
40+
$methodNames = [];
41+
foreach ($calledOnType->getObjectClassNames() as $objectClassName) {
42+
$methodNames [] = $objectClassName . '::' . strtolower($node->name->name);
43+
}
44+
45+
$errors = [];
46+
foreach ($methodNames as $methodName) {
47+
if (in_array($methodName, ResourceOperations::getMethods(), true)) {
48+
$errors[] = RuleErrorBuilder::message(
49+
sprintf("Don't resource operation inside constructor. Method %s() is called.", $methodName)
50+
)->identifier('sfp-dont-operation.resourceOperationMethodCall')->build();
51+
}
52+
}
53+
54+
return $errors;
55+
}
5256
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SfpTest\PHPStan\DontOperationInsideConstructor\Rules;
6+
7+
use PHPStan\Rules\Rule;
8+
use PHPStan\Testing\RuleTestCase;
9+
use Sfp\PHPStan\DontOperationInsideConstructor\Rules\ResourceOperationFuncCallRule;
10+
11+
/**
12+
* @extends RuleTestCase<ResourceOperationFuncCallRule>
13+
* @covers \Sfp\PHPStan\DontOperationInsideConstructor\Rules\ResourceOperationFuncCallRule
14+
*/
15+
class ResourceOperationFuncCallRuleTest extends RuleTestCase
16+
{
17+
public function getRule(): Rule
18+
{
19+
return new ResourceOperationFuncCallRule();
20+
}
21+
22+
public function testProcess(): void
23+
{
24+
$this->analyse([__DIR__ . '/data/ResourceOperationFuncCall.php'], [
25+
[
26+
"Don't resource operation inside constructor. function fopen() is called.",
27+
13,
28+
],
29+
]);
30+
}
31+
}
Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace SfpTest\PHPStan\DontOperationInsideConstructor\Rules;
46

57
use PHPStan\Rules\Rule;
@@ -8,21 +10,22 @@
810

911
/**
1012
* @extends RuleTestCase<ResourceOperationMethodCallRule>
13+
* @covers \Sfp\PHPStan\DontOperationInsideConstructor\Rules\ResourceOperationMethodCallRule
1114
*/
1215
class ResourceOperationMethodCallRuleTest extends RuleTestCase
1316
{
14-
public function getRule(): Rule
15-
{
16-
return new ResourceOperationMethodCallRule();
17-
}
17+
public function getRule(): Rule
18+
{
19+
return new ResourceOperationMethodCallRule();
20+
}
1821

19-
public function testProcess(): void
20-
{
21-
$this->analyse([__DIR__ . '/data/resourceOperationMethodCall.php'], [
22-
[
23-
"Don't resource operation inside constructor. Method SplFileInfo::openfile() is called.",
24-
8
25-
]
26-
]);
27-
}
22+
public function testProcess(): void
23+
{
24+
$this->analyse([__DIR__ . '/data/ResourceOperationMethodCall.php'], [
25+
[
26+
"Don't resource operation inside constructor. Method SplFileInfo::openfile() is called.",
27+
14,
28+
],
29+
]);
30+
}
2831
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SfpTest\PHPStan\DontOperationInsideConstructor\Rules\data;
6+
7+
use function fopen;
8+
9+
class ResourceOperationFuncCall
10+
{
11+
public function __construct()
12+
{
13+
$fp = fopen('test', 'r');
14+
15+
(function () {
16+
})();
17+
}
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SfpTest\PHPStan\DontOperationInsideConstructor\Rules\data;
6+
7+
use SplFileInfo;
8+
9+
class ResourceOperationMethodCall
10+
{
11+
public function __construct()
12+
{
13+
$fileInfo = new SplFileInfo('test');
14+
$fileInfo->openFile('r');
15+
}
16+
}

test/Rules/data/resourceOperationMethodCall.php

Lines changed: 0 additions & 10 deletions
This file was deleted.

test/example.output

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<testsuite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" failures="2" name="phpstan" tests="2" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/junit-team/junit5/r5.5.1/platform-tests/src/test/resources/jenkins-junit.xsd">
3+
<testcase name="example/example.php:11">
4+
<failure type="ERROR" message="Don't resource operation inside constructor. Method SplFileInfo::openfile() is called."/>
5+
</testcase>
6+
<testcase name="example/example.php:13">
7+
<failure type="ERROR" message="Don't resource operation inside constructor. function fopen() is called."/>
8+
</testcase>
9+
</testsuite>

0 commit comments

Comments
 (0)