Skip to content

Commit

Permalink
enhance PHPStan error/rule display with SARIF viewer and helpUri
Browse files Browse the repository at this point in the history
  • Loading branch information
llaville committed Jul 31, 2024
1 parent 4d144de commit 867f2a2
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 14 deletions.
Binary file modified docs/assets/images/phpstorm-phpstan.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/images/sarif-web-phpstan.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 12 additions & 2 deletions docs/converter/phpstan.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
4. [How to customize your converter](#how-to-customize-your-converter)
5. [Learn more](#learn-more)
6. [IDE Integration](#ide-integration)
7. [Web SARIF viewer](#web-sarif-viewer)

![phpstan converter](../assets/images/converter-phpstan.graphviz.svg)

## Requirements

* [PHPStan][phpstan] requires PHP version 7.2.0 or greater
* This SARIF converter requires at least PHPStan version 1.9.0
* [PHPStan][phpstan] requires PHP version 8.1.0 or greater
* This SARIF converter requires at least PHPStan version 1.11.0

## Installation

Expand Down Expand Up @@ -110,6 +111,15 @@ The SARIF report file `[*].sarif.json` is automagically recognized and interpret

![PHPStorm integration](../assets/images/phpstorm-phpstan.png)

## Web SARIF viewer

With the [React based component][sarif-web-component], you are able to explore a sarif report file previously generated.

For example:

![sarif-web-phpstan](../assets/images/sarif-web-phpstan.png)

[example-folder]: https://github.com/llaville/sarif-php-converters/blob/1.0/examples/phpstan/
[json-encode]: https://www.php.net/manual/en/function.json-encode
[phpstan]: https://github.com/phpstan/phpstan
[sarif-web-component]: https://github.com/Microsoft/sarif-web-component
2 changes: 1 addition & 1 deletion examples/phpstan/.sarif.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"$schema":"https://json.schemastore.org/sarif-2.1.0.json","version":"2.1.0","runs":[{"tool":{"driver":{"name":"PHPStan","shortDescription":{"text":"PHP Static Analysis Tool"},"fullDescription":{"text":"PHPStan - PHP Static Analysis Tool"},"fullName":"PHPStan - PHP Static Analysis Tool 1.11.6.0","semanticVersion":"1.11.6.0","informationUri":"https://phpstan.org","rules":[{"id":"PHPSTAN101","shortDescription":{"text":"Analysis error"},"fullDescription":{"text":"Errors detected during analysis of source files"},"helpUri":"https://phpstan.org/user-guide/getting-started","help":{"text":"https://phpstan.org/user-guide/command-line-usage"}}]},"extensions":[{"name":"bartlett/sarif-php-converters","shortDescription":{"text":"PHPStan SARIF Converter"},"version":"1.0.9999999.9999999-dev"}]},"invocations":[{"executionSuccessful":true,"commandLine":"vendor/bin/phpstan","arguments":["analyse","--error-format","sarif","--configuration","examples/phpstan/phpstan.neon.dist","--autoload-file","examples/phpstan/bootstrap.php"],"workingDirectory":{"uri":"file:///shared/backups/bartlett/sarif-php-converters/"}}],"originalUriBaseIds":{"WORKINGDIR":{"uri":"file:///shared/backups/bartlett/sarif-php-converters/"}},"results":[{"message":{"text":"Invalid numeric literal on line 3"},"ruleId":"PHPSTAN101","locations":[{"physicalLocation":{"artifactLocation":{"uri":"examples/fixtures/php_bad_1.php","uriBaseId":"WORKINGDIR"},"region":{"startLine":3,"snippet":{"rendered":{"text":" > 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29"}}},"contextRegion":{"startLine":1,"endLine":5,"snippet":{"rendered":{"text":" > 1| <?php\n 2| \n 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29\n 4| "}}}}}],"partialFingerprints":{"phpstan.parse":"b72968e694d9f576c2adc3cdc3f479a0834ab688b7dc8a6fe2657d59e034ae1f"},"properties":{"ignorable":false}},{"message":{"text":"Syntax error, unexpected '=' on line 3"},"ruleId":"PHPSTAN101","locations":[{"physicalLocation":{"artifactLocation":{"uri":"examples/fixtures/php_bad_1.php","uriBaseId":"WORKINGDIR"},"region":{"startLine":3,"snippet":{"rendered":{"text":" > 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29"}}},"contextRegion":{"startLine":1,"endLine":5,"snippet":{"rendered":{"text":" > 1| <?php\n 2| \n 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29\n 4| "}}}}}],"partialFingerprints":{"phpstan.parse":"b72968e694d9f576c2adc3cdc3f479a0834ab688b7dc8a6fe2657d59e034ae1f"},"properties":{"ignorable":false}},{"message":{"text":"Syntax error, unexpected T_LNUMBER on line 3"},"ruleId":"PHPSTAN101","locations":[{"physicalLocation":{"artifactLocation":{"uri":"examples/fixtures/php_bad_1.php","uriBaseId":"WORKINGDIR"},"region":{"startLine":3,"snippet":{"rendered":{"text":" > 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29"}}},"contextRegion":{"startLine":1,"endLine":5,"snippet":{"rendered":{"text":" > 1| <?php\n 2| \n 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29\n 4| "}}}}}],"partialFingerprints":{"phpstan.parse":"b72968e694d9f576c2adc3cdc3f479a0834ab688b7dc8a6fe2657d59e034ae1f"},"properties":{"ignorable":false}},{"message":{"text":"Syntax error, unexpected T_STRING on line 3"},"ruleId":"PHPSTAN101","locations":[{"physicalLocation":{"artifactLocation":{"uri":"examples/fixtures/php_bad_1.php","uriBaseId":"WORKINGDIR"},"region":{"startLine":3,"snippet":{"rendered":{"text":" > 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29"}}},"contextRegion":{"startLine":1,"endLine":5,"snippet":{"rendered":{"text":" > 1| <?php\n 2| \n 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29\n 4| "}}}}}],"partialFingerprints":{"phpstan.parse":"b72968e694d9f576c2adc3cdc3f479a0834ab688b7dc8a6fe2657d59e034ae1f"},"properties":{"ignorable":false}},{"message":{"text":"Syntax error, unexpected '}' on line 15"},"ruleId":"PHPSTAN101","locations":[{"physicalLocation":{"artifactLocation":{"uri":"examples/fixtures/php_bad_2.php","uriBaseId":"WORKINGDIR"},"region":{"startLine":15,"snippet":{"rendered":{"text":" > 15| } elseif ($condition) {}"}}},"contextRegion":{"startLine":13,"endLine":17,"snippet":{"rendered":{"text":" > 13| $condition = rand(0, 5);\n 14| iff ($condition) {\n 15| } elseif ($condition) {}\n 16| "}}}}}],"partialFingerprints":{"phpstan.parse":"2e508d59ec5ba941128ccdf751869d555c2c618018b0979124ee4530b68fbc28"},"properties":{"ignorable":false}}],"automationDetails":{"id":"Daily run 2024-07-03T07:49:22+00:00"}}]}
{"$schema":"https://json.schemastore.org/sarif-2.1.0.json","version":"2.1.0","runs":[{"tool":{"driver":{"name":"PHPStan","shortDescription":{"text":"PHP Static Analysis Tool"},"fullDescription":{"text":"PHPStan - PHP Static Analysis Tool"},"fullName":"PHPStan - PHP Static Analysis Tool 1.11.8.0","semanticVersion":"1.11.8.0","informationUri":"https://phpstan.org","rules":[{"id":"PHPSTAN/phpstan.parse","name":"phpstan.parse","helpUri":"https://phpstan.org/error-identifiers/phpstan.parse","help":{"text":"https://phpstan.org/user-guide/ignoring-errors"}}]},"extensions":[{"name":"bartlett/sarif-php-converters","shortDescription":{"text":"PHPStan SARIF Converter"},"version":"1.0.9999999.9999999-dev"}]},"invocations":[{"executionSuccessful":true,"commandLine":"vendor/bin/phpstan","arguments":["analyse","--error-format","sarif","--configuration","examples/phpstan/phpstan.neon.dist","--autoload-file","examples/phpstan/bootstrap.php"],"workingDirectory":{"uri":"file:///shared/backups/bartlett/sarif-php-converters/"}}],"originalUriBaseIds":{"WORKINGDIR":{"uri":"file:///shared/backups/bartlett/sarif-php-converters/"}},"results":[{"message":{"text":"Invalid numeric literal on line 3"},"ruleId":"PHPSTAN/phpstan.parse","locations":[{"physicalLocation":{"artifactLocation":{"uri":"examples/fixtures/php_bad_1.php","uriBaseId":"WORKINGDIR"},"region":{"startLine":3,"snippet":{"rendered":{"text":" > 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29"}}},"contextRegion":{"startLine":1,"endLine":5,"snippet":{"rendered":{"text":" > 1| <?php\n 2| \n 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29\n 4| "}}}}}],"partialFingerprints":{"phpstan.parse":"b72968e694d9f576c2adc3cdc3f479a0834ab688b7dc8a6fe2657d59e034ae1f"},"properties":{"ignorable":false}},{"message":{"text":"Syntax error, unexpected '=' on line 3"},"ruleId":"PHPSTAN/phpstan.parse","locations":[{"physicalLocation":{"artifactLocation":{"uri":"examples/fixtures/php_bad_1.php","uriBaseId":"WORKINGDIR"},"region":{"startLine":3,"snippet":{"rendered":{"text":" > 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29"}}},"contextRegion":{"startLine":1,"endLine":5,"snippet":{"rendered":{"text":" > 1| <?php\n 2| \n 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29\n 4| "}}}}}],"partialFingerprints":{"phpstan.parse":"b72968e694d9f576c2adc3cdc3f479a0834ab688b7dc8a6fe2657d59e034ae1f"},"properties":{"ignorable":false}},{"message":{"text":"Syntax error, unexpected T_LNUMBER on line 3"},"ruleId":"PHPSTAN/phpstan.parse","locations":[{"physicalLocation":{"artifactLocation":{"uri":"examples/fixtures/php_bad_1.php","uriBaseId":"WORKINGDIR"},"region":{"startLine":3,"snippet":{"rendered":{"text":" > 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29"}}},"contextRegion":{"startLine":1,"endLine":5,"snippet":{"rendered":{"text":" > 1| <?php\n 2| \n 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29\n 4| "}}}}}],"partialFingerprints":{"phpstan.parse":"b72968e694d9f576c2adc3cdc3f479a0834ab688b7dc8a6fe2657d59e034ae1f"},"properties":{"ignorable":false}},{"message":{"text":"Syntax error, unexpected T_STRING on line 3"},"ruleId":"PHPSTAN/phpstan.parse","locations":[{"physicalLocation":{"artifactLocation":{"uri":"examples/fixtures/php_bad_1.php","uriBaseId":"WORKINGDIR"},"region":{"startLine":3,"snippet":{"rendered":{"text":" > 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29"}}},"contextRegion":{"startLine":1,"endLine":5,"snippet":{"rendered":{"text":" > 1| <?php\n 2| \n 3| 2pe98y r-n0u823n=r 092u3- r08u2q098ry 09nq2yr09n2yr9 y2n-93yr 298yr3 29\n 4| "}}}}}],"partialFingerprints":{"phpstan.parse":"b72968e694d9f576c2adc3cdc3f479a0834ab688b7dc8a6fe2657d59e034ae1f"},"properties":{"ignorable":false}},{"message":{"text":"Syntax error, unexpected '}' on line 15"},"ruleId":"PHPSTAN/phpstan.parse","locations":[{"physicalLocation":{"artifactLocation":{"uri":"examples/fixtures/php_bad_2.php","uriBaseId":"WORKINGDIR"},"region":{"startLine":15,"snippet":{"rendered":{"text":" > 15| } elseif ($condition) {}"}}},"contextRegion":{"startLine":13,"endLine":17,"snippet":{"rendered":{"text":" > 13| $condition = rand(0, 5);\n 14| iff ($condition) {\n 15| } elseif ($condition) {}\n 16| "}}}}}],"partialFingerprints":{"phpstan.parse":"2e508d59ec5ba941128ccdf751869d555c2c618018b0979124ee4530b68fbc28"},"properties":{"ignorable":false}}],"automationDetails":{"id":"Daily run 2024-07-31T13:48:59+00:00"}}]}
24 changes: 14 additions & 10 deletions src/Converter/Normalizer/PhpStanNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
use ArrayObject;
use function array_unique;
use function in_array;
use function sprintf;

/**
* @author Laurent Laville
* @since Release 1.0.0
*/
final class PhpStanNormalizer extends AbstractNormalizer
{
public const URI_PATTERN = 'https://phpstan.org/error-identifiers/%s';

public function normalize($data, string $format, array $context): ?ArrayObject
{
if (!in_array($format, $this->getSupportedFormats())) {
Expand All @@ -40,15 +43,23 @@ protected function fromInternal($data, array $context, array $mapping = []): arr
{
$files = [];
$errors = [];
$rules = [];

$analysisResult = $data;

$ruleId = $context['rulePrefix'] . '101';

foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) {
$file = $fileSpecificError->getFile();
$files[] = $file;

$ruleId = sprintf('%s/%s', $context['rulePrefix'], $fileSpecificError->getIdentifier());
$helpUri = sprintf(self::URI_PATTERN, $fileSpecificError->getIdentifier());

$rules[$ruleId] = [
'name' => $fileSpecificError->getIdentifier(),
'help' => 'https://phpstan.org/user-guide/ignoring-errors',
'helpUri' => $helpUri,
];

$attributes = [
'ReportingDescriptor.id' => $ruleId,
'Result.fingerprint' => $fileSpecificError->getIdentifier(),
Expand All @@ -63,14 +74,7 @@ protected function fromInternal($data, array $context, array $mapping = []): arr
return [
'files' => array_unique($files),
'errors' => $errors,
'rules' => [
$ruleId => [
'shortDescription' => 'Analysis error',
'fullDescription' => 'Errors detected during analysis of source files',
'help' => 'https://phpstan.org/user-guide/command-line-usage',
'helpUri' => 'https://phpstan.org/user-guide/getting-started',
],
],
'rules' => $rules,
];
}
}
2 changes: 1 addition & 1 deletion vendor-bin/phpstan/composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"require-dev": {
"phpstan/phpstan": "^1.9"
"phpstan/phpstan": "^1.11"
}
}

0 comments on commit 867f2a2

Please sign in to comment.