diff --git a/conf/parametersSchema.neon b/conf/parametersSchema.neon index c82bd7f69e..dd4c63b8ca 100644 --- a/conf/parametersSchema.neon +++ b/conf/parametersSchema.neon @@ -111,42 +111,16 @@ parametersSchema: ignoreErrors: listOf( anyOf( string(), - structure([ - ?messages: listOf(string()) - ?identifier: string() - ?identifiers: listOf(string()) - ?path: string() - ?reportUnmatched: bool() - ]), structure([ ?message: string() + ?messages: listOf(string()) ?identifier: string() ?identifiers: listOf(string()) ?path: string() + ?paths: listOf(string()) + ?count: int() ?reportUnmatched: bool() ]), - structure([ - ?message: string() - count: int() - path: string() - ?identifier: string() - ?identifiers: listOf(string()) - ?reportUnmatched: bool() - ]), - structure([ - ?message: string() - paths: listOf(string()) - ?identifier: string() - ?identifiers: listOf(string()) - ?reportUnmatched: bool() - ]), - structure([ - ?messages: listOf(string()) - paths: listOf(string()) - ?identifier: string() - ?identifiers: listOf(string()) - ?reportUnmatched: bool() - ]) ) ) internalErrorsCountLimit: int() diff --git a/src/DependencyInjection/ContainerFactory.php b/src/DependencyInjection/ContainerFactory.php index 38b6d24f54..2d3e70691d 100644 --- a/src/DependencyInjection/ContainerFactory.php +++ b/src/DependencyInjection/ContainerFactory.php @@ -32,7 +32,9 @@ use PHPStan\ShouldNotHappenException; use PHPStan\Type\ObjectType; use function array_diff_key; +use function array_intersect; use function array_key_exists; +use function array_keys; use function array_map; use function array_merge; use function array_unique; @@ -40,10 +42,12 @@ use function dirname; use function extension_loaded; use function getenv; +use function implode; use function ini_get; use function is_array; use function is_file; use function is_readable; +use function is_string; use function spl_object_id; use function sprintf; use function str_ends_with; @@ -318,15 +322,35 @@ private function validateParameters(array $parameters, array $parametersSchema): $processor->process($schema, $parameters); if ( - !array_key_exists('phpVersion', $parameters) - || !is_array($parameters['phpVersion'])) { - return; + array_key_exists('phpVersion', $parameters) + && is_array($parameters['phpVersion']) + ) { + $phpVersion = $parameters['phpVersion']; + + if ($phpVersion['max'] < $phpVersion['min']) { + throw new InvalidPhpVersionException('Invalid PHP version range: phpVersion.max should be greater or equal to phpVersion.min.'); + } } - $phpVersion = $parameters['phpVersion']; + foreach ($parameters['ignoreErrors'] ?? [] as $ignoreError) { + if (is_string($ignoreError)) { + continue; + } + + $atLeastOneOf = ['message', 'messages', 'identifier', 'identifiers', 'path', 'paths']; + if (array_intersect($atLeastOneOf, array_keys($ignoreError)) === []) { + throw new InvalidIgnoredErrorException('An ignoreErrors entry must contain at least one of the following fields: ' . implode(', ', $atLeastOneOf) . '.'); + } - if ($phpVersion['max'] < $phpVersion['min']) { - throw new InvalidPhpVersionException('Invalid PHP version range: phpVersion.max should be greater or equal to phpVersion.min.'); + foreach (['message', 'identifier', 'path'] as $field) { + if (array_key_exists($field, $ignoreError) && array_key_exists($field . 's', $ignoreError)) { + throw new InvalidIgnoredErrorException(sprintf('An ignoreErrors entry cannot contain both %s and %s fields.', $field, $field . 's')); + } + } + + if (array_key_exists('count', $ignoreError) && !array_key_exists('path', $ignoreError)) { + throw new InvalidIgnoredErrorException('An ignoreErrors entry with count field must also contain path field.'); + } } } diff --git a/src/DependencyInjection/InvalidIgnoredErrorException.php b/src/DependencyInjection/InvalidIgnoredErrorException.php new file mode 100644 index 0000000000..c553301519 --- /dev/null +++ b/src/DependencyInjection/InvalidIgnoredErrorException.php @@ -0,0 +1,10 @@ + + */ + public static function dataValidateIgnoreErrors(): iterable + { + yield [ + __DIR__ . '/invalidIgnoreErrors/message-and-messages.neon', + 'An ignoreErrors entry cannot contain both message and messages fields.', + ]; + yield [ + __DIR__ . '/invalidIgnoreErrors/identifier-and-identifiers.neon', + 'An ignoreErrors entry cannot contain both identifier and identifiers fields.', + ]; + yield [ + __DIR__ . '/invalidIgnoreErrors/path-and-paths.neon', + 'An ignoreErrors entry cannot contain both path and paths fields.', + ]; + yield [ + __DIR__ . '/invalidIgnoreErrors/missing-main-key.neon', + 'An ignoreErrors entry must contain at least one of the following fields: message, messages, identifier, identifiers, path, paths.', + ]; + yield [ + __DIR__ . '/invalidIgnoreErrors/count-without-path.neon', + 'An ignoreErrors entry with count field must also contain path field.', + ]; + } + + #[DataProvider('dataValidateIgnoreErrors')] + public function testValidateIgnoreErrors(string $file, string $expectedMessage): void + { + self::$configFile = $file; + $this->expectExceptionMessage($expectedMessage); + self::getContainer(); + } + + public static function getAdditionalConfigFiles(): array + { + return [ + __DIR__ . '/../../../conf/bleedingEdge.neon', + self::$configFile, + ]; + } + +} diff --git a/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/count-without-path.neon b/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/count-without-path.neon new file mode 100644 index 0000000000..6e712c383f --- /dev/null +++ b/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/count-without-path.neon @@ -0,0 +1,5 @@ +parameters: + ignoreErrors: + - + message: '#One#' + count: 3 diff --git a/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/identifier-and-identifiers.neon b/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/identifier-and-identifiers.neon new file mode 100644 index 0000000000..a0df67723d --- /dev/null +++ b/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/identifier-and-identifiers.neon @@ -0,0 +1,5 @@ +parameters: + ignoreErrors: + - + identifier: argument.type + identifiers: [argument.type] diff --git a/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/message-and-messages.neon b/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/message-and-messages.neon new file mode 100644 index 0000000000..4015170048 --- /dev/null +++ b/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/message-and-messages.neon @@ -0,0 +1,5 @@ +parameters: + ignoreErrors: + - + message: '#One#' + messages: ['#Two#'] diff --git a/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/missing-main-key.neon b/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/missing-main-key.neon new file mode 100644 index 0000000000..08c705b7a6 --- /dev/null +++ b/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/missing-main-key.neon @@ -0,0 +1,4 @@ +parameters: + ignoreErrors: + - + reportUnmatched: false diff --git a/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/path-and-paths.neon b/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/path-and-paths.neon new file mode 100644 index 0000000000..63a543f41b --- /dev/null +++ b/tests/PHPStan/DependencyInjection/invalidIgnoreErrors/path-and-paths.neon @@ -0,0 +1,5 @@ +parameters: + ignoreErrors: + - + path: ../IgnoreErrorsTest.php + paths: [../IgnoreErrorsTest.php]