diff --git a/.github/workflows/php-qa.yml b/.github/workflows/php-qa.yml deleted file mode 100644 index 3bf57e2..0000000 --- a/.github/workflows/php-qa.yml +++ /dev/null @@ -1,76 +0,0 @@ -name: PHP Quality Assurance -on: - push: - pull_request: - workflow_dispatch: -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true -jobs: - static-qa: - runs-on: ubuntu-latest - if: ${{ !contains(github.event.head_commit.message, 'no static qa') }} - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: 7.4 - coverage: none - tools: cs2pr - - - name: Install dependencies - uses: ramsey/composer-install@v2 - - - name: Check code styles - run: | - ./vendor/bin/phpcs -q --report-full --report-checkstyle="phpcs-report.xml" --runtime-set testVersion 7.0- --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 - cs2pr --graceful-warnings phpcs-report.xml - - - name: Check Psalm - run: ./vendor/bin/psalm --output-format=github --no-cache - - unit-tests: - runs-on: ubuntu-latest - if: ${{ !contains(github.event.head_commit.message, 'no unit tests') }} - strategy: - fail-fast: true - matrix: - php-ver: [ '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2' ] - deps-mode: [ 'lowest', 'highest' ] - include: - - php-ver: '8.1' - dependency-versions: 'highest' - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-ver }} - ini-values: zend.assertions=1, error_reporting=-1, display_errors=On - coverage: none - tools: cs2pr, parallel-lint:^1.3.1 - - - name: Check syntax error in sources - if: ${{ (matrix.deps-mode == 'highest') }} - run: parallel-lint ./Inpsyde/ ./tests/src/ ./tests/cases/ --checkstyle | cs2pr - - - name: Remove Psalm before tests to prevent installation conflicts - run: composer remove vimeo/psalm --no-update - - - name: Install dependencies - uses: ramsey/composer-install@v2 - with: - dependency-versions: ${{ matrix.deps-mode }} - - - name: Migrate PHPUnit config for PHPUnit 9 - if: ${{ (matrix.php-ver >= 7.3) && (matrix.deps-mode == 'highest') }} - run: ./vendor/bin/phpunit --migrate-configuration - - - name: Run unit tests - run: ./vendor/bin/phpunit --testsuite=unit --no-coverage diff --git a/.github/workflows/quality-assurance-php.yml b/.github/workflows/quality-assurance-php.yml new file mode 100644 index 0000000..cee505f --- /dev/null +++ b/.github/workflows/quality-assurance-php.yml @@ -0,0 +1,51 @@ +name: PHP Quality Assurance + +on: + push: + paths: + - '**workflows/quality-assurance-php.yml' + - '**.php' + - '**phpcs.xml.dist' + - '**phpunit.xml.dist' + - '**psalm.xml' + workflow_dispatch: + inputs: + jobs: + required: true + type: choice + default: 'Run all' + description: 'Choose jobs to run' + options: + - 'Run all' + - 'Run PHPCS only' + - 'Run Psalm only' + - 'Run lint only' + - 'Run static analysis' + - 'Run unit tests only' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint-php: + uses: inpsyde/reusable-workflows/.github/workflows/lint-php.yml@main + if: ${{ (github.event_name != 'workflow_dispatch') || ((github.event.inputs.jobs == 'Run all') || (github.event.inputs.jobs == 'Run lint only') || (github.event.inputs.jobs == 'Run static analysis')) }} + with: + PHP_MATRIX: '["7.4", "8.0", "8.1", "8.2"]' + LINT_ARGS: '-e php --colors --show-deprecated ./Inpsyde' + + coding-standards-analysis-php: + if: ${{ (github.event_name != 'workflow_dispatch') || ((github.event.inputs.jobs == 'Run all') || (github.event.inputs.jobs == 'Run PHPCS only') || (github.event.inputs.jobs == 'Run static analysis')) }} + uses: inpsyde/reusable-workflows/.github/workflows/coding-standards-php.yml@main + + static-code-analysis-php: + if: ${{ (github.event_name != 'workflow_dispatch') || ((github.event.inputs.jobs == 'Run all') || (github.event.inputs.jobs == 'Run Psalm only') || (github.event.inputs.jobs == 'Run static analysis')) }} + uses: inpsyde/reusable-workflows/.github/workflows/static-analysis-php.yml@main + + tests-unit-php: + if: ${{ (github.event_name != 'workflow_dispatch') || ((github.event.inputs.jobs == 'Run all') || (github.event.inputs.jobs == 'Run unit tests only')) }} + uses: inpsyde/reusable-workflows/.github/workflows/tests-unit-php.yml@main + with: + PHP_MATRIX: '["7.4", "8.0", "8.1", "8.2"]' + PHPUNIT_ARGS: '--no-coverage' diff --git a/.gitignore b/.gitignore index 8a6f193..88f6304 100644 --- a/.gitignore +++ b/.gitignore @@ -2,11 +2,4 @@ composer.phar composer.lock /vendor/ /phpunit.xml - -# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file -# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file -# composer.lock -.buildpath -.project -.settings/ .phpunit.result.cache diff --git a/Inpsyde/PhpcsHelpers.php b/Inpsyde/PhpcsHelpers.php index fc6bd50..9bcd6c4 100644 --- a/Inpsyde/PhpcsHelpers.php +++ b/Inpsyde/PhpcsHelpers.php @@ -119,13 +119,14 @@ public static function findOopContext(File $file, int $position): int $targetLevel = (int)$tokens[$position]['level'] - 1; foreach ($tokens[$position]['conditions'] as $condPosition => $condCode) { + assert(is_int($condPosition)); $condLevel = (int)($tokens[$condPosition]['level'] ?? -1); if ( in_array($condCode, Tokens::$ooScopeTokens, true) && ($condLevel === $targetLevel) ) { - return (int)$condPosition; + return $condPosition; } } @@ -387,7 +388,7 @@ public static function functionDocBlockTags( $normalizedTags = []; static $rand; $rand or $rand = bin2hex(random_bytes(3)); - foreach ($tags as list($tagName, $tagContent)) { + foreach ($tags as [$tagName, $tagContent]) { empty($normalizedTags[$tagName]) and $normalizedTags[$tagName] = []; if (!$normalizeContent) { $normalizedTags[$tagName][] = $tagContent; @@ -433,7 +434,7 @@ public static function functionDocBlockParamTypes(File $file, int $functionPosit $types = []; foreach ($params as $param) { - preg_match('~^([^$]+)\s*(\$(?:[^\s]+))~', trim($param), $matches); + preg_match('~^([^$]+)\s*(\$\S+)~', trim($param), $matches); if (empty($matches[1]) || empty($matches[2])) { continue; } @@ -461,7 +462,7 @@ public static function isHookFunction(File $file, int $position): bool */ public static function functionBody(File $file, int $position): string { - list($start, $end) = static::functionBoundaries($file, $position); + [$start, $end] = static::functionBoundaries($file, $position); if ($start < 0 || $end < 0) { return ''; } @@ -470,7 +471,7 @@ public static function functionBody(File $file, int $position): string $tokens = $file->getTokens(); $body = ''; for ($i = $start + 1; $i < $end; $i++) { - $body .= (string)$tokens[$i]['content']; + $body .= (string)($tokens[$i]['content'] ?? ''); } return $body; @@ -531,7 +532,7 @@ public static function returnsCountInfo(File $file, int $position): array { $returnCount = ['nonEmpty' => 0, 'void' => 0, 'null' => 0, 'total' => 0]; - list($start, $end) = self::functionBoundaries($file, $position); + [$start, $end] = self::functionBoundaries($file, $position); if ($start < 0 || $end <= 0) { return $returnCount; } @@ -541,8 +542,8 @@ public static function returnsCountInfo(File $file, int $position): array $pos = $start + 1; while ($pos < $end) { - list(, $innerFunctionEnd) = self::functionBoundaries($file, $pos); - list(, $innerClassEnd) = self::classBoundaries($file, $pos); + [, $innerFunctionEnd] = self::functionBoundaries($file, $pos); + [, $innerClassEnd] = self::classBoundaries($file, $pos); if ($innerFunctionEnd > 0 || $innerClassEnd > 0) { $pos = ($innerFunctionEnd > 0) ? $innerFunctionEnd + 1 : $innerClassEnd + 1; continue; diff --git a/Inpsyde/Sniffs/CodeQuality/ArgumentTypeDeclarationSniff.php b/Inpsyde/Sniffs/CodeQuality/ArgumentTypeDeclarationSniff.php index c715c6d..2a19d85 100644 --- a/Inpsyde/Sniffs/CodeQuality/ArgumentTypeDeclarationSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/ArgumentTypeDeclarationSniff.php @@ -19,65 +19,54 @@ class ArgumentTypeDeclarationSniff implements Sniff { - const TYPE_CODES = [ + public const TYPE_CODES = [ T_STRING, T_ARRAY_HINT, T_CALLABLE, T_SELF, ]; - const METHODS_WHITELIST = [ + public const METHODS_WHITELIST = [ 'unserialize', 'seek', ]; /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_FUNCTION, T_CLOSURE]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * - * phpcs:disable Inpsyde.CodeQuality + * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration + * phpcs:disable Generic.Metrics.CyclomaticComplexity */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { - // phpcs:enable Inpsyde.CodeQuality + // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration + // phpcs:enable Generic.Metrics.CyclomaticComplexity - if ( - PhpcsHelpers::functionIsArrayAccess($file, $position) - || PhpcsHelpers::isHookClosure($file, $position) - || PhpcsHelpers::isHookFunction($file, $position) - || PhpcsHelpers::isUntypedPsrMethod($file, $position) - || ( - PhpcsHelpers::functionIsMethod($file, $position) - && in_array($file->getDeclarationName($position), self::METHODS_WHITELIST, true) - ) - ) { + if ($this->shouldIgnore($phpcsFile, $stackPtr)) { return; } /** @var array> $tokens */ - $tokens = $file->getTokens(); - $paramsStart = (int)($tokens[$position]['parenthesis_opener'] ?? 0); - $paramsEnd = (int)($tokens[$position]['parenthesis_closer'] ?? 0); + $tokens = $phpcsFile->getTokens(); + $paramsStart = (int)($tokens[$stackPtr]['parenthesis_opener'] ?? 0); + $paramsEnd = (int)($tokens[$stackPtr]['parenthesis_closer'] ?? 0); if (!$paramsStart || !$paramsEnd || $paramsStart >= ($paramsEnd - 1)) { return; } - $docBlockTypes = PhpcsHelpers::functionDocBlockParamTypes($file, $position); - $variables = PhpcsHelpers::filterTokensByType($paramsStart, $paramsEnd, $file, T_VARIABLE); + $docBlockTypes = PhpcsHelpers::functionDocBlockParamTypes($phpcsFile, $stackPtr); + $variables = PhpcsHelpers::filterTokensByType($paramsStart, $paramsEnd, $phpcsFile, T_VARIABLE); foreach ($variables as $varPosition => $varToken) { // Not triggering error for variable explicitly declared as mixed (or mixed|null) @@ -85,7 +74,7 @@ public function process(File $file, $position) continue; } - $typePosition = $file->findPrevious( + $typePosition = $phpcsFile->findPrevious( [T_WHITESPACE, T_ELLIPSIS, T_BITWISE_AND], $varPosition - 1, $paramsStart + 1, @@ -93,13 +82,35 @@ public function process(File $file, $position) ); $type = $tokens[$typePosition] ?? null; - /** @psalm-suppress MixedArgument */ - if ($type && !in_array($type['code'], self::TYPE_CODES, true)) { - $file->addWarning('Argument type is missing', $position, 'NoArgumentType'); + if ($type && !in_array($type['code'] ?? '', self::TYPE_CODES, true)) { + $phpcsFile->addWarning('Argument type is missing', $stackPtr, 'NoArgumentType'); } } } + /** + * @param File $phpcsFile + * @param int $stackPtr + * @return bool + * + * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration + */ + private function shouldIgnore(File $phpcsFile, $stackPtr): bool + { + // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration + + $name = $phpcsFile->getDeclarationName($stackPtr); + + return PhpcsHelpers::functionIsArrayAccess($phpcsFile, $stackPtr) + || PhpcsHelpers::isHookClosure($phpcsFile, $stackPtr) + || PhpcsHelpers::isHookFunction($phpcsFile, $stackPtr) + || PhpcsHelpers::isUntypedPsrMethod($phpcsFile, $stackPtr) + || ( + PhpcsHelpers::functionIsMethod($phpcsFile, $stackPtr) + && in_array($name, self::METHODS_WHITELIST, true) + ); + } + /** * @param string $paramName * @param array> $docBlockTypes diff --git a/Inpsyde/Sniffs/CodeQuality/ConstantVisibilitySniff.php b/Inpsyde/Sniffs/CodeQuality/ConstantVisibilitySniff.php deleted file mode 100644 index 0a178e5..0000000 --- a/Inpsyde/Sniffs/CodeQuality/ConstantVisibilitySniff.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_OPEN_TAG, T_INLINE_HTML]; } } diff --git a/Inpsyde/Sniffs/CodeQuality/ElementNameMinimalLengthSniff.php b/Inpsyde/Sniffs/CodeQuality/ElementNameMinimalLengthSniff.php index d425a59..4c28d0a 100644 --- a/Inpsyde/Sniffs/CodeQuality/ElementNameMinimalLengthSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/ElementNameMinimalLengthSniff.php @@ -10,15 +10,12 @@ class ElementNameMinimalLengthSniff implements Sniff { - /** - * @var int - */ - public $minLength = 3; + public int $minLength = 3; /** - * @var string[] + * @var list */ - public $allowedShortNames = [ + public array $allowedShortNames = [ 'as', 'at', 'be', @@ -45,46 +42,36 @@ class ElementNameMinimalLengthSniff implements Sniff 'wp', ]; - /** - * @var string[] - */ - public $additionalAllowedNames = []; + /** @var list */ + public array $additionalAllowedNames = []; /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_CLASS, T_TRAIT, T_INTERFACE, T_CONST, T_FUNCTION, T_VARIABLE]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - $elementName = PhpcsHelpers::tokenName($file, $position); + $elementName = PhpcsHelpers::tokenName($phpcsFile, $stackPtr); $elementNameLength = mb_strlen($elementName); if ($this->shouldBeSkipped($elementNameLength, $elementName)) { return; } - $typeName = PhpcsHelpers::tokenTypeName($file, $position); + $typeName = PhpcsHelpers::tokenTypeName($phpcsFile, $stackPtr); $message = sprintf( '%s name "%s" is only %d chars long. Must be at least %d.', $typeName, @@ -93,7 +80,7 @@ public function process(File $file, $position) $this->minLength ); - $file->addError($message, $position, 'TooShort'); + $phpcsFile->addError($message, $stackPtr, 'TooShort'); } /** diff --git a/Inpsyde/Sniffs/CodeQuality/ForbiddenPublicPropertySniff.php b/Inpsyde/Sniffs/CodeQuality/ForbiddenPublicPropertySniff.php index 510654f..04a3365 100644 --- a/Inpsyde/Sniffs/CodeQuality/ForbiddenPublicPropertySniff.php +++ b/Inpsyde/Sniffs/CodeQuality/ForbiddenPublicPropertySniff.php @@ -12,46 +12,38 @@ class ForbiddenPublicPropertySniff implements Sniff { /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_VARIABLE]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - if (!PhpcsHelpers::variableIsProperty($file, $position)) { + if (!PhpcsHelpers::variableIsProperty($phpcsFile, $stackPtr)) { return; } // Skip sniff classes, they have public properties for configuration (unfortunately) - if ($this->isSniffClass($file, $position)) { + if ($this->isSniffClass($phpcsFile, $stackPtr)) { return; } - $scopeModifierToken = $this->propertyScopeModifier($file, $position); + $scopeModifierToken = $this->propertyScopeModifier($phpcsFile, $stackPtr); if ($scopeModifierToken['code'] === T_PUBLIC) { - $file->addError( + $phpcsFile->addError( 'Do not use public properties. Use method access instead.', - $position, + $stackPtr, 'Found' ); } @@ -87,7 +79,7 @@ private function isSniffClass(File $file, int $position): bool /** * @param File $file * @param int $position - * @return array + * @return array */ private function propertyScopeModifier(File $file, int $position): array { diff --git a/Inpsyde/Sniffs/CodeQuality/FunctionBodyStartSniff.php b/Inpsyde/Sniffs/CodeQuality/FunctionBodyStartSniff.php index 83ff8d5..885e11b 100644 --- a/Inpsyde/Sniffs/CodeQuality/FunctionBodyStartSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/FunctionBodyStartSniff.php @@ -11,35 +11,27 @@ class FunctionBodyStartSniff implements Sniff { /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_FUNCTION]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration /** @var array> $tokens */ - $tokens = $file->getTokens(); - $token = $tokens[$position] ?? []; + $tokens = $phpcsFile->getTokens(); + $token = $tokens[$stackPtr] ?? []; $scopeOpener = (int)($token['scope_opener'] ?? -1); $scopeCloser = (int)($token['scope_closer'] ?? -1); @@ -48,7 +40,7 @@ public function process(File $file, $position) return; } - $bodyStart = $file->findNext([T_WHITESPACE], $scopeOpener + 1, null, true); + $bodyStart = $phpcsFile->findNext([T_WHITESPACE], $scopeOpener + 1, null, true); if ( !$bodyStart || !array_key_exists($bodyStart, $tokens) @@ -58,20 +50,20 @@ public function process(File $file, $position) return; } - list($code, $message, $expectedLine) = $this->checkBodyStart( + [$code, $message, $expectedLine] = $this->checkBodyStart( $bodyStart, (int)($tokens[$scopeOpener]['line'] ?? -1), (int)($token['line'] ?? -1), - $file + $phpcsFile ); if ( $code && $message && $expectedLine - && $file->addFixableWarning($message, $position, $code) + && $phpcsFile->addFixableWarning($message, $stackPtr, $code) ) { - $this->fix($bodyStart, $expectedLine, $scopeOpener, $file); + $this->fix($bodyStart, $expectedLine, $scopeOpener, $phpcsFile); } } @@ -80,7 +72,7 @@ public function process(File $file, $position) * @param int $openerLine * @param int $functionLine * @param File $file - * @return array{null, null, null}|array{string, string, int} + * @return list{null, null, null}|list{string, string, int} */ private function checkBodyStart( int $bodyStart, @@ -143,7 +135,7 @@ private function checkBodyStart( * @param File $file * @return void */ - private function fix(int $bodyStart, int $expectedLine, int $scopeOpener, File $file) + private function fix(int $bodyStart, int $expectedLine, int $scopeOpener, File $file): void { /** @var array> $tokens */ $tokens = $file->getTokens(); diff --git a/Inpsyde/Sniffs/CodeQuality/FunctionLengthSniff.php b/Inpsyde/Sniffs/CodeQuality/FunctionLengthSniff.php index 0181d77..b807d8e 100644 --- a/Inpsyde/Sniffs/CodeQuality/FunctionLengthSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/FunctionLengthSniff.php @@ -9,57 +9,31 @@ class FunctionLengthSniff implements Sniff { - /** - * @var mixed - */ - public $maxLength = 50; - - /** - * @var mixed - */ - public $ignoreDocBlocks = true; - - /** - * @var mixed - */ - public $ignoreComments = true; - - /** - * @var mixed - */ - public $ignoreBlankLines = true; + public int $maxLength = 50; + public bool $ignoreDocBlocks = true; + public bool $ignoreComments = true; + public bool $ignoreBlankLines = true; /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_FUNCTION]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - - is_numeric($this->maxLength) or $this->maxLength = 50; - $this->maxLength = (int)$this->maxLength; - $length = $this->structureLinesCount($file, $position); + $length = $this->structureLinesCount($phpcsFile, $stackPtr); if ($length <= $this->maxLength) { return; } @@ -84,7 +58,7 @@ public function process(File $file, $position) $this->maxLength ); - $file->addError($error, $position, 'TooLong'); + $phpcsFile->addError($error, $stackPtr, 'TooLong'); } /** @@ -200,7 +174,7 @@ private function docBlocksData(array $tokens, int $position, array $docBlocks): /** * @return void */ - private function normalizeIgnoreFlags() + private function normalizeIgnoreFlags(): void { $flags = [ 'ignoreBlankLines', diff --git a/Inpsyde/Sniffs/CodeQuality/HookClosureReturnSniff.php b/Inpsyde/Sniffs/CodeQuality/HookClosureReturnSniff.php index ba0cacb..73159e7 100644 --- a/Inpsyde/Sniffs/CodeQuality/HookClosureReturnSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/HookClosureReturnSniff.php @@ -11,42 +11,34 @@ class HookClosureReturnSniff implements Sniff { /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_CLOSURE]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - if (!PhpcsHelpers::isHookClosure($file, $position)) { + if (!PhpcsHelpers::isHookClosure($phpcsFile, $stackPtr)) { return; } - list($functionStart, $functionEnd) = PhpcsHelpers::functionBoundaries($file, $position); + [$functionStart, $functionEnd] = PhpcsHelpers::functionBoundaries($phpcsFile, $stackPtr); if ($functionStart < 0 || $functionEnd <= 0) { return; } - $returnData = PhpcsHelpers::returnsCountInfo($file, $position); + $returnData = PhpcsHelpers::returnsCountInfo($phpcsFile, $stackPtr); $nonVoidReturnCount = $returnData['nonEmpty']; $voidReturnCount = $returnData['void']; $nullReturnsCount = $returnData['null']; @@ -54,18 +46,22 @@ public function process(File $file, $position) // Allow a filter to return null on purpose $nonVoidReturnCount += $nullReturnsCount; - $isFilterClosure = PhpcsHelpers::isHookClosure($file, $position, true, false); + $isFilterClosure = PhpcsHelpers::isHookClosure($phpcsFile, $stackPtr, true, false); if ($isFilterClosure && (!$nonVoidReturnCount || $voidReturnCount)) { - $file->addError( + $phpcsFile->addError( 'No (or void) return from filter closure.', - $position, + $stackPtr, 'NoReturnFromFilter' ); } if (!$isFilterClosure && $nonVoidReturnCount) { - $file->addError('Return value from action closure.', $position, 'ReturnFromAction'); + $phpcsFile->addError( + 'Return value from action closure.', + $stackPtr, + 'ReturnFromAction' + ); } } } diff --git a/Inpsyde/Sniffs/CodeQuality/LineLengthSniff.php b/Inpsyde/Sniffs/CodeQuality/LineLengthSniff.php index 7027bee..0473033 100644 --- a/Inpsyde/Sniffs/CodeQuality/LineLengthSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/LineLengthSniff.php @@ -10,7 +10,7 @@ class LineLengthSniff implements Sniff { - const I18N_FUNCTIONS = [ + public const I18N_FUNCTIONS = [ '__', '_e', '_x', @@ -29,58 +29,47 @@ class LineLengthSniff implements Sniff /** * The limit that the length of a line should not exceed. - * - * @var integer */ - public $lineLimit = 100; + public int $lineLimit = 100; /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_OPEN_TAG]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return int * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): int { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - $longLinesData = $this->collectLongLinesData($file, max(1, $position)); + $longLinesData = $this->collectLongLinesData($phpcsFile, max(1, $stackPtr)); if (!$longLinesData) { - return $file->numTokens + 1; + return $phpcsFile->numTokens + 1; } - foreach ($longLinesData as $lineNum => list($length, $position)) { - $file->addWarning( + foreach ($longLinesData as $lineNum => [$length, $stackPtr]) { + $phpcsFile->addWarning( sprintf( 'Line %d exceeds %s characters; contains %s characters.', $lineNum, $this->lineLimit, $length ), - $position, + $stackPtr, 'TooLong' ); } - // phpcs:enable - return $file->numTokens + 1; + return $phpcsFile->numTokens + 1; } /** @@ -93,31 +82,27 @@ private function collectLongLinesData(File $file, int $start): array /** @var array> $tokens */ $tokens = $file->getTokens(); - /** @var array< - * int, - * array{length:int, nonEmptyLength:int, start:int, end:int|null} - * > $linesData - */ - $linesData = []; + /** @var array $data */ + $data = []; /** @var int|null $lastLine */ $lastLine = null; for ($i = $start; $i < $file->numTokens; $i++) { // Still processing previous line: increment length and continue. if ($lastLine && ($tokens[$i]['line'] === $lastLine)) { $content = (string)$tokens[$i]['content']; - $linesData[$lastLine]['length'] += strlen($content); - $linesData[$lastLine]['nonEmptyLength'] += strlen(trim($content)); + $data[$lastLine]['length'] += strlen($content); + $data[$lastLine]['nonEmptyLength'] += strlen(trim($content)); continue; } // A new line started: let's set "end" for the previous line (if this isn't 1st line) - if ($lastLine && isset($linesData[$lastLine])) { - $linesData[$lastLine]['end'] = $i - 1; + if ($lastLine && isset($data[$lastLine])) { + $data[$lastLine]['end'] = $i - 1; } $lastLine = (int)$tokens[$i]['line']; $content = (string)$tokens[$i]['content']; - $linesData[$lastLine] = [ + $data[$lastLine] = [ 'length' => strlen($content), 'nonEmptyLength' => strlen(trim($content)), 'start' => $i, @@ -126,12 +111,12 @@ private function collectLongLinesData(File $file, int $start): array } // We still have to set the "end" for last file line. - if ($lastLine && ($linesData[$lastLine]['end'] === null)) { - $linesData[$lastLine]['end'] = $i - 1; + if ($lastLine && ($data[$lastLine]['end'] === null)) { + $data[$lastLine]['end'] = $i - 1; } $longLines = []; - foreach ($linesData as $lineNumber => $lineData) { + foreach ($data as $lineNumber => $lineData) { $lineEnd = $lineData['end'] ?? $lineData['start']; if ( (($lineData['length'] - $this->lineLimit) <= 1) // 1 char of tolerance @@ -228,7 +213,7 @@ private function isLongHtmlAttribute( } // Instead of counting single _word_ length we will count single _attribute_ length - preg_match_all('~[^\s]+\s*=\s*["\'][^"\']*["\']~', $content, $matches); + preg_match_all('~\S+\s*=\s*["\'][^"\']*["\']~', $content, $matches); /** @var non-empty-array $matches */ $attributesNumber = count($matches[0]); diff --git a/Inpsyde/Sniffs/CodeQuality/NestingLevelSniff.php b/Inpsyde/Sniffs/CodeQuality/NestingLevelSniff.php index 23ca2dd..9e386c7 100644 --- a/Inpsyde/Sniffs/CodeQuality/NestingLevelSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/NestingLevelSniff.php @@ -9,60 +9,41 @@ class NestingLevelSniff implements Sniff { - /** - * @var mixed - */ - public $warningLimit = 3; - - /** - * @var mixed - */ - public $errorLimit = 5; - - /** - * @var mixed - */ - public $ignoreTopLevelTryBlock = true; + public int $warningLimit = 3; + public int $errorLimit = 5; + public bool $ignoreTopLevelTryBlock = true; /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_FUNCTION]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration /** @var array> $tokens */ - $tokens = $file->getTokens(); + $tokens = $phpcsFile->getTokens(); // Ignore abstract methods. - if (isset($tokens[$position]['scope_opener']) === false) { + if (isset($tokens[$stackPtr]['scope_opener']) === false) { return; } - $start = (int)$tokens[$position]['scope_opener']; - $end = (int)$tokens[$position]['scope_closer']; + $start = (int)$tokens[$stackPtr]['scope_opener']; + $end = (int)$tokens[$stackPtr]['scope_closer']; - $baseLevel = (int)$tokens[$position]['level']; + $baseLevel = (int)$tokens[$stackPtr]['level']; $nestingLevel = 0; $inTry = false; $endTry = null; @@ -90,7 +71,7 @@ public function process(File $file, $position) && ($tokens[$i]['code'] === T_CATCH || $tokens[$i]['code'] === T_FINALLY) && $level === $tryTargetLevel ) { - $endTry = $this->endOfTryBlock($i, $file); + $endTry = $this->endOfTryBlock($i, $phpcsFile); continue; } @@ -106,16 +87,16 @@ public function process(File $file, $position) // We subtract the nesting level of the function itself . $nestingLevel -= ($baseLevel + 1); - $this->maybeTrigger($nestingLevel, $file, $position); + $this->maybeTrigger($nestingLevel, $phpcsFile, $stackPtr); } /** * @param int $nestingLevel - * @param File $file + * @param File $phpcsFile * @param int $stackPtr * @return void */ - private function maybeTrigger(int $nestingLevel, File $phpcsFile, int $stackPtr) + private function maybeTrigger(int $nestingLevel, File $phpcsFile, int $stackPtr): void { $isError = $nestingLevel >= $this->errorLimit; $isWarning = !$isError && ($nestingLevel >= $this->warningLimit); diff --git a/Inpsyde/Sniffs/CodeQuality/NoAccessorsSniff.php b/Inpsyde/Sniffs/CodeQuality/NoAccessorsSniff.php index 2123903..b7e93f5 100644 --- a/Inpsyde/Sniffs/CodeQuality/NoAccessorsSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/NoAccessorsSniff.php @@ -11,66 +11,51 @@ class NoAccessorsSniff implements Sniff { - const ALLOWED_NAMES = [ + public const ALLOWED_NAMES = [ 'getIterator', 'getInnerIterator', 'getChildren', 'setUp', ]; - /** - * @var bool - */ - public $skipForPrivate = true; + public bool $skipForPrivate = true; + public bool $skipForProtected = false; /** - * @var bool + * @return list */ - public $skipForProtected = false; - - /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration - */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_FUNCTION]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration * phpcs:disable Inpsyde.CodeQuality.FunctionLength * phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration // phpcs:enable Inpsyde.CodeQuality.FunctionLength - if (!PhpcsHelpers::functionIsMethod($file, $position)) { + if (!PhpcsHelpers::functionIsMethod($phpcsFile, $stackPtr)) { return; } - $functionName = $file->getDeclarationName($position); + $functionName = $phpcsFile->getDeclarationName($stackPtr); if (!$functionName || in_array($functionName, self::ALLOWED_NAMES, true)) { return; } if ($this->skipForPrivate || $this->skipForProtected) { - $modifierPointerPosition = $file->findPrevious( + $modifierPointerPosition = $phpcsFile->findPrevious( [T_WHITESPACE, T_ABSTRACT], - $position - 1, + $stackPtr - 1, null, true, null, @@ -78,7 +63,7 @@ public function process(File $file, $position) ); /** @var array> $tokens */ - $tokens = $file->getTokens(); + $tokens = $phpcsFile->getTokens(); $modifierPointer = $tokens[$modifierPointerPosition] ?? null; if ( $modifierPointer @@ -102,22 +87,22 @@ public function process(File $file, $position) } if ($matches[1] === 'set') { - $file->addWarning( + $phpcsFile->addWarning( 'Setters are discouraged. Try to use immutable objects, constructor injection ' . 'and for objects that really needs changing state try behavior naming instead, ' . 'e.g. changeName() instead of setName().', - $position, + $stackPtr, 'NoSetter' ); return; } - $file->addWarning( + $phpcsFile->addWarning( 'Getters are discouraged. "Tell Don\'t Ask" principle should be applied if possible, ' . 'and if getters are really needed consider naming methods after properties, ' . 'e.g. id() instead of getId().', - $position, + $stackPtr, 'NoGetter' ); } diff --git a/Inpsyde/Sniffs/CodeQuality/NoElseSniff.php b/Inpsyde/Sniffs/CodeQuality/NoElseSniff.php index ca5ae8c..83cb06a 100644 --- a/Inpsyde/Sniffs/CodeQuality/NoElseSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/NoElseSniff.php @@ -10,35 +10,27 @@ class NoElseSniff implements Sniff { /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_ELSE]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - $file->addWarning( + $phpcsFile->addWarning( 'Do not use "else". Prefer early return statement instead.', - $position, + $stackPtr, 'ElseFound' ); } diff --git a/Inpsyde/Sniffs/CodeQuality/NoTopLevelDefineSniff.php b/Inpsyde/Sniffs/CodeQuality/NoTopLevelDefineSniff.php index 9d33ed7..760bc01 100644 --- a/Inpsyde/Sniffs/CodeQuality/NoTopLevelDefineSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/NoTopLevelDefineSniff.php @@ -11,46 +11,38 @@ class NoTopLevelDefineSniff implements Sniff { /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_STRING]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration /** @var array> $tokens */ - $tokens = $file->getTokens(); + $tokens = $phpcsFile->getTokens(); if ( - ($tokens[$position]['content'] ?? '') !== 'define' - || ($tokens[$position]['level'] ?? -1) !== 0 - || !PhpcsHelpers::looksLikeFunctionCall($file, $position) + ($tokens[$stackPtr]['content'] ?? '') !== 'define' + || ($tokens[$stackPtr]['level'] ?? -1) !== 0 + || !PhpcsHelpers::looksLikeFunctionCall($phpcsFile, $stackPtr) ) { return; } - $file->addWarning( + $phpcsFile->addWarning( 'Do not use "define" for top-level constant definition. Prefer "const" instead.', - $position, + $stackPtr, 'Found' ); } diff --git a/Inpsyde/Sniffs/CodeQuality/PropertyPerClassLimitSniff.php b/Inpsyde/Sniffs/CodeQuality/PropertyPerClassLimitSniff.php index eed812f..79eb2e2 100644 --- a/Inpsyde/Sniffs/CodeQuality/PropertyPerClassLimitSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/PropertyPerClassLimitSniff.php @@ -11,53 +11,38 @@ class PropertyPerClassLimitSniff implements Sniff { - /** - * @var mixed - */ - public $maxCount = 10; + public int $maxCount = 10; /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return array_values(Tokens::$ooScopeTokens); } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - - is_numeric($this->maxCount) or $this->maxCount = 10; - $this->maxCount = (int)$this->maxCount; - - $count = count(PhpcsHelpers::allPropertiesTokenPositions($file, $position)); + $count = count(PhpcsHelpers::allPropertiesTokenPositions($phpcsFile, $stackPtr)); if ($count <= $this->maxCount) { return; } $message = sprintf( '"%s" has too many properties: %d. Can be up to %d properties.', - PhpcsHelpers::tokenTypeName($file, $position), + PhpcsHelpers::tokenTypeName($phpcsFile, $stackPtr), $count, $this->maxCount ); - $file->addWarning($message, $position, 'TooManyProperties'); + $phpcsFile->addWarning($message, $stackPtr, 'TooManyProperties'); } } diff --git a/Inpsyde/Sniffs/CodeQuality/Psr4Sniff.php b/Inpsyde/Sniffs/CodeQuality/Psr4Sniff.php index aaa4ac0..dc7a5b4 100644 --- a/Inpsyde/Sniffs/CodeQuality/Psr4Sniff.php +++ b/Inpsyde/Sniffs/CodeQuality/Psr4Sniff.php @@ -10,48 +10,33 @@ class Psr4Sniff implements Sniff { - /** - * @var mixed - */ - public $psr4; + public array $psr4 = []; + public array $exclude = []; /** - * @var mixed + * @return list */ - public $exclude = []; - - /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration - */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_CLASS, T_INTERFACE, T_TRAIT]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - $className = (string)$file->getDeclarationName($position); + $className = (string)$phpcsFile->getDeclarationName($stackPtr); /** @var array> $tokens */ - $tokens = $file->getTokens(); - $code = $tokens[$position]['code']; + $tokens = $phpcsFile->getTokens(); + $code = $tokens[$stackPtr]['code']; $entityType = 'class'; if ($code !== T_CLASS) { $entityType = $code === T_TRAIT ? 'trait' : 'interface'; @@ -59,13 +44,13 @@ public function process(File $file, $position) $this->normalizeExcluded(); - if (!$this->psr4 || !is_array($this->psr4)) { - $this->checkFilenameOnly($file, $position, $className, $entityType); + if (!$this->psr4) { + $this->checkFilenameOnly($phpcsFile, $stackPtr, $className, $entityType); return; } - $this->checkPsr4($file, $position, $className, $entityType); + $this->checkPsr4($phpcsFile, $stackPtr, $className, $entityType); } /** @@ -104,7 +89,7 @@ private function checkFilenameOnly( */ private function checkPsr4(File $file, int $position, string $className, string $entityType) { - list(, $namespace) = PhpcsHelpers::findNamespace($file, $position); + [, $namespace] = PhpcsHelpers::findNamespace($file, $position); $namespace = is_string($namespace) ? "{$namespace}\\" : ''; $namespace = rtrim($namespace, '\\'); @@ -155,6 +140,14 @@ private function checkPsr4(File $file, int $position, string $className, string ); } + /** + * @param string $filePath + * @param string $baseNamespace + * @param string $namespace + * @param string $className + * @param string ...$folders + * @return bool + */ private function checkPsr4Folders( string $filePath, string $baseNamespace, @@ -193,14 +186,9 @@ private function checkPsr4Folders( * @return void * @psalm-assert array $this->exclude */ - private function normalizeExcluded() + private function normalizeExcluded(): void { $excluded = $this->exclude; - if (!$excluded || !is_array($excluded)) { - $this->exclude = []; - - return; - } $this->exclude = []; foreach ($excluded as $className) { diff --git a/Inpsyde/Sniffs/CodeQuality/ReturnTypeDeclarationSniff.php b/Inpsyde/Sniffs/CodeQuality/ReturnTypeDeclarationSniff.php index 44561e3..33d1c6c 100644 --- a/Inpsyde/Sniffs/CodeQuality/ReturnTypeDeclarationSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/ReturnTypeDeclarationSniff.php @@ -10,14 +10,14 @@ class ReturnTypeDeclarationSniff implements Sniff { - const TYPE_CODES = [ + public const TYPE_CODES = [ T_STRING, T_ARRAY_HINT, T_CALLABLE, T_SELF, ]; - const METHODS_WHITELIST = [ + public const METHODS_WHITELIST = [ 'serialize', 'jsonSerialize', 'getIterator', @@ -30,63 +30,59 @@ class ReturnTypeDeclarationSniff implements Sniff ]; /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality - return [T_FUNCTION, T_CLOSURE]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * - * phpcs:disable Inpsyde.CodeQuality + * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { - // phpcs:enable Inpsyde.CodeQuality + // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration if ( - PhpcsHelpers::functionIsArrayAccess($file, $position) - || PhpcsHelpers::isUntypedPsrMethod($file, $position) + PhpcsHelpers::functionIsArrayAccess($phpcsFile, $stackPtr) + || PhpcsHelpers::isUntypedPsrMethod($phpcsFile, $stackPtr) ) { return; } - list($functionStart, $functionEnd) = PhpcsHelpers::functionBoundaries($file, $position); + [$functionStart, $functionEnd] = PhpcsHelpers::functionBoundaries($phpcsFile, $stackPtr); if (($functionStart < 0) || ($functionEnd <= 0)) { return; } - list( + [ $hasNonVoidReturnType, $hasVoidReturnType, $hasNoReturnType, $hasNullableReturn, $returnsGenerator - ) = $this->returnTypeInfo($file, $position); + ] = $this->returnTypeInfo($phpcsFile, $stackPtr); - $returnData = PhpcsHelpers::returnsCountInfo($file, $position); + $returnData = PhpcsHelpers::returnsCountInfo($phpcsFile, $stackPtr); $nonVoidReturnCount = $returnData['nonEmpty']; $voidReturnCount = $returnData['void']; $nullReturnCount = $returnData['null']; - $yieldCount = $this->countYield($functionStart, $functionEnd, $file); + $yieldCount = $this->countYield($functionStart, $functionEnd, $phpcsFile); if ($yieldCount || $returnsGenerator) { $this->maybeGeneratorErrors( $yieldCount, $returnsGenerator, $nonVoidReturnCount, - $file, - $position + $phpcsFile, + $stackPtr ); return; @@ -100,8 +96,8 @@ public function process(File $file, $position) $nonVoidReturnCount, $nullReturnCount, $voidReturnCount, - $file, - $position + $phpcsFile, + $stackPtr ); } @@ -129,7 +125,7 @@ private function maybeErrors( int $voidReturnCount, File $file, int $position - ) { + ): void { $hasNullableReturn ? $nonVoidReturnCount += $nullReturnCount @@ -197,7 +193,7 @@ private function maybeGeneratorErrors( int $nonVoidReturnCount, File $file, int $position - ) { + ): void { if ($nonVoidReturnCount > 1) { $file->addWarning( @@ -287,7 +283,7 @@ private function returnTypeInfo(File $file, int $functionPosition): array return [false, false, true, false, false]; } - $start = (int)((int)($tokens[$functionPosition]['parenthesis_closer']) + 1); + $start = (int)($tokens[$functionPosition]['parenthesis_closer']) + 1; $end = (int)($tokens[$functionPosition]['scope_opener']); $hasNullable = false; for ($i = $start; $i < $end; $i++) { @@ -295,9 +291,6 @@ private function returnTypeInfo(File $file, int $functionPosition): array $hasNullable = true; break; } - if ($tokens[$i]['code'] === T_WHITESPACE) { - continue; - } } $hasNonVoidReturnType = $returnTypeContent !== 'void'; @@ -361,8 +354,7 @@ private function countYield(int $functionStart, int $functionEnd, File $file): i $tokens = $file->getTokens(); for ($i = ($functionStart + 1); $i < $functionEnd; $i++) { if ($tokens[$i]['code'] === T_CLOSURE) { - /** @psalm-suppress LoopInvalidation */ - $i = (int)($tokens[$i]['scope_closer']); + $i = (int)($tokens[$i]['scope_closer'] ?? -1); continue; } if ($tokens[$i]['code'] === T_YIELD || $tokens[$i]['code'] === T_YIELD_FROM) { diff --git a/Inpsyde/Sniffs/CodeQuality/StaticClosureSniff.php b/Inpsyde/Sniffs/CodeQuality/StaticClosureSniff.php index 1945d6c..fe31154 100644 --- a/Inpsyde/Sniffs/CodeQuality/StaticClosureSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/StaticClosureSniff.php @@ -11,38 +11,30 @@ class StaticClosureSniff implements Sniff { /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration + * @return list */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_CLOSURE]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - list($functionStart, $functionEnd) = PhpcsHelpers::functionBoundaries($file, $position); + [$functionStart, $functionEnd] = PhpcsHelpers::functionBoundaries($phpcsFile, $stackPtr); if ($functionStart < 0 || $functionEnd <= 0) { return; } - $isStatic = $file->findPrevious(T_STATIC, $position, $position - 3, false, null, true); + $isStatic = $phpcsFile->findPrevious(T_STATIC, $stackPtr, $stackPtr - 3, false, null, true); if ($isStatic) { return; } @@ -51,7 +43,7 @@ public function process(File $file, $position) $i = $functionStart + 1; /** @var array> $tokens */ - $tokens = $file->getTokens(); + $tokens = $phpcsFile->getTokens(); while (!$thisFound && ($i < $functionEnd)) { $token = $tokens[$i]; $thisFound = ($token['code'] === T_VARIABLE) && ($token['content'] === '$this'); @@ -62,23 +54,23 @@ public function process(File $file, $position) return; } - $boundDoc = PhpcsHelpers::functionDocBlockTag('@bound', $file, $position); + $boundDoc = PhpcsHelpers::functionDocBlockTag('@bound', $phpcsFile, $stackPtr); if ($boundDoc) { return; } - $varDoc = PhpcsHelpers::functionDocBlockTag('@var', $file, $position); + $varDoc = PhpcsHelpers::functionDocBlockTag('@var', $phpcsFile, $stackPtr); foreach ($varDoc as $content) { if (preg_match('~(?:^|\s+)\$this(?:$|\s+)~', $content)) { return; } } - $line = (int)$tokens[$position]['line']; + $line = (int)$tokens[$stackPtr]['line']; $message = sprintf('Closure found at line %d could be static.', $line); - if ($file->addFixableWarning($message, $position, 'PossiblyStaticClosure')) { - $this->fix($position, $file); + if ($phpcsFile->addFixableWarning($message, $stackPtr, 'PossiblyStaticClosure')) { + $this->fix($stackPtr, $phpcsFile); } } diff --git a/Inpsyde/Sniffs/CodeQuality/VariablesNameSniff.php b/Inpsyde/Sniffs/CodeQuality/VariablesNameSniff.php index acfdec1..dbe8502 100644 --- a/Inpsyde/Sniffs/CodeQuality/VariablesNameSniff.php +++ b/Inpsyde/Sniffs/CodeQuality/VariablesNameSniff.php @@ -10,7 +10,7 @@ class VariablesNameSniff implements Sniff { - const GLOBALS = [ + public const GLOBALS = [ '$_GET', '$_POST', '$_REQUEST', @@ -22,7 +22,7 @@ class VariablesNameSniff implements Sniff '$GLOBALS', ]; - const WP_GLOBALS = [ + public const WP_GLOBALS = [ '$current_user', '$is_iphone', '$is_chrome', @@ -46,58 +46,35 @@ class VariablesNameSniff implements Sniff '$interim_login', ]; - /** - * @var mixed - */ - public $checkType = 'camelCase'; - - /** - * @var mixed - */ - public $ignoredNames = []; + public string $checkType = 'camelCase'; + public array $ignoredNames = []; + public bool $ignoreLocalVars = false; + public bool $ignoreProperties = false; /** - * @var mixed + * @return list */ - public $ignoreLocalVars = false; - - /** - * @var mixed - */ - public $ignoreProperties = false; - - /** - * @return array - * - * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration - */ - public function register() + public function register(): array { - // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration - return [T_VARIABLE]; } /** - * @param File $file - * @param int $position + * @param File $phpcsFile + * @param int $stackPtr * @return void * * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration - * phpcs:disable Inpsyde.CodeQuality.ReturnTypeDeclaration */ - public function process(File $file, $position) + public function process(File $phpcsFile, $stackPtr): void { // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration - // phpcs:enable Inpsyde.CodeQuality.ReturnTypeDeclaration $ignored = $this->allIgnored(); /** @var array> $tokens */ - $tokens = $file->getTokens(); - $name = (string)$tokens[$position]['content']; + $tokens = $phpcsFile->getTokens(); + $name = (string)$tokens[$stackPtr]['content']; if ( in_array($name, $ignored, true) @@ -114,7 +91,7 @@ public function process(File $file, $position) return; } - $isProperty = PhpcsHelpers::variableIsProperty($file, $position); + $isProperty = PhpcsHelpers::variableIsProperty($phpcsFile, $stackPtr); if ( ($isProperty && $this->arePropertiesIgnored()) @@ -123,12 +100,12 @@ public function process(File $file, $position) return; } - $file->addWarning( + $phpcsFile->addWarning( sprintf( '"%s" should be used for variable names.', $isCamelCase ? '$camelCase' : '$snake_case' ), - $position, + $stackPtr, $isCamelCase ? 'SnakeCaseVar' : 'CamelCaseVar' ); } @@ -138,10 +115,6 @@ public function process(File $file, $position) */ private function checkType(): string { - if (!is_string($this->checkType)) { - return 'camelCase'; - } - $type = strtolower(trim($this->checkType)); if (in_array($type, ['camelcase', 'snake_case'], true)) { return $type === 'camelcase' ? 'camelCase' : 'snake_case'; @@ -192,17 +165,9 @@ private function checkSnakeCase(string $name): bool */ private function allIgnored(): array { - if (is_string($this->ignoredNames)) { - $this->ignoredNames = explode(',', $this->ignoredNames); - } - - if (!is_array($this->ignoredNames)) { - $this->ignoredNames = []; - } - $ignored = $this->ignoredNames; - /** @var array $normalized */ + /** @var list $normalized */ $normalized = []; foreach ($ignored as $name) { if (is_string($name)) { diff --git a/Inpsyde/ruleset.xml b/Inpsyde/ruleset.xml index afd920b..c70db7a 100644 --- a/Inpsyde/ruleset.xml +++ b/Inpsyde/ruleset.xml @@ -11,7 +11,6 @@ --> - - + - - - - - - warning - - - warning - - - warning - - - warning - - - warning - - - warning - - - warning - - - + - - - - - - - - - - - error - - - error - - - - - - - - - error - - - - - - - - - - - - @@ -119,9 +55,6 @@ - - - + + @@ -161,6 +94,7 @@ + @@ -173,6 +107,8 @@ + + - diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 76b6d6e..d997102 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,22 +1,20 @@ - - - tests/cases/FixturesTest.php - - - tests/cases/PhpcsHelpersTest.php - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd" + bootstrap="tests/bootstrap.php" + colors="true"> + + + ./Inpsyde + + + + + tests/cases/FixturesTest.php + + + tests/cases/PhpcsHelpersTest.php + + diff --git a/psalm.xml b/psalm.xml index ee09b08..53e46c1 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,11 +1,14 @@ - - - diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 878abe6..6fd220d 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,5 +1,6 @@ -parse($fixtureFile); + [$sniffClass, $expected, $properties] = $parser->parse($fixtureFile); $file = $this->createPhpcsForFixture($sniffClass, $fixtureFile, $properties); $actual = (new SniffMessagesExtractor($file))->extractMessages(); @@ -105,7 +103,7 @@ private function validateCodes( SniffMessages $actual, string $fixture, string $sniffClass - ) { + ): void { $where = sprintf("\nin fixture file '%s' line %%d\nfor sniff '%s'", $fixture, $sniffClass); @@ -136,7 +134,7 @@ private function validateCode( string $code, string $where, string $actualCode = null - ) { + ): void { $message = $code ? sprintf('Expected %s code \'%s\' was not found', $type, $code) @@ -158,7 +156,7 @@ private function validateTotals( SniffMessages $actual, string $fixtureFile, string $sniffClass - ) { + ): void { $expectedTotal = $expected->total(); $actualTotal = $actual->total(); @@ -195,21 +193,20 @@ private function createPhpcsForFixture( array $properties ): File { - $sniffName = str_replace('.', DIRECTORY_SEPARATOR, $sniffName) . 'Sniff'; - $sniffFile = getenv('SNIFFS_PATH') . DIRECTORY_SEPARATOR . "{$sniffName}.php"; - if (!file_exists($sniffFile) || !is_readable($sniffFile)) { - throw new Exception("Non-existent of unreadable sniff file '$sniffFile' found."); + $sniffFile = str_replace('.', '/', "{$sniffName}Sniff"); + $sniffPath = getenv('SNIFFS_PATH') . "/{$sniffFile}.php"; + if (!file_exists($sniffPath) || !is_readable($sniffPath)) { + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + throw new Exception("Non-existent of unreadable sniff file '{$sniffPath}' found."); } $config = new Config(); - $config->standards = []; - /** @var Ruleset $ruleset */ - $ruleset = (new \ReflectionClass(Ruleset::class))->newInstanceWithoutConstructor(); - $ruleset->registerSniffs([$sniffFile], [], []); - $ruleset->populateTokenListeners(); + $config->standards = [dirname(getenv('SNIFFS_PATH'))]; + $config->sniffs = ["Inpsyde.{$sniffName}"]; + $ruleset = new Ruleset($config); $baseSniffNamespace = getenv('SNIFFS_NAMESPACE'); - $sniffFqn = str_replace(DIRECTORY_SEPARATOR, '\\', $sniffName); + $sniffFqn = str_replace('/', '\\', $sniffFile); foreach ($properties as $name => $value) { $ruleset->setSniffProperty("{$baseSniffNamespace}\\{$sniffFqn}", $name, $value); } diff --git a/tests/cases/PhpcsHelpersTest.php b/tests/cases/PhpcsHelpersTest.php index d94b1e3..bbdc19e 100644 --- a/tests/cases/PhpcsHelpersTest.php +++ b/tests/cases/PhpcsHelpersTest.php @@ -1,5 +1,14 @@ readFile($fixturePath) as $lineNum => $line) { $this->readLine($lineNum, $line, $accumulator); } - // phpcs:enable return $this->processResults($accumulator, $fixturePath); } /** - * @param \stdClass $accumulator + * @param object $accumulator * @param string $fixturePath * @return array */ - private function processResults(\stdClass $accumulator, string $fixturePath): array + private function processResults(object $accumulator, string $fixturePath): array { - $results = [ - $accumulator->sniff, - $accumulator->messages, - $accumulator->warnings, - $accumulator->errors, - $accumulator->properties->values, - ]; - if (!$accumulator->process->content) { return [ - $this->checkSniffName(array_shift($results)), - new SniffMessages($results[1], $results[2], $results[0]), + $this->checkSniffName($accumulator->sniff), + new SniffMessages( + $accumulator->warnings, + $accumulator->errors, + $accumulator->messages + ), $accumulator->properties->values, ]; } // phpcs:disable eval("\$cb = {$accumulator->process->content};"); - /** @var callable $cb */ - $results = $cb(...$results); + $params = [ + $accumulator->sniff, + $accumulator->messages, + $accumulator->warnings, + $accumulator->errors, + $accumulator->properties->values, + ]; + /** @var mixed $cb */ + $results = is_callable($cb) ? $cb(...$params) : null; // phpcs:enable + $results = array_values(array_pad(is_array($results) ? $results : [], 5, null)); + [$sniff, $messages, $warnings, $errors, $properties] = $results; + if ( - $accumulator->process->content - && !is_array($results) - || count($results) !== 5 - || !is_string($results[0] ?? null) - || !is_array($results[1] ?? null) - || !is_array($results[2] ?? null) - || !is_array($results[3] ?? null) - || !is_array($results[4] ?? null) + !is_string($sniff) + || !is_array($messages) + || !is_array($warnings) + || !is_array($errors) + || !is_array($properties) ) { - throw new Exception( + throw new \Error( sprintf( "Process callback for fixture '%s' (lines #%s:#%s) returned invalid output.", $fixturePath, @@ -114,9 +112,9 @@ private function processResults(\stdClass $accumulator, string $fixturePath): ar } return [ - $this->checkSniffName(array_shift($results)), - new SniffMessages($results[1], $results[2], $results[0]), - $results[3], + $this->checkSniffName($sniff), + new SniffMessages($warnings, $errors, $messages), + $properties, ]; } @@ -124,10 +122,10 @@ private function processResults(\stdClass $accumulator, string $fixturePath): ar * @param string|null $sniff * @return string */ - private function checkSniffName(string $sniff = null): string + private function checkSniffName(?string $sniff): string { if ($sniff === null) { - throw new Exception("No sniff class found for the test."); + throw new \Error("No sniff class found for the test."); } static $regex; @@ -137,7 +135,7 @@ private function checkSniffName(string $sniff = null): string } if (!preg_match('~^' . $regex . '$~', $sniff)) { - throw new Exception("Invalid sniff name '{$sniff}'."); + throw new \Error("Invalid sniff name '{$sniff}'."); } return $sniff; @@ -150,6 +148,10 @@ private function checkSniffName(string $sniff = null): string private function readFile(string $file): \Generator { $handle = fopen($file, 'rb'); + if ($handle === false) { + throw new \Error("Could not open '{$file}' for reading."); + } + $lineNum = 1; $line = fgets($handle); @@ -164,9 +166,9 @@ private function readFile(string $file): \Generator /** * @param int $lineNum * @param string $line - * @param \stdClass $accumulator + * @param object $accumulator */ - private function readLine(int $lineNum, string $line, \stdClass $accumulator) + private function readLine(int $lineNum, string $line, object $accumulator): void { if ( !$this->readProcessLine($lineNum, $line, $accumulator) @@ -180,10 +182,10 @@ private function readLine(int $lineNum, string $line, \stdClass $accumulator) /** * @param int $lineNum * @param string $line - * @param \stdClass $accumulator + * @param object $accumulator * @return bool */ - private function readProcessLine(int $lineNum, string $line, \stdClass $accumulator): bool + private function readProcessLine(int $lineNum, string $line, object $accumulator): bool { if ($accumulator->process->end !== false) { return false; @@ -209,10 +211,10 @@ private function readProcessLine(int $lineNum, string $line, \stdClass $accumula /** * @param string $line - * @param \stdClass $accumulator + * @param object $accumulator * @return bool */ - private function readSniffLine(string $line, \stdClass $accumulator): bool + private function readSniffLine(string $line, object $accumulator): bool { if ($accumulator->sniff) { return false; @@ -234,10 +236,10 @@ private function readSniffLine(string $line, \stdClass $accumulator): bool /** * @param int $lineNum * @param string $line - * @param \stdClass $accumulator + * @param object $accumulator * @return bool */ - private function readPropertiesLine(int $lineNum, string $line, \stdClass $accumulator): bool + private function readPropertiesLine(int $lineNum, string $line, object $accumulator): bool { static $pattern; $pattern or $pattern = '~\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\s*=\s*([^;]+);~'; @@ -270,9 +272,9 @@ private function readPropertiesLine(int $lineNum, string $line, \stdClass $accum /** * @param int $lineNum * @param string $line - * @param \stdClass $accumulator + * @param object $accumulator */ - private function readTokenLine(int $lineNum, string $line, \stdClass $accumulator) + private function readTokenLine(int $lineNum, string $line, object $accumulator): void { static $pattern; if (!$pattern) { diff --git a/tests/src/SniffMessages.php b/tests/src/SniffMessages.php index c5aa846..339b8f5 100644 --- a/tests/src/SniffMessages.php +++ b/tests/src/SniffMessages.php @@ -1,9 +1,6 @@ messagesContainTotal = true; } @@ -69,7 +53,7 @@ public function messages(): array * @param int $line * @return string|null */ - public function messageIn(int $line) + public function messageIn(int $line): ?string { return $this->messages[$line] ?? null; } @@ -99,7 +83,7 @@ public function errors(): array * @param int $line * @return string|null */ - public function errorIn(int $line) + public function errorIn(int $line): ?string { return $this->errors[$line] ?? null; } @@ -124,7 +108,7 @@ public function warnings(): array * @param int $line * @return string|null */ - public function warningIn(int $line) + public function warningIn(int $line): ?string { return $this->warnings[$line] ?? null; } diff --git a/tests/src/SniffMessagesExtractor.php b/tests/src/SniffMessagesExtractor.php index 6f8f8b7..1f98b27 100644 --- a/tests/src/SniffMessagesExtractor.php +++ b/tests/src/SniffMessagesExtractor.php @@ -1,9 +1,6 @@ file->process(); - list($warnings, $errors) = $this->normalize( + [$warnings, $errors] = $this->normalize( $this->file->getWarnings(), $this->file->getErrors() );