From f96b17f2299778a8f9a9f6894644408a35ee1581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Tue, 6 Sep 2022 14:03:43 +0200 Subject: [PATCH] Add support for validation of missing method synopses --- build/gen_stub.php | 68 +++++++++++++++++++++++++++++---- ext/dl_test/dl_test.stub.php | 5 ++- ext/dl_test/dl_test_arginfo.h | 2 +- ext/skeleton/skeleton.stub.php | 5 ++- ext/skeleton/skeleton_arginfo.h | 2 +- ext/zlib/zlib.stub.php | 1 + ext/zlib/zlib_arginfo.h | 2 +- 7 files changed, 72 insertions(+), 13 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index 9dff45649671e..c199dde15b45a 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -1222,6 +1222,8 @@ class FuncInfo { public $numRequiredArgs; /** @var string|null */ public $cond; + /** @var bool */ + public $isUndocumentable; /** * @param ArgInfo[] $args @@ -1238,7 +1240,8 @@ public function __construct( array $args, ReturnInfo $return, int $numRequiredArgs, - ?string $cond + ?string $cond, + bool $isUndocumentable ) { $this->name = $name; $this->classFlags = $classFlags; @@ -1252,6 +1255,7 @@ public function __construct( $this->return = $return; $this->numRequiredArgs = $numRequiredArgs; $this->cond = $cond; + $this->isUndocumentable = $isUndocumentable; } public function isMethod(): bool @@ -3218,7 +3222,8 @@ function parseFunctionLike( int $classFlags, int $flags, Node\FunctionLike $func, - ?string $cond + ?string $cond, + bool $isUndocumentable ): FuncInfo { try { $comment = $func->getDocComment(); @@ -3283,6 +3288,10 @@ function parseFunctionLike( } $paramMeta[$varName][$tag->name] = true; break; + + case 'undocumentable': + $isUndocumentable = true; + break; } } } @@ -3383,7 +3392,8 @@ function parseFunctionLike( $args, $return, $numRequiredArgs, - $cond + $cond, + $isUndocumentable ); } catch (Exception $e) { throw new Exception($name . "(): " .$e->getMessage()); @@ -3570,6 +3580,12 @@ function parseClass( throw new Exception("Unknown class kind " . get_class($class)); } + if ($isUndocumentable) { + foreach ($methods as $method) { + $method->isUndocumentable = true; + } + } + return new ClassInfo( $name, $flags, @@ -3674,7 +3690,8 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac 0, 0, $stmt, - $cond + $cond, + $fileInfo->isUndocumentable ); continue; } @@ -3731,7 +3748,8 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac $classFlags, $classStmt->flags | $abstractFlag, $classStmt, - $cond + $cond, + $fileInfo->isUndocumentable ); } else if ($classStmt instanceof Stmt\EnumCase) { $enumCaseInfos[] = new EnumCaseInfo( @@ -4342,7 +4360,7 @@ function replaceClassSynopses(string $targetDirectory, array $classMap, iterable foreach ($missingClassSynopses as $className => $info) { /** @var ClassInfo $info */ if (!$info->isUndocumentable) { - echo "Warning: Missing class synopsis page for $className\n"; + echo "Warning: Missing class synopsis for $className\n"; } } } @@ -4388,7 +4406,8 @@ function generateMethodSynopses(array $funcMap, array $aliasMap): array { * @param array $aliasMap * @return array */ -function replaceMethodSynopses(string $targetDirectory, array $funcMap, array $aliasMap): array { +function replaceMethodSynopses(string $targetDirectory, array $funcMap, array $aliasMap, bool $isVerify): array { + $existingMethodSynopses = []; $methodSynopses = []; $it = new RecursiveIteratorIterator( @@ -4407,6 +4426,27 @@ function replaceMethodSynopses(string $targetDirectory, array $funcMap, array $a continue; } + if ($isVerify) { + $matches = []; + preg_match("/\s*([\w:]+)\s*<\/refname>\s*\s*&Alias;\s*<(?:function|methodname)>\s*([\w:]+)\s*<\/(?:function|methodname)>\s*<\/refpurpose>/i", $xml, $matches); + $aliasName = $matches[1] ?? null; + $alias = $funcMap[$aliasName] ?? null; + $funcName = $matches[2] ?? null; + $func = $funcMap[$funcName] ?? null; + + if ($alias && + !$alias->isUndocumentable && + ($func === null || $func->alias === null || $func->alias->__toString() !== $aliasName) && + ($alias->alias === null || $alias->alias->__toString() !== $funcName) + ) { + echo "Warning: $aliasName()" . ($alias->alias ? " is an alias of " . $alias->alias->__toString() . "(), but it" : "") . " is incorrectly documented as an alias for $funcName()\n"; + } + + if ($aliasName) { + $existingMethodSynopses[$aliasName] = $aliasName; + } + } + if (stripos($xml, "name->__toString()] = $funcInfo->name->__toString(); $newMethodSynopsis = $funcInfo->getMethodSynopsisElement($funcMap, $aliasMap, $doc); if ($newMethodSynopsis === null) { @@ -4534,6 +4576,16 @@ function replaceMethodSynopses(string $targetDirectory, array $funcMap, array $a } } + if ($isVerify) { + $missingMethodSynopses = array_diff_key($funcMap, $existingMethodSynopses); + foreach ($missingMethodSynopses as $functionName => $info) { + /** @var FuncInfo $info */ + if (!$info->isUndocumentable) { + echo "Warning: Missing method synopsis for $functionName()\n"; + } + } + } + return $methodSynopses; } @@ -4845,7 +4897,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc } if ($replaceMethodSynopses) { - $methodSynopses = replaceMethodSynopses($targetSynopses, $funcMap, $aliasMap); + $methodSynopses = replaceMethodSynopses($targetSynopses, $funcMap, $aliasMap, $verify); foreach ($methodSynopses as $filename => $content) { if (file_put_contents($filename, $content)) { diff --git a/ext/dl_test/dl_test.stub.php b/ext/dl_test/dl_test.stub.php index 36d59480a8d25..524c8206365b8 100644 --- a/ext/dl_test/dl_test.stub.php +++ b/ext/dl_test/dl_test.stub.php @@ -1,6 +1,9 @@