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 @@
+