Skip to content

Commit 4450554

Browse files
committed
Initial commit
0 parents  commit 4450554

20 files changed

+696
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
vendor
2+
composer.lock
3+
var/*
4+
!var/.gitkeep
5+
.phpunit.result.cache

.travis.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
language: php
2+
dist: bionic
3+
4+
php:
5+
- "7.3"
6+
- "7.4"
7+
8+
install: travis_retry composer update --prefer-lowest --prefer-dist
9+
10+
before_script:
11+
- phpenv config-rm xdebug.ini
12+
13+
script:
14+
- make --keep-going tests-unit
15+
16+
cache:
17+
directories:
18+
- $HOME/.composer/cache

Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM php:7.3-alpine
2+
3+
COPY --from=composer /usr/bin/composer /usr/bin/composer
4+
5+
RUN composer global require hirak/prestissimo && composer clearcache
6+
7+
RUN apk add --no-cache make git

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 Sourceability
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.PHONY: help
2+
.DEFAULT_GOAL := help
3+
4+
help:
5+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
6+
7+
tests-unit:
8+
vendor/bin/phpunit
9+
10+
bash: ## Starts a bash session in the php container
11+
docker-compose exec php /bin/sh

composer.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "sourceability/phpstan-rules",
3+
"description": "PHPStan additional rules",
4+
"autoload": {
5+
"psr-4": {
6+
"Sourceability\\PHPStan\\": "src/"
7+
}
8+
},
9+
"autoload-dev": {
10+
"psr-4": {
11+
"Sourceability\\PHPStan\\Tests\\": "tests/"
12+
}
13+
},
14+
"require": {
15+
"php": "^7.3",
16+
"phpstan/phpstan": "^0.12",
17+
"phpstan/phpstan-strict-rules": "^0.12"
18+
},
19+
"require-dev": {
20+
"phpunit/phpunit": "^8.5"
21+
},
22+
"type": "library",
23+
"license": "MIT"
24+
}

docker-compose.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
version: "3.2"
2+
3+
services:
4+
php:
5+
build: .
6+
volumes:
7+
- .:/app:cached
8+
working_dir: /app
9+
command: tail -f /dev/null

phpunit.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<!-- https://phpunit.de/manual/current/en/appendixes.configuration.html -->
4+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/7.4/phpunit.xsd"
6+
backupGlobals="false"
7+
colors="true"
8+
bootstrap="vendor/autoload.php"
9+
>
10+
<testsuites>
11+
<testsuite name="Project Test Suite">
12+
<directory>tests</directory>
13+
</testsuite>
14+
</testsuites>
15+
</phpunit>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
namespace Sourceability\PHPStan\Rules;
4+
5+
use PhpParser\Node;
6+
use PhpParser\Node\Expr\BinaryOp;
7+
use PhpParser\Node\Expr\BinaryOp\Identical;
8+
use PHPStan\Analyser\Scope;
9+
use PHPStan\Rules\BooleansInConditions\BooleanRuleHelper;
10+
use PHPStan\Rules\Rule;
11+
12+
class ConstantBooleanIdenticalRule implements Rule
13+
{
14+
/**
15+
* @var ConstantBooleanRuleHelper
16+
*/
17+
private $constantBooleanRuleHelper;
18+
19+
/**
20+
* @var BooleanRuleHelper
21+
*/
22+
private $booleanRuleHelper;
23+
24+
public function __construct(
25+
ConstantBooleanRuleHelper $constantBooleanRuleHelper,
26+
BooleanRuleHelper $booleanRuleHelper
27+
) {
28+
$this->constantBooleanRuleHelper = $constantBooleanRuleHelper;
29+
$this->booleanRuleHelper = $booleanRuleHelper;
30+
}
31+
32+
public function getNodeType(): string
33+
{
34+
return Identical::class;
35+
}
36+
37+
/**
38+
* @return string[] errors
39+
*/
40+
public function processNode(Node $node, Scope $scope): array
41+
{
42+
if (!$node instanceof BinaryOp) {
43+
return [];
44+
}
45+
46+
$constantBooleanTypeLeft = $this->constantBooleanRuleHelper->getNonMixedConstantBooleanType(
47+
$scope,
48+
$node->left
49+
);
50+
$constantBooleanTypeRight = $this->constantBooleanRuleHelper->getNonMixedConstantBooleanType(
51+
$scope,
52+
$node->right
53+
);
54+
55+
if (null === $constantBooleanTypeLeft
56+
&& null === $constantBooleanTypeRight
57+
) {
58+
return [];
59+
}
60+
61+
if (null !== $constantBooleanTypeLeft
62+
&& null !== $constantBooleanTypeRight
63+
) {
64+
return [];
65+
}
66+
67+
if (null !== $constantBooleanTypeLeft) {
68+
if ($this->booleanRuleHelper->passesAsBoolean($scope, $node->right)) {
69+
if ($constantBooleanTypeLeft->getValue()) {
70+
return ['Replace true === $boolean with $boolean'];
71+
}
72+
73+
return ['Replace false === $boolean with !$boolean'];
74+
}
75+
}
76+
77+
if (null !== $constantBooleanTypeRight) {
78+
if ($this->booleanRuleHelper->passesAsBoolean($scope, $node->right)) {
79+
if ($constantBooleanTypeRight->getValue()) {
80+
return ['Replace $boolean === true with $boolean'];
81+
}
82+
83+
return ['Replace $boolean === false with !$boolean'];
84+
}
85+
}
86+
87+
return [];
88+
}
89+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
namespace Sourceability\PHPStan\Rules;
4+
5+
use PhpParser\Node;
6+
use PhpParser\Node\Expr\BinaryOp;
7+
use PhpParser\Node\Expr\BinaryOp\NotIdentical;
8+
use PHPStan\Analyser\Scope;
9+
use PHPStan\Rules\BooleansInConditions\BooleanRuleHelper;
10+
use PHPStan\Rules\Rule;
11+
12+
class ConstantBooleanNotIdenticalRule implements Rule
13+
{
14+
/**
15+
* @var ConstantBooleanRuleHelper
16+
*/
17+
private $constantBooleanRuleHelper;
18+
19+
/**
20+
* @var BooleanRuleHelper
21+
*/
22+
private $booleanRuleHelper;
23+
24+
public function __construct(
25+
ConstantBooleanRuleHelper $constantBooleanRuleHelper,
26+
BooleanRuleHelper $booleanRuleHelper
27+
) {
28+
$this->constantBooleanRuleHelper = $constantBooleanRuleHelper;
29+
$this->booleanRuleHelper = $booleanRuleHelper;
30+
}
31+
32+
public function getNodeType(): string
33+
{
34+
return NotIdentical::class;
35+
}
36+
37+
/**
38+
* @return string[] errors
39+
*/
40+
public function processNode(Node $node, Scope $scope): array
41+
{
42+
if (!$node instanceof BinaryOp) {
43+
return [];
44+
}
45+
46+
$constantBooleanTypeLeft = $this->constantBooleanRuleHelper->getNonMixedConstantBooleanType(
47+
$scope,
48+
$node->left
49+
);
50+
$constantBooleanTypeRight = $this->constantBooleanRuleHelper->getNonMixedConstantBooleanType(
51+
$scope,
52+
$node->right
53+
);
54+
55+
if (null === $constantBooleanTypeLeft
56+
&& null === $constantBooleanTypeRight
57+
) {
58+
return [];
59+
}
60+
61+
if (null !== $constantBooleanTypeLeft
62+
&& null !== $constantBooleanTypeRight
63+
) {
64+
return [];
65+
}
66+
67+
if (null !== $constantBooleanTypeLeft) {
68+
if ($this->booleanRuleHelper->passesAsBoolean($scope, $node->right)) {
69+
if ($constantBooleanTypeLeft->getValue()) {
70+
return ['Replace true !== $boolean with !$boolean'];
71+
}
72+
73+
return ['Replace false !== $boolean with $boolean'];
74+
}
75+
}
76+
77+
if (null !== $constantBooleanTypeRight) {
78+
if ($this->booleanRuleHelper->passesAsBoolean($scope, $node->right)) {
79+
if ($constantBooleanTypeRight->getValue()) {
80+
return ['Replace $boolean !== true with !$boolean'];
81+
}
82+
83+
return ['Replace $boolean !== false with $boolean'];
84+
}
85+
}
86+
87+
return [];
88+
}
89+
}

0 commit comments

Comments
 (0)