-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b95fcd1
commit a1e3eb9
Showing
33 changed files
with
1,047 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
name: "All Tests" | ||
|
||
on: | ||
pull_request: | ||
push: | ||
|
||
jobs: | ||
test: | ||
name: "Run all checks for all supported PHP versions" | ||
|
||
runs-on: "ubuntu-22.04" | ||
|
||
strategy: | ||
fail-fast: false | ||
matrix: | ||
php-version: | ||
- "8.0" | ||
- "8.1" | ||
- "8.2" | ||
- "8.3" | ||
|
||
steps: | ||
- name: "Checkout" | ||
uses: "actions/checkout@v4" | ||
|
||
- name: "Install PHP" | ||
uses: "shivammathur/setup-php@v2" | ||
with: | ||
php-version: "${{ matrix.php-version }}" | ||
tools: composer | ||
|
||
- name: Get composer cache directory | ||
id: composercache | ||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT | ||
|
||
- name: Cache dependencies | ||
uses: actions/cache@v4 | ||
with: | ||
path: ${{ steps.composercache.outputs.dir }} | ||
key: "php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}" | ||
restore-keys: "php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}" | ||
|
||
- name: "Install composer dependencies" | ||
run: "composer install --no-interaction --no-progress" | ||
|
||
- name: "Run tests" | ||
run: "composer tests" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/vendor/ | ||
composer.lock | ||
.idea | ||
.phpunit.cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,107 @@ | ||
# phpstan-extension | ||
PHPStan extension to read static analysis attributes | ||
# PHP Static Analysis Attributes PHPStan Extension | ||
[![Continuous Integration](https://github.com/php-static-analysis/phpstan-extension/workflows/All%20Tests/badge.svg)](https://github.com/php-static-analysis/phpstan-extension/actions) | ||
[![Latest Stable Version](https://poser.pugx.org/php-static-analysis/phpstan-extension/v/stable)](https://packagist.org/packages/php-static-analysis/phpstan-extension) | ||
[![PHP Version Require](http://poser.pugx.org/php-static-analysis/phpstan-extension/require/php)](https://packagist.org/packages/php-static-analysis/phpstan-extension) | ||
[![License](https://poser.pugx.org/php-static-analysis/phpstan-extension/license)](https://github.com/php-static-analysis/phpstan-extension/blob/main/LICENSE) | ||
[![Total Downloads](https://poser.pugx.org/php-static-analysis/phpstan-extension/downloads)](https://packagist.org/packages/php-static-analysis/phpstan-extension/stats) | ||
|
||
Since the release of PHP 8.0 more and more libraries, frameworks and tools have been updated to use attributes instead of annotations in PHPDocs. | ||
|
||
However, static analysis tools like PHPStan have not made this transition to attributes and they still rely on annotations in PHPDocs for a lot of their functionality. | ||
|
||
This is a PHPStan extension that allows PHPStan to understand a new set of attributes that replace the PHPDoc annotations. These attributes are defined in [this repository](https://github.com/php-static-analysis/attributes) | ||
|
||
## Example | ||
|
||
In order to show how code would look with these attributes, we can look at the following example. This is how a class looks like with the current annotations: | ||
|
||
```php | ||
<?php | ||
|
||
class ArrayAdder | ||
{ | ||
/** @var array<string> */ | ||
private array $result; | ||
|
||
/** | ||
* @param array<string> $array1 | ||
* @param array<string> $array2 | ||
* @return array<string> | ||
*/ | ||
public function addArrays(array $array1, array $array2): array | ||
{ | ||
$this->result = $array1 + $array2; | ||
return $this->result; | ||
} | ||
} | ||
``` | ||
|
||
And this is how it would look like using the new attributes: | ||
|
||
```php | ||
<?php | ||
|
||
use PhpStaticAnalysis\Attributes\Type; | ||
use PhpStaticAnalysis\Attributes\Param; | ||
use PhpStaticAnalysis\Attributes\Returns; | ||
|
||
class ArrayAdder | ||
{ | ||
#[Type('array<string>')] | ||
private array $result; | ||
|
||
#[Param(array1: 'array<string>')] | ||
#[Param(array2: 'array<string>')] | ||
#[Returns('array<string>')] | ||
public function addArrays(array $array1, array $array2): array | ||
{ | ||
$this->array = $array1 + $array2; | ||
return $this->array; | ||
} | ||
} | ||
``` | ||
|
||
## Installation | ||
|
||
First of all, to make the attributes available for your codebase use: | ||
|
||
``` | ||
composer require php-static-analysis/attributes | ||
``` | ||
|
||
To use this extension, require it in Composer: | ||
|
||
``` | ||
composer require --dev php-static-analysis/phpstan-extension | ||
``` | ||
|
||
If you also install [phpstan/extension-installer](https://github.com/phpstan/extension-installer) then you're all set! | ||
|
||
<details> | ||
<summary>Manual installation</summary> | ||
|
||
If you don't want to use `phpstan/extension-installer`, include `extension.neon` in your project's PHPStan config: | ||
|
||
``` | ||
includes: | ||
- vendor/php-static-analysis/phpstan-extension/extension.neon | ||
``` | ||
</details> | ||
|
||
## Using the extension | ||
|
||
This extension works by interacting with the parser that PHPStan uses to parse the code and replacing the new Attributes with PHPDoc annotations that PHPStan can understand. The functionality provided by the attribute is exactly the same as the one provided by the corresponding PHPDoc annotation. | ||
|
||
These are the available attributes and their corresponding PHPDoc annotations: | ||
|
||
| Attribute | PHPDoc Annotation | | ||
|---------------------------------------------------------------------------------------------|-------------------| | ||
| [IsReadOnly](https://github.com/php-static-analysis/attributes/blob/main/doc/IsReadOnly.md) | `@readonly` | | ||
| [Param](https://github.com/php-static-analysis/attributes/blob/main/doc/Param.md) | `@param` | | ||
| [Returns](https://github.com/php-static-analysis/attributes/blob/main/doc/Returns.md) | `@return` | | ||
| [Template](https://github.com/php-static-analysis/attributes/blob/main/doc/Template.md) | `@template` | | ||
| [Type](https://github.com/php-static-analysis/attributes/blob/main/doc/Type.md) | `@var` | | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
{ | ||
"name": "php-static-analysis/phpstan-extension", | ||
"description": "PHPStan extension to read static analysis attributes", | ||
"type": "phpstan-extension", | ||
"keywords": ["dev", "static analysis"], | ||
"license": "MIT", | ||
"autoload": { | ||
"psr-4": { | ||
"PhpStaticAnalysis\\PHPStanExtension\\": "src/" | ||
} | ||
}, | ||
"autoload-dev": { | ||
"psr-4": { | ||
"test\\PhpStaticAnalysis\\PHPStanExtension\\": "tests/" | ||
} | ||
}, | ||
"authors": [ | ||
{ | ||
"name": "Carlos Granados", | ||
"email": "[email protected]" | ||
} | ||
], | ||
"minimum-stability": "dev", | ||
"prefer-stable": true, | ||
"require": { | ||
"php": ">=8.0", | ||
"php-static-analysis/attributes": "^0.1 || dev-main", | ||
"php-static-analysis/node-visitor": "^0.1 || dev-main", | ||
"phpstan/phpstan": "^1.8" | ||
}, | ||
"require-dev": { | ||
"php-static-analysis/psalm-plugin": "dev-main", | ||
"phpunit/phpunit": "^9.0", | ||
"symplify/easy-coding-standard": "^12.1", | ||
"vimeo/psalm": "^5" | ||
}, | ||
"extra": { | ||
"phpstan": { | ||
"includes": [ | ||
"extension.neon" | ||
] | ||
} | ||
}, | ||
"config": { | ||
"sort-packages": true | ||
}, | ||
"scripts": { | ||
"phpstan": "phpstan analyse", | ||
"phpstan-debug": "phpstan analyse --xdebug --debug", | ||
"ecs": "ecs", | ||
"ecs-fix": "ecs --fix", | ||
"phpunit": "phpunit", | ||
"psalm": "psalm", | ||
"tests": [ | ||
"@ecs", | ||
"@phpstan", | ||
"@phpunit", | ||
"@psalm" | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
use PhpCsFixer\Fixer\Import\NoUnusedImportsFixer; | ||
use Symplify\EasyCodingStandard\Config\ECSConfig; | ||
|
||
return ECSConfig::configure() | ||
->withPaths([ | ||
__DIR__ . '/src', | ||
__DIR__ . '/tests', | ||
]) | ||
->withPreparedSets( | ||
psr12: true, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
services: | ||
attributeParser: | ||
class: PhpStaticAnalysis\PHPStanExtension\Parser\AttributeParser | ||
arguments: | ||
parser: @pathRoutingParser | ||
autowired: false | ||
|
||
defaultAnalysisParser: | ||
class: PHPStan\Parser\CachedParser | ||
arguments: | ||
originalParser: @attributeParser | ||
cachedNodesByStringCountMax: %cache.nodesByStringCountMax% | ||
autowired: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
includes: | ||
- extension.neon | ||
- phar://phpstan.phar/conf/bleedingEdge.neon | ||
|
||
parameters: | ||
level: max | ||
paths: | ||
- src | ||
- tests | ||
excludePaths: | ||
- tests/data/* | ||
ignoreErrors: | ||
- | ||
message: '#^Accessing [a-zA-Z\\]+::class is not covered by backward compatibility promise. The class might change in a minor PHPStan version.$#' | ||
path: tests/BaseAttributeTestCase.php | ||
- | ||
message: '#^Calling [a-zA-Z\\]+::[a-zA-Z]+\(\) is not covered by backward compatibility promise. The method might change in a minor PHPStan version.$#' | ||
path: tests/BaseAttributeTestCase.php |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.6/phpunit.xsd" | ||
bootstrap="vendor/autoload.php" | ||
cacheResultFile=".phpunit.cache/test-results" | ||
executionOrder="depends,defects" | ||
beStrictAboutCoversAnnotation="true" | ||
beStrictAboutOutputDuringTests="true" | ||
beStrictAboutTodoAnnotatedTests="true" | ||
convertDeprecationsToExceptions="true" | ||
failOnRisky="true" | ||
failOnWarning="true" | ||
verbose="true"> | ||
<testsuites> | ||
<testsuite name="default"> | ||
<directory>tests</directory> | ||
</testsuite> | ||
</testsuites> | ||
</phpunit> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?xml version="1.0" ?> | ||
<psalm | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns="https://getpsalm.org/schema/config" | ||
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" | ||
|
||
errorLevel="1" | ||
findUnusedBaselineEntry="true" | ||
findUnusedCode="false" | ||
> | ||
<projectFiles> | ||
<directory name="src" /> | ||
<directory name="tests" /> | ||
<ignoreFiles> | ||
<directory name="vendor" /> | ||
<directory name="tests/data" /> | ||
</ignoreFiles> | ||
</projectFiles> | ||
|
||
<plugins> | ||
<pluginClass class="PhpStaticAnalysis\PsalmPlugin\Plugin" /> | ||
</plugins> | ||
</psalm> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace PhpStaticAnalysis\PHPStanExtension\Parser; | ||
|
||
use PhpParser\Node\Stmt; | ||
use PhpParser\NodeTraverser; | ||
use PHPStan\Parser\Parser; | ||
use PhpStaticAnalysis\Attributes\Param; | ||
use PhpStaticAnalysis\Attributes\Returns; | ||
use PhpStaticAnalysis\NodeVisitor\AttributeNodeVisitor; | ||
|
||
class AttributeParser implements Parser | ||
{ | ||
public function __construct( | ||
private Parser $parser | ||
) { | ||
} | ||
|
||
public function parseFile(string $file): array | ||
{ | ||
$ast = $this->parser->parseFile($file); | ||
return $this->traverseAst($ast); | ||
} | ||
|
||
public function parseString(string $sourceCode): array | ||
{ | ||
$ast = $this->parser->parseString($sourceCode); | ||
return $this->traverseAst($ast); | ||
} | ||
|
||
#[Param(ast: 'Stmt[]')] | ||
#[Returns('Stmt[]')] | ||
private function traverseAst(array $ast): array | ||
{ | ||
$traverser = new NodeTraverser(); | ||
$nodeVisitor = new AttributeNodeVisitor(); | ||
$traverser->addVisitor($nodeVisitor); | ||
|
||
$ast = $traverser->traverse($ast); | ||
/** @var Stmt[] $ast */ | ||
return $ast; | ||
} | ||
} |
Oops, something went wrong.