feat(compiler): 添加测试模式和静态变量重复检测功能

- 引入 CompilerTest 类用于测试模式运行
- 在 CompilerBase 中添加 forTest 标志和 TestError 异常
- 实现静态变量重复定义的检测和报错功能
- 添加 phpunit 配置文件和引导文件
- 创建重复静态变量的测试用例
- 添加基本静态变量功能的测试文件
- 修改 Translator 的 addFiles 方法支持文件列表添加
- convert 方法中添加文件路径解析功能
pull/1/head
韩天峰 5 months ago
parent 3a3c8eb6b6
commit 76c1104234
  1. 8
      phpunit.xml
  2. 9
      phpunit/bootstrap.php
  3. 6
      phpunit/code/duplicate.php
  4. 23
      phpunit/src/ErrorTest.php
  5. 15
      src/Php/CompilerBase.php
  6. 23
      src/Php/CompilerTest.php
  7. 8
      src/Php/Exception/TestError.php
  8. 6
      src/Php/Translator.php
  9. 87
      tests/core/lang/static_basic_001.phpt

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="./phpunit/bootstrap.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.4/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
<testsuites>
<testsuite name="Tests">
<directory suffix="Test.php">./phpunit</directory>
</testsuite>
</testsuites>
</phpunit>

@ -0,0 +1,9 @@
<?php
use PhpAot\Php\CompilerTest;
require __DIR__ . '/../bin/bootstrap.php';
CompilerTest::getInstance(ROOT_PATH);

@ -0,0 +1,6 @@
<?php
function main()
{
static $a = 10;
static $a = 11;
}

@ -0,0 +1,23 @@
<?php
use PhpAot\Php\CompilerTest;
use PhpAot\Php\Exception\TestError;
use PHPUnit\Framework\TestCase;
class ErrorTest extends TestCase
{
public function testDuplicateStaticVar()
{
try {
$o = CompilerTest::getInstance();
$file = __DIR__ . '/../code/duplicate.php';
$o->addFiles([$file]);
$o->convert($file);
} catch (TestError $exception) {
$this->assertStringContainsString('Duplicate static variable', $exception->getMessage());
return;
}
$this->fail();
}
}

@ -19,6 +19,7 @@ use PhpAot\Php\Exception\DynamicCall;
use PhpAot\Php\Exception\PlaceHolder;
use PhpAot\Php\Exception\Redo;
use PhpAot\Php\Exception\Skip;
use PhpAot\Php\Exception\TestError;
use PhpAot\Php\Generator\ClosureGenerator;
use PhpAot\Php\Generator\PlaceHolderGenerator;
use PhpAot\Php\Generator\PropertyPromotion;
@ -244,6 +245,7 @@ class CompilerBase extends \PhpAot\Core\Translator
protected bool $defaultNativeType = false;
protected bool $stubFile = false;
protected bool $enableProfiler = false;
protected bool $forTest = false;
protected Parser $parser;
protected PrettyPrinter $printer;
@ -1567,6 +1569,9 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function addStaticVar(string $name, string $type): void
{
$this->context->staticVars[$name] = $type;
if ($this->hasStaticVar($name)) {
$this->error('Duplicate static variable `$' . $name . '`');
}
$this->addGlobalVar($this->getStaticVarName($name), $type);
}
@ -2175,9 +2180,13 @@ class CompilerBase extends \PhpAot\Core\Translator
protected function error(string $msg): never
{
$this->climate->red("Fatal error: {$msg}");
debug_print_backtrace();
exit(255);
if ($this->forTest) {
throw new TestError($msg);
} else {
$this->climate->red("Fatal error: {$msg}");
debug_print_backtrace();
exit(255);
}
}
protected function fatalError(Node $node, string $msg): never

@ -0,0 +1,23 @@
<?php
/**
* This file is part of Swoole-Compiler(AOT).
*
* @link https://www.swoole.com/
* @contact service@swoole.com
*/
namespace PhpAot\Php;
class CompilerTest extends Translator
{
protected static ?self $instance = null;
public static function getInstance(string $rootPath = ''): CompilerTest
{
if (!self::$instance) {
self::$instance = new self($rootPath);
self::$instance->forTest = true;
}
return self::$instance;
}
}

@ -0,0 +1,8 @@
<?php
namespace PhpAot\Php\Exception;
class TestError extends \RuntimeException
{
}

@ -99,6 +99,7 @@ class Translator extends Preprocessor
public function convert(string $file): string
{
$file = realpath($file);
if ($this->hasCppFileCache($file)) {
$this->climate->darkGray('skip: ' . $file . ', cache exists');
@ -148,6 +149,11 @@ class Translator extends Preprocessor
$this->targetName = $name;
}
public function addFiles(array $files): void
{
$this->sourceDirs = array_merge($this->sourceDirs, $files);
}
public function getFiles(string $path): array
{
$realpath = realpath($path);

@ -0,0 +1,87 @@
--TEST--
Static keyword - basic tests
--FILE--
<?php
function staticNonStatic() {
echo "---------\n";
$a=0;
echo "$a\n";
static $a=10;
echo "$a\n";
$a++;
}
function manyInits() {
static $counter=0;
echo "------------- Call $counter --------------\n";
static $a, $b=10, $c=20, $d, $e=30;
echo "Uninitialized : $a\n";
echo "Initialized to 10: $b\n";
echo "Initialized to 20: $c\n";
echo "Uninitialized : $d\n";
echo "Initialized to 30: $e\n";
$a++;
$b++;
$c++;
$d++;
$e++;
$counter++;
}
function main() {
echo "\nSame variable used as static and non static.\n";
staticNonStatic();
staticNonStatic();
staticNonStatic();
echo "\nLots of initialisations in the same statement.\n";
manyInits();
manyInits();
manyInits();
echo "\nUsing static keyword at global scope\n";
for ($i=0; $i<3; $i++) {
static $s, $k=10;
echo "$s $k\n";
$s++;
$k++;
}
}
?>
--EXPECT--
Same variable used as static and non static.
---------
0
10
---------
0
11
---------
0
12
Lots of initialisations in the same statement.
------------- Call 0 --------------
Uninitialized :
Initialized to 10: 10
Initialized to 20: 20
Uninitialized :
Initialized to 30: 30
------------- Call 1 --------------
Uninitialized : 1
Initialized to 10: 11
Initialized to 20: 21
Uninitialized : 1
Initialized to 30: 31
------------- Call 2 --------------
Uninitialized : 2
Initialized to 10: 12
Initialized to 20: 22
Uninitialized : 2
Initialized to 30: 32
Using static keyword at global scope
10
1 11
2 12
Loading…
Cancel
Save