Skip to content

Commit

Permalink
Fix unused class ignores (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
janedbal authored Jan 17, 2024
1 parent fe882e6 commit 58da2ff
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 5 deletions.
3 changes: 1 addition & 2 deletions src/Analyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,7 @@ public function run(): AnalysisResult
if (!$this->isInClassmap($usedSymbol)) {
if (
!$this->isConstOrFunction($usedSymbol)
&& !$ignoreList->shouldIgnoreUnknownClass($usedSymbol)
&& !$ignoreList->shouldIgnoreError(ErrorType::UNKNOWN_CLASS, $filePath, null)
&& !$ignoreList->shouldIgnoreUnknownClass($usedSymbol, $filePath)
) {
foreach ($lineNumbers as $lineNumber) {
$classmapErrors[$usedSymbol][] = new SymbolUsage($filePath, $lineNumber);
Expand Down
19 changes: 17 additions & 2 deletions src/Config/Ignore/IgnoreList.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,28 @@ public function getUnusedIgnores(): array
return $unused;
}

public function shouldIgnoreUnknownClass(string $class): bool
public function shouldIgnoreUnknownClass(string $class, string $filePath): bool
{
$ignoredGlobally = $this->shouldIgnoreErrorGlobally(ErrorType::UNKNOWN_CLASS);
$ignoredByPath = $this->shouldIgnoreErrorOnPath(ErrorType::UNKNOWN_CLASS, $filePath);
$ignoredByRegex = $this->shouldIgnoreUnknownClassByRegex($class);
$ignoredByBlacklist = $this->shouldIgnoreUnknownClassByBlacklist($class);

return $ignoredGlobally || $ignoredByPath || $ignoredByRegex || $ignoredByBlacklist;
}

private function shouldIgnoreUnknownClassByBlacklist(string $class): bool
{
if (isset($this->ignoredUnknownClasses[$class])) {
$this->ignoredUnknownClasses[$class] = true;
return true;
}

return false;
}

private function shouldIgnoreUnknownClassByRegex(string $class): bool
{
foreach ($this->ignoredUnknownClassesRegexes as $regex => $ignoreUsed) {
$matches = preg_match($regex, $class);

Expand All @@ -156,7 +171,7 @@ public function shouldIgnoreUnknownClass(string $class): bool
}

/**
* @param ErrorType::* $errorType
* @param ErrorType::SHADOW_DEPENDENCY|ErrorType::UNUSED_DEPENDENCY|ErrorType::DEV_DEPENDENCY_IN_PROD|ErrorType::PROD_DEPENDENCY_ONLY_IN_DEV $errorType
*/
public function shouldIgnoreError(string $errorType, ?string $realPath, ?string $packageName): bool
{
Expand Down
48 changes: 47 additions & 1 deletion tests/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use PHPUnit\Framework\TestCase;
use ShipMonk\ComposerDependencyAnalyser\Config\Configuration;
use ShipMonk\ComposerDependencyAnalyser\Config\ErrorType;
use ShipMonk\ComposerDependencyAnalyser\Config\Ignore\UnusedClassIgnore;
use ShipMonk\ComposerDependencyAnalyser\Config\Ignore\UnusedErrorIgnore;
use ShipMonk\ComposerDependencyAnalyser\Exception\InvalidConfigException;
use ShipMonk\ComposerDependencyAnalyser\Exception\InvalidPathException;
Expand All @@ -17,13 +18,18 @@ class ConfigurationTest extends TestCase
public function testShouldIgnore(): void
{
$configuration = new Configuration();
$configuration->ignoreErrors([ErrorType::UNUSED_DEPENDENCY]);
$configuration->ignoreUnknownClasses(['Unknown\Clazz']);
$configuration->ignoreErrors([ErrorType::UNUSED_DEPENDENCY, ErrorType::UNKNOWN_CLASS]);
$configuration->ignoreErrorsOnPath(__DIR__ . '/app/../', [ErrorType::SHADOW_DEPENDENCY]);
$configuration->ignoreErrorsOnPackage('my/package', [ErrorType::PROD_DEPENDENCY_ONLY_IN_DEV]);
$configuration->ignoreErrorsOnPackageAndPath('vendor/package', __DIR__ . '/../tests/app', [ErrorType::DEV_DEPENDENCY_IN_PROD]);

$ignoreList = $configuration->getIgnoreList();

self::assertTrue($ignoreList->shouldIgnoreUnknownClass('Unknown\Clazz', __DIR__));
self::assertTrue($ignoreList->shouldIgnoreUnknownClass('Unknown\Clazz', __DIR__ . '/app'));
self::assertTrue($ignoreList->shouldIgnoreUnknownClass('Any\Clazz', __DIR__));

self::assertTrue($ignoreList->shouldIgnoreError(ErrorType::UNUSED_DEPENDENCY, null, null));
self::assertTrue($ignoreList->shouldIgnoreError(ErrorType::UNUSED_DEPENDENCY, null, 'some/package'));
self::assertTrue($ignoreList->shouldIgnoreError(ErrorType::UNUSED_DEPENDENCY, __DIR__, null));
Expand Down Expand Up @@ -87,6 +93,46 @@ public function testOverlappingUnusedIgnores(): void
], $ignoreList3->getUnusedIgnores());
}

public function testOverlappingUnusedIgnoresOfUnknownClass(): void
{
$configuration = new Configuration();
$configuration->ignoreErrors([ErrorType::UNKNOWN_CLASS]);
$configuration->ignoreErrorsOnPath(__DIR__, [ErrorType::UNKNOWN_CLASS]);
$configuration->ignoreUnknownClasses(['Unknown\Clazz']);
$configuration->ignoreUnknownClassesRegex('~^Unknown~');

$ignoreList1 = $configuration->getIgnoreList();
$ignoreList2 = $configuration->getIgnoreList();
$ignoreList3 = $configuration->getIgnoreList();

$parentDir = realpath(__DIR__ . '/..');
self::assertNotFalse($parentDir);

foreach ([$ignoreList1, $ignoreList2, $ignoreList3] as $ignoreList) {
self::assertEquals([
new UnusedErrorIgnore(ErrorType::UNKNOWN_CLASS, null, null),
new UnusedErrorIgnore(ErrorType::UNKNOWN_CLASS, __DIR__, null),
new UnusedClassIgnore('Unknown\Clazz', false),
new UnusedClassIgnore('~^Unknown~', true),
], $ignoreList->getUnusedIgnores());
}

self::assertTrue($ignoreList1->shouldIgnoreUnknownClass('Unknown\Clazz', __DIR__));
self::assertEquals([], $ignoreList1->getUnusedIgnores());

self::assertTrue($ignoreList2->shouldIgnoreUnknownClass('Unknown\Clazz', $parentDir));
self::assertEquals([
new UnusedErrorIgnore(ErrorType::UNKNOWN_CLASS, __DIR__, null),
], $ignoreList2->getUnusedIgnores());

self::assertTrue($ignoreList3->shouldIgnoreUnknownClass('Another\Clazz', $parentDir));
self::assertEquals([
new UnusedErrorIgnore(ErrorType::UNKNOWN_CLASS, __DIR__, null),
new UnusedClassIgnore('Unknown\Clazz', false),
new UnusedClassIgnore('~^Unknown~', true),
], $ignoreList3->getUnusedIgnores());
}

/**
* @param callable(Configuration): void $configure
* @dataProvider provideInvalidConfigs
Expand Down

0 comments on commit 58da2ff

Please sign in to comment.