Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ services:
class: WP_CLI\Tests\PHPStan\WPCliDoHookDynamicReturnTypeExtension
tags:
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
-
class: WP_CLI\Tests\PHPStan\WPCliGetConfigDynamicReturnTypeExtension
tags:
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
-
class: SzepeViktor\PHPStan\WordPress\HookDocsVisitor
tags:
Expand Down
138 changes: 138 additions & 0 deletions src/PHPStan/WPCliGetConfigDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

declare(strict_types=1);

namespace WP_CLI\Tests\PHPStan;

use PhpParser\Node\Expr\StaticCall;
use PHPStan\Analyser\Scope;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\ArrayType;
use PHPStan\Type\BooleanType;
use PHPStan\Type\Constant\ConstantArrayType;
use PHPStan\Type\Constant\ConstantBooleanType;
use PHPStan\Type\Constant\ConstantStringType;
use PHPStan\Type\DynamicStaticMethodReturnTypeExtension;
use PHPStan\Type\IntegerType;
use PHPStan\Type\NullType;
use PHPStan\Type\StringType;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;

use function count;
use function array_values;

final class WPCliGetConfigDynamicReturnTypeExtension implements DynamicStaticMethodReturnTypeExtension {

public function getClass(): string {
return 'WP_CLI';
}

public function isStaticMethodSupported( MethodReflection $methodReflection ): bool {
return $methodReflection->getName() === 'get_config';
}

public function getTypeFromStaticMethodCall(
MethodReflection $methodReflection,
StaticCall $methodCall,
Scope $scope
): Type {
$args = $methodCall->getArgs();

if ( count( $args ) === 0 ) {
return $this->getGlobalConfigArrayType();
}

$keyType = $scope->getType( $args[0]->value );

if ( $keyType->isNull()->yes() ) {
return $this->getGlobalConfigArrayType();
}

$constantStrings = $keyType->getConstantStrings();
if ( count( $constantStrings ) > 0 ) {
$types = [];
$configMap = $this->getConfigMap();

foreach ( $constantStrings as $constantString ) {
$key = $constantString->getValue();
if ( isset( $configMap[ $key ] ) ) {
$types[] = $configMap[ $key ];
} else {
$types[] = new NullType();
}
}

if ( count( $types ) > 0 ) {
$returnType = TypeCombinator::union( ...$types );
if ( $keyType->isNull()->maybe() ) {
$returnType = TypeCombinator::union( $returnType, $this->getGlobalConfigArrayType() );
}
return $returnType;
}
}

// Fallback for non-constant string or unknown types
$fallback = TypeCombinator::addNull( $this->getFallbackValueType() );
if ( $keyType->isNull()->maybe() ) {
return TypeCombinator::union( $fallback, $this->getGlobalConfigArrayType() );
}

return $fallback;
}

/**
* @return array<string, Type>
*/
private function getConfigMap(): array {
$stringType = new StringType();
$stringOrNull = TypeCombinator::addNull( $stringType );
$stringList = new ArrayType( new IntegerType(), $stringType );
$boolType = new BooleanType();
$trueOrStringList = TypeCombinator::union( new ConstantBooleanType( true ), $stringList );
$stringOrTrue = TypeCombinator::union( $stringType, new ConstantBooleanType( true ) );
$stringOrFalse = TypeCombinator::union( $stringType, new ConstantBooleanType( false ) );
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return [
'path' => $stringOrNull,

Check warning on line 97 in src/PHPStan/WPCliGetConfigDynamicReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPCS

Array double arrow not aligned correctly; expected 14 space(s) between "'path'" and double arrow, but found 11.
'ssh' => $stringOrNull,

Check warning on line 98 in src/PHPStan/WPCliGetConfigDynamicReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPCS

Array double arrow not aligned correctly; expected 15 space(s) between "'ssh'" and double arrow, but found 12.
'ssh-args' => $stringList,

Check warning on line 99 in src/PHPStan/WPCliGetConfigDynamicReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPCS

Array double arrow not aligned correctly; expected 10 space(s) between "'ssh-args'" and double arrow, but found 7.
'http' => $stringOrNull,

Check warning on line 100 in src/PHPStan/WPCliGetConfigDynamicReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPCS

Array double arrow not aligned correctly; expected 14 space(s) between "'http'" and double arrow, but found 11.
'url' => $stringOrNull,

Check warning on line 101 in src/PHPStan/WPCliGetConfigDynamicReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPCS

Array double arrow not aligned correctly; expected 15 space(s) between "'url'" and double arrow, but found 12.
'user' => $stringOrNull,

Check warning on line 102 in src/PHPStan/WPCliGetConfigDynamicReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPCS

Array double arrow not aligned correctly; expected 14 space(s) between "'user'" and double arrow, but found 11.
'skip-plugins' => $trueOrStringList,

Check warning on line 103 in src/PHPStan/WPCliGetConfigDynamicReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPCS

Array double arrow not aligned correctly; expected 6 space(s) between "'skip-plugins'" and double arrow, but found 3.
'skip-themes' => $trueOrStringList,

Check warning on line 104 in src/PHPStan/WPCliGetConfigDynamicReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPCS

Array double arrow not aligned correctly; expected 7 space(s) between "'skip-themes'" and double arrow, but found 4.
'skip-packages' => $boolType,

Check warning on line 105 in src/PHPStan/WPCliGetConfigDynamicReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPCS

Array double arrow not aligned correctly; expected 5 space(s) between "'skip-packages'" and double arrow, but found 2.
'require' => $stringList,

Check warning on line 106 in src/PHPStan/WPCliGetConfigDynamicReturnTypeExtension.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPCS

Array double arrow not aligned correctly; expected 11 space(s) between "'require'" and double arrow, but found 8.
'exec' => $stringList,
'context' => $stringType,
Comment thread
swissspidy marked this conversation as resolved.
Outdated
'debug' => TypeCombinator::union( $stringType, $boolType ),
'prompt' => TypeCombinator::union( $stringType, $boolType ),
'quiet' => $boolType,
'apache_modules' => $stringList,
'assume-https' => $boolType,
'color' => TypeCombinator::union( $stringType, $boolType ),
'disabled_commands' => $stringList,
'locale' => $stringType,
'allow-root' => $boolType,
'alias' => $stringType,
];
}

private function getGlobalConfigArrayType(): Type {
$keyTypes = [];
$valueTypes = [];

foreach ( $this->getConfigMap() as $key => $type ) {
$keyTypes[] = new ConstantStringType( $key );
$valueTypes[] = $type;
}

return new ConstantArrayType( $keyTypes, $valueTypes );
}

private function getFallbackValueType(): Type {
$types = array_values( $this->getConfigMap() );
return TypeCombinator::union( ...$types );
}
}
27 changes: 27 additions & 0 deletions tests/data/get_config.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/**
* Test data for WPCliGetConfigDynamicReturnTypeExtension.
*/

declare(strict_types=1);

namespace WP_CLI\Tests\Tests\PHPStan;

use WP_CLI;
use function PHPStan\Testing\assertType;

// No arguments
assertType( 'array{path: string|null, ssh: string|null, ssh-args: array<int, string>, http: string|null, url: string|null, user: string|null, skip-plugins: array<int, string>|true, skip-themes: array<int, string>|true, skip-packages: bool, require: array<int, string>, exec: array<int, string>, context: string, debug: bool|string, prompt: bool|string, quiet: bool, apache_modules: array<int, string>, assume-https: bool, color: bool|string, disabled_commands: array<int, string>, locale: string, allow-root: bool, alias: string}', WP_CLI::get_config() );
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

// Specific keys
assertType( 'string|null', WP_CLI::get_config( 'path' ) );
assertType( 'array<int, string>', WP_CLI::get_config( 'ssh-args' ) );
assertType( 'bool', WP_CLI::get_config( 'skip-packages' ) );
assertType( 'array<int, string>|true', WP_CLI::get_config( 'skip-plugins' ) );
assertType( 'bool|string', WP_CLI::get_config( 'prompt' ) );
assertType( 'bool', WP_CLI::get_config( 'quiet' ) );
assertType( 'bool', WP_CLI::get_config( 'assume-https' ) );

// Invalid key
assertType( 'null', WP_CLI::get_config( 'invalid_key' ) );
1 change: 1 addition & 0 deletions tests/tests/PHPStan/TestDynamicReturnTypeExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public static function dataFileAsserts(): iterable {
yield from self::gatherAssertTypes( dirname( __DIR__, 2 ) . '/data/get_flag_value.php' );
yield from self::gatherAssertTypes( dirname( __DIR__, 2 ) . '/data/runcommand.php' );
yield from self::gatherAssertTypes( dirname( __DIR__, 2 ) . '/data/do_hook.php' );
yield from self::gatherAssertTypes( dirname( __DIR__, 2 ) . '/data/get_config.php' );
}

/**
Expand Down
Loading