Skip to content

Commit eebf3bc

Browse files
committed
Better document constructors
Until #10098 default constructors were sometimes documented, sometimes omitted. The above PR made adding documentation for constructor of all non-abstract classes required. However, this is not desired when such a class inherits a constructor from its parent. The current PR fixes the behavior the following way: - documents inherited constructors (along with destructors) - makes it possible to generate/replace the methodsynopsis of implicit default constructors which don't have a stub counterpart
1 parent e6c9b17 commit eebf3bc

File tree

1 file changed

+129
-30
lines changed

1 file changed

+129
-30
lines changed

build/gen_stub.php

+129-30
Original file line numberDiff line numberDiff line change
@@ -2700,17 +2700,18 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, itera
27002700
}
27012701
$classSynopsisInfo->appendChild(new DOMText("\n "));
27022702

2703-
/** @var Name[] $parentsWithInheritedConstants */
2703+
/** @var array<string, Name> $parentsWithInheritedConstants */
27042704
$parentsWithInheritedConstants = [];
2705-
/** @var Name[] $parentsWithInheritedProperties */
2705+
/** @var array<string, Name> $parentsWithInheritedProperties */
27062706
$parentsWithInheritedProperties = [];
2707-
/** @var Name[] $parentsWithInheritedMethods */
2707+
/** @var array<int, array{name: Name, types: int[]}> $parentsWithInheritedMethods */
27082708
$parentsWithInheritedMethods = [];
27092709

27102710
$this->collectInheritedMembers(
27112711
$parentsWithInheritedConstants,
27122712
$parentsWithInheritedProperties,
27132713
$parentsWithInheritedMethods,
2714+
$this->hasConstructor(),
27142715
$classMap
27152716
);
27162717

@@ -2756,9 +2757,9 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, itera
27562757
"&InheritedProperties;"
27572758
);
27582759

2759-
$isConcreteClass = ($this->type === "class" && !($this->flags & Class_::MODIFIER_ABSTRACT));
2760+
$isConcreteClassWithoutParentConstructor = $this->isConcreteClassWithoutParentConstructor($classMap);
27602761

2761-
if ($isConcreteClass || !empty($this->funcInfos)) {
2762+
if ($isConcreteClassWithoutParentConstructor || !empty($this->funcInfos)) {
27622763
$classSynopsis->appendChild(new DOMText("\n\n "));
27632764
$classSynopsisInfo = $doc->createElement("classsynopsisinfo", "&Methods;");
27642765
$classSynopsisInfo->setAttribute("role", "comment");
@@ -2768,7 +2769,7 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, itera
27682769
$classReference = self::getClassSynopsisReference($this->name);
27692770
$escapedName = addslashes($this->name->__toString());
27702771

2771-
if ($isConcreteClass || $this->hasConstructor()) {
2772+
if ($isConcreteClassWithoutParentConstructor || $this->hasConstructor()) {
27722773
$classSynopsis->appendChild(new DOMText("\n "));
27732774
$includeElement = $this->createIncludeElement(
27742775
$doc,
@@ -2802,14 +2803,21 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, itera
28022803
$classSynopsis->appendChild($classSynopsisInfo);
28032804

28042805
foreach ($parentsWithInheritedMethods as $parent) {
2805-
$classSynopsis->appendChild(new DOMText("\n "));
2806-
$parentReference = self::getClassSynopsisReference($parent);
2807-
$escapedParentName = addslashes($parent->__toString());
2808-
$includeElement = $this->createIncludeElement(
2809-
$doc,
2810-
"xmlns(db=http://docbook.org/ns/docbook) xpointer(id('$parentReference')/db:refentry/db:refsect1[@role='description']/descendant::db:methodsynopsis[@role='$escapedParentName'])"
2811-
);
2812-
$classSynopsis->appendChild($includeElement);
2806+
$parentName = $parent["name"];
2807+
$parentMethodsynopsisTypes = $parent["types"];
2808+
2809+
$parentReference = self::getClassSynopsisReference($parentName);
2810+
$escapedParentName = addslashes($parentName->__toString());
2811+
2812+
foreach ($parentMethodsynopsisTypes as $parentMethodsynopsisType) {
2813+
$classSynopsis->appendChild(new DOMText("\n "));
2814+
$includeElement = $this->createIncludeElement(
2815+
$doc,
2816+
"xmlns(db=http://docbook.org/ns/docbook) xpointer(id('$parentReference')/db:refentry/db:refsect1[@role='description']/descendant::db:{$parentMethodsynopsisType}[@role='$escapedParentName'])"
2817+
);
2818+
2819+
$classSynopsis->appendChild($includeElement);
2820+
}
28132821
}
28142822
}
28152823

@@ -2818,6 +2826,31 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, itera
28182826
return $classSynopsis;
28192827
}
28202828

2829+
/**
2830+
* @param array<string, ClassInfo> $classMap
2831+
*/
2832+
public function getNonExistentDefaultConstructorForManual(array $classMap): ?FuncInfo {
2833+
if (!$this->isConcreteClassWithoutParentConstructor($classMap) || $this->hasConstructor()) {
2834+
return null;
2835+
}
2836+
2837+
return new FuncInfo(
2838+
new MethodName($this->name, "__construct"),
2839+
$this->flags,
2840+
0,
2841+
null,
2842+
null,
2843+
false,
2844+
false,
2845+
true,
2846+
[],
2847+
new ReturnInfo(false, null, null, false, null),
2848+
0,
2849+
null,
2850+
false
2851+
);
2852+
}
2853+
28212854
private static function createOoElement(
28222855
DOMDocument $doc,
28232856
ClassInfo $classInfo,
@@ -2867,39 +2900,54 @@ public static function getClassSynopsisReference(Name $name): string {
28672900
}
28682901

28692902
/**
2870-
* @param Name[] $parentsWithInheritedConstants
2871-
* @param Name[] $parentsWithInheritedProperties
2872-
* @param Name[] $parentsWithInheritedMethods
2903+
* @param array<string, Name> $parentsWithInheritedConstants
2904+
* @param array<string, Name> $parentsWithInheritedProperties
2905+
* @param array<string, array{name: Name, types: int[]}> $parentsWithInheritedMethods
28732906
* @param array<string, ClassInfo> $classMap
28742907
*/
28752908
private function collectInheritedMembers(
28762909
array &$parentsWithInheritedConstants,
28772910
array &$parentsWithInheritedProperties,
28782911
array &$parentsWithInheritedMethods,
2912+
bool $hasConstructor,
28792913
array $classMap
28802914
): void {
28812915
foreach ($this->extends as $parent) {
28822916
$parentInfo = $classMap[$parent->toString()] ?? null;
2917+
$parentName = $parent->toString();
2918+
28832919
if (!$parentInfo) {
2884-
throw new Exception("Missing parent class " . $parent->toString());
2920+
throw new Exception("Missing parent class $parentName");
28852921
}
28862922

2887-
if (!empty($parentInfo->constInfos) && !isset($parentsWithInheritedConstants[$parent->toString()])) {
2888-
$parentsWithInheritedConstants[$parent->toString()] = $parent;
2923+
if (!empty($parentInfo->constInfos) && !isset($parentsWithInheritedConstants[$parentName])) {
2924+
$parentsWithInheritedConstants[] = $parent;
2925+
}
2926+
2927+
if (!empty($parentInfo->propertyInfos) && !isset($parentsWithInheritedProperties[$parentName])) {
2928+
$parentsWithInheritedProperties[$parentName] = $parent;
28892929
}
28902930

2891-
if (!empty($parentInfo->propertyInfos) && !isset($parentsWithInheritedProperties[$parent->toString()])) {
2892-
$parentsWithInheritedProperties[$parent->toString()] = $parent;
2931+
if (!$hasConstructor && $parentInfo->hasConstructor()) {
2932+
$parentsWithInheritedMethods[$parentName]["name"] = $parent;
2933+
$parentsWithInheritedMethods[$parentName]["types"][] = "constructorsynopsis";
28932934
}
28942935

2895-
if (!isset($parentsWithInheritedMethods[$parent->toString()]) && $parentInfo->hasMethods()) {
2896-
$parentsWithInheritedMethods[$parent->toString()] = $parent;
2936+
if ($parentInfo->hasMethods()) {
2937+
$parentsWithInheritedMethods[$parentName]["name"] = $parent;
2938+
$parentsWithInheritedMethods[$parentName]["types"][] = "methodsynopsis";
2939+
}
2940+
2941+
if ($parentInfo->hasDestructor()) {
2942+
$parentsWithInheritedMethods[$parentName]["name"] = $parent;
2943+
$parentsWithInheritedMethods[$parentName]["types"][] = "destructorsynopsis";
28972944
}
28982945

28992946
$parentInfo->collectInheritedMembers(
29002947
$parentsWithInheritedConstants,
29012948
$parentsWithInheritedProperties,
29022949
$parentsWithInheritedMethods,
2950+
$hasConstructor,
29032951
$classMap
29042952
);
29052953
}
@@ -2921,6 +2969,7 @@ private function collectInheritedMembers(
29212969
$parentsWithInheritedConstants,
29222970
$unusedParentsWithInheritedProperties,
29232971
$unusedParentsWithInheritedMethods,
2972+
$hasConstructor,
29242973
$classMap
29252974
);
29262975
}
@@ -2937,6 +2986,29 @@ private function hasConstructor(): bool
29372986
return false;
29382987
}
29392988

2989+
/**
2990+
* @param array<string, ClassInfo> $classMap
2991+
*/
2992+
private function hasParentConstructor(array $classMap): bool
2993+
{
2994+
foreach ($this->extends as $parentName) {
2995+
$parent = $classMap[$parentName->toString()] ?? null;
2996+
if ($parent === null) {
2997+
throw new Exception("Missing parent class " . $parent->toString());
2998+
}
2999+
3000+
if ($parent->hasConstructor()) {
3001+
return true;
3002+
}
3003+
3004+
if ($parent->hasParentConstructor($classMap)) {
3005+
return true;
3006+
}
3007+
}
3008+
3009+
return false;
3010+
}
3011+
29403012
private function hasDestructor(): bool
29413013
{
29423014
foreach ($this->funcInfos as $funcInfo) {
@@ -2959,6 +3031,13 @@ private function hasMethods(): bool
29593031
return false;
29603032
}
29613033

3034+
/**
3035+
* @param array<string, ClassInfo> $classMap
3036+
*/
3037+
private function isConcreteClassWithoutParentConstructor(array $classMap) {
3038+
return $this->type === "class" && !($this->flags & Class_::MODIFIER_ABSTRACT) && !$this->hasParentConstructor($classMap);
3039+
}
3040+
29623041
private function createIncludeElement(DOMDocument $doc, string $query): DOMElement
29633042
{
29643043
$includeElement = $doc->createElement("xi:include");
@@ -3036,6 +3115,18 @@ public function getAllFuncInfos(): iterable {
30363115
}
30373116
}
30383117

3118+
/**
3119+
* @return array<string, ClassInfo> $classMap
3120+
*/
3121+
public function getAllNonExistentDefaultConstructorsForManual(array $classMap): iterable {
3122+
foreach ($this->classInfos as $classInfo) {
3123+
$funcInfo = $classInfo->getNonExistentDefaultConstructorForManual($classMap);
3124+
if ($funcInfo !== null) {
3125+
yield $funcInfo;
3126+
}
3127+
}
3128+
}
3129+
30393130
/**
30403131
* @return iterable<ConstInfo>
30413132
*/
@@ -4058,14 +4149,14 @@ static function (FuncInfo $funcInfo) use ($allConstInfos) {
40584149
);
40594150
}
40604151

4061-
/** @param FuncInfo<string, FuncInfo> $funcInfos */
4062-
function generateOptimizerInfo(array $funcInfos): string {
4152+
/** @param array<string, FuncInfo> $funcMap */
4153+
function generateOptimizerInfo(array $funcMap): string {
40634154

40644155
$code = "/* This is a generated file, edit the .stub.php files instead. */\n\n";
40654156

40664157
$code .= "static const func_info_t func_infos[] = {\n";
40674158

4068-
$code .= generateCodeWithConditions($funcInfos, "", static function (FuncInfo $funcInfo) {
4159+
$code .= generateCodeWithConditions($funcMap, "", static function (FuncInfo $funcInfo) {
40694160
return $funcInfo->getOptimizerInfo();
40704161
});
40714162

@@ -4688,7 +4779,6 @@ function initPhpParser() {
46884779

46894780
foreach ($fileInfos as $fileInfo) {
46904781
foreach ($fileInfo->getAllFuncInfos() as $funcInfo) {
4691-
/** @var FuncInfo $funcInfo */
46924782
$funcMap[$funcInfo->name->__toString()] = $funcInfo;
46934783

46944784
// TODO: Don't use aliasMap for methodsynopsis?
@@ -4702,6 +4792,15 @@ function initPhpParser() {
47024792
}
47034793
}
47044794

4795+
/** @var array<string, FuncInfo> $funcMapForManual */
4796+
$funcMapForManual = $funcMap;
4797+
4798+
foreach ($fileInfos as $fileInfo) {
4799+
foreach ($fileInfo->getAllNonExistentDefaultConstructorsForManual($classMap) as $funcInfo) {
4800+
$funcMapForManual[$funcInfo->name->__toString()] = $funcInfo;
4801+
}
4802+
}
4803+
47054804
if ($verify) {
47064805
$errors = [];
47074806

@@ -4817,7 +4916,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc
48174916
if ($generateMethodSynopses) {
48184917
$methodSynopsesDirectory = getcwd() . "/methodsynopses";
48194918

4820-
$methodSynopses = generateMethodSynopses($funcMap, $aliasMap);
4919+
$methodSynopses = generateMethodSynopses($funcMapForManual, $aliasMap);
48214920
if (!empty($methodSynopses)) {
48224921
if (!file_exists($methodSynopsesDirectory)) {
48234922
mkdir($methodSynopsesDirectory);
@@ -4832,7 +4931,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc
48324931
}
48334932

48344933
if ($replaceMethodSynopses) {
4835-
$methodSynopses = replaceMethodSynopses($targetSynopses, $funcMap, $aliasMap, $verify);
4934+
$methodSynopses = replaceMethodSynopses($targetSynopses, $funcMapForManual, $aliasMap, $verify);
48364935

48374936
foreach ($methodSynopses as $filename => $content) {
48384937
if (file_put_contents($filename, $content)) {

0 commit comments

Comments
 (0)