Skip to content

Commit

Permalink
MixedType returns valid properties, methods and constants
Browse files Browse the repository at this point in the history
  • Loading branch information
ondrejmirtes committed Apr 27, 2018
1 parent 8085989 commit eb8947d
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 2 deletions.
73 changes: 73 additions & 0 deletions src/Reflection/Dummy/DummyMethodReflection.php
@@ -0,0 +1,73 @@
<?php declare(strict_types = 1);

namespace PHPStan\Reflection\Dummy;

use PHPStan\Broker\Broker;
use PHPStan\Reflection\ClassMemberReflection;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;

class DummyMethodReflection implements MethodReflection
{

/** @var string */
private $name;

public function __construct(string $name)
{
$this->name = $name;
}

public function getDeclaringClass(): ClassReflection
{
$broker = Broker::getInstance();

return $broker->getClass(\stdClass::class);
}

public function isStatic(): bool
{
return false;
}

public function isPrivate(): bool
{
return false;
}

public function isPublic(): bool
{
return true;
}

public function getName(): string
{
return $this->name;
}

public function getPrototype(): ClassMemberReflection
{
return $this;
}

/**
* @return \PHPStan\Reflection\ParameterReflection[]
*/
public function getParameters(): array
{
return [];
}

public function isVariadic(): bool
{
return true;
}

public function getReturnType(): Type
{
return new MixedType();
}

}
51 changes: 51 additions & 0 deletions src/Reflection/Dummy/DummyPropertyReflection.php
@@ -0,0 +1,51 @@
<?php declare(strict_types = 1);

namespace PHPStan\Reflection\Dummy;

use PHPStan\Broker\Broker;
use PHPStan\Reflection\ClassReflection;
use PHPStan\Reflection\PropertyReflection;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;

class DummyPropertyReflection implements PropertyReflection
{

public function getDeclaringClass(): ClassReflection
{
$broker = Broker::getInstance();

return $broker->getClass(\stdClass::class);
}

public function isStatic(): bool
{
return false;
}

public function isPrivate(): bool
{
return false;
}

public function isPublic(): bool
{
return true;
}

public function getType(): Type
{
return new MixedType();
}

public function isReadable(): bool
{
return true;
}

public function isWritable(): bool
{
return true;
}

}
58 changes: 56 additions & 2 deletions src/Type/MixedType.php
Expand Up @@ -2,10 +2,15 @@

namespace PHPStan\Type;

use PHPStan\Analyser\Scope;
use PHPStan\Reflection\ClassConstantReflection;
use PHPStan\Reflection\Dummy\DummyMethodReflection;
use PHPStan\Reflection\Dummy\DummyPropertyReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\PropertyReflection;
use PHPStan\TrinaryLogic;
use PHPStan\Type\Traits\MaybeCallableTypeTrait;
use PHPStan\Type\Traits\MaybeIterableTypeTrait;
use PHPStan\Type\Traits\MaybeObjectTypeTrait;
use PHPStan\Type\Traits\MaybeOffsetAccessibleTypeTrait;
use PHPStan\Type\Traits\UndecidedBooleanTypeTrait;

Expand All @@ -14,7 +19,6 @@ class MixedType implements CompoundType

use MaybeCallableTypeTrait;
use MaybeIterableTypeTrait;
use MaybeObjectTypeTrait;
use MaybeOffsetAccessibleTypeTrait;
use UndecidedBooleanTypeTrait;

Expand Down Expand Up @@ -53,6 +57,56 @@ public function isSubTypeOf(Type $otherType): TrinaryLogic
return TrinaryLogic::createMaybe();
}

public function canAccessProperties(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function hasProperty(string $propertyName): bool
{
return true;
}

public function getProperty(string $propertyName, Scope $scope): PropertyReflection
{
return new DummyPropertyReflection();
}

public function canCallMethods(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function hasMethod(string $methodName): bool
{
return true;
}

public function getMethod(string $methodName, Scope $scope): MethodReflection
{
return new DummyMethodReflection($methodName);
}

public function canAccessConstants(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function hasConstant(string $constantName): bool
{
return false;
}

public function getConstant(string $constantName): ClassConstantReflection
{
throw new \PHPStan\ShouldNotHappenException();
}

public function isCloneable(): TrinaryLogic
{
return TrinaryLogic::createYes();
}

public function describe(VerbosityLevel $level): string
{
return 'mixed';
Expand Down
43 changes: 43 additions & 0 deletions tests/PHPStan/Analyser/NodeScopeResolverTest.php
Expand Up @@ -5602,6 +5602,49 @@ public function testArrayKeysInBranches(
);
}

public function dataElementsOnMixed(): array
{
return [
[
'mixed',
'$mixed->foo',
],
[
'mixed',
'$mixed->foo->bar',
],
[
'mixed',
'$mixed->foo()',
],
[
'mixed',
'$mixed->foo()->bar()',
],
[
'mixed',
'$mixed::TEST_CONSTANT',
],
];
}

/**
* @dataProvider dataElementsOnMixed
* @param string $description
* @param string $expression
*/
public function testElementsOnMixed(
string $description,
string $expression
): void
{
$this->assertTypes(
__DIR__ . '/data/mixed-elements.php',
$description,
$expression
);
}

private function assertTypes(
string $file,
string $description,
Expand Down
7 changes: 7 additions & 0 deletions tests/PHPStan/Analyser/data/mixed-elements.php
@@ -0,0 +1,7 @@
<?php

namespace MixedElements;

function ($mixed) {
die;
};
6 changes: 6 additions & 0 deletions tests/PHPStan/Rules/Operators/data/invalid-binary.php
Expand Up @@ -98,3 +98,9 @@ function ()
$result['allowedRoomCounter'] += $x;
}
};

function () {
$o = new stdClass;
$o->user ?? '';
$o->user->name ?? '';
};

0 comments on commit eb8947d

Please sign in to comment.