From bfe7f96b563e6e12da83b1f77b7de8f6ab7cd782 Mon Sep 17 00:00:00 2001 From: AndrolGenhald Date: Sat, 11 Dec 2021 13:21:45 -0600 Subject: [PATCH 1/3] Allow suppressing UnusedPsalmSuppress, remove unused suppressions. --- psalm.xml.dist | 1 + src/Psalm/CodeLocation.php | 3 -- src/Psalm/Config.php | 7 ----- src/Psalm/Config/Creator.php | 1 - src/Psalm/FileBasedPluginAdapter.php | 3 -- .../FunctionLike/ReturnTypeAnalyzer.php | 1 - .../Analyzer/FunctionLikeAnalyzer.php | 9 ++++-- .../Expression/SimpleTypeInferer.php | 1 - .../Internal/Analyzer/StatementsAnalyzer.php | 20 ++++++++----- src/Psalm/Internal/CliUtils.php | 3 -- .../Codebase/InternalCallMapHandler.php | 4 --- src/Psalm/Internal/Codebase/Reflection.php | 3 -- src/Psalm/Internal/Fork/Pool.php | 11 ------- .../LanguageServer/LanguageServer.php | 1 - .../LanguageServer/ProtocolStreamReader.php | 4 --- .../PhpVisitor/CheckTrivialExprVisitor.php | 4 --- .../PhpVisitor/OffsetShifterVisitor.php | 3 -- .../Reflector/ClassLikeDocblockParser.php | 2 -- .../Internal/Provider/FakeFileProvider.php | 3 -- .../Internal/Provider/ParserCacheProvider.php | 7 ----- .../Internal/Provider/StatementsProvider.php | 1 - src/Psalm/Internal/Type/TypeTokenizer.php | 1 - tests/IssueSuppressionTest.php | 29 +++++++++++++++++++ tests/TestConfig.php | 3 -- 24 files changed, 50 insertions(+), 75 deletions(-) diff --git a/psalm.xml.dist b/psalm.xml.dist index bcf32dfb3..135cadc66 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -16,6 +16,7 @@ xsi:schemaLocation="https://getpsalm.org/schema/config config.xsd" limitMethodComplexity="true" errorBaseline="psalm-baseline.xml" + findUnusedPsalmSuppress="true" > diff --git a/src/Psalm/CodeLocation.php b/src/Psalm/CodeLocation.php index 83d08c347..e9e8277ef 100644 --- a/src/Psalm/CodeLocation.php +++ b/src/Psalm/CodeLocation.php @@ -137,9 +137,6 @@ class CodeLocation $this->docblock_line_number = $line; } - /** - * @psalm-suppress MixedArrayAccess - */ private function calculateRealLocation(): void { if ($this->have_recalculated) { diff --git a/src/Psalm/Config.php b/src/Psalm/Config.php index 0bc379286..cca393351 100644 --- a/src/Psalm/Config.php +++ b/src/Psalm/Config.php @@ -850,7 +850,6 @@ class Config /** * @psalm-suppress MixedMethodCall * @psalm-suppress MixedAssignment - * @psalm-suppress MixedOperand * @psalm-suppress MixedArgument * @psalm-suppress MixedPropertyFetch * @@ -1294,8 +1293,6 @@ class Config /** * Initialises all the plugins (done once the config is fully loaded) - * - * @psalm-suppress MixedAssignment */ public function initializePlugins(ProjectAnalyzer $project_analyzer): void { @@ -2065,10 +2062,6 @@ class Config $this->include_collector = $include_collector; } - /** - * @psalm-suppress MixedAssignment - * @psalm-suppress MixedArrayAccess - */ public function visitComposerAutoloadFiles(ProjectAnalyzer $project_analyzer, ?Progress $progress = null): void { if ($progress === null) { diff --git a/src/Psalm/Config/Creator.php b/src/Psalm/Config/Creator.php index aa7ac6170..7bfbda78f 100644 --- a/src/Psalm/Config/Creator.php +++ b/src/Psalm/Config/Creator.php @@ -208,7 +208,6 @@ class Creator * @return list * @psalm-suppress MixedAssignment * @psalm-suppress MixedArgument - * @psalm-suppress PossiblyUndefinedArrayOffset */ private static function getPsr4Or0Paths(string $current_dir, array $composer_json): array { diff --git a/src/Psalm/FileBasedPluginAdapter.php b/src/Psalm/FileBasedPluginAdapter.php index 8921c2e9d..86977a724 100644 --- a/src/Psalm/FileBasedPluginAdapter.php +++ b/src/Psalm/FileBasedPluginAdapter.php @@ -36,9 +36,6 @@ class FileBasedPluginAdapter implements Plugin\PluginEntryPointInterface $this->codebase = $codebase; } - /** - * @psalm-suppress PossiblyUnusedParam - */ public function __invoke(RegistrationInterface $registration, ?SimpleXMLElement $config = null): void { $fq_class_name = $this->getPluginClassForPath($this->path); diff --git a/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeAnalyzer.php b/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeAnalyzer.php index cc6ca0d09..1dc5fa930 100644 --- a/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeAnalyzer.php @@ -67,7 +67,6 @@ class ReturnTypeAnalyzer * @return false|null * * @psalm-suppress PossiblyUnusedReturnValue unused but seems important - * @psalm-suppress ComplexMethod to be refactored */ public static function verifyReturnType( FunctionLike $function, diff --git a/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php b/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php index fe99cb29f..e320950be 100644 --- a/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php @@ -56,6 +56,7 @@ use function array_search; use function array_values; use function count; use function end; +use function in_array; use function is_string; use function md5; use function microtime; @@ -186,8 +187,12 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer $project_analyzer = $this->getProjectAnalyzer(); if ($codebase->track_unused_suppressions && !isset($storage->suppressed_issues[0])) { - foreach ($storage->suppressed_issues as $offset => $issue_name) { - IssueBuffer::addUnusedSuppression($this->getFilePath(), $offset, $issue_name); + if (count($storage->suppressed_issues) === 1 + || !in_array("UnusedPsalmSuppress", $storage->suppressed_issues) + ) { + foreach ($storage->suppressed_issues as $offset => $issue_name) { + IssueBuffer::addUnusedSuppression($this->getFilePath(), $offset, $issue_name); + } } } diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php b/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php index 80518e010..94fb0bbd4 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/SimpleTypeInferer.php @@ -695,7 +695,6 @@ class SimpleTypeInferer $array_creation_info->property_types[$new_offset] = $property_value; } } elseif ($unpacked_atomic_type instanceof Type\Atomic\TArray) { - /** @psalm-suppress PossiblyUndefinedArrayOffset provably true, but Psalm can’t see it */ if ($unpacked_atomic_type->type_params[1]->isEmpty()) { continue; } diff --git a/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php b/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php index 63f91056c..7d19352a1 100644 --- a/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php @@ -57,8 +57,10 @@ use function array_combine; use function array_keys; use function array_merge; use function array_search; +use function count; use function fwrite; use function get_class; +use function in_array; use function is_string; use function preg_split; use function reset; @@ -420,18 +422,22 @@ class StatementsAnalyzer extends SourceAnalyzer foreach ($suppressed as $offset => $suppress_entry) { foreach (DocComment::parseSuppressList($suppress_entry) as $issue_offset => $issue_type) { $new_issues[$issue_offset + $offset] = $issue_type; + } + } + if ($codebase->track_unused_suppressions + && (count($new_issues) === 1) || !in_array("UnusedPsalmSuppress", $new_issues) + ) { + foreach ($new_issues as $offset => $issue_type) { if ($issue_type === 'InaccessibleMethod') { continue; } - if ($codebase->track_unused_suppressions) { - IssueBuffer::addUnusedSuppression( - $statements_analyzer->getFilePath(), - $issue_offset + $offset, - $issue_type - ); - } + IssueBuffer::addUnusedSuppression( + $statements_analyzer->getFilePath(), + $offset, + $issue_type + ); } } diff --git a/src/Psalm/Internal/CliUtils.php b/src/Psalm/Internal/CliUtils.php index 23b40166b..4a940429a 100644 --- a/src/Psalm/Internal/CliUtils.php +++ b/src/Psalm/Internal/CliUtils.php @@ -58,7 +58,6 @@ final class CliUtils $psalm_dir = dirname(__DIR__, 3); - /** @psalm-suppress UndefinedConstant */ $in_phar = Phar::running() || strpos(__NAMESPACE__, 'HumbugBox'); if ($in_phar) { @@ -154,9 +153,7 @@ final class CliUtils } /** - * @psalm-suppress MixedArrayAccess * @psalm-suppress MixedAssignment - * @psalm-suppress PossiblyUndefinedStringArrayOffset */ public static function getVendorDir(string $current_dir): string { diff --git a/src/Psalm/Internal/Codebase/InternalCallMapHandler.php b/src/Psalm/Internal/Codebase/InternalCallMapHandler.php index 37ab3c466..7c322bb4d 100644 --- a/src/Psalm/Internal/Codebase/InternalCallMapHandler.php +++ b/src/Psalm/Internal/Codebase/InternalCallMapHandler.php @@ -338,9 +338,6 @@ class InternalCallMapHandler * Gets the method/function call map * * @return array> - * @psalm-suppress MixedInferredReturnType as the use of require buggers things up - * @psalm-suppress MixedReturnStatement - * @psalm-suppress MixedReturnTypeCoercion */ public static function getCallMap(): array { @@ -397,7 +394,6 @@ class InternalCallMapHandler * }>, * removed: array> * } - * @psalm-suppress UnresolvableInclude */ $diff_call_map = require($delta_file); diff --git a/src/Psalm/Internal/Codebase/Reflection.php b/src/Psalm/Internal/Codebase/Reflection.php index 18162dad8..8a2aee70d 100644 --- a/src/Psalm/Internal/Codebase/Reflection.php +++ b/src/Psalm/Internal/Codebase/Reflection.php @@ -422,9 +422,6 @@ class Reflection return Type::getMixed(); } - /** - * @psalm-suppress UndefinedClass,TypeDoesNotContainType - */ if ($reflection_type instanceof ReflectionNamedType) { $type = $reflection_type->getName(); } elseif ($reflection_type instanceof ReflectionUnionType) { diff --git a/src/Psalm/Internal/Fork/Pool.php b/src/Psalm/Internal/Fork/Pool.php index 4584b991e..8ca01eff3 100644 --- a/src/Psalm/Internal/Fork/Pool.php +++ b/src/Psalm/Internal/Fork/Pool.php @@ -367,10 +367,6 @@ class Pool } elseif ($message instanceof ForkProcessErrorMessage) { // Kill all children foreach ($this->child_pid_list as $child_pid) { - /** - * @psalm-suppress UndefinedConstant - does not exist on windows - * @psalm-suppress MixedArgument - */ posix_kill($child_pid, SIGTERM); } throw new Exception($message->message); @@ -421,10 +417,6 @@ class Pool $status = 0; if ($process_lookup) { - /** - * @psalm-suppress UndefinedConstant - does not exist on windows - * @psalm-suppress MixedArgument - */ posix_kill($child_pid, SIGALRM); if (pcntl_waitpid($child_pid, $status) < 0) { @@ -437,9 +429,6 @@ class Pool $return_code = pcntl_wexitstatus($status); $term_sig = pcntl_wtermsig($status); - /** - * @psalm-suppress UndefinedConstant - does not exist on windows - */ if ($term_sig !== SIGALRM) { $this->did_have_error = true; error_log("Child terminated with return code $return_code and signal $term_sig"); diff --git a/src/Psalm/Internal/LanguageServer/LanguageServer.php b/src/Psalm/Internal/LanguageServer/LanguageServer.php index c5608aeab..8af4a6537 100644 --- a/src/Psalm/Internal/LanguageServer/LanguageServer.php +++ b/src/Psalm/Internal/LanguageServer/LanguageServer.php @@ -140,7 +140,6 @@ class LanguageServer extends AdvancedJsonRpc\Dispatcher // Invoke the method handler to get a result /** * @var Promise - * @psalm-suppress UndefinedDocblockClass */ $dispatched = $this->dispatch($msg->body); /** @psalm-suppress MixedAssignment */ diff --git a/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php b/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php index f034e891a..997a8a7d8 100644 --- a/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php +++ b/src/Psalm/Internal/LanguageServer/ProtocolStreamReader.php @@ -51,9 +51,6 @@ class ProtocolStreamReader implements ProtocolReader asyncCall( /** * @return Generator, ?string, void> - * @psalm-suppress MixedReturnTypeCoercion - * @psalm-suppress MixedArgument in old Amp versions - * @psalm-suppress MixedAssignment in old Amp versions */ function () use ($input): Generator { while ($this->is_accepting_new_requests) { @@ -119,7 +116,6 @@ class ProtocolStreamReader implements ProtocolReader $this->emit('message', [$msg]); /** * @psalm-suppress DocblockTypeContradiction - * @psalm-suppress RedundantConditionGivenDocblockType */ if (!$this->is_accepting_new_requests) { // If we fork, don't read any bytes in the input buffer from the worker process. diff --git a/src/Psalm/Internal/PhpVisitor/CheckTrivialExprVisitor.php b/src/Psalm/Internal/PhpVisitor/CheckTrivialExprVisitor.php index 8f2011d5a..71a936d36 100644 --- a/src/Psalm/Internal/PhpVisitor/CheckTrivialExprVisitor.php +++ b/src/Psalm/Internal/PhpVisitor/CheckTrivialExprVisitor.php @@ -15,10 +15,6 @@ class CheckTrivialExprVisitor extends PhpParser\NodeVisitorAbstract private function checkNonTrivialExpr(PhpParser\Node\Expr $node): bool { - /** - * @psalm-suppress UndefinedClass - * @psalm-suppress TypeDoesNotContainType - */ if ($node instanceof PhpParser\Node\Expr\ArrayDimFetch || $node instanceof PhpParser\Node\Expr\Closure || $node instanceof PhpParser\Node\Expr\ClosureUse diff --git a/src/Psalm/Internal/PhpVisitor/OffsetShifterVisitor.php b/src/Psalm/Internal/PhpVisitor/OffsetShifterVisitor.php index 5bb19da3a..71e792cef 100644 --- a/src/Psalm/Internal/PhpVisitor/OffsetShifterVisitor.php +++ b/src/Psalm/Internal/PhpVisitor/OffsetShifterVisitor.php @@ -54,9 +54,6 @@ class OffsetShifterVisitor extends PhpParser\NodeVisitorAbstract $node->setAttribute('comments', $new_comments); } - /** - * @psalm-suppress MixedOperand - */ $node->setAttribute( 'startFilePos', $attrs['startFilePos'] + $this->file_offset + ($this->extra_offsets[$attrs['startFilePos']] ?? 0) diff --git a/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php b/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php index b7e978af0..0589a430a 100644 --- a/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php +++ b/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php @@ -46,8 +46,6 @@ class ClassLikeDocblockParser { /** * @throws DocblockParseException if there was a problem parsing the docblock - * - * @psalm-suppress MixedArrayAccess */ public static function parse( Node $node, diff --git a/src/Psalm/Internal/Provider/FakeFileProvider.php b/src/Psalm/Internal/Provider/FakeFileProvider.php index 7d693ec47..7cafa391b 100644 --- a/src/Psalm/Internal/Provider/FakeFileProvider.php +++ b/src/Psalm/Internal/Provider/FakeFileProvider.php @@ -49,9 +49,6 @@ class FakeFileProvider extends FileProvider return $this->fake_file_times[$file_path] ?? parent::getModifiedTime($file_path); } - /** - * @psalm-suppress InvalidPropertyAssignmentValue because microtime is needed for cache busting - */ public function registerFile(string $file_path, string $file_contents): void { $this->fake_files[$file_path] = $file_contents; diff --git a/src/Psalm/Internal/Provider/ParserCacheProvider.php b/src/Psalm/Internal/Provider/ParserCacheProvider.php index 09543d00a..b24ce7f97 100644 --- a/src/Psalm/Internal/Provider/ParserCacheProvider.php +++ b/src/Psalm/Internal/Provider/ParserCacheProvider.php @@ -72,8 +72,6 @@ class ParserCacheProvider /** * @return list|null - * - * @psalm-suppress UndefinedFunction */ public function loadStatementsFromCache( string $file_path, @@ -117,8 +115,6 @@ class ParserCacheProvider /** * @return list|null - * - * @psalm-suppress UndefinedFunction */ public function loadExistingStatementsFromCache(string $file_path): ?array { @@ -218,9 +214,6 @@ class ParserCacheProvider /** * @param list $stmts - * - * - * @psalm-suppress UndefinedFunction */ public function saveStatementsToCache( string $file_path, diff --git a/src/Psalm/Internal/Provider/StatementsProvider.php b/src/Psalm/Internal/Provider/StatementsProvider.php index 8c49a77d4..f8c4624e3 100644 --- a/src/Psalm/Internal/Provider/StatementsProvider.php +++ b/src/Psalm/Internal/Provider/StatementsProvider.php @@ -150,7 +150,6 @@ class StatementsProvider $existing_statements = $this->parser_cache_provider->loadExistingStatementsFromCache($file_path); - /** @psalm-suppress DocblockTypeContradiction */ if ($existing_statements && !$existing_statements[0] instanceof PhpParser\Node\Stmt) { $existing_statements = null; } diff --git a/src/Psalm/Internal/Type/TypeTokenizer.php b/src/Psalm/Internal/Type/TypeTokenizer.php index e05082af8..e893fd06f 100644 --- a/src/Psalm/Internal/Type/TypeTokenizer.php +++ b/src/Psalm/Internal/Type/TypeTokenizer.php @@ -97,7 +97,6 @@ class TypeTokenizer * * @return list * - * @psalm-suppress ComplexMethod * @psalm-suppress PossiblyUndefinedIntArrayOffset */ public static function tokenize(string $string_type, bool $ignore_space = true): array diff --git a/tests/IssueSuppressionTest.php b/tests/IssueSuppressionTest.php index ef8d19d6b..c2290f577 100644 --- a/tests/IssueSuppressionTest.php +++ b/tests/IssueSuppressionTest.php @@ -371,6 +371,24 @@ class IssueSuppressionTest extends TestCase } ', ], + 'suppressUnusedSuppression' => [ + ' 'UndefinedClass', ], + 'suppressUnusedSuppressionByItselfIsNotSuppressed' => [ + ' 'UnusedPsalmSuppress', + ], ]; } } diff --git a/tests/TestConfig.php b/tests/TestConfig.php index ef8e51d10..35c469b05 100644 --- a/tests/TestConfig.php +++ b/tests/TestConfig.php @@ -15,9 +15,6 @@ class TestConfig extends Config /** @var ProjectFileFilter|null */ private static $cached_project_files = null; - /** - * @psalm-suppress PossiblyNullPropertyAssignmentValue because cache_directory isn't strictly nullable - */ public function __construct() { parent::__construct(); From 684cbfeab9cdde0d41277c6a8283821c0a1947c8 Mon Sep 17 00:00:00 2001 From: AndrolGenhald Date: Sat, 11 Dec 2021 15:37:09 -0600 Subject: [PATCH 2/3] Add back suppressions for undefined constants on Windows. --- src/Psalm/Internal/Fork/Pool.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Psalm/Internal/Fork/Pool.php b/src/Psalm/Internal/Fork/Pool.php index 8ca01eff3..19d3f6c54 100644 --- a/src/Psalm/Internal/Fork/Pool.php +++ b/src/Psalm/Internal/Fork/Pool.php @@ -367,6 +367,12 @@ class Pool } elseif ($message instanceof ForkProcessErrorMessage) { // Kill all children foreach ($this->child_pid_list as $child_pid) { + /** + * SIGTERM does not exist on windows + * @psalm-suppress UnusedPsalmSuppress + * @psalm-suppress UndefinedConstant + * @psalm-suppress MixedArgument + */ posix_kill($child_pid, SIGTERM); } throw new Exception($message->message); @@ -417,6 +423,12 @@ class Pool $status = 0; if ($process_lookup) { + /** + * SIGALRM does not exist on windows + * @psalm-suppress UnusedPsalmSuppress + * @psalm-suppress UndefinedConstant + * @psalm-suppress MixedArgument + */ posix_kill($child_pid, SIGALRM); if (pcntl_waitpid($child_pid, $status) < 0) { @@ -429,6 +441,11 @@ class Pool $return_code = pcntl_wexitstatus($status); $term_sig = pcntl_wtermsig($status); + /** + * SIGALRM does not exist on windows + * @psalm-suppress UnusedPsalmSuppress + * @psalm-suppress UndefinedConstant + */ if ($term_sig !== SIGALRM) { $this->did_have_error = true; error_log("Child terminated with return code $return_code and signal $term_sig"); From 225af970ccbc30d43d62be89f5ffa84c4bccc468 Mon Sep 17 00:00:00 2001 From: AndrolGenhald Date: Sat, 11 Dec 2021 16:14:25 -0600 Subject: [PATCH 3/3] Add comments explaining condition for UnusedPsalmSuppress. --- src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php | 2 +- src/Psalm/Internal/Analyzer/StatementsAnalyzer.php | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php b/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php index e320950be..38a1dd9a0 100644 --- a/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php @@ -187,7 +187,7 @@ abstract class FunctionLikeAnalyzer extends SourceAnalyzer $project_analyzer = $this->getProjectAnalyzer(); if ($codebase->track_unused_suppressions && !isset($storage->suppressed_issues[0])) { - if (count($storage->suppressed_issues) === 1 + if (count($storage->suppressed_issues) === 1 // UnusedPsalmSuppress by itself should be marked as unused || !in_array("UnusedPsalmSuppress", $storage->suppressed_issues) ) { foreach ($storage->suppressed_issues as $offset => $issue_name) { diff --git a/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php b/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php index 7d19352a1..39badf3bc 100644 --- a/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/StatementsAnalyzer.php @@ -426,7 +426,10 @@ class StatementsAnalyzer extends SourceAnalyzer } if ($codebase->track_unused_suppressions - && (count($new_issues) === 1) || !in_array("UnusedPsalmSuppress", $new_issues) + && ( + (count($new_issues) === 1) // UnusedPsalmSuppress by itself should be marked as unused + || !in_array("UnusedPsalmSuppress", $new_issues) + ) ) { foreach ($new_issues as $offset => $issue_type) { if ($issue_type === 'InaccessibleMethod') {