|
3 | 3 | namespace PHPStan\Command;
|
4 | 4 |
|
5 | 5 | use OndraM\CiDetector\CiDetector;
|
| 6 | +use PHPStan\Analyser\InternalError; |
6 | 7 | use PHPStan\Command\ErrorFormatter\BaselineNeonErrorFormatter;
|
7 | 8 | use PHPStan\Command\ErrorFormatter\BaselinePhpErrorFormatter;
|
8 | 9 | use PHPStan\Command\ErrorFormatter\ErrorFormatter;
|
@@ -328,13 +329,108 @@ protected function execute(InputInterface $input, OutputInterface $output): int
|
328 | 329 | throw $t;
|
329 | 330 | }
|
330 | 331 |
|
| 332 | + $internalErrors = []; |
| 333 | + foreach ($analysisResult->getInternalErrorObjects() as $internalError) { |
| 334 | + $internalErrors[$internalError->getMessage()] = new InternalError( |
| 335 | + sprintf('Internal error: %s', $internalError->getMessage()), |
| 336 | + $internalError->getContextDescription(), |
| 337 | + $internalError->getTrace(), |
| 338 | + $internalError->getTraceAsString(), |
| 339 | + ); |
| 340 | + } |
| 341 | + foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { |
| 342 | + if (!$fileSpecificError->hasNonIgnorableException()) { |
| 343 | + continue; |
| 344 | + } |
| 345 | + |
| 346 | + $message = $fileSpecificError->getMessage(); |
| 347 | + if ($fileSpecificError->getIdentifier() === 'phpstan.internal') { |
| 348 | + $message = sprintf('Internal error: %s', $message); |
| 349 | + } |
| 350 | + |
| 351 | + $metadata = $fileSpecificError->getMetadata(); |
| 352 | + $internalErrors[$fileSpecificError->getMessage()] = new InternalError( |
| 353 | + $message, |
| 354 | + sprintf('analysing file %s', $fileSpecificError->getTraitFilePath() ?? $fileSpecificError->getFilePath()), |
| 355 | + $metadata[InternalError::STACK_TRACE_METADATA_KEY] ?? [], |
| 356 | + $metadata[InternalError::STACK_TRACE_AS_STRING_METADATA_KEY] ?? null, |
| 357 | + ); |
| 358 | + } |
| 359 | + |
| 360 | + $internalErrors = array_values($internalErrors); |
| 361 | + $bugReportUrl = 'https://github.com/phpstan/phpstan/issues/new?template=Bug_report.yaml'; |
| 362 | + foreach ($internalErrors as $i => $internalError) { |
| 363 | + $message = sprintf('%s while %s', $internalError->getMessage(), $internalError->getContextDescription()); |
| 364 | + if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { |
| 365 | + $firstTraceItem = $internalError->getTrace()[0] ?? null; |
| 366 | + $trace = ''; |
| 367 | + if ($firstTraceItem !== null && $firstTraceItem['file'] !== null && $firstTraceItem['line'] !== null) { |
| 368 | + $trace = sprintf('## %s(%d)%s', $firstTraceItem['file'], $firstTraceItem['line'], "\n"); |
| 369 | + } |
| 370 | + $trace .= $internalError->getTraceAsString(); |
| 371 | + $message .= sprintf('%sPost the following stack trace to %s: %s%s', "\n\n", $bugReportUrl, "\n", $trace); |
| 372 | + } else { |
| 373 | + $message .= sprintf('%sRun PHPStan with -v option and post the stack trace to:%s%s', "\n", "\n", $bugReportUrl); |
| 374 | + } |
| 375 | + $internalErrors[$i] = new InternalError( |
| 376 | + $message, |
| 377 | + $internalError->getContextDescription(), |
| 378 | + $internalError->getTrace(), |
| 379 | + $internalError->getTraceAsString(), |
| 380 | + ); |
| 381 | + } |
| 382 | + |
| 383 | + $internalErrors = array_values($internalErrors); |
| 384 | + |
331 | 385 | if ($generateBaselineFile !== null) {
|
| 386 | + if (count($internalErrors) > 0) { |
| 387 | + foreach ($internalErrors as $internalError) { |
| 388 | + $inceptionResult->getStdOutput()->writeLineFormatted($internalError->getMessage()); |
| 389 | + $inceptionResult->getStdOutput()->writeLineFormatted(''); |
| 390 | + } |
| 391 | + |
| 392 | + $inceptionResult->getStdOutput()->getStyle()->error(sprintf( |
| 393 | + '%s occurred. Baseline could not be generated.', |
| 394 | + count($internalErrors) === 1 ? 'An internal error' : 'Internal errors', |
| 395 | + )); |
| 396 | + |
| 397 | + return $inceptionResult->handleReturn(1, $analysisResult->getPeakMemoryUsageBytes()); |
| 398 | + } |
| 399 | + |
332 | 400 | return $this->generateBaseline($generateBaselineFile, $inceptionResult, $analysisResult, $output, $allowEmptyBaseline, $baselineExtension, $failWithoutResultCache);
|
333 | 401 | }
|
334 | 402 |
|
335 | 403 | /** @var ErrorFormatter $errorFormatter */
|
336 | 404 | $errorFormatter = $container->getService($errorFormatterServiceName);
|
337 | 405 |
|
| 406 | + if (count($internalErrors) > 0) { |
| 407 | + $analysisResult = new AnalysisResult( |
| 408 | + [], |
| 409 | + array_map(static fn (InternalError $internalError) => $internalError->getMessage(), $internalErrors), |
| 410 | + [], |
| 411 | + [], |
| 412 | + [], |
| 413 | + $analysisResult->isDefaultLevelUsed(), |
| 414 | + $analysisResult->getProjectConfigFile(), |
| 415 | + $analysisResult->isResultCacheSaved(), |
| 416 | + $analysisResult->getPeakMemoryUsageBytes(), |
| 417 | + $analysisResult->isResultCacheUsed(), |
| 418 | + $analysisResult->getChangedProjectExtensionFilesOutsideOfAnalysedPaths(), |
| 419 | + ); |
| 420 | + |
| 421 | + $exitCode = $errorFormatter->formatErrors($analysisResult, $inceptionResult->getStdOutput()); |
| 422 | + |
| 423 | + $errorOutput->writeLineFormatted('⚠️ Result is incomplete because of internal errors. ⚠️'); |
| 424 | + $errorOutput->writeLineFormatted(' Fix these errors first and then re-run PHPStan'); |
| 425 | + $errorOutput->writeLineFormatted(' to get all reported errors.'); |
| 426 | + $errorOutput->writeLineFormatted(''); |
| 427 | + |
| 428 | + return $inceptionResult->handleReturn( |
| 429 | + $exitCode, |
| 430 | + $analysisResult->getPeakMemoryUsageBytes(), |
| 431 | + ); |
| 432 | + } |
| 433 | + |
338 | 434 | $exitCode = $errorFormatter->formatErrors($analysisResult, $inceptionResult->getStdOutput());
|
339 | 435 | if ($failWithoutResultCache && !$analysisResult->isResultCacheUsed()) {
|
340 | 436 | $exitCode = 2;
|
@@ -413,35 +509,6 @@ private function generateBaseline(string $generateBaselineFile, InceptionResult
|
413 | 509 |
|
414 | 510 | return $inceptionResult->handleReturn(1, $analysisResult->getPeakMemoryUsageBytes());
|
415 | 511 | }
|
416 |
| - if ($analysisResult->hasInternalErrors()) { |
417 |
| - $internalErrors = array_values(array_unique($analysisResult->getInternalErrors())); |
418 |
| - |
419 |
| - foreach ($internalErrors as $internalError) { |
420 |
| - $inceptionResult->getStdOutput()->writeLineFormatted($internalError); |
421 |
| - $inceptionResult->getStdOutput()->writeLineFormatted(''); |
422 |
| - } |
423 |
| - |
424 |
| - $inceptionResult->getStdOutput()->getStyle()->error(sprintf( |
425 |
| - '%s occurred. Baseline could not be generated.', |
426 |
| - count($internalErrors) === 1 ? 'An internal error' : 'Internal errors', |
427 |
| - )); |
428 |
| - |
429 |
| - return $inceptionResult->handleReturn(1, $analysisResult->getPeakMemoryUsageBytes()); |
430 |
| - } |
431 |
| - |
432 |
| - foreach ($analysisResult->getFileSpecificErrors() as $fileSpecificError) { |
433 |
| - if (!$fileSpecificError->hasNonIgnorableException()) { |
434 |
| - continue; |
435 |
| - } |
436 |
| - |
437 |
| - $inceptionResult->getStdOutput()->getStyle()->error('An internal error occurred. Baseline could not be generated.'); |
438 |
| - |
439 |
| - $inceptionResult->getStdOutput()->writeLineFormatted($fileSpecificError->getMessage()); |
440 |
| - $inceptionResult->getStdOutput()->writeLineFormatted($fileSpecificError->getFile()); |
441 |
| - $inceptionResult->getStdOutput()->writeLineFormatted(''); |
442 |
| - |
443 |
| - return $inceptionResult->handleReturn(1, $analysisResult->getPeakMemoryUsageBytes()); |
444 |
| - } |
445 | 512 |
|
446 | 513 | $streamOutput = $this->createStreamOutput();
|
447 | 514 | $errorConsoleStyle = new ErrorsConsoleStyle(new StringInput(''), $streamOutput);
|
|
0 commit comments