- 实现了 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