@@ -2217,10 +2217,10 @@ public function enterNode(Node $expr)
22172217 $isUnknownConstValue = false;
22182218
22192219 $evaluator = new ConstExprEvaluator(
2220- static function (Expr $expr) use ($allConstInfos, &$isUnknownConstValue) {
2221- // $expr is a ConstFetch with a name of a C macro here
2220+ function (Expr $expr) use ($allConstInfos, &$isUnknownConstValue) {
2221+ // $expr is a ConstFetch with a name of a C macro here. Class constants are not supported yet
22222222 if (!$expr instanceof Expr\ConstFetch) {
2223- throw new Exception($this->getVariableTypeName() . " " . $this->name->__toString() . " has an unsupported value ");
2223+ throw new Exception("Cannot evaluate expression ");
22242224 }
22252225
22262226 $constName = $expr->name->__toString();
@@ -2379,7 +2379,7 @@ abstract protected function getFieldSynopsisDefaultLinkend(): string;
23792379 abstract protected function getFieldSynopsisName(): string;
23802380
23812381 /** @param array<string, ConstInfo> $allConstInfos */
2382- abstract protected function getFieldSynopsisValueString(array $allConstInfos): ?string;
2382+ abstract public function getFieldSynopsisValueString(array $allConstInfos): ?string;
23832383
23842384 abstract public function discardInfoForOldPhpVersions(?int $minimumPhpVersionIdCompatibility): void;
23852385
@@ -2604,7 +2604,7 @@ protected function getFieldSynopsisName(): string
26042604 }
26052605
26062606 /** @param array<string, ConstInfo> $allConstInfos */
2607- protected function getFieldSynopsisValueString(array $allConstInfos): ?string
2607+ public function getFieldSynopsisValueString(array $allConstInfos): ?string
26082608 {
26092609 $value = EvaluatedValue::createFromExpression($this->value, null, $this->cValue, $allConstInfos);
26102610 if ($value->isUnknownConstValue) {
@@ -2939,7 +2939,7 @@ protected function getFieldSynopsisName(): string
29392939 }
29402940
29412941 /** @param array<string, ConstInfo> $allConstInfos */
2942- protected function getFieldSynopsisValueString(array $allConstInfos): ?string
2942+ public function getFieldSynopsisValueString(array $allConstInfos): ?string
29432943 {
29442944 return $this->defaultValueString;
29452945 }
@@ -3061,10 +3061,12 @@ public function __clone()
30613061class EnumCaseInfo {
30623062 public string $name;
30633063 public ?Expr $value;
3064+ public ?string $valueString;
30643065
3065- public function __construct(string $name, ?Expr $value) {
3066+ public function __construct(string $name, ?Expr $value, ?string $valueString ) {
30663067 $this->name = $name;
30673068 $this->value = $value;
3069+ $this->valueString = $valueString;
30683070 }
30693071
30703072 /** @param array<string, ConstInfo> $allConstInfos */
@@ -3082,6 +3084,51 @@ public function getDeclaration(array $allConstInfos): string {
30823084
30833085 return $code;
30843086 }
3087+
3088+ /** @param array<string, ConstInfo> $allConstInfos */
3089+ public function getEnumItemElement(DOMDocument $doc, array $allConstInfos): DOMElement
3090+ {
3091+ $enumItemElement = $doc->createElement("enumitem");
3092+
3093+ $enumItemElement->appendChild(new DOMText("\n "));
3094+ $enumIdentifierElement = $doc->createElement("enumidentifier");
3095+ $enumIdentifierElement->appendChild(new DOMText($this->name));
3096+ $enumItemElement->appendChild($enumIdentifierElement);
3097+
3098+ $valueString = $this->getEnumValueString($allConstInfos);
3099+ if ($valueString) {
3100+ $enumValueElement = $doc->createElement("enumvalue");
3101+ $enumItemElement->appendChild(new DOMText("\n "));
3102+ $initializerElement = $doc->createElement("initializer", $valueString);
3103+ $enumValueElement->appendChild($initializerElement);
3104+ $enumItemElement->appendChild($enumValueElement);
3105+ }
3106+
3107+ $enumItemElement->appendChild(new DOMText("\n "));
3108+
3109+ return $enumItemElement;
3110+ }
3111+
3112+ /** @param array<string, ConstInfo> $allConstInfos */
3113+ protected function getEnumValueString(array $allConstInfos): ?string
3114+ {
3115+ if ($this->value === null) {
3116+ return null;
3117+ };
3118+
3119+ $value = EvaluatedValue::createFromExpression($this->value, null, null, $allConstInfos);
3120+ if ($value->isUnknownConstValue) {
3121+ return null;
3122+ }
3123+
3124+ if ($value->originatingConsts) {
3125+ return implode("\n", array_map(function (ConstInfo $const) use ($allConstInfos) {
3126+ return $const->getFieldSynopsisValueString($allConstInfos);
3127+ }, $value->originatingConsts));
3128+ }
3129+
3130+ return $this->valueString;
3131+ }
30853132}
30863133
30873134class AttributeInfo {
@@ -3468,17 +3515,36 @@ public function getClassSynopsisDocument(array $classMap, array $allConstInfos):
34683515 * @param array<string, ConstInfo> $allConstInfos
34693516 */
34703517 public function getClassSynopsisElement(DOMDocument $doc, array $classMap, array $allConstInfos): ?DOMElement {
3518+ $isEnum = $this->type === "enum";
3519+
3520+ $classSynopsis = $doc->createElement($isEnum ? "enumsynopsis" : "classsynopsis");
3521+ $synopsisInfoName = $isEnum ? "synopsisinfo" : "classsynopsisinfo";
34713522
3472- $classSynopsis = $doc->createElement("classsynopsis");
3473- $classSynopsis->setAttribute("class", $this->type === "interface" ? "interface" : "class");
3523+ if (!$isEnum) {
3524+ $classSynopsis->setAttribute("class", $this->type);
3525+ }
34743526
34753527 $exceptionOverride = $this->type === "class" && $this->isException($classMap) ? "exception" : null;
3528+ $classSynopsis->appendChild(new DOMText("\n "));
3529+
34763530 $ooElement = self::createOoElement($doc, $this, $exceptionOverride, true, null, 4);
3477- if (!$ooElement) {
3478- return null;
3531+ if ($ooElement) {
3532+ $classSynopsis->appendChild($ooElement);
3533+ }
3534+
3535+ if ($isEnum) {
3536+ $enumNameElement = $doc->createElement("enumname");
3537+ $enumNameElement->appendChild(new DOMText($this->name->toString()));
3538+ $classSynopsis->appendChild($enumNameElement);
3539+
3540+ if ($this->enumBackingType) {
3541+ $classSynopsis->appendChild(new DOMText("\n "));
3542+ $enumNameElement = $doc->createElement("modifier");
3543+ $enumNameElement->setAttribute("role", "enum_backing_type");
3544+ $enumNameElement->appendChild(new DOMText($this->enumBackingType->name));
3545+ $classSynopsis->appendChild($enumNameElement);
3546+ }
34793547 }
3480- $classSynopsis->appendChild(new DOMText("\n "));
3481- $classSynopsis->appendChild($ooElement);
34823548
34833549 foreach ($this->extends as $k => $parent) {
34843550 $parentInfo = $classMap[$parent->toString()] ?? null;
@@ -3502,6 +3568,11 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, array
35023568 $classSynopsis->appendChild($ooElement);
35033569 }
35043570
3571+ // Enums implicitly implement either UnitEnum or BackEnum. This way inherited methods can be displayed.
3572+ if ($isEnum) {
3573+ $this->implements[] = new Name\FullyQualified($this->enumBackingType ? "BackedEnum" : "UnitEnum");
3574+ }
3575+
35053576 foreach ($this->implements as $k => $interface) {
35063577 $interfaceInfo = $classMap[$interface->toString()] ?? null;
35073578 if (!$interfaceInfo) {
@@ -3535,13 +3606,14 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, array
35353606 $doc,
35363607 $classSynopsis,
35373608 $parentsWithInheritedConstants,
3609+ $synopsisInfoName,
35383610 "&Constants;",
35393611 "&InheritedConstants;"
35403612 );
35413613
35423614 if (!empty($this->constInfos)) {
35433615 $classSynopsis->appendChild(new DOMText("\n\n "));
3544- $classSynopsisInfo = $doc->createElement("classsynopsisinfo" , "&Constants;");
3616+ $classSynopsisInfo = $doc->createElement($synopsisInfoName , "&Constants;");
35453617 $classSynopsisInfo->setAttribute("role", "comment");
35463618 $classSynopsis->appendChild($classSynopsisInfo);
35473619
@@ -3552,9 +3624,22 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, array
35523624 }
35533625 }
35543626
3627+ if (!empty($this->enumCaseInfos)) {
3628+ $classSynopsis->appendChild(new DOMText("\n\n "));
3629+ $classSynopsisInfo = $doc->createElement($synopsisInfoName, "&EnumCases;");
3630+ $classSynopsisInfo->setAttribute("role", "comment");
3631+ $classSynopsis->appendChild($classSynopsisInfo);
3632+
3633+ foreach ($this->enumCaseInfos as $enumCaseInfo) {
3634+ $classSynopsis->appendChild(new DOMText("\n "));
3635+ $enumItemElement = $enumCaseInfo->getEnumItemElement($doc, $allConstInfos);
3636+ $classSynopsis->appendChild($enumItemElement);
3637+ }
3638+ }
3639+
35553640 if (!empty($this->propertyInfos)) {
35563641 $classSynopsis->appendChild(new DOMText("\n\n "));
3557- $classSynopsisInfo = $doc->createElement("classsynopsisinfo" , "&Properties;");
3642+ $classSynopsisInfo = $doc->createElement($synopsisInfoName , "&Properties;");
35583643 $classSynopsisInfo->setAttribute("role", "comment");
35593644 $classSynopsis->appendChild($classSynopsisInfo);
35603645
@@ -3569,13 +3654,14 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, array
35693654 $doc,
35703655 $classSynopsis,
35713656 $parentsWithInheritedProperties,
3657+ $synopsisInfoName,
35723658 "&Properties;",
35733659 "&InheritedProperties;"
35743660 );
35753661
35763662 if (!empty($this->funcInfos)) {
35773663 $classSynopsis->appendChild(new DOMText("\n\n "));
3578- $classSynopsisInfo = $doc->createElement("classsynopsisinfo" , "&Methods;");
3664+ $classSynopsisInfo = $doc->createElement($synopsisInfoName , "&Methods;");
35793665 $classSynopsisInfo->setAttribute("role", "comment");
35803666 $classSynopsis->appendChild($classSynopsisInfo);
35813667
@@ -3612,7 +3698,7 @@ public function getClassSynopsisElement(DOMDocument $doc, array $classMap, array
36123698
36133699 if (!empty($parentsWithInheritedMethods)) {
36143700 $classSynopsis->appendChild(new DOMText("\n\n "));
3615- $classSynopsisInfo = $doc->createElement("classsynopsisinfo" , "&InheritedMethods;");
3701+ $classSynopsisInfo = $doc->createElement($synopsisInfoName , "&InheritedMethods;");
36163702 $classSynopsisInfo->setAttribute("role", "comment");
36173703 $classSynopsis->appendChild($classSynopsisInfo);
36183704
@@ -3650,8 +3736,7 @@ private static function createOoElement(
36503736 ): ?DOMElement {
36513737 $indentation = str_repeat(" ", $indentationLevel);
36523738
3653- if ($classInfo->type !== "class" && $classInfo->type !== "interface") {
3654- echo "Class synopsis generation is not implemented for " . $classInfo->type . "\n";
3739+ if ($classInfo->type === "enum") {
36553740 return null;
36563741 }
36573742
@@ -3745,6 +3830,8 @@ private function collectInheritedMembers(
37453830 );
37463831 }
37473832
3833+ $isEnum = $this->type === "enum";
3834+
37483835 foreach ($this->implements as $parent) {
37493836 $parentInfo = $classMap[$parent->toString()] ?? null;
37503837 if (!$parentInfo) {
@@ -3758,13 +3845,25 @@ private function collectInheritedMembers(
37583845 $unusedParentsWithInheritedProperties = [];
37593846 $unusedParentsWithInheritedMethods = [];
37603847
3761- $parentInfo->collectInheritedMembers(
3762- $parentsWithInheritedConstants,
3763- $unusedParentsWithInheritedProperties,
3764- $unusedParentsWithInheritedMethods,
3765- $hasConstructor,
3766- $classMap
3767- );
3848+ if ($isEnum) {
3849+ $parentInfo->collectInheritedMembers(
3850+ $parentsWithInheritedConstants,
3851+ $unusedParentsWithInheritedProperties,
3852+ // We only want to collect inherited methods in case of enums
3853+ $parentsWithInheritedMethods,
3854+ $hasConstructor,
3855+ $classMap
3856+ );
3857+ } else {
3858+ $parentInfo->collectInheritedMembers(
3859+ $parentsWithInheritedConstants,
3860+ $unusedParentsWithInheritedProperties,
3861+ // We only want to collect inherited methods in case of enums
3862+ $unusedParentsWithInheritedMethods,
3863+ $hasConstructor,
3864+ $classMap
3865+ );
3866+ }
37683867 }
37693868 }
37703869
@@ -3886,14 +3985,14 @@ public function __clone()
38863985 /**
38873986 * @param Name[] $parents
38883987 */
3889- private function appendInheritedMemberSectionToClassSynopsis(DOMDocument $doc, DOMElement $classSynopsis, array $parents, string $label, string $inheritedLabel): void
3988+ private function appendInheritedMemberSectionToClassSynopsis(DOMDocument $doc, DOMElement $classSynopsis, array $parents, string $synopsisInfoName, string $ label, string $inheritedLabel): void
38903989 {
38913990 if (empty($parents)) {
38923991 return;
38933992 }
38943993
38953994 $classSynopsis->appendChild(new DOMText("\n\n "));
3896- $classSynopsisInfo = $doc->createElement("classsynopsisinfo" , "$inheritedLabel");
3995+ $classSynopsisInfo = $doc->createElement($synopsisInfoName , "$inheritedLabel");
38973996 $classSynopsisInfo->setAttribute("role", "comment");
38983997 $classSynopsis->appendChild($classSynopsisInfo);
38993998
@@ -4738,7 +4837,10 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac
47384837 );
47394838 } else if ($classStmt instanceof Stmt\EnumCase) {
47404839 $enumCaseInfos[] = new EnumCaseInfo(
4741- $classStmt->name->toString(), $classStmt->expr);
4840+ $classStmt->name->toString(),
4841+ $classStmt->expr,
4842+ $prettyPrinter->prettyPrintExpr($classStmt->expr)
4843+ );
47424844 } else {
47434845 throw new Exception("Not implemented {$classStmt->getType()}");
47444846 }
0 commit comments