@@ -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
46894780foreach ($ 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+
47054804if ($ verify ) {
47064805 $ errors = [];
47074806
@@ -4817,7 +4916,7 @@ function(?ArgInfo $aliasArg, ?ArgInfo $aliasedArg) use ($aliasFunc, $aliasedFunc
48174916if ($ 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
48344933if ($ 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