Skip to content

Commit

Permalink
[generator] make ErrorType into an actual type
Browse files Browse the repository at this point in the history
Enums have been supported since php 8.1, we don't need to be passing primitives around any more \o/
  • Loading branch information
shish committed Feb 8, 2025
1 parent 9ca504d commit 21ec6f5
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 60 deletions.
7 changes: 4 additions & 3 deletions generator/src/Generator/WritePhpFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Safe\XmlDocParser\Method;
use Safe\XmlDocParser\Parameter;
use Safe\XmlDocParser\ErrorType;

class WritePhpFunction
{
Expand Down Expand Up @@ -97,9 +98,9 @@ private function writePhpFunction(): string
private function generateExceptionCode(string $moduleName, Method $method) : string
{
$errorValue = match ($method->getErrorType()) {
Method::FALSY_TYPE => 'false',
Method::NULLSY_TYPE => 'null',
Method::EMPTY_TYPE => "''",
ErrorType::FALSY => 'false',
ErrorType::NULLSY => 'null',
ErrorType::EMPTY => "''",
default => throw new \LogicException("Method doesn't have an error type"),
};

Expand Down
20 changes: 10 additions & 10 deletions generator/src/PhpStanFunctions/PhpStanType.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Safe\PhpStanFunctions;

use Safe\XmlDocParser\Method;
use Safe\XmlDocParser\ErrorType;
use Safe\XmlDocParser\Type;

/**
Expand Down Expand Up @@ -116,7 +116,7 @@ public function __construct(string|\SimpleXMLElement $data, bool $writeOnly = fa
public static function selectMostUsefulType(
?PhpStanType $phpStanType,
PhpStanType $phpDocType,
?int $errorType = null
?ErrorType $errorType = null
): PhpStanType {
// If phpstan's database doesn't mention this function at all,
// use the PHPDoc type
Expand All @@ -139,29 +139,29 @@ public static function selectMostUsefulType(
return $phpStanType;
}

public function getDocBlockType(?int $errorType = null): string
public function getDocBlockType(?ErrorType $errorType = null): string
{
$returnTypes = $this->types;
//add back either null or false to the return types unless the target function return null or false on error (only relevant on return type)
if ($this->falsable && $errorType !== Method::FALSY_TYPE) {
if ($this->falsable && $errorType !== ErrorType::FALSY) {
$returnTypes[] = 'false';
} elseif ($this->nullable && $errorType !== Method::NULLSY_TYPE) {
} elseif ($this->nullable && $errorType !== ErrorType::NULLSY) {
$returnTypes[] = 'null';
}
$type = join('|', $returnTypes);
if ($type === 'bool' && !$this->nullable && $errorType === Method::FALSY_TYPE) {
if ($type === 'bool' && !$this->nullable && $errorType === ErrorType::FALSY) {
// If the function only returns a boolean, since false is for error, true is for success.
// Let's replace this with a "void".
return 'void';
}
return $type;
}

public function getSignatureType(?int $errorType = null): string
public function getSignatureType(?ErrorType $errorType = null): string
{
//We edit the return type depending of the "onErrorType" of the function. For example, a function that is both nullable and "nullsy" will created a non nullable safe function. Only relevant on return type.
$nullable = $errorType === Method::NULLSY_TYPE ? false : $this->nullable;
$falsable = $errorType === Method::FALSY_TYPE ? false : $this->falsable;
$nullable = $errorType === ErrorType::NULLSY ? false : $this->nullable;
$falsable = $errorType === ErrorType::FALSY ? false : $this->falsable;
$types = $this->types;
//no typehint exists for thoses cases
if (\array_intersect(self::NO_SIGNATURE_TYPES, $types) !== []) {
Expand Down Expand Up @@ -199,7 +199,7 @@ public function getSignatureType(?int $errorType = null): string


$finalType = $types[0] ?? '';
if ($finalType === 'bool' && !$nullable && $errorType === Method::FALSY_TYPE) {
if ($finalType === 'bool' && !$nullable && $errorType === ErrorType::FALSY) {
// If the function only returns a boolean, since false is for error, true is for success.
// Let's replace this with a "void".
return 'void';
Expand Down
10 changes: 5 additions & 5 deletions generator/src/XmlDocParser/DocPage.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,18 @@ private function getIsDeprecated(string $file): bool
return false;
}

public function getErrorType(): int
public function getErrorType(): ErrorType
{
if ($this->detectFalsyFunction()) {
return Method::FALSY_TYPE;
return ErrorType::FALSY;
}
if ($this->detectNullsyFunction()) {
return Method::NULLSY_TYPE;
return ErrorType::NULLSY;
}
if ($this->detectEmptyFunction()) {
return Method::EMPTY_TYPE;
return ErrorType::EMPTY;
}
return Method::UNKNOWN_TYPE;
return ErrorType::UNKNOWN;
}

/*
Expand Down
13 changes: 13 additions & 0 deletions generator/src/XmlDocParser/ErrorType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Safe\XmlDocParser;

enum ErrorType
{
case UNKNOWN;
case FALSY;
case NULLSY;
case EMPTY;
}
18 changes: 7 additions & 11 deletions generator/src/XmlDocParser/Method.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@

class Method
{
const UNKNOWN_TYPE = 0;
const FALSY_TYPE = 1;
const NULLSY_TYPE = 2;
const EMPTY_TYPE = 3;
/**
* @var Parameter[]|null
*/
Expand All @@ -30,7 +26,7 @@ public function __construct(
private \SimpleXMLElement $rootEntity,
private string $moduleName,
PhpStanFunctionMapReader $phpStanFunctionMapReader,
private int $errorType
private ErrorType $errorType
) {
$this->phpstanSignature = $phpStanFunctionMapReader->getFunction($this->getFunctionName());
$this->returnType = PhpStanType::selectMostUsefulType(
Expand Down Expand Up @@ -59,7 +55,7 @@ public function __toString(): string
$data .= " Safe: " . $param->getDocBlockType() . "\n";
}
$data .= "\n";
$data .= "Error type: " . [0=>"unknown", 1=>"false", 2=>"null", 3=>"empty"][$this->errorType] . "\n";
$data .= "Error type: " . $this->errorType->name . "\n";
$data .= "\n";
$data .= "Return type:\n";
$phpStanType = $this->phpstanSignature ? $this->phpstanSignature->getReturnType() : null;
Expand All @@ -75,7 +71,7 @@ public function getFunctionName(): string
return $this->functionObject->methodname->__toString();
}

public function getErrorType(): int
public function getErrorType(): ErrorType
{
return $this->errorType;
}
Expand Down Expand Up @@ -163,16 +159,16 @@ private function stripReturnFalseText(string $string): string
{
$string = \strip_tags($string);
switch ($this->errorType) {
case self::UNKNOWN_TYPE:
case ErrorType::UNKNOWN:
break;

case self::NULLSY_TYPE:
case ErrorType::NULLSY:
$string = $this->removeString($string, ', or NULL if an error occurs');
$string = $this->removeString($string, ' and NULL on failure');
$string = $this->removeString($string, ' or NULL on failure');
break;

case self::FALSY_TYPE:
case ErrorType::FALSY:
$string = $this->removeString($string, 'or FALSE on failure');
$string = $this->removeString($string, ', FALSE on failure');
$string = $this->removeString($string, ', FALSE on errors');
Expand All @@ -189,7 +185,7 @@ private function stripReturnFalseText(string $string): string
$string = $this->removeString($string, ', FALSE if the pipe cannot be established');
break;

case self::EMPTY_TYPE:
case ErrorType::EMPTY:
$string = $this->removeString($string, ' or an empty string on error');
break;

Expand Down
2 changes: 1 addition & 1 deletion generator/src/XmlDocParser/Scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public function getMethods(array $paths, OutputInterface $output): ScannerRespon

$docPage = new DocPage($path->getPathname());
$errorType = $docPage->getErrorType();
if ($errorType !== Method::UNKNOWN_TYPE) {
if ($errorType !== ErrorType::UNKNOWN) {
$functionObjects = $docPage->getMethodSynopsis();
if (count($functionObjects) > 1) {
$overloadedFunctions = array_merge($overloadedFunctions, \array_map(function ($functionObject) {
Expand Down
34 changes: 17 additions & 17 deletions generator/tests/PhpStanFunctions/PhpStanTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace Safe\PhpStanFunctions;

use PHPUnit\Framework\TestCase;
use Safe\XmlDocParser\Method;
use Safe\XmlDocParser\ErrorType;

class PhpStanTypeTest extends TestCase
{
Expand Down Expand Up @@ -137,22 +137,22 @@ public function testErrorTypeInteraction(): void
{
//bool => void if the method is falsy
$param = new PhpStanType('bool');
$this->assertEquals('void', $param->getDocBlockType(Method::FALSY_TYPE));
$this->assertEquals('void', $param->getSignatureType(Method::FALSY_TYPE));
$this->assertEquals('void', $param->getDocBlockType(ErrorType::FALSY));
$this->assertEquals('void', $param->getSignatureType(ErrorType::FALSY));

//int|false => int if the method is falsy
$param = new PhpStanType('int|false');
$this->assertEquals('int', $param->getDocBlockType(Method::FALSY_TYPE));
$this->assertEquals('int', $param->getSignatureType(Method::FALSY_TYPE));
$this->assertEquals('int', $param->getDocBlockType(ErrorType::FALSY));
$this->assertEquals('int', $param->getSignatureType(ErrorType::FALSY));

//int|null => int if the method is nullsy
$param = new PhpStanType('int|null');
$this->assertEquals('int', $param->getDocBlockType(Method::NULLSY_TYPE));
$this->assertEquals('int', $param->getSignatureType(Method::NULLSY_TYPE));
$this->assertEquals('int', $param->getDocBlockType(ErrorType::NULLSY));
$this->assertEquals('int', $param->getSignatureType(ErrorType::NULLSY));

$param = new PhpStanType('array|false|null');
$this->assertEquals('array|null', $param->getDocBlockType(Method::FALSY_TYPE));
$this->assertEquals('?array', $param->getSignatureType(Method::FALSY_TYPE));
$this->assertEquals('array|null', $param->getDocBlockType(ErrorType::FALSY));
$this->assertEquals('?array', $param->getSignatureType(ErrorType::FALSY));
}

public function testDuplicateType(): void
Expand All @@ -165,15 +165,15 @@ public function testDuplicateType(): void
public function testNullOrFalseBecomingNull(): void
{
$param = new PhpStanType('null|false');
$this->assertEquals('null', $param->getDocBlockType(Method::FALSY_TYPE));
$this->assertEquals('', $param->getSignatureType(Method::FALSY_TYPE));
$this->assertEquals('null', $param->getDocBlockType(ErrorType::FALSY));
$this->assertEquals('', $param->getSignatureType(ErrorType::FALSY));
}

public function testNotEmptyStringBecomingString(): void
{
$param = new PhpStanType('non-empty-string|false');
$this->assertEquals('non-empty-string', $param->getDocBlockType(Method::FALSY_TYPE));
$this->assertEquals('string', $param->getSignatureType(Method::FALSY_TYPE));
$this->assertEquals('non-empty-string', $param->getDocBlockType(ErrorType::FALSY));
$this->assertEquals('string', $param->getSignatureType(ErrorType::FALSY));
}

public function testPositiveIntBecomingInt(): void
Expand All @@ -186,8 +186,8 @@ public function testPositiveIntBecomingInt(): void
public function testListBecomingArray(): void
{
$param = new PhpStanType('list<string>|false');
$this->assertEquals('array<string>', $param->getDocBlockType(Method::FALSY_TYPE));
$this->assertEquals('array', $param->getSignatureType(Method::FALSY_TYPE));
$this->assertEquals('array<string>', $param->getDocBlockType(ErrorType::FALSY));
$this->assertEquals('array', $param->getSignatureType(ErrorType::FALSY));
}

public function testNumbersAreRemoved(): void
Expand All @@ -200,8 +200,8 @@ public function testNumbersAreRemoved(): void
public function testIgnoreBenevolence(): void
{
$param = new PhpStanType('__benevolent<string|false>');
$this->assertEquals('string', $param->getDocBlockType(Method::FALSY_TYPE));
$this->assertEquals('string', $param->getSignatureType(Method::FALSY_TYPE));
$this->assertEquals('string', $param->getDocBlockType(ErrorType::FALSY));
$this->assertEquals('string', $param->getSignatureType(ErrorType::FALSY));
}

public function testTypeFromXML(): void
Expand Down
Loading

0 comments on commit 21ec6f5

Please sign in to comment.