Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions lib/Baseline.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

final class Baseline {
/**
* @var array{parameters?: array{ignoreErrors?: list<array{message: string, count: int, path: string}>}}
* @var array{parameters?: array{ignoreErrors?: list<array{message: ?string, count: int, path: ?string, identifier: ?string, rawMessage: ?string}>}}
*/
private $content;

Expand All @@ -32,7 +32,7 @@ static public function forFile(string $filePath):self {
}

$baseline = new self();
$baseline->content = $decoded;
$baseline->content = $decoded; // @phpstan-ignore assign.propertyType
$baseline->filePath = $filePath;
return $baseline;
}
Expand All @@ -41,18 +41,20 @@ static public function forFile(string $filePath):self {
* @return Iterator<BaselineError>
*/
public function getIgnoreErrors(): Iterator {
// @phpstan-ignore function.alreadyNarrowedType
if (!array_key_exists('parameters', $this->content) || !is_array($this->content['parameters'])) {
throw new RuntimeException(sprintf('missing parameters from baseline %s', $this->filePath));
}
$parameters = $this->content['parameters'];

// @phpstan-ignore function.alreadyNarrowedType
if (!array_key_exists('ignoreErrors', $parameters) || !is_array($parameters['ignoreErrors'])) {
throw new RuntimeException(sprintf('missing ignoreErrors from baseline %s', $this->filePath));
}
$ignoreErrors = $parameters['ignoreErrors'];

foreach($ignoreErrors as $error) {
yield new BaselineError($error['count'], $error['message'], $error['path']);
yield new BaselineError($error['count'], $error['message'] ?? null, $error['path'] ?? null, $error['identifier'] ?? null, $error['rawMessage'] ?? null);
}
}

Expand Down
46 changes: 32 additions & 14 deletions lib/BaselineError.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,36 @@ final class BaselineError
{
public int $count;

public string $message;
public ?string $message;

public string $path;
public ?string $rawMessage;

public function __construct(int $count, string $message, string $path)
public ?string $path;

public ?string $identifier;

public function __construct(int $count, ?string $message, ?string $path, ?string $identifier, ?string $rawMessage)
{
$this->count = $count;
$this->message = $message;
$this->rawMessage = $rawMessage;
$this->path = $path;
$this->identifier = $identifier;
}

/**
* Returns the baseline error message, without regex delimiters.
* Note: the message may still contain escaped regex meta characters.
*/
public function unwrapMessage(): string {
if ($this->rawMessage !== null) {
return $this->rawMessage;
}

if ($this->message === null) {
return '';
}

$msg = $this->message;
$msg = str_replace(['\\-', '\\.', '%%'], ['-', '.', '%'], $msg);
$msg = trim($msg, '#^$');
Expand All @@ -33,10 +47,12 @@ public function unwrapMessage(): string {

public function isDeprecationError(): bool
{
return str_contains($this->message, ' deprecated class ')
|| str_contains($this->message, ' deprecated method ')
|| str_contains($this->message, ' deprecated function ')
|| str_contains($this->message, ' deprecated property ');
$message = $this->unwrapMessage();

return str_contains($message, ' deprecated class ')
|| str_contains($message, ' deprecated method ')
|| str_contains($message, ' deprecated function ')
|| str_contains($message, ' deprecated property ');
}

public function isComplexityError(): bool
Expand All @@ -46,24 +62,26 @@ public function isComplexityError(): bool

public function isInvalidPhpDocError(): bool
{
return str_contains($this->message, 'PHPDoc tag ');
return str_contains($this->unwrapMessage(), 'PHPDoc tag ');
}

public function isUnknownTypeError(): bool
{
return preg_match('/Instantiated class .+ not found/', $this->message, $matches) === 1
|| str_contains($this->message, 'on an unknown class')
|| str_contains($this->message, 'has invalid type unknown')
|| str_contains($this->message, 'unknown_type as its type');
$message = $this->unwrapMessage();

return preg_match('/Instantiated class .+ not found/', $message, $matches) === 1
|| str_contains($message, 'on an unknown class')
|| str_contains($message, 'has invalid type unknown')
|| str_contains($message, 'unknown_type as its type');
}

public function isAnonymousVariableError(): bool
{
return str_contains($this->message, 'Anonymous variable');
return str_contains($this->unwrapMessage(), 'Anonymous variable');
}

public function isUnusedSymbolError(): bool
{
return str_ends_with($this->message, 'is never used$#');
return str_ends_with($this->unwrapMessage(), 'is never used');
}
}
24 changes: 19 additions & 5 deletions lib/FilterApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,25 @@ private function printResult(array $errors): void
{
$ignoreErrors = [];
foreach ($errors as $error) {
$ignoreErrors[] = [
'message' => $error->message,
'count' => $error->count,
'path' => $error->path,
];
$ignoreError = [];

if ($error->message !== null) {
$ignoreError['message'] = $error->message;
}

$ignoreError['count'] = $error->count;

if ($error->path !== null) {
$ignoreError['path'] = $error->path;
}
if ($error->identifier !== null) {
$ignoreError['identifier'] = $error->identifier;
}
if ($error->rawMessage !== null) {
$ignoreError['rawMessage'] = $error->rawMessage;
}

$ignoreErrors[] = $ignoreError;

}

Expand Down
6 changes: 3 additions & 3 deletions tests/AnalyzeApplicationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function testTextPrinting():void
$expected = <<<PHP
Analyzing /fixtures/all-in.neon
Date: {$expectedDate}
Overall-Errors: 41
Overall-Errors: 43
Classes-Cognitive-Complexity: 70
Deprecations: 2
Invalid-Phpdocs: 5
Expand All @@ -30,7 +30,7 @@ function testTextPrinting():void
Native-Property-Type-Coverage: 1
Native-Param-Type-Coverage: 27
Native-Return-Type-Coverage: 4
Unused-Symbols: 3
Unused-Symbols: 4

PHP;

Expand All @@ -50,7 +50,7 @@ function testJsonPrinting():void

$expectedDate = date(ResultPrinter::DATE_FORMAT);
$expected = <<<PHP
[{"\/fixtures\/all-in.neon":{"Date":"{$expectedDate}","Overall-Errors":41,"Classes-Cognitive-Complexity":70,"Deprecations":2,"Invalid-Phpdocs":5,"Unknown-Types":1,"Anonymous-Variables":4,"Native-Property-Type-Coverage":1,"Native-Param-Type-Coverage":27,"Native-Return-Type-Coverage":4,"Unused-Symbols":3}}]
[{"\/fixtures\/all-in.neon":{"Date":"{$expectedDate}","Overall-Errors":43,"Classes-Cognitive-Complexity":70,"Deprecations":2,"Invalid-Phpdocs":5,"Unknown-Types":1,"Anonymous-Variables":4,"Native-Property-Type-Coverage":1,"Native-Param-Type-Coverage":27,"Native-Return-Type-Coverage":4,"Unused-Symbols":4}}]
PHP;

$this->assertSame($expected, $rendered);
Expand Down
4 changes: 2 additions & 2 deletions tests/BaselineAnalyzerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ function testNeverUsed():void

private function allInAssertions(AnalyzerResult $result): void
{
$this->assertSame(41, $result->overallErrors);
$this->assertSame(43, $result->overallErrors);
$this->assertSame(70, $result->classesComplexity);
$this->assertSame(2, $result->deprecations);
$this->assertSame(5, $result->invalidPhpdocs);
Expand All @@ -214,7 +214,7 @@ private function allInAssertions(AnalyzerResult $result): void
$this->assertSame(1, $result->propertyTypeCoverage);
$this->assertSame(27, $result->paramTypeCoverage);
$this->assertSame(4, $result->returnTypeCoverage);
$this->assertSame(3, $result->unusedSymbols);
$this->assertSame(4, $result->unusedSymbols);
}

}
10 changes: 10 additions & 0 deletions tests/FilterApplicationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ function testMultiInclude():void
count: 1
path: scripts/portal/SearchExport.php

-
count: 1
path: scripts/portal/SearchExport.php
rawMessage: Public constant "SearchExport::OTHER_PATH" is never used

PHP;

$this->assertSame($expected, $rendered);
Expand Down Expand Up @@ -102,6 +107,11 @@ function testUnusedTypes():void
count: 1
path: scripts/portal/SearchExport.php

-
count: 1
path: scripts/portal/SearchExport.php
rawMessage: Public constant "SearchExport::OTHER_PATH" is never used

PHP;

$this->assertSame($expected, $rendered);
Expand Down
11 changes: 10 additions & 1 deletion tests/fixtures/all-in.neon
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,13 @@ parameters:
-
message: "#^Public constant \"SearchExport\\:\\:TMP_PATH\" is never used$#"
count: 1
path: scripts/portal/SearchExport.php
path: scripts/portal/SearchExport.php

-
rawMessage: "Public constant \"SearchExport::OTHER_PATH\" is never used"
count: 1
path: scripts/portal/SearchExport.php

-
identifier: myident.test
count: 1
9 changes: 9 additions & 0 deletions tests/fixtures/all-in.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,14 @@
'count' => 1,
'path' => 'scripts/portal/SearchExport.php',
];
$ignoreErrors[] = [
'rawMessage' => 'Public constant "SearchExport::TMP_PATH" is never used',
'count' => 1,
'path' => 'scripts/portal/SearchExport.php',
];
$ignoreErrors[] = [
'identifier' => 'myident.test',
'count' => 1,
];

return ['parameters' => ['ignoreErrors' => $ignoreErrors]];