Skip to content

Commit

Permalink
Merge pull request #27 from stevebauman/anonymous-class-fix
Browse files Browse the repository at this point in the history
Fix parsing classes containing anonymous classes
  • Loading branch information
freekmurze authored Jan 13, 2025
2 parents 4f3db2b + e39b0e4 commit 42d1612
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 2 deletions.
28 changes: 26 additions & 2 deletions src/TokenParsers/FileTokenParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Spatie\StructureDiscoverer\Collections\TokenCollection;
use Spatie\StructureDiscoverer\Collections\UsageCollection;
use Spatie\StructureDiscoverer\Data\DiscoveredStructure;
use Spatie\StructureDiscoverer\Data\Token;
use Spatie\StructureDiscoverer\Enums\DiscoveredStructureType;
use Spatie\StructureDiscoverer\Exceptions\CouldNotParseFile;
use Throwable;
Expand Down Expand Up @@ -40,7 +39,6 @@ public function execute(

$index = 0;


try {
do {
if ($tokens->get($index)->is(T_NAMESPACE)) {
Expand Down Expand Up @@ -74,6 +72,15 @@ public function execute(
continue;
}

if (
$type === DiscoveredStructureType::ClassDefinition
&& $this->isAnonymousClass($tokens, $index)
) {
$index++;

continue;
}

$discoveredStructure = $this->discoveredDataResolver->execute(
$index + 1,
$tokens,
Expand All @@ -97,4 +104,21 @@ public function execute(

return $found;
}

private function isAnonymousClass(TokenCollection $tokens, int $index): bool
{
$prevIndex = $index - 1;

// find the previous non-whitespace token
while ($prevIndex >= 0 && $tokens->get($prevIndex)->is(T_WHITESPACE)) {
$prevIndex--;
}

// if the token before T_CLASS is T_NEW, it's an anonymous class
if ($prevIndex >= 0 && $tokens->get($prevIndex)->is(T_NEW)) {
return true;
}

return false;
}
}
15 changes: 15 additions & 0 deletions tests/Fakes/FakeWithAnonymousClass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace Spatie\StructureDiscoverer\Tests\Fakes;

class FakeWithAnonymousClass
{
public function foo(): object
{
return new class() {
public function bar(): string {
return 'baz';
}
};
}
}
11 changes: 11 additions & 0 deletions tests/Fakes/FakeWithMultipleClasses.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace Spatie\StructureDiscoverer\Tests\Fakes;

class FakeWithMultipleClasses
{
}

class FakeWithMultipleClassesSub
{
}
4 changes: 4 additions & 0 deletions tests/ReflectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
use Spatie\StructureDiscoverer\Tests\Fakes\FakeSubChildClass;
use Spatie\StructureDiscoverer\Tests\Fakes\FakeSubChildInterface;
use Spatie\StructureDiscoverer\Tests\Fakes\FakeTrait;
use Spatie\StructureDiscoverer\Tests\Fakes\FakeWithAnonymousClass;
use Spatie\StructureDiscoverer\Tests\Fakes\FakeWithMultipleClasses;
use Spatie\StructureDiscoverer\Tests\Fakes\Nested\FakeNestedClass;
use Spatie\StructureDiscoverer\Tests\Fakes\Nested\FakeNestedInterface;
use Spatie\StructureDiscoverer\Tests\Fakes\OtherNested\FakeOtherNestedClass;
Expand Down Expand Up @@ -116,7 +118,9 @@
FakeOtherNestedClass::class,
FakeSubChildInterface::class,
FakeSubChildClass::class,
FakeWithMultipleClasses::class,
FakeClassDepender::class,
FakeInterfaceDepender::class,
FakeWithAnonymousClass::class,
]);
});
27 changes: 27 additions & 0 deletions tests/StructureDiscovererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
use Spatie\StructureDiscoverer\Tests\Fakes\Nested\FakeNestedInterface;
use Spatie\StructureDiscoverer\Tests\Fakes\OtherNested\FakeOtherNestedClass;
use Spatie\StructureDiscoverer\Tests\Stubs\StubStructureScout;
use Spatie\StructureDiscoverer\Tests\Fakes\FakeWithAnonymousClass;
use Spatie\StructureDiscoverer\Tests\Fakes\FakeWithMultipleClasses;
use Spatie\StructureDiscoverer\Tests\Fakes\FakeWithMultipleClassesSub;

beforeEach(function () {
StaticDiscoverCacheDriver::clear();
Expand All @@ -55,6 +58,9 @@
FakeSubChildClass::class,
FakeClassDepender::class,
FakeInterfaceDepender::class,
FakeWithAnonymousClass::class,
FakeWithMultipleClasses::class,
FakeWithMultipleClassesSub::class,
]);
});

Expand All @@ -77,6 +83,9 @@
FakeOtherNestedClass::class,
FakeSubChildClass::class,
FakeClassDepender::class,
FakeWithAnonymousClass::class,
FakeWithMultipleClasses::class,
FakeWithMultipleClassesSub::class,
],
],
'interfaces' => [
Expand Down Expand Up @@ -310,6 +319,9 @@ public function satisfies(DiscoveredStructure $discoveredData): bool
FakeChildClass::class,
FakeRootClass::class,
FakeSubChildClass::class,
FakeWithAnonymousClass::class,
FakeWithMultipleClasses::class,
FakeWithMultipleClassesSub::class,
FakeNestedClass::class,
FakeOtherNestedClass::class,
],
Expand All @@ -331,6 +343,9 @@ public function satisfies(DiscoveredStructure $discoveredData): bool
[
FakeOtherNestedClass::class,
FakeNestedClass::class,
FakeWithMultipleClasses::class,
FakeWithMultipleClassesSub::class,
FakeWithAnonymousClass::class,
FakeSubChildClass::class,
FakeRootClass::class,
FakeChildClass::class,
Expand Down Expand Up @@ -507,3 +522,15 @@ public function satisfies(DiscoveredStructure $discoveredData): bool
FakeIntEnum::class,
]);
});

it('can parse anonymous classes', function () {
$found = Discover::in(__DIR__.'/Fakes')->get();

expect($found)->not->toContain("Spatie\StructureDiscoverer\Tests\Fakes\(");
});

it('can parse multiple nested classes', function () {
$found = Discover::in(__DIR__.'/Fakes')->get();

expect($found)->toContain("Spatie\StructureDiscoverer\Tests\Fakes\FakeWithMultipleClassesSub");
});

0 comments on commit 42d1612

Please sign in to comment.