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
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,24 @@
use Psr\Log\LoggerInterface;
use RuntimeException;
use SebastianBergmann\Diff\Parser;
use ArrayIterator;

/**
* @phpstan-type PhpcsResult object{
* @phpstan-type PhpcsResult array{
* files: array<string, PhpcsFileResult>,
* totals: object{
* totals: array{
* errors: int<0, max>,
* warnings: int<0, max>,
* fixable: int<0, max>
* }
* }
*
* @phpstan-type PhpcsFileResult object{
* @phpstan-type PhpcsFileResult array{
* errors: int<0, max>,
* warnings: int<0, max>,
* messages: PhpcsRule[]
* }
*
* @phpstan-type PhpcsRule object{
* @phpstan-type PhpcsRule array{
* message: string,
* source: string,
* severity: int,
Expand Down Expand Up @@ -70,9 +69,7 @@ public function provideDiagnostics(TextDocumentItem $textDocument, CancellationT
}

return call(function () use ($textDocument, $cancel) {
$diagnostics = yield $this->findDiagnostics($textDocument, $cancel);

return $diagnostics ?: [];
return yield $this->findDiagnostics($textDocument, $cancel);
});
}

Expand All @@ -86,28 +83,26 @@ public function provideActionsFor(TextDocumentItem $textDocument, Range $range,

$diagnostics = yield $this->findDiagnostics($textDocument, $cancel);

if ($diagnostics === false) {
if ($diagnostics === []) {
return [];
}

$title = 'Format with PHP Code Sniffer';

$actions = [
CodeAction::fromArray([
'title' => $title,
'kind' => 'source.fixAll.phpactor.phpCodeSniffer',
'diagnostics' => $diagnostics,
'command' => new Command(
$title,
'php_code_sniffer.fix',
[
$textDocument->uri
]
)
])
return [
CodeAction::fromArray([
'title' => $title,
'kind' => 'source.fixAll.phpactor.phpCodeSniffer',
'diagnostics' => $diagnostics,
'command' => new Command(
$title,
'php_code_sniffer.fix',
[
$textDocument->uri
]
)
])
];

return $actions;
});
}

Expand All @@ -132,68 +127,49 @@ public function describe(): string
private function hasFixableDiagnostics(TextDocumentItem $textDocument): Promise
{
return call(function () use ($textDocument) {
/** @var string $outputJson */
$outputJson = yield $this->phpCodeSniffer->diagnose($textDocument, [ '-m' ]);

try {
/** @var PhpcsResult $output */
$output = json_decode($outputJson, flags: JSON_THROW_ON_ERROR);
} catch (JsonException $error) {
throw new RuntimeException(sprintf(
'Could not decode JSON: %s',
$outputJson
));
}

return $output->totals->fixable > 0;
return $this->parseOutput($outputJson)['totals']['fixable'] > 0;
});
}

/**
* @return Promise<Diagnostic[]|false> False when there are no diagnostics available for file, array othwerwise
* Array containing diagnostics to show
* @return Promise<Diagnostic[]>
*/
private function findDiagnostics(TextDocumentItem $textDocument, CancellationToken $cancel): Promise
{
return call(function () use ($textDocument) {
/** @var string $outputJson */
$outputJson = yield $this->phpCodeSniffer->diagnose($textDocument);

try {
/** @var PhpcsResult $output */
$output = json_decode($outputJson, flags: JSON_THROW_ON_ERROR);
} catch (JsonException $error) {
throw new RuntimeException(sprintf(
'Could not decode JSON: %s',
$outputJson
));
}

if (empty($output->files)) {
return false;
$files = $this->parseOutput($outputJson)['files'];
if (empty($files)) {
return [];
}

// phpcs return array indexed by file name,
// but we only deal with one file, thus don't care about
// actual key
$files = new ArrayIterator($output->files);
$rules = $files->current()->messages;
$rules = current($files)['messages'];

$diagnostics = [];

$diffParser = new Parser();

foreach ($rules as $rule) {
// We treat non-fixable rules as 1 char range.
if ($rule->fixable === false) {
$lineNo = $rule->line - 1;
if ($rule['fixable'] === false) {
$lineNo = $rule['line'] - 1;
$range = new Range(
new Position($lineNo, $rule->column),
new Position($lineNo, $rule->column + 1)
new Position($lineNo, $rule['column']),
new Position($lineNo, $rule['column'] + 1)
);
$diagnostics[] = $this->createRuleDiagnostics($rule, $range);
continue;
}

$sniffWithoutSuffix = $this->getSniffGroup($rule->source);
$sniffWithoutSuffix = $this->getSniffGroup($rule['source']);
if ($sniffWithoutSuffix === null) {
continue;
}
Expand Down Expand Up @@ -224,14 +200,14 @@ private function findDiagnostics(TextDocumentItem $textDocument, CancellationTok
/**
* @param PhpcsRule $rule
*/
private function createRuleDiagnostics(object $rule, Range $range): Diagnostic
private function createRuleDiagnostics(array $rule, Range $range): Diagnostic
{
return new Diagnostic(
message: $rule->message,
message: $rule['message'],
range: $range,
severity: DiagnosticSeverity::WARNING,
source: $this->name(),
code: $rule->source
code: $rule['source']
);
}

Expand All @@ -251,4 +227,17 @@ private function getSniffGroup(string $source): ?string
$sniffWithoutSuffix = $matches[1];
return $sniffWithoutSuffix;
}

/** @return PhpcsResult */
private function parseOutput(string $rawOutput): array
{
try {
/** @var PhpcsResult $output */
$output = json_decode($rawOutput, associative: true, flags: JSON_THROW_ON_ERROR);
} catch (JsonException $error) {
throw new RuntimeException(sprintf('Could not decode JSON: %s', $rawOutput));
}

return $output;
}
}
66 changes: 0 additions & 66 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3438,18 +3438,6 @@ parameters:
count: 1
path: lib/Extension/Behat/Tests/Integration/Behat/BehatConfigTest.php

-
message: '#^Cannot call method completorForType\(\) on mixed\.$#'
identifier: method.nonObject
count: 1
path: lib/Extension/Behat/Tests/Integration/Completor/FeatureStepCompletorTest.php

-
message: '#^Method Phpactor\\Extension\\Behat\\Tests\\Integration\\Completor\\FeatureStepCompletorTest\:\:completor\(\) should return Phpactor\\Completion\\Core\\Completor but returns mixed\.$#'
identifier: return.type
count: 1
path: lib/Extension/Behat/Tests/Integration/Completor/FeatureStepCompletorTest.php

-
message: '#^Method Phpactor\\Extension\\ClassMover\\Application\\ClassCopy\:\:copy\(\) has no return type specified\.$#'
identifier: missingType.return
Expand Down Expand Up @@ -6246,36 +6234,12 @@ parameters:
count: 1
path: lib/Extension/Completion/Tests/Unit/CompletionExtensionTest.php

-
message: '#^Cannot call method complete\(\) on mixed\.$#'
identifier: method.nonObject
count: 1
path: lib/Extension/Completion/Tests/Unit/CompletionExtensionTest.php

-
message: '#^Cannot call method completorForType\(\) on mixed\.$#'
identifier: method.nonObject
count: 1
path: lib/Extension/Completion/Tests/Unit/CompletionExtensionTest.php

-
message: '#^Cannot call method name\(\) on mixed\.$#'
identifier: method.nonObject
count: 1
path: lib/Extension/Completion/Tests/Unit/CompletionExtensionTest.php

-
message: '#^Cannot call method signatureHelp\(\) on mixed\.$#'
identifier: method.nonObject
count: 1
path: lib/Extension/Completion/Tests/Unit/CompletionExtensionTest.php

-
message: '#^Parameter \#1 \$iterator of function iterator_to_array expects Traversable, mixed given\.$#'
identifier: argument.type
count: 1
path: lib/Extension/Completion/Tests/Unit/CompletionExtensionTest.php

-
message: '#^Property Phpactor\\Extension\\Completion\\Tests\\Unit\\CompletionExtensionTest\:\:\$completor1 with generic class Prophecy\\Prophecy\\ObjectProphecy does not specify its types\: T$#'
identifier: missingType.generics
Expand Down Expand Up @@ -6336,12 +6300,6 @@ parameters:
count: 1
path: lib/Extension/CompletionExtra/CompletionExtraExtension.php

-
message: '#^Parameter \#1 \$registry of class Phpactor\\Extension\\CompletionExtra\\Application\\Complete constructor expects Phpactor\\Completion\\Core\\TypedCompletorRegistry, mixed given\.$#'
identifier: argument.type
count: 1
path: lib/Extension/CompletionExtra/CompletionExtraExtension.php

-
message: '#^Parameter \#2 \$dumperRegistry of class Phpactor\\Extension\\CompletionExtra\\Command\\CompleteCommand constructor expects Phpactor\\Extension\\Core\\Console\\Dumper\\DumperRegistry, mixed given\.$#'
identifier: argument.type
Expand Down Expand Up @@ -6384,12 +6342,6 @@ parameters:
count: 1
path: lib/Extension/CompletionExtra/Rpc/HoverHandler.php

-
message: '#^Parameter \#1 \$registry of class Phpactor\\Extension\\CompletionRpc\\Handler\\CompleteHandler constructor expects Phpactor\\Completion\\Core\\TypedCompletorRegistry, mixed given\.$#'
identifier: argument.type
count: 1
path: lib/Extension/CompletionRpc/CompletionRpcExtension.php

-
message: '#^Parameter \#1 \$language of method Phpactor\\TextDocument\\TextDocumentBuilder\:\:language\(\) expects string, mixed given\.$#'
identifier: argument.type
Expand Down Expand Up @@ -6642,12 +6594,6 @@ parameters:
count: 1
path: lib/Extension/CompletionWorse/Tests/Unit/CompletionWorseExtensionTest.php

-
message: '#^Cannot call method completorForType\(\) on mixed\.$#'
identifier: method.nonObject
count: 1
path: lib/Extension/CompletionWorse/Tests/Unit/CompletionWorseExtensionTest.php

-
message: '#^Instanceof between Phpactor\\Completion\\Core\\Completor and Phpactor\\Completion\\Core\\Completor will always evaluate to true\.$#'
identifier: instanceof.alwaysTrue
Expand Down Expand Up @@ -10878,24 +10824,12 @@ parameters:
count: 1
path: lib/Extension/PhpCodeSniffer/PhpCodeSnifferExtension.php

-
message: '#^Parameter \#1 \$json of function json_decode expects string, mixed given\.$#'
identifier: argument.type
count: 2
path: lib/Extension/PhpCodeSniffer/Provider/PhpCodeSnifferDiagnosticsProvider.php

-
message: '#^Parameter \#1 \$string of method SebastianBergmann\\Diff\\Parser\:\:parse\(\) expects string, mixed given\.$#'
identifier: argument.type
count: 1
path: lib/Extension/PhpCodeSniffer/Provider/PhpCodeSnifferDiagnosticsProvider.php

-
message: '#^Parameter \#2 \.\.\.\$values of function sprintf expects bool\|float\|int\|string\|null, mixed given\.$#'
identifier: argument.type
count: 2
path: lib/Extension/PhpCodeSniffer/Provider/PhpCodeSnifferDiagnosticsProvider.php

-
message: '#^Cannot call method getStdout\(\) on mixed\.$#'
identifier: method.nonObject
Expand Down