- 实现了 project.yml 配置文件解析支持 include-paths、defines、lto 等选项 - 添加了命令行参数与配置文件选项的合并逻辑 - 增强了类型检查错误消息中的可调用名称显示 - 添加了多个测试用例验证配置文件解析和类型检查行为 - 实现了 PHP 代码中父类方法重写和联合类型的功能测试pull/5/head
parent
409c0959f4
commit
4632a8bba4
12 changed files with 320 additions and 5 deletions
@ -0,0 +1,32 @@ |
||||
<?php |
||||
|
||||
namespace Demo\Dispatch { |
||||
class ChildOverrideNs extends ParentBaseNs |
||||
{ |
||||
public function bar(): void |
||||
{ |
||||
echo "Child\n"; |
||||
} |
||||
} |
||||
|
||||
class ParentBaseNs |
||||
{ |
||||
public function run(): void |
||||
{ |
||||
$this->bar(); |
||||
} |
||||
|
||||
public function bar(): void |
||||
{ |
||||
echo "Parent\n"; |
||||
} |
||||
} |
||||
} |
||||
|
||||
namespace { |
||||
function main(): void |
||||
{ |
||||
$o = new Demo\Dispatch\ChildOverrideNs(); |
||||
$o->run(); |
||||
} |
||||
} |
||||
@ -0,0 +1,12 @@ |
||||
<?php |
||||
class A |
||||
{ |
||||
public function f() {} |
||||
} |
||||
|
||||
class B extends A |
||||
{ |
||||
protected function f() {} |
||||
} |
||||
|
||||
function main() {} |
||||
@ -0,0 +1,12 @@ |
||||
<?php |
||||
class A |
||||
{ |
||||
public function f($x) {} |
||||
} |
||||
|
||||
class B extends A |
||||
{ |
||||
public function f($x, $y = 1) {} |
||||
} |
||||
|
||||
function main() {} |
||||
@ -0,0 +1,16 @@ |
||||
<?php |
||||
|
||||
interface ITypeParent |
||||
{ |
||||
} |
||||
|
||||
class BaseIntersectionParent implements ITypeParent |
||||
{ |
||||
} |
||||
|
||||
class DemoParentIntersection extends BaseIntersectionParent |
||||
{ |
||||
public function run(parent&ITypeParent $value): void {} |
||||
} |
||||
|
||||
function main() {} |
||||
@ -0,0 +1,12 @@ |
||||
<?php |
||||
|
||||
interface ITypeSelf |
||||
{ |
||||
} |
||||
|
||||
class DemoSelfIntersection implements ITypeSelf |
||||
{ |
||||
public function run(self&ITypeSelf $value): void {} |
||||
} |
||||
|
||||
function main() {} |
||||
@ -0,0 +1,15 @@ |
||||
<?php |
||||
|
||||
interface ITypeStatic |
||||
{ |
||||
} |
||||
|
||||
class DemoStaticIntersection implements ITypeStatic |
||||
{ |
||||
public function run(): static&ITypeStatic |
||||
{ |
||||
return $this; |
||||
} |
||||
} |
||||
|
||||
function main() {} |
||||
@ -0,0 +1,12 @@ |
||||
<?php |
||||
|
||||
class BaseParentUnion |
||||
{ |
||||
} |
||||
|
||||
class DemoParentUnion extends BaseParentUnion |
||||
{ |
||||
public function run(parent|string $value): void {} |
||||
} |
||||
|
||||
function main() {} |
||||
@ -0,0 +1,8 @@ |
||||
<?php |
||||
|
||||
class DemoSelfUnion |
||||
{ |
||||
public function run(self|string $value): void {} |
||||
} |
||||
|
||||
function main() {} |
||||
@ -0,0 +1,70 @@ |
||||
<?php |
||||
|
||||
use PhpAot\Php\ArgInfo; |
||||
use PhpAot\Php\CompilerTest; |
||||
use PhpAot\Php\Entity\ClassDef; |
||||
use PhpAot\Php\Entity\FunctionDef; |
||||
|
||||
class TypeCheckGeneratorTest extends \PHPUnit\Framework\TestCase |
||||
{ |
||||
private function setProtectedProperty(object $object, string $property, mixed $value): void |
||||
{ |
||||
$ref = new ReflectionProperty($object, $property); |
||||
$ref->setAccessible(true); |
||||
$ref->setValue($object, $value); |
||||
} |
||||
|
||||
private function invokeMethod(object $object, string $method, array $args = []): mixed |
||||
{ |
||||
$ref = new ReflectionMethod($object, $method); |
||||
$ref->setAccessible(true); |
||||
return $ref->invokeArgs($object, $args); |
||||
} |
||||
|
||||
public function testMethodTypeCheckErrorUsesClassQualifiedCallableName(): void |
||||
{ |
||||
$compiler = CompilerTest::create(ROOT_PATH); |
||||
$classDef = new ClassDef('Demo', 0, 'Foo\\Bar'); |
||||
$functionDef = new FunctionDef('run', 'php::Var', 'Foo\\Bar'); |
||||
$argInfo = new ArgInfo(); |
||||
$argInfo->name = 'value'; |
||||
$argInfo->typeStr = 'int|string'; |
||||
|
||||
$functionDef->returnTypeCheck = [['kind' => 'isInt'], ['kind' => 'isString']]; |
||||
$functionDef->returnTypeStr = 'int|string'; |
||||
|
||||
$this->setProtectedProperty($compiler, 'classDef', $classDef); |
||||
$this->setProtectedProperty($compiler, 'functionDef', $functionDef); |
||||
|
||||
$callableName = $this->invokeMethod($compiler, 'getTypeCheckCallableName'); |
||||
$paramExpr = $this->invokeMethod($compiler, 'genUnionParamTypeErrorExpr', [$argInfo, 'value', '1']); |
||||
$returnCode = $this->invokeMethod($compiler, 'genUnionReturnCheck', ['retval']); |
||||
|
||||
$this->assertSame('Foo\\Bar\\Demo::run', $callableName); |
||||
$this->assertStringContainsString('Foo\\\\Bar\\\\Demo::run(): Argument #', $paramExpr); |
||||
$this->assertStringContainsString('Foo\\\\Bar\\\\Demo::run', $returnCode); |
||||
} |
||||
|
||||
public function testFunctionTypeCheckErrorUsesFunctionQualifiedCallableName(): void |
||||
{ |
||||
$compiler = CompilerTest::create(ROOT_PATH); |
||||
$functionDef = new FunctionDef('run', 'php::Var', 'Foo\\Bar'); |
||||
$argInfo = new ArgInfo(); |
||||
$argInfo->name = 'value'; |
||||
$argInfo->typeStr = 'int|string'; |
||||
|
||||
$functionDef->returnTypeCheck = [['kind' => 'isInt'], ['kind' => 'isString']]; |
||||
$functionDef->returnTypeStr = 'int|string'; |
||||
|
||||
$this->setProtectedProperty($compiler, 'classDef', null); |
||||
$this->setProtectedProperty($compiler, 'functionDef', $functionDef); |
||||
|
||||
$callableName = $this->invokeMethod($compiler, 'getTypeCheckCallableName'); |
||||
$paramExpr = $this->invokeMethod($compiler, 'genUnionParamTypeErrorExpr', [$argInfo, 'value', '1']); |
||||
$returnCode = $this->invokeMethod($compiler, 'genUnionReturnCheck', ['retval']); |
||||
|
||||
$this->assertSame('Foo\\Bar\\run', $callableName); |
||||
$this->assertStringContainsString('Foo\\\\Bar\\\\run(): Argument #', $paramExpr); |
||||
$this->assertStringContainsString('Foo\\\\Bar\\\\run', $returnCode); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue