Skip to content

Commit

Permalink
FIXUP
Browse files Browse the repository at this point in the history
  • Loading branch information
spaze committed Nov 24, 2022
1 parent 1cd0865 commit 34725e2
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 28 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ jobs:
run: composer lint
include:
- php-version: "7.2"
run: composer lint -- --exclude tests/libs/TypesEverywhere.php
run: composer lint -- --exclude tests/libs/TypesEverywhere.php --exclude tests/src/disallowed/functionCallsNamedParams.php --exclude tests/src/disallowed-allowed/functionCallsNamedParams.php
- php-version: "7.3"
run: composer lint -- --exclude tests/libs/TypesEverywhere.php
run: composer lint -- --exclude tests/libs/TypesEverywhere.php --exclude tests/src/disallowed/functionCallsNamedParams.php --exclude tests/src/disallowed-allowed/functionCallsNamedParams.php
- php-version: "7.4"
run: composer lint -- --exclude tests/libs/TypesEverywhere.php
run: composer lint -- --exclude tests/libs/TypesEverywhere.php --exclude tests/src/disallowed/functionCallsNamedParams.php --exclude tests/src/disallowed-allowed/functionCallsNamedParams.php
- php-version: "8.0"
run: composer lint -- --exclude tests/libs/TypesEverywhere.php

Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,20 @@ parameters:

Calling `waldo()` is disallowed, and allowed back again only when the file is in the `views/` subdirectory **and** `waldo()` is called in the file with a 2nd parameter being the string `quux`.

Named parameters are partially supported:

```neon
parameters:
disallowedFunctionCalls:
- -
- function: 'json_decode()'
- message: 'set the $flags parameter to `JSON_THROW_ON_ERROR` to throw a JsonException'
- allowParamsAnywhere:
- flags: ::JSON_THROW_ON_ERROR
```

Currently, this will only allow a call like `json_decode($foo, flags: JSON_THROW_ON_ERROR)` but won't allow "positional" call like `json_decode($foo, null, 512, JSON_THROW_ON_ERROR)` even though it's technically the same parameter.

## Case-(in)sensitivity

Function names, method names, class names, namespaces are matched irrespective of their case (disallowing `print_r` will also find `print_R` calls), while anything else like constants, file names, paths are not.
Expand Down
5 changes: 0 additions & 5 deletions disallowed-loose-calls.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,3 @@ parameters:
message: 'set the $flags parameter to `ENT_QUOTES` to also convert single quotes to entities to prevent some HTML injection bugs'
allowParamsAnywhere:
2: ::ENT_QUOTES
-
function: 'json_decode()'
message: 'set the $flags parameter to `JSON_THROW_ON_ERROR` to throw a JsonException()'
allowParamsAnywhere:
'flags': ::JSON_THROW_ON_ERROR
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ parameters:
- src
level: max
typeAliases:
ForbiddenCallsConfig: 'array<array{function?:string, method?:string, message?:string, allowIn?:string[], allowExceptIn?:string[], disallowIn?:string[], allowInFunctions?:string[], allowInMethods?:string[], allowExceptInFunctions?:string[], allowExceptInMethods?:string[], disallowInFunctions?:string[], disallowInMethods?:string[], allowParamsInAllowed?:array<integer, integer|boolean|string>, allowParamsInAllowedAnyValue?:array<integer, integer>, allowParamsAnywhere?:array<integer, integer|boolean|string>, allowParamsAnywhereAnyValue?:array<integer, integer>, allowExceptParamsInAllowed?:array<integer, integer|boolean|string>, disallowParamsInAllowed?:array<integer, integer|boolean|string>, allowExceptParams?:array<integer, integer|boolean|string>, disallowParams?:array<integer, integer|boolean|string>, allowExceptCaseInsensitiveParams?:array<integer, integer|boolean|string>, disallowCaseInsensitiveParams?:array<integer, integer|boolean|string>, errorIdentifier?:string, errorTip?:string}>'
ForbiddenCallsConfig: 'array<array{function?:string, method?:string, message?:string, allowIn?:string[], allowExceptIn?:string[], disallowIn?:string[], allowInFunctions?:string[], allowInMethods?:string[], allowExceptInFunctions?:string[], allowExceptInMethods?:string[], disallowInFunctions?:string[], disallowInMethods?:string[], allowParamsInAllowed?:array<int|string, int|bool|string>, allowParamsInAllowedAnyValue?:array<int|string, int>, allowParamsAnywhere?:array<int|string, int|bool|string>, allowParamsAnywhereAnyValue?:array<int|string, int>, allowExceptParamsInAllowed?:array<int|string, int|bool|string>, disallowParamsInAllowed?:array<int|string, int|bool|string>, allowExceptParams?:array<int|string, int|bool|string>, disallowParams?:array<int|string, int|bool|string>, allowExceptCaseInsensitiveParams?:array<int|string, int|bool|string>, disallowCaseInsensitiveParams?:array<int|string, int|bool|string>, errorIdentifier?:string, errorTip?:string}>'

includes:
- vendor/phpstan/phpstan/conf/bleedingEdge.neon
Expand Down
24 changes: 12 additions & 12 deletions src/DisallowedCall.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ class DisallowedCall implements Disallowed
/** @var string[] */
private $allowExceptInCalls;

/** @var array<int, DisallowedCallParam> */
/** @var array<int|string, DisallowedCallParam> */
private $allowParamsInAllowed;

/** @var array<int, DisallowedCallParam> */
/** @var array<int|string, DisallowedCallParam> */
private $allowParamsAnywhere;

/** @var array<int, DisallowedCallParam> */
/** @var array<int|string, DisallowedCallParam> */
private $allowExceptParamsInAllowed;

/** @var array<int, DisallowedCallParam> */
/** @var array<int|string, DisallowedCallParam> */
private $allowExceptParams;

/** @var string|null */
Expand All @@ -52,10 +52,10 @@ class DisallowedCall implements Disallowed
* @param string[] $allowExceptIn
* @param string[] $allowInCalls
* @param string[] $allowExceptInCalls
* @param array<int, DisallowedCallParam> $allowParamsInAllowed
* @param array<int, DisallowedCallParam> $allowParamsAnywhere
* @param array<int, DisallowedCallParam> $allowExceptParamsInAllowed
* @param array<int, DisallowedCallParam> $allowExceptParams
* @param array<int|string, DisallowedCallParam> $allowParamsInAllowed
* @param array<int|string, DisallowedCallParam> $allowParamsAnywhere
* @param array<int|string, DisallowedCallParam> $allowExceptParamsInAllowed
* @param array<int|string, DisallowedCallParam> $allowExceptParams
* @param string|null $errorIdentifier
* @param string|null $errorTip
*/
Expand Down Expand Up @@ -133,7 +133,7 @@ public function getAllowExceptInCalls(): array


/**
* @return array<int, DisallowedCallParam>
* @return array<int|string, DisallowedCallParam>
*/
public function getAllowParamsInAllowed(): array
{
Expand All @@ -142,7 +142,7 @@ public function getAllowParamsInAllowed(): array


/**
* @return array<int, DisallowedCallParam>
* @return array<int|string, DisallowedCallParam>
*/
public function getAllowParamsAnywhere(): array
{
Expand All @@ -151,7 +151,7 @@ public function getAllowParamsAnywhere(): array


/**
* @return array<int, DisallowedCallParam>
* @return array<int|string, DisallowedCallParam>
*/
public function getAllowExceptParamsInAllowed(): array
{
Expand All @@ -160,7 +160,7 @@ public function getAllowExceptParamsInAllowed(): array


/**
* @return array<int, DisallowedCallParam>
* @return array<int|string, DisallowedCallParam>
*/
public function getAllowExceptParams(): array
{
Expand Down
16 changes: 10 additions & 6 deletions src/DisallowedHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

namespace Spaze\PHPStan\Rules\Disallowed;

use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\CallLike;
use PhpParser\Node\Identifier;
Expand Down Expand Up @@ -96,7 +95,7 @@ private function hasAllowedParamsInAllowed(Scope $scope, ?CallLike $node, Disall
/**
* @param Scope $scope
* @param CallLike|null $node
* @param array<int, DisallowedCallParam> $allowConfig
* @param array<int|string, DisallowedCallParam> $allowConfig
* @param bool $paramsRequired
* @return bool
*/
Expand All @@ -119,14 +118,19 @@ private function hasAllowedParams(Scope $scope, ?CallLike $node, array $allowCon
}


private function getArgType(CallLike $node, Scope $scope, int|string $param): ?Type
/**
* @param CallLike $node
* @param Scope $scope
* @param int|string $param
* @return Type|null
*/
private function getArgType(CallLike $node, Scope $scope, $param): ?Type
{
if (is_numeric($param)) {
$arg = $node->getArgs()[$param - 1] ?? null;
} else if (is_string($param)) {
/** @var Arg $a */
} elseif (is_string($param)) {
foreach ($node->getArgs() as $a) {
if ($a->name->name === $param) {
if ($a->name && $a->name->name === $param) {
$arg = $a;
break;
}
Expand Down
87 changes: 87 additions & 0 deletions tests/Calls/FunctionCallsNamedParamsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php
declare(strict_types = 1);

namespace Spaze\PHPStan\Rules\Disallowed\Calls;

use PHPStan\File\FileHelper;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
use Spaze\PHPStan\Rules\Disallowed\DisallowedHelper;
use Spaze\PHPStan\Rules\Disallowed\IsAllowedFileHelper;

/**
* @requires PHP > 8.0
*/
class FunctionCallsNamedParamsTest extends RuleTestCase
{

protected function getRule(): Rule
{
return new FunctionCalls(
new DisallowedHelper(new IsAllowedFileHelper(new FileHelper(__DIR__))),
new DisallowedCallFactory(),
[
[
'function' => 'setcookie()',
'allowIn' => [
'../src/disallowed-allowed/*.php',
'../src/*-allow/*.*',
],
'allowParamsAnywhereAnyValue' => [
'value',
],
'allowParamsInAllowedAnyValue' => [
'path',
],
],
]
);
}


public function testRule(): void
{
// Based on the configuration above, in this file:
$this->analyse([__DIR__ . '/../src/disallowed/functionCallsNamedParams.php'], [
[
// expect this error message:
'Calling setcookie() is forbidden, because reasons',
// on this line:
5,
],
[
'Calling setcookie() is forbidden, because reasons',
6,
],
[
'Calling setcookie() is forbidden, because reasons',
8,
],
[
'Calling setcookie() is forbidden, because reasons',
9,
],
]);
// Based on the configuration above, no errors in this file:
$this->analyse([__DIR__ . '/../src/disallowed-allow/functionCallsNamedParams.php'], [
[
'Calling setcookie() is forbidden, because reasons',
5,
],
[
'Calling setcookie() is forbidden, because reasons',
6,
],
[
'Calling setcookie() is forbidden, because reasons',
7,
],
[
'Calling setcookie() is forbidden, because reasons',
8,
],
]);
}

}
1 change: 0 additions & 1 deletion tests/src/configs/looseCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,3 @@
htmlspecialchars('foo', ENT_QUOTES);
htmlspecialchars('foo', 3);
htmlspecialchars('foo', 4);
json_decode('foo', flags: JSON_THROW_ON_ERROR);
9 changes: 9 additions & 0 deletions tests/src/disallowed-allow/functionCallsNamedParams.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php
declare(strict_types = 1);

// fourth/$path param needed
setcookie('foo');
setcookie('foo', 'bar');
setcookie('foo', value: 'bar');
setcookie('foo', 'bar', 0, '/');
setcookie('foo', 'bar', path: '/');
9 changes: 9 additions & 0 deletions tests/src/disallowed/functionCallsNamedParams.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php
declare(strict_types = 1);

// second/$value param needed
setcookie('foo');
setcookie('foo', 'bar');
setcookie('foo', value: 'bar');
setcookie('foo', 'bar', 0, '/');
setcookie('foo', 'bar', path: '/');

0 comments on commit 34725e2

Please sign in to comment.