Skip to content

Commit

Permalink
Merge pull request #97 from ruudk/identifier
Browse files Browse the repository at this point in the history
Allow specifying `errorIdentifier` to `RuleError`
  • Loading branch information
spaze authored Dec 30, 2021
2 parents 2cc2d86 + 16d56cc commit dd58d51
Show file tree
Hide file tree
Showing 23 changed files with 97 additions and 34 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ parameters:
-
method: 'Redis::connect()'
message: 'use our own Redis instead'
errorIdentifier: 'redis.connect'
disallowedStaticCalls:
-
Expand Down Expand Up @@ -136,6 +137,8 @@ parameters:

The `message` key is optional. Functions and methods can be specified with or without `()`. Omitting `()` is not recommended though to avoid confusing method calls with class constants.

The `errorIdentifier` key is optional. It can be used to provide a unique identifier to the PHPStan error.

Use wildcard (`*`) to ignore all functions, methods, namespaces starting with a prefix, for example:
```neon
parameters:
Expand Down
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[], allowInFunctions?:string[], allowInMethods?: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>, allowExceptParams?:array<integer, integer|boolean|string>, allowExceptCaseInsensitiveParams?:array<integer, integer|boolean|string>}>'
ForbiddenCallsConfig: 'array<array{function?:string, method?:string, message?:string, allowIn?:string[], allowInFunctions?:string[], allowInMethods?: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>, allowExceptParams?:array<integer, integer|boolean|string>, allowExceptCaseInsensitiveParams?:array<integer, integer|boolean|string>, errorIdentifier?:string}>'

includes:
- vendor/phpstan/phpstan/conf/bleedingEdge.neon
Expand Down
3 changes: 2 additions & 1 deletion src/Calls/EchoCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpParser\Node\Stmt\Echo_;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
Expand Down Expand Up @@ -52,7 +53,7 @@ public function getNodeType(): string
/**
* @param Echo_ $node
* @param Scope $scope
* @return string[]
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand Down
3 changes: 2 additions & 1 deletion src/Calls/EmptyCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpParser\Node\Expr\Empty_;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
Expand Down Expand Up @@ -52,7 +53,7 @@ public function getNodeType(): string
/**
* @param Empty_ $node
* @param Scope $scope
* @return string[]
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand Down
3 changes: 2 additions & 1 deletion src/Calls/EvalCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpParser\Node\Expr\Eval_;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
Expand Down Expand Up @@ -52,7 +53,7 @@ public function getNodeType(): string
/**
* @param Eval_ $node
* @param Scope $scope
* @return string[]
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand Down
3 changes: 2 additions & 1 deletion src/Calls/ExitDieCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpParser\Node\Expr\Exit_;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
Expand Down Expand Up @@ -52,7 +53,7 @@ public function getNodeType(): string
/**
* @param Exit_ $node
* @param Scope $scope
* @return string[]
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand Down
3 changes: 2 additions & 1 deletion src/Calls/FunctionCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PhpParser\Node\Name;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
Expand Down Expand Up @@ -53,7 +54,7 @@ public function getNodeType(): string
/**
* @param FuncCall $node
* @param Scope $scope
* @return string[]
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand Down
3 changes: 2 additions & 1 deletion src/Calls/MethodCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
Expand Down Expand Up @@ -55,7 +56,7 @@ public function getNodeType(): string
/**
* @param MethodCall $node
* @param Scope $scope
* @return string[]
* @return RuleError[]
* @throws ClassNotFoundException
*/
public function processNode(Node $node, Scope $scope): array
Expand Down
3 changes: 2 additions & 1 deletion src/Calls/NewCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PhpParser\Node\Name;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use PHPStan\Type\ConstantScalarType;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
Expand Down Expand Up @@ -55,7 +56,7 @@ public function getNodeType(): string
/**
* @param New_ $node
* @param Scope $scope
* @return string[]
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand Down
3 changes: 2 additions & 1 deletion src/Calls/PrintCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpParser\Node\Expr\Print_;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
Expand Down Expand Up @@ -52,7 +53,7 @@ public function getNodeType(): string
/**
* @param Print_ $node
* @param Scope $scope
* @return string[]
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand Down
3 changes: 2 additions & 1 deletion src/Calls/ShellExecCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpParser\Node\Expr\ShellExec;
use PHPStan\Analyser\Scope;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
Expand Down Expand Up @@ -56,7 +57,7 @@ public function getNodeType(): string
/**
* @param ShellExec $node
* @param Scope $scope
* @return string[]
* @return RuleError[]
*/
public function processNode(Node $node, Scope $scope): array
{
Expand Down
3 changes: 2 additions & 1 deletion src/Calls/StaticCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PHPStan\Analyser\Scope;
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\ShouldNotHappenException;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCall;
use Spaze\PHPStan\Rules\Disallowed\DisallowedCallFactory;
Expand Down Expand Up @@ -55,7 +56,7 @@ public function getNodeType(): string
/**
* @param StaticCall $node
* @param Scope $scope
* @return string[]
* @return RuleError[]
* @throws ClassNotFoundException
*/
public function processNode(Node $node, Scope $scope): array
Expand Down
13 changes: 12 additions & 1 deletion src/DisallowedCall.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class DisallowedCall
/** @var array<int, DisallowedCallParam> */
private $allowExceptParams;

/** @var string */
private $errorIdentifier;


/**
* DisallowedCall constructor.
Expand All @@ -44,8 +47,9 @@ class DisallowedCall
* @param array<int, DisallowedCallParam> $allowParamsAnywhere
* @param array<int, DisallowedCallParam> $allowExceptParamsInAllowed
* @param array<int, DisallowedCallParam> $allowExceptParams
* @param string $errorIdentifier
*/
public function __construct(string $call, ?string $message, array $allowIn, array $allowInCalls, array $allowParamsInAllowed, array $allowParamsAnywhere, array $allowExceptParamsInAllowed, array $allowExceptParams)
public function __construct(string $call, ?string $message, array $allowIn, array $allowInCalls, array $allowParamsInAllowed, array $allowParamsAnywhere, array $allowExceptParamsInAllowed, array $allowExceptParams, string $errorIdentifier)
{
$this->call = $call;
$this->message = $message;
Expand All @@ -55,6 +59,7 @@ public function __construct(string $call, ?string $message, array $allowIn, arra
$this->allowParamsAnywhere = $allowParamsAnywhere;
$this->allowExceptParamsInAllowed = $allowExceptParamsInAllowed;
$this->allowExceptParams = $allowExceptParams;
$this->errorIdentifier = $errorIdentifier;
}


Expand Down Expand Up @@ -124,6 +129,12 @@ public function getAllowExceptParams(): array
}


public function getErrorIdentifier(): string
{
return $this->errorIdentifier;
}


public function getKey(): string
{
// The key consists of "initial" config values that would be overwritten with more specific details in a custom config.
Expand Down
3 changes: 2 additions & 1 deletion src/DisallowedCallFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public function createFromConfig(array $config): array
$allowParamsInAllowed,
$allowParamsAnywhere,
$allowExceptParamsInAllowed,
$allowExceptParams
$allowExceptParams,
$disallowedCall['errorIdentifier'] ?? ''
);
$calls[$disallowedCall->getKey()] = $disallowedCall;
}
Expand Down
13 changes: 12 additions & 1 deletion src/DisallowedConstant.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,24 @@ class DisallowedConstant
/** @var string[] */
private $allowIn;

/** @var string */
private $errorIdentifier;


/**
* DisallowedCall constructor.
*
* @param string $constant
* @param string|null $message
* @param string[] $allowIn
* @param string $errorIdentifier
*/
public function __construct(string $constant, ?string $message, array $allowIn)
public function __construct(string $constant, ?string $message, array $allowIn, string $errorIdentifier)
{
$this->constant = ltrim($constant, '\\');
$this->message = $message;
$this->allowIn = $allowIn;
$this->errorIdentifier = $errorIdentifier;
}


Expand All @@ -51,4 +56,10 @@ public function getAllowIn(): array
return $this->allowIn;
}


public function getErrorIdentifier(): string
{
return $this->errorIdentifier;
}

}
5 changes: 3 additions & 2 deletions src/DisallowedConstantFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class DisallowedConstantFactory
{

/**
* @param array<array{class?:string, constant?:string, message?:string, allowIn?:string[]}> $config
* @param array<array{class?:string, constant?:string, message?:string, allowIn?:string[], errorIdentifier?:string}> $config
* @return DisallowedConstant[]
* @throws ShouldNotHappenException
*/
Expand All @@ -25,7 +25,8 @@ public function createFromConfig(array $config): array
$disallowedConstant = new DisallowedConstant(
$class ? "{$class}::{$constant}" : $constant,
$disallowedConstant['message'] ?? null,
$disallowedConstant['allowIn'] ?? []
$disallowedConstant['allowIn'] ?? [],
$disallowedConstant['errorIdentifier'] ?? ''
);
$constants[$disallowedConstant->getConstant()] = $disallowedConstant;
}
Expand Down
20 changes: 13 additions & 7 deletions src/DisallowedHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
use PHPStan\Broker\ClassNotFoundException;
use PHPStan\Reflection\FunctionReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\ConstantScalarType;
use PHPStan\Type\ObjectType;
use PHPStan\Type\Type;
Expand Down Expand Up @@ -111,19 +113,21 @@ private function getArgType(CallLike $node, Scope $scope, int $param): ?Type
* @param string|null $displayName
* @param DisallowedCall[] $disallowedCalls
* @param string|null $message
* @return string[]
* @return RuleError[]
*/
public function getDisallowedMessage(?CallLike $node, Scope $scope, string $name, ?string $displayName, array $disallowedCalls, ?string $message = null): array
{
foreach ($disallowedCalls as $disallowedCall) {
if ($this->callMatches($disallowedCall, $name) && !$this->isAllowed($scope, $node, $disallowedCall)) {
return [
sprintf(
RuleErrorBuilder::message(sprintf(
$message ?? 'Calling %s is forbidden, %s%s',
($displayName && $displayName !== $name) ? "{$name}() (as {$displayName}())" : "{$name}()",
$disallowedCall->getMessage(),
$disallowedCall->getCall() !== $name ? " [{$name}() matches {$disallowedCall->getCall()}()]" : ''
),
))
->identifier($disallowedCall->getErrorIdentifier())
->build(),
];
}
}
Expand All @@ -145,7 +149,7 @@ private function callMatches(DisallowedCall $disallowedCall, string $name): bool
* @param CallLike $node
* @param Scope $scope
* @param DisallowedCall[] $disallowedCalls
* @return string[]
* @return RuleError[]
* @throws ClassNotFoundException
*/
public function getDisallowedMethodMessage($class, CallLike $node, Scope $scope, array $disallowedCalls): array
Expand Down Expand Up @@ -215,19 +219,21 @@ private function isAllowedPath(Scope $scope, DisallowedConstant $disallowedConst
* @param Scope $scope
* @param string|null $displayName
* @param DisallowedConstant[] $disallowedConstants
* @return string[]
* @return RuleError[]
*/
public function getDisallowedConstantMessage(string $constant, Scope $scope, ?string $displayName, array $disallowedConstants): array
{
foreach ($disallowedConstants as $disallowedConstant) {
if ($disallowedConstant->getConstant() === $constant && !$this->isAllowedPath($scope, $disallowedConstant)) {
return [
sprintf(
RuleErrorBuilder::message(sprintf(
'Using %s%s is forbidden, %s',
$disallowedConstant->getConstant(),
$displayName && $displayName !== $disallowedConstant->getConstant() ? ' (as ' . $displayName . ')' : '',
$disallowedConstant->getMessage()
),
))
->identifier($disallowedConstant->getErrorIdentifier())
->build(),
];
}
}
Expand Down
Loading

0 comments on commit dd58d51

Please sign in to comment.