Skip to content

Commit

Permalink
Gh 2588 false not bool and show project + runtime php versions in LSP…
Browse files Browse the repository at this point in the history
… status (#2591)

* Add passing test for false type

* Show PHP version and source in status

* Fix test case name

* GH-2588: Do not generalize types for return and PHP version in status

* Update CL
  • Loading branch information
dantleech committed Mar 9, 2024
1 parent 5dc22be commit 9e7b375
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -21,9 +21,11 @@ Improvements:
- Remove "on develop warning" service #2533
- Disable the processing of includes/requires, it doesn't work very well but
it has massive performance impact on certain projects #2580
- Include project PHP and runtime version and LSP status

Bug fixes:

- Do not generalize generated return types (i.e. false instead of bool) #2588
- Fix diagnostic process concurrency and do not lint outdated files #2538
- Upgrade `amp/process` to fix #2516 thanks to @gerardroche
- Fix division by zero edge case
Expand Down
Expand Up @@ -40,7 +40,7 @@ public function transform(SourceCode $code): Promise
$classBuilder = $builder->class($method->class()->name()->short());
$methodBuilder = $classBuilder->method($method->name());
$replacement = $this->returnType($method);
$localReplacement = $replacement->toLocalType($method->scope())->generalize();
$localReplacement = $replacement->toLocalType($method->scope());
$notNullReplacement = $replacement->stripNullable();

foreach ($replacement->allTypes()->classLike() as $classType) {
Expand Down
Expand Up @@ -13,7 +13,7 @@
use Phpactor\CodeTransform\Tests\Adapter\TolerantParser\TolerantTestCase;
use Phpactor\TextDocument\TextEdits;

abstract class AbstractTolerantImportNameTest extends TolerantTestCase
abstract class AbstractTolerantImportNameCase extends TolerantTestCase
{
/**
* @dataProvider provideImportClass
Expand Down Expand Up @@ -204,7 +204,10 @@ abstract public function provideImportFunction(): Generator;

abstract protected function importName(string $source, int $offset, NameImport $nameImport, bool $importGlobals = true): TextEdits;

private function importNameFromTestFile(string $type, string $test, string $name, string $alias = null)
/**
* @return array{string,string}
*/
private function importNameFromTestFile(string $type, string $test, string $name, string $alias = null): array
{
[$source, $expected, $offset] = $this->sourceExpectedAndOffset(__DIR__ . '/fixtures/' . $test);
$edits = TextEdits::none();
Expand Down
Expand Up @@ -9,7 +9,7 @@
use Phpactor\TextDocument\ByteOffset;
use Phpactor\TextDocument\TextEdits;

class TolerantImportNameOnlyTest extends AbstractTolerantImportNameTest
class TolerantImportNameOnlyTest extends AbstractTolerantImportNameCase
{
public function provideImportClass(): Generator
{
Expand Down
Expand Up @@ -9,7 +9,7 @@
use Phpactor\TextDocument\ByteOffset;
use Phpactor\TextDocument\TextEdits;

class TolerantImportNameTest extends AbstractTolerantImportNameTest
class TolerantImportNameTest extends AbstractTolerantImportNameCase
{
public function provideImportClass(): Generator
{
Expand Down
Expand Up @@ -175,6 +175,74 @@ private function baz(): void
}
EOT
];
yield 'adds false type' => [
<<<'EOT'
<?php
class Foobar {
private function foo()
{
return $this->baz();
}
private function baz(): string|false
{
}
}
EOT
,
<<<'EOT'
<?php
class Foobar {
private function foo(): string|false
{
return $this->baz();
}
private function baz(): string|false
{
}
}
EOT
];
yield 'adds array shape type' => [
<<<'EOT'
<?php
class Foobar {
private function foo()
{
return $this->baz();
}
/**
* @return array{string,string}
*/
private function baz(): array
{
}
}
EOT
,
<<<'EOT'
<?php
class Foobar {
private function foo(): array
{
return $this->baz();
}
/**
* @return array{string,string}
*/
private function baz(): array
{
}
}
EOT
];
}

/**
Expand Down
18 changes: 18 additions & 0 deletions lib/Extension/Php/Model/ChainResolver.php
Expand Up @@ -32,4 +32,22 @@ public function resolve(): ?string
count($this->versionResolvers)
));
}

public function source(): string
{
foreach ($this->versionResolvers as $versionResolver) {
if (!$version = $versionResolver->resolve()) {
continue;
}

return $versionResolver->name();
}

return 'unknown';
}

public function name(): string
{
return 'chain';
}
}
5 changes: 5 additions & 0 deletions lib/Extension/Php/Model/ComposerPhpVersionResolver.php
Expand Up @@ -35,6 +35,11 @@ public function resolve(): ?string
return null;
}

public function name(): string
{
return 'composer';
}

private function resolveLowestVersion(string $versionString): ?string
{
/** @phpstan-ignore-next-line */
Expand Down
5 changes: 5 additions & 0 deletions lib/Extension/Php/Model/ConstantPhpVersionResolver.php
Expand Up @@ -13,4 +13,9 @@ public function resolve(): ?string
{
return $this->version;
}

public function name(): string
{
return 'user configured';
}
}
1 change: 1 addition & 0 deletions lib/Extension/Php/Model/PhpVersionResolver.php
Expand Up @@ -5,4 +5,5 @@
interface PhpVersionResolver
{
public function resolve(): ?string;
public function name(): string;
}
5 changes: 5 additions & 0 deletions lib/Extension/Php/Model/RuntimePhpVersionResolver.php
Expand Up @@ -8,4 +8,9 @@ public function resolve(): ?string
{
return phpversion();
}

public function name(): string
{
return 'runtime';
}
}
10 changes: 9 additions & 1 deletion lib/Extension/Php/PhpExtension.php
Expand Up @@ -11,6 +11,7 @@
use Phpactor\Extension\Php\Model\PhpVersionResolver;
use Phpactor\Extension\Php\Model\RuntimePhpVersionResolver;
use Phpactor\Extension\FilePathResolver\FilePathResolverExtension;
use Phpactor\Extension\Php\Status\PhpStatusProvider;
use Phpactor\MapResolver\Resolver;

class PhpExtension implements Extension
Expand All @@ -20,7 +21,7 @@ class PhpExtension implements Extension

public function load(ContainerBuilder $container): void
{
$container->register(PhpVersionResolver::class, function (Container $container) {
$container->register(ChainResolver::class, function (Container $container) {
$pathResolver = $container->get(FilePathResolverExtension::SERVICE_FILE_PATH_RESOLVER);
$composerPath = $pathResolver->resolve('%project_root%/composer.json');

Expand All @@ -30,6 +31,13 @@ public function load(ContainerBuilder $container): void
new RuntimePhpVersionResolver()
);
});
$container->register(PhpVersionResolver::class, function (Container $container) {
return $container->get(ChainResolver::class);
});

$container->register(PhpStatusProvider::class, function (Container $container) {
return new PhpStatusProvider($container->get(ChainResolver::class));
}, []);
}


Expand Down
28 changes: 28 additions & 0 deletions lib/Extension/Php/Status/PhpStatusProvider.php
@@ -0,0 +1,28 @@
<?php

namespace Phpactor\Extension\Php\Status;

use Phpactor\Extension\LanguageServer\Status\StatusProvider;
use Phpactor\Extension\Php\Model\ChainResolver;

class PhpStatusProvider implements StatusProvider
{
public function __construct(
private ChainResolver $chainResolver,
) {
}

public function title(): string
{
return 'php';
}

public function provide(): array
{
return [
'project' => (string)$this->chainResolver->resolve(),
'source' => $this->chainResolver->source(),
'runtime' => phpversion(),
];
}
}
18 changes: 18 additions & 0 deletions lib/WorseReflection/Tests/Inference/type/false.test
@@ -0,0 +1,18 @@
<?php

namespace Foo;

wrAssertType('string|false', possiblyFalse());

function possiblyFalse(array $foo): string|false
{
}

/**
* @return string|false a formatted date string. If a non-numeric value is used for
*/
function date()
{
}

wrAssertType('string|false', date());

0 comments on commit 9e7b375

Please sign in to comment.