diff --git a/README.md b/README.md index e4fbbc3..4ee17ee 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,5 @@ $reflector = TyphoonReflector::build( ## TODO -- [ ] traits - [ ] class constants - [ ] functions diff --git a/docs/compatibility.md b/docs/compatibility.md index e6d88cd..b520240 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -32,7 +32,7 @@ | `getStartLine()` | ✅️ | | `getStaticProperties()` | ✅ Via native reflection | | `getStaticPropertyValue()` | ✅ Via native reflection | -| `getTraitAliases()` | ✅ Via native reflection. TODO | +| `getTraitAliases()` | ✅ | | `getTraitNames()` | ✅ | | `getTraits()` | ✅ | | `hasConstant()` | ✅ Via native reflection. TODO | diff --git a/psalm.xml.dist b/psalm.xml.dist index f4d51a1..3a9d963 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -73,6 +73,7 @@ + diff --git a/src/AttributeReflection/AttributeReflections.php b/src/AttributeReflection/AttributeReflections.php index ab43d06..ad9595b 100644 --- a/src/AttributeReflection/AttributeReflections.php +++ b/src/AttributeReflection/AttributeReflections.php @@ -12,7 +12,6 @@ * @internal * @psalm-internal Typhoon\Reflection * @template-covariant T of object - * @psalm-suppress PossiblyUnusedProperty */ final class AttributeReflections { diff --git a/src/ClassReflection.php b/src/ClassReflection.php index 13d486f..6055ca4 100644 --- a/src/ClassReflection.php +++ b/src/ClassReflection.php @@ -289,9 +289,21 @@ public function getTemplates(): array public function getTraitAliases(): array { - $this->loadNative(); + $traitAliases = []; + + foreach ($this->metadata->traitMethodAliases as $trait => $methodAliases) { + foreach ($methodAliases as $method => $aliases) { + foreach ($aliases as $alias) { + if ($alias->alias === null) { + continue; + } + + $traitAliases[$alias->alias] = $trait . '::' . $method; + } + } + } - return parent::getTraitAliases(); + return $traitAliases; } public function getTraitNames(): array diff --git a/src/Inheritance/MethodInheritanceResolver.php b/src/Inheritance/MethodInheritanceResolver.php index d398853..93c4699 100644 --- a/src/Inheritance/MethodInheritanceResolver.php +++ b/src/Inheritance/MethodInheritanceResolver.php @@ -11,6 +11,7 @@ /** * @internal * @psalm-internal Typhoon\Reflection\Inheritance + * @psalm-import-type Prototype from MethodMetadata */ final class MethodInheritanceResolver { @@ -19,7 +20,7 @@ final class MethodInheritanceResolver private bool $own = false; /** - * @var ?array{class-string, non-empty-string} + * @var Prototype */ private ?array $prototype = null; diff --git a/src/Inheritance/MethodsInheritanceResolver.php b/src/Inheritance/MethodsInheritanceResolver.php index 6a34c27..4bb0d9b 100644 --- a/src/Inheritance/MethodsInheritanceResolver.php +++ b/src/Inheritance/MethodsInheritanceResolver.php @@ -13,6 +13,8 @@ * @internal * @psalm-internal Typhoon\Reflection * @psalm-import-type ClassMetadataReflector from ClassMetadata + * @psalm-import-type TraitMethodAliases from ClassMetadata + * @psalm-import-type TraitMethodPrecedence from ClassMetadata */ final class MethodsInheritanceResolver { @@ -31,28 +33,46 @@ public function __construct( ) {} /** - * @param iterable $methods + * @param list $methods */ - public function setOwn(iterable $methods): void + public function setOwn(array $methods): void { foreach ($methods as $method) { $this->method($method->name)->setOwn($method); } } - public function addUsed(NamedObjectType ...$types): void + /** + * @param list $types + * @param TraitMethodAliases $traitMethodAliases + * @param TraitMethodPrecedence $traitMethodPrecedence + */ + public function addUsed(array $types, array $traitMethodAliases, array $traitMethodPrecedence): void { - foreach ($types as $type) { - $class = ($this->classMetadataReflector)($type->class); - $templateResolver = TemplateResolver::create($class->templates, $type->templateArguments); + foreach (array_column($types, null, 'class') as $type) { + $trait = ($this->classMetadataReflector)($type->class); + $templateResolver = TemplateResolver::create($trait->templates, $type->templateArguments); - foreach ($class->resolvedMethods($this->classMetadataReflector) as $method) { - $this->method($method->name)->addUsed($method, $templateResolver); + foreach ($trait->resolvedMethods($this->classMetadataReflector) as $method) { + $name = $method->name; + + if (isset($traitMethodPrecedence[$name]) && $traitMethodPrecedence[$name] !== $trait->name) { + continue; + } + + foreach ($traitMethodAliases[$trait->name][$name] ?? [] as $alias) { + $this->method($alias->alias ?? $name)->addUsed($method->toAlias($alias), $templateResolver); + } + + $this->method($name)->addUsed($method, $templateResolver); } } } - public function addInherited(NamedObjectType ...$types): void + /** + * @param list $types + */ + public function addInherited(array $types): void { foreach ($types as $type) { $class = ($this->classMetadataReflector)($type->class); diff --git a/src/Metadata/AttributeMetadata.php b/src/Metadata/AttributeMetadata.php index 10057da..4251707 100644 --- a/src/Metadata/AttributeMetadata.php +++ b/src/Metadata/AttributeMetadata.php @@ -9,7 +9,6 @@ * @psalm-internal Typhoon\Reflection * @psalm-immutable * @template TAttribute of object - * @psalm-suppress PossiblyUnusedProperty */ final class AttributeMetadata { diff --git a/src/Metadata/ClassMetadata.php b/src/Metadata/ClassMetadata.php index 7d519ea..5344d1d 100644 --- a/src/Metadata/ClassMetadata.php +++ b/src/Metadata/ClassMetadata.php @@ -15,8 +15,9 @@ * @psalm-internal Typhoon\Reflection * @template-covariant T of object * @template-extends RootMetadata> - * @psalm-suppress PossiblyUnusedProperty * @psalm-type ClassMetadataReflector = \Closure(class-string): ClassMetadata + * @psalm-type TraitMethodAliases = array>> + * @psalm-type TraitMethodPrecedence = array */ final class ClassMetadata extends RootMetadata { @@ -32,6 +33,7 @@ final class ClassMetadata extends RootMetadata /** * @param class-string $name + * @param int-mask-of<\ReflectionClass::IS_*> $modifiers * @param non-empty-string|false $extension * @param non-empty-string|false $file * @param positive-int|false $startLine @@ -40,9 +42,10 @@ final class ClassMetadata extends RootMetadata * @param list $attributes * @param array $typeAliases * @param list $templates - * @param int-mask-of<\ReflectionClass::IS_*> $modifiers * @param list $interfaceTypes * @param list $traitTypes + * @param TraitMethodAliases $traitMethodAliases + * @param TraitMethodPrecedence $traitMethodPrecedence * @param list $ownProperties * @param list $ownMethods */ @@ -67,6 +70,8 @@ public function __construct( public readonly ?NamedObjectType $parentType = null, public readonly array $interfaceTypes = [], public readonly array $traitTypes = [], + public readonly array $traitMethodAliases = [], + public readonly array $traitMethodPrecedence = [], public readonly array $ownProperties = [], public readonly array $ownMethods = [], ) { @@ -129,11 +134,11 @@ public function resolvedMethods(\Closure $classMetadataReflector): array $resolver = new MethodsInheritanceResolver($this->name, $classMetadataReflector); $resolver->setOwn($this->ownMethods); - $resolver->addUsed(...$this->traitTypes); + $resolver->addUsed($this->traitTypes, $this->traitMethodAliases, $this->traitMethodPrecedence); if ($this->parentType !== null) { - $resolver->addInherited($this->parentType); + $resolver->addInherited([$this->parentType]); } - $resolver->addInherited(...$this->interfaceTypes); + $resolver->addInherited($this->interfaceTypes); return $this->resolvedMethods = $resolver->resolve(); } diff --git a/src/Metadata/MethodMetadata.php b/src/Metadata/MethodMetadata.php index 8c18ac8..c52edea 100644 --- a/src/Metadata/MethodMetadata.php +++ b/src/Metadata/MethodMetadata.php @@ -10,12 +10,12 @@ * @internal * @psalm-internal Typhoon\Reflection * @psalm-immutable - * @psalm-suppress PossiblyUnusedProperty + * @psalm-type Prototype = ?array{class-string, non-empty-string} */ final class MethodMetadata { /** - * @var ?array{class-string, non-empty-string} + * @var Prototype */ public ?array $prototype = null; @@ -33,9 +33,9 @@ final class MethodMetadata * @param list $attributes */ public function __construct( - public readonly string $name, + public string $name, public string $class, - public readonly int $modifiers, + public int $modifiers, public array $parameters, public TypeMetadata $returnType, public readonly array $templates = [], @@ -51,6 +51,25 @@ public function __construct( public readonly array $attributes = [], ) {} + public function toAlias(TraitMethodAlias $alias): self + { + $metadata = clone $this; + + if ($alias->alias !== null) { + $metadata->name = $alias->alias; + } + + if ($alias->visibility !== null) { + $metadata->modifiers = $metadata->modifiers + & ~\ReflectionMethod::IS_PUBLIC + & ~\ReflectionMethod::IS_PROTECTED + & ~\ReflectionMethod::IS_PRIVATE + | $alias->visibility; + } + + return $metadata; + } + /** * @param class-string $class */ @@ -63,9 +82,9 @@ public function withClass(string $class): self } /** - * @param array{class-string, non-empty-string} $prototype + * @param Prototype $prototype */ - public function withPrototype(array $prototype): self + public function withPrototype(?array $prototype): self { $metadata = clone $this; $metadata->prototype = $prototype; diff --git a/src/Metadata/TraitMethodAlias.php b/src/Metadata/TraitMethodAlias.php new file mode 100644 index 0000000..fc95ab1 --- /dev/null +++ b/src/Metadata/TraitMethodAlias.php @@ -0,0 +1,22 @@ +reflectTraitInfo($class); + return new ClassMetadata( name: $class->name, modifiers: $class->getModifiers(), @@ -52,6 +58,8 @@ traitTypes: array_map( static fn(string $trait): Type\NamedObjectType => types::object($trait), $class->getTraitNames(), ), + traitMethodAliases: $traitMethodAliases, + traitMethodPrecedence: $traitMethodPrecedence, ownProperties: $this->reflectOwnProperties($class), ownMethods: $this->reflectOwnMethods($class), ); @@ -139,6 +147,11 @@ private function isOwnMethod(\ReflectionClass $class, \ReflectionMethod $method) return false; } + return $this->isMethodFromSameFile($class, $method); + } + + private function isMethodFromSameFile(\ReflectionClass $class, \ReflectionMethod $method): bool + { if ($method->getFileName() !== $class->getFileName()) { return false; } @@ -152,6 +165,71 @@ private function isOwnMethod(\ReflectionClass $class, \ReflectionMethod $method) && ($methodEndLine === $classEndLine || \is_int($methodEndLine) && \is_int($classEndLine) && $methodEndLine <= $classEndLine); } + /** + * @return array{TraitMethodAliases, TraitMethodPrecedence} + */ + private function reflectTraitInfo(\ReflectionClass $class): array + { + $traits = $class->getTraits(); + + if ($traits === []) { + return [[], []]; + } + + /** @var TraitMethodAliases */ + $traitMethodAliases = []; + /** @var TraitMethodPrecedence */ + $traitMethodPrecedence = []; + + foreach ($class->getTraitAliases() as $alias => $traitMethodName) { + [$traitName, $methodName] = explode('::', $traitMethodName); + + /** + * @var class-string $traitName + * @var non-empty-string $methodName + */ + $traitMethodAliases[$traitName][$methodName][] = new TraitMethodAlias( + visibility: $this->calculateMethodVisibilityDiff(new \ReflectionMethod($traitName, $methodName), $class->getMethod($alias)), + alias: $alias, + ); + } + + foreach ($traits as $trait) { + foreach ($trait->getMethods() as $traitMethod) { + $classMethod = $class->getMethod($traitMethod->name); + + if (!$this->isMethodFromSameFile($trait, $classMethod)) { + continue; + } + + $traitMethodPrecedence[$traitMethod->name] = $trait->name; + $visibilityDiff = $this->calculateMethodVisibilityDiff($traitMethod, $classMethod); + + if ($visibilityDiff !== null) { + $traitMethodAliases[$trait->name][$traitMethod->name][] = new TraitMethodAlias($visibilityDiff); + } + } + } + + return [$traitMethodAliases, $traitMethodPrecedence]; + } + + /** + * @return Visibility + */ + private function calculateMethodVisibilityDiff(\ReflectionMethod $old, \ReflectionMethod $new): ?int + { + if ($new->isPublic()) { + return $old->isPublic() ? null : \ReflectionMethod::IS_PUBLIC; + } + + if ($new->isProtected()) { + return $old->isProtected() ? null : \ReflectionMethod::IS_PROTECTED; + } + + return $old->isPrivate() ? null : \ReflectionMethod::IS_PRIVATE; + } + /** * @param ?class-string $class * @return list diff --git a/src/PhpParserReflector/ClassReflections.php b/src/PhpParserReflector/ClassReflections.php index 1bda6f5..ec48a37 100644 --- a/src/PhpParserReflector/ClassReflections.php +++ b/src/PhpParserReflector/ClassReflections.php @@ -30,14 +30,14 @@ public static function modifiers(ClassLike $node): int } $modifiers = ($node->isAbstract() ? ClassReflection::IS_EXPLICIT_ABSTRACT : 0) - + ($node->isFinal() ? ClassReflection::IS_FINAL : 0); + | ($node->isFinal() ? ClassReflection::IS_FINAL : 0); if (\PHP_VERSION_ID >= 80200 && $node->isReadonly()) { /** * @var int-mask-of<\ReflectionClass::IS_*> * @psalm-suppress MixedOperand, UndefinedConstant, UnusedPsalmSuppress */ - $modifiers += \ReflectionClass::IS_READONLY; + $modifiers |= \ReflectionClass::IS_READONLY; } return $modifiers; diff --git a/src/PhpParserReflector/ContextualPhpParserReflector.php b/src/PhpParserReflector/ContextualPhpParserReflector.php index f5f27c5..16f12e9 100644 --- a/src/PhpParserReflector/ContextualPhpParserReflector.php +++ b/src/PhpParserReflector/ContextualPhpParserReflector.php @@ -8,6 +8,7 @@ use PhpParser\Node\Expr; use PhpParser\Node\Name; use PhpParser\Node\Stmt; +use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode; use PHPStan\PhpDocParser\Ast\Type\TypeNode; use Typhoon\Reflection\FileResource; use Typhoon\Reflection\Metadata\AttributeMetadata; @@ -15,6 +16,7 @@ use Typhoon\Reflection\Metadata\MethodMetadata; use Typhoon\Reflection\Metadata\ParameterMetadata; use Typhoon\Reflection\Metadata\PropertyMetadata; +use Typhoon\Reflection\Metadata\TraitMethodAlias; use Typhoon\Reflection\Metadata\TypeMetadata; use Typhoon\Reflection\PhpDocParser\ContextualPhpDocTypeReflector; use Typhoon\Reflection\PhpDocParser\PhpDoc; @@ -28,6 +30,8 @@ /** * @internal * @psalm-internal Typhoon\Reflection\PhpParserReflector + * @psalm-import-type TraitMethodAliases from ClassMetadata + * @psalm-import-type TraitMethodPrecedence from ClassMetadata */ final class ContextualPhpParserReflector { @@ -46,7 +50,7 @@ public function __construct( */ public function resolveClassName(Node\Identifier $name): string { - return $this->typeContext->resolveNameAsClass($name->name); + return $this->resolveNameAsClass($name); } /** @@ -57,6 +61,7 @@ public function resolveClassName(Node\Identifier $name): string public function reflectClass(Stmt\ClassLike $node, string $name): ClassMetadata { $phpDoc = $this->parsePhpDoc($node); + [$traitTypes, $traitMethodAliases, $traitMethodPrecedence] = $this->reflectTraits($node); return $this->executeWithTypes(types::atClass($name), $phpDoc, fn(): ClassMetadata => new ClassMetadata( name: $name, @@ -78,7 +83,9 @@ trait: $node instanceof Stmt\Trait_, deprecated: $phpDoc->isDeprecated(), parentType: $this->reflectParentType($node, $phpDoc), interfaceTypes: $this->reflectInterfaceTypes($node, $phpDoc), - traitTypes: $this->reflectTraitTypes($node), + traitTypes: $traitTypes, + traitMethodAliases: $traitMethodAliases, + traitMethodPrecedence: $traitMethodPrecedence, ownProperties: $this->reflectOwnProperties($name, $node), ownMethods: $this->reflectOwnMethods($name, $node), )); @@ -104,7 +111,7 @@ private function reflectAttributes(array $attrGroups, int $target): array foreach ($attrGroups as $attrGroup) { foreach ($attrGroup->attrs as $attr) { - $name = $this->typeContext->resolveNameAsClass($attr->name->toCodeString()); + $name = $this->resolveNameAsClass($attr->name); if (str_starts_with($name, 'JetBrains\PhpStorm\Internal')) { continue; @@ -140,7 +147,7 @@ private function reflectParentType(Stmt\ClassLike $node, PhpDoc $phpDoc): ?Type\ return null; } - $parentClass = $this->typeContext->resolveNameAsClass($node->extends->toCodeString()); + $parentClass = $this->resolveNameAsClass($node->extends); foreach ($phpDoc->extendedTypes() as $phpDocExtendedType) { /** @var Type\NamedObjectType $extendedType */ @@ -198,7 +205,7 @@ private function reflectInterfaceTypes(Stmt\ClassLike $node, PhpDoc $phpDoc): ar continue; } - $class = $this->typeContext->resolveNameAsClass($nameAsString); + $class = $this->resolveNameAsClass($nameAsString); $types[] = $phpDocTypesByClass[$class] ?? types::object($class); } @@ -206,12 +213,12 @@ private function reflectInterfaceTypes(Stmt\ClassLike $node, PhpDoc $phpDoc): ar } /** - * @return list + * @return array{list, TraitMethodAliases, TraitMethodPrecedence} */ - private function reflectTraitTypes(Stmt\ClassLike $node): array + private function reflectTraits(Stmt\ClassLike $node): array { if ($node instanceof Stmt\Interface_) { - return []; + return [[], [], []]; } $phpDocTypesByClass = []; @@ -224,16 +231,45 @@ private function reflectTraitTypes(Stmt\ClassLike $node): array } } - $types = []; + $traitTypes = []; + /** @var TraitMethodAliases */ + $traitMethodAliases = []; + /** @var TraitMethodPrecedence */ + $traitMethodPrecedence = []; foreach ($node->getTraitUses() as $useNode) { + $useTraitClasses = []; + foreach ($useNode->traits as $name) { - $class = $this->typeContext->resolveNameAsClass($name->toCodeString()); - $types[] = $phpDocTypesByClass[$class] ?? types::object($class); + $useTraitClass = $this->resolveNameAsClass($name); + $useTraitClasses[] = $useTraitClass; + $traitTypes[] = $phpDocTypesByClass[$useTraitClass] ?? types::object($useTraitClass); + } + + foreach ($useNode->adaptations as $adaptation) { + if ($adaptation instanceof Stmt\TraitUseAdaptation\Alias) { + if ($adaptation->trait === null) { + $aliasClasses = $useTraitClasses; + } else { + $aliasClasses = [$this->resolveNameAsClass($adaptation->trait)]; + } + + foreach ($aliasClasses as $aliasClass) { + $traitMethodAliases[$aliasClass][$adaptation->method->name][] = new TraitMethodAlias( + visibility: $adaptation->newModifier, + alias: $adaptation->newName?->name, + ); + } + } + + if ($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) { + \assert($adaptation->trait !== null); + $traitMethodPrecedence[$adaptation->method->name] = $this->resolveNameAsClass($adaptation->trait); + } } } - return $types; + return [$traitTypes, $traitMethodAliases, $traitMethodPrecedence]; } /** @@ -460,7 +496,7 @@ private function executeWithTypes(Type\AtClass|Type\AtMethod $declaredAt, PhpDoc foreach ($phpDoc->typeAliasImports() as $typeImport) { $alias = $typeImport->importedAs ?? $typeImport->importedAlias; $types[$alias] = function () use ($class, $typeImport): Type\Type { - $fromClass = $this->typeContext->resolveNameAsClass($typeImport->importedFrom->name); + $fromClass = $this->resolveNameAsClass($typeImport->importedFrom); if ($fromClass === $class) { return $this->typeContext->resolveNameAsType($typeImport->importedAlias); @@ -481,6 +517,17 @@ private function executeWithTypes(Type\AtClass|Type\AtMethod $declaredAt, PhpDoc return $this->typeContext->executeWithTypes($action, $types); } + /** + * @return class-string + */ + private function resolveNameAsClass(string|Node\Identifier|Name|IdentifierTypeNode $name): string + { + return $this->typeContext->resolveNameAsClass(match (true) { + $name instanceof Name => $name->toCodeString(), + default => (string) $name, + }); + } + private function parsePhpDoc(Node $node): PhpDoc { $text = $node->getDocComment()?->getText(); diff --git a/src/PhpParserReflector/EnumReflections.php b/src/PhpParserReflector/EnumReflections.php index dd5d206..1c380a5 100644 --- a/src/PhpParserReflector/EnumReflections.php +++ b/src/PhpParserReflector/EnumReflections.php @@ -25,7 +25,7 @@ public static function name(string $class): PropertyMetadata return new PropertyMetadata( name: 'name', class: $class, - modifiers: \ReflectionProperty::IS_PUBLIC + \ReflectionProperty::IS_READONLY, + modifiers: \ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_READONLY, type: TypeMetadata::create(native: types::string, phpDoc: types::nonEmptyString), ); } @@ -38,7 +38,7 @@ public static function value(string $class, TypeMetadata $type): PropertyMetadat return new PropertyMetadata( name: 'value', class: $class, - modifiers: \ReflectionProperty::IS_PUBLIC + \ReflectionProperty::IS_READONLY, + modifiers: \ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_READONLY, type: $type, ); } @@ -51,7 +51,7 @@ public static function cases(string $class): MethodMetadata return new MethodMetadata( name: 'cases', class: $class, - modifiers: \ReflectionMethod::IS_STATIC + \ReflectionMethod::IS_PUBLIC, + modifiers: \ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC, parameters: [], returnType: TypeMetadata::create(types::array(), types::list(types::object($class))), internal: true, @@ -66,7 +66,7 @@ public static function from(string $class, TypeMetadata $valueType): MethodMetad return new MethodMetadata( name: 'from', class: $class, - modifiers: \ReflectionMethod::IS_STATIC + \ReflectionMethod::IS_PUBLIC, + modifiers: \ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC, parameters: [ new ParameterMetadata( position: 0, @@ -89,7 +89,7 @@ public static function tryFrom(string $class, TypeMetadata $valueType): MethodMe return new MethodMetadata( name: 'tryFrom', class: $class, - modifiers: \ReflectionMethod::IS_STATIC + \ReflectionMethod::IS_PUBLIC, + modifiers: \ReflectionMethod::IS_STATIC | \ReflectionMethod::IS_PUBLIC, parameters: [ new ParameterMetadata( position: 0, diff --git a/src/PhpParserReflector/MethodReflections.php b/src/PhpParserReflector/MethodReflections.php index 9165443..e86808b 100644 --- a/src/PhpParserReflector/MethodReflections.php +++ b/src/PhpParserReflector/MethodReflections.php @@ -46,10 +46,10 @@ public function enterNode(Node $node): ?int public static function modifiers(ClassMethod $node, bool $interface): int { return ($node->isStatic() ? \ReflectionMethod::IS_STATIC : 0) - + ($node->isPublic() ? \ReflectionMethod::IS_PUBLIC : 0) - + ($node->isProtected() ? \ReflectionMethod::IS_PROTECTED : 0) - + ($node->isPrivate() ? \ReflectionMethod::IS_PRIVATE : 0) - + (($interface || $node->isAbstract()) ? \ReflectionMethod::IS_ABSTRACT : 0) - + ($node->isFinal() ? \ReflectionMethod::IS_FINAL : 0); + | ($node->isPublic() ? \ReflectionMethod::IS_PUBLIC : 0) + | ($node->isProtected() ? \ReflectionMethod::IS_PROTECTED : 0) + | ($node->isPrivate() ? \ReflectionMethod::IS_PRIVATE : 0) + | (($interface || $node->isAbstract()) ? \ReflectionMethod::IS_ABSTRACT : 0) + | ($node->isFinal() ? \ReflectionMethod::IS_FINAL : 0); } } diff --git a/src/PhpParserReflector/PropertyReflections.php b/src/PhpParserReflector/PropertyReflections.php index 23c26a9..5096c53 100644 --- a/src/PhpParserReflector/PropertyReflections.php +++ b/src/PhpParserReflector/PropertyReflections.php @@ -21,10 +21,10 @@ private function __construct() {} public static function modifiers(Property $node, bool $classReadOnly): int { return ($node->isStatic() ? \ReflectionProperty::IS_STATIC : 0) - + ($node->isPublic() ? \ReflectionProperty::IS_PUBLIC : 0) - + ($node->isProtected() ? \ReflectionProperty::IS_PROTECTED : 0) - + ($node->isPrivate() ? \ReflectionProperty::IS_PRIVATE : 0) - + ($classReadOnly || $node->isReadonly() ? \ReflectionProperty::IS_READONLY : 0); + | ($node->isPublic() ? \ReflectionProperty::IS_PUBLIC : 0) + | ($node->isProtected() ? \ReflectionProperty::IS_PROTECTED : 0) + | ($node->isPrivate() ? \ReflectionProperty::IS_PRIVATE : 0) + | ($classReadOnly || $node->isReadonly() ? \ReflectionProperty::IS_READONLY : 0); } /** @@ -33,8 +33,8 @@ public static function modifiers(Property $node, bool $classReadOnly): int public static function promotedModifiers(Param $node, bool $classReadOnly): int { return (($node->flags & Class_::MODIFIER_PUBLIC) !== 0 ? \ReflectionProperty::IS_PUBLIC : 0) - + (($node->flags & Class_::MODIFIER_PROTECTED) !== 0 ? \ReflectionProperty::IS_PROTECTED : 0) - + (($node->flags & Class_::MODIFIER_PRIVATE) !== 0 ? \ReflectionProperty::IS_PRIVATE : 0) - + (($classReadOnly || ($node->flags & Class_::MODIFIER_READONLY) !== 0) ? \ReflectionProperty::IS_READONLY : 0); + | (($node->flags & Class_::MODIFIER_PROTECTED) !== 0 ? \ReflectionProperty::IS_PROTECTED : 0) + | (($node->flags & Class_::MODIFIER_PRIVATE) !== 0 ? \ReflectionProperty::IS_PRIVATE : 0) + | (($classReadOnly || ($node->flags & Class_::MODIFIER_READONLY) !== 0) ? \ReflectionProperty::IS_READONLY : 0); } } diff --git a/stubs/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.phpstub b/stubs/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.phpstub new file mode 100644 index 0000000..a33a3e9 --- /dev/null +++ b/stubs/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.phpstub @@ -0,0 +1,13 @@ +