Skip to content

Commit

Permalink
Test anonymous class-related calls and usages (#277)
Browse files Browse the repository at this point in the history
The things were already detected and now there's a test for them as well. Anonymous classes are displayed as `class@anonymous` similar to what `get_class(new class {})` would return.

- Test disallowed constants on anonymous child classes
- Test disallowed method calls on anonymous classes
- Test anonymous class inheriting from a disallowed class

Ref #275
  • Loading branch information
spaze authored Dec 6, 2024
2 parents 20fd804 + 3b45f4d commit 02d0741
Show file tree
Hide file tree
Showing 14 changed files with 130 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/RuleErrors/DisallowedMethodRuleErrors.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ public function get($class, CallLike $node, Scope $scope, array $disallowedCalls
if ($calledOnType->canCallMethods()->yes() && $calledOnType->hasMethod($node->name->name)->yes()) {
$method = $calledOnType->getMethod($node->name->name, $scope);
$declaringClass = $method->getDeclaringClass();
$classNames = $calledOnType->getObjectClassNames();
$classes = $calledOnType->getObjectClassReflections();
$classNames = array_map(fn($class): string => $class->isAnonymous() ? 'class@anonymous' : $class->getName(), $classes);
if (count($classNames) === 0) {
$calledAs = null;
} else {
Expand Down
4 changes: 3 additions & 1 deletion src/Usages/ClassConstantUsages.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ private function getConstantRuleErrors(Scope $scope, string $constant, Type $typ
}

$usedOnType = $type->getObjectTypeOrClassStringObjectType();
$displayName = $usedOnType->getObjectClassNames() ? $this->getFullyQualified($usedOnType->getObjectClassNames(), $constant) : null;
$classes = $usedOnType->getObjectClassReflections();
$classNames = array_map(fn($class): string => $class->isAnonymous() ? 'class@anonymous' : $class->getName(), $classes);
$displayName = $classNames ? $this->getFullyQualified($classNames, $constant) : null;
if ($usedOnType->getConstantStrings()) {
$classNames = array_map(
function (ConstantStringType $constantString): string {
Expand Down
8 changes: 8 additions & 0 deletions tests/Calls/MethodCallsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ public function testRule(): void
'Calling Interfaces\BaseInterface::x() (as Interfaces\Implementation::x()) is forbidden, BaseInterface::x*() methods are dangerous. [Interfaces\BaseInterface::x() matches Interfaces\BaseInterface::x*()]',
74,
],
[
'Calling Interfaces\BaseInterface::x() (as class@anonymous::x()) is forbidden, BaseInterface::x*() methods are dangerous. [Interfaces\BaseInterface::x() matches Interfaces\BaseInterface::x*()]',
87,
],
[
'Calling Inheritance\Base::x() (as class@anonymous::x()) is forbidden, Base::x*() methods are dangerous. [Inheritance\Base::x() matches Inheritance\Base::x*()]',
91,
],
]);
$this->analyse([__DIR__ . '/../src/disallowed-allow/methodCalls.php'], [
[
Expand Down
8 changes: 8 additions & 0 deletions tests/Calls/StaticCallsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ public function testRule(): void
'Calling Interfaces\BaseInterface::y() (as Interfaces\Implementation::y()) is forbidden, method BaseInterface::y() is dangerous. [Interfaces\BaseInterface::y() matches Interfaces\BaseInterface::y*()]',
40,
],
[
'Calling Interfaces\BaseInterface::y() (as class@anonymous::y()) is forbidden, method BaseInterface::y() is dangerous. [Interfaces\BaseInterface::y() matches Interfaces\BaseInterface::y*()]',
53,
],
[
'Calling Inheritance\Base::woofer() (as class@anonymous::woofer()) is forbidden, method Base::woofer() is dangerous. [Inheritance\Base::woofer() matches Inheritance\Base::w*f*r()]',
57,
],
]);
$this->analyse([__DIR__ . '/../src/disallowed-allow/staticCalls.php'], [
[
Expand Down
4 changes: 4 additions & 0 deletions tests/Usages/ClassConstantUsagesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ public function testRule(): void
'Using PhpOption\Option::NAME (as PhpOption\None::NAME) is forbidden, no PhpOption.',
37,
],
[
'Using Inheritance\Base::BELONG (as class@anonymous::BELONG) is forbidden, belong to us.',
44,
],
]);
$this->analyse([__DIR__ . '/../src/disallowed-allow/constantUsages.php'], []);
}
Expand Down
4 changes: 4 additions & 0 deletions tests/Usages/NamespaceUsagesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ public function testRule(): void
'Class ZipArchive is forbidden, use clippy instead of zippy.',
50,
],
[
'Namespace Inheritance\Base is forbidden, no inheritance sub base.',
56,
],
]);
$this->analyse([__DIR__ . '/../src/disallowed-allow/namespaceUsages.php'], []);
}
Expand Down
4 changes: 4 additions & 0 deletions tests/src/disallowed-allow/constantUsages.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@

// not disallowed by path
PHP_EOL;

// allowed by path
$foo = new class extends Base {};
$foo::BELONG;
17 changes: 17 additions & 0 deletions tests/src/disallowed-allow/methodCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,20 @@

// allowed by path
(new Interfaces\Implementation())->x();
$foo = new class implements Interfaces\BaseInterface {

public function x(): void
{
}


public static function y(): void
{
}

};
$foo->x();

// allowed by path
$foo = new class extends Inheritance\Base {};
$foo->x();
19 changes: 19 additions & 0 deletions tests/src/disallowed-allow/namespaceUsages.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Traits\TestTrait;
use Waldo\Foo\Bar;
use Waldo\Quux\blade;
use ZipArchive;

class Service extends Base implements SomeInterface
{
Expand Down Expand Up @@ -37,4 +38,22 @@ public function callConstant()
return Bar::NAME;
}


public function callNew()
{
return new Bar();
}


public function disallowedByPath()
{
return ZipArchive::EM_TRAD_PKWARE;
}


public function anonymousClass()
{
return new class extends Base {};
}

}
17 changes: 17 additions & 0 deletions tests/src/disallowed-allow/staticCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,20 @@

// interface method allowed by path
Interfaces\Implementation::y();
$foo = new class implements Interfaces\BaseInterface {

public function x(): void
{
}


public static function y(): void
{
}

};
$foo::y();

// allowed by path
$foo = new class extends Inheritance\Base {};
$foo::woofer();
4 changes: 4 additions & 0 deletions tests/src/disallowed/constantUsages.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,7 @@

// disallowed by path
PHP_EOL;

// disallowed
$foo = new class extends Base {};
$foo::BELONG;
17 changes: 17 additions & 0 deletions tests/src/disallowed/methodCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,20 @@

// disallowed interface method
(new Interfaces\Implementation())->x();
$foo = new class implements Interfaces\BaseInterface {

public function x(): void
{
}


public static function y(): void
{
}

};
$foo->x();

// disallowed parent method
$foo = new class extends Inheritance\Base {};
$foo->x();
6 changes: 6 additions & 0 deletions tests/src/disallowed/namespaceUsages.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,10 @@ public function disallowedByPath()
return ZipArchive::EM_TRAD_PKWARE;
}


public function anonymousClass()
{
return new class extends Base {};
}

}
17 changes: 17 additions & 0 deletions tests/src/disallowed/staticCalls.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,20 @@

// disallowed on interface
Interfaces\Implementation::y();
$foo = new class implements Interfaces\BaseInterface {

public function x(): void
{
}


public static function y(): void
{
}

};
$foo::y();

// disallowed parent method
$foo = new class extends Inheritance\Base {};
$foo::woofer();

0 comments on commit 02d0741

Please sign in to comment.