Skip to content

Commit

Permalink
Merge pull request #586 from PHPCSStandards/develop
Browse files Browse the repository at this point in the history
Release 1.0.11
  • Loading branch information
jrfnl authored Apr 24, 2024
2 parents f627b49 + d7667db commit c457da9
Show file tree
Hide file tree
Showing 21 changed files with 579 additions and 64 deletions.
26 changes: 10 additions & 16 deletions .github/workflows/basics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,15 @@ jobs:
# Bust the cache at least once a month - output format: YYYY-MM.
custom-cache-suffix: $(date -u "+%Y-%m")

# Updating the lists can fail intermittently, typically after Microsoft has released a new package.
# This should not be blocking for this job, so ignore any errors from this step.
# Ref: https://github.com/dotnet/core/issues/4167
- name: Update the available packages list
continue-on-error: true
run: sudo apt-get update

- name: Install xmllint
run: |
sudo apt-get update
sudo apt-get install --no-install-recommends -y libxml2-utils
run: sudo apt-get install --no-install-recommends -y libxml2-utils

# Show XML violations inline in the file diff.
# @link https://github.com/marketplace/actions/xmllint-problem-matcher
Expand Down Expand Up @@ -118,24 +123,13 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

# This action also handles the caching of the dependencies.
# https://github.com/actions/setup-node
- name: Set up node and enable caching of dependencies
uses: actions/setup-node@v4
with:
node-version: '16'

# @link https://github.com/DavidAnson/markdownlint-cli2
# @link https://github.com/DavidAnson/markdownlint
- name: Install Markdownlint CLI2
run: npm install -g markdownlint-cli2

# @link https://github.com/marketplace/actions/problem-matcher-for-markdownlint-cli
- name: Enable showing issue in PRs
uses: xt0rted/markdownlint-problem-matcher@v3

# @link https://github.com/marketplace/actions/markdownlint-cli2-action
- name: Check markdown with CLI2
run: markdownlint-cli2
uses: DavidAnson/markdownlint-cli2-action@v16

remark:
name: 'QA Markdown'
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/quicktest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ jobs:
if: ${{ matrix.phpcs_version != 'lowest' }}
run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts --no-interaction

- name: "Composer: use lock file when necessary"
if: ${{ matrix.phpcs_version == 'lowest' }}
run: composer config --unset lock

# Install dependencies and handle caching in one go.
# @link https://github.com/marketplace/actions/install-php-dependencies-with-composer
- name: Install Composer dependencies
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ jobs:
- name: 'Composer: remove PHPCSDevCS'
run: composer remove --dev --no-update phpcsstandards/phpcsdevcs

- name: "Composer: use lock file when necessary"
if: ${{ matrix.phpcs_version == 'lowest' }}
run: composer config --unset lock

# Install dependencies and handle caching in one go.
# @link https://github.com/marketplace/actions/install-php-dependencies-with-composer
- name: Install Composer dependencies - normal
Expand Down Expand Up @@ -308,6 +312,10 @@ jobs:
if: ${{ matrix.phpcs_version != 'lowest' }}
run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts --no-interaction

- name: "Composer: use lock file when necessary"
if: ${{ matrix.phpcs_version == 'lowest' }}
run: composer config --unset lock

- name: Install Composer dependencies
uses: "ramsey/composer-install@v3"
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ jobs:
retention-days: 5

- name: Setup GH Pages
uses: actions/configure-pages@v4
uses: actions/configure-pages@v5

- name: Build the GH Pages site with Jekyll
uses: actions/jekyll-build-pages@v1
Expand Down
26 changes: 24 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,27 @@ This projects adheres to [Keep a CHANGELOG](https://keepachangelog.com/) and use

_Nothing yet._

## [1.0.11] - 2024-04-24

### Changed

#### Other

* Various housekeeping and documentation improvements. Includes a contribution from [@fredden].

### Fixed

#### PHPCS BackCompat

* `BCFile::getMethodProperties()`: small performance improvement & more defensive coding, in line with same fix in PHPCS 3.9.2. [#573]

#### Utils

* `FunctionDeclarations::getProperties()`: small performance improvement & more defensive coding, in line with same fix in PHPCS 3.9.2. [#573]

[#573]: https://github.com/PHPCSStandards/PHPCSUtils/pull/573


## [1.0.10] - 2024-03-18

### Changed
Expand Down Expand Up @@ -477,7 +498,7 @@ Please report any bugs/oversights you encounter!
All properties have a replacement which should be used instead, in most cases this will be a method with the same name as the previously used property,

| Deprecated | Replacement | PR | Remarks |
|---------------------------------------------------------------|------------------------------------------------------------------------------------------------------|----------------|------------------------------------------|
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | -------------- | ---------------------------------------- |
| `Collections::$alternativeControlStructureSyntaxTokens` | `Collections::alternativeControlStructureSyntaxes()` | [#311] | Mind the change in the name! |
| `Collections::$alternativeControlStructureSyntaxCloserTokens` | `Collections::alternativeControlStructureSyntaxClosers()` | [#311] | Mind the change in the name! |
| `Collections::$arrayTokens` | `Collections::arrayTokens()` | [#311] | |
Expand Down Expand Up @@ -510,7 +531,7 @@ All properties have a replacement which should be used instead, in most cases th
Additionally, the following methods in the `Collections` class have been deprecated:

| Deprecated | Replacement | PR |
|----------------------------------------------|--------------------------------------------|--------|
| -------------------------------------------- | ------------------------------------------ | ------ |
| `Collections::arrowFunctionTokensBC()` | Use the `T_FN` token instead. | [#347] |
| `Collections::functionDeclarationTokensBC()` | `Collections::functionDeclarationTokens()` | [#347] |
| `Collections::parameterTypeTokensBC()` | `Collections::parameterTypeTokens()` | [#347] |
Expand Down Expand Up @@ -984,6 +1005,7 @@ This initial alpha release contains the following utility classes:


[Unreleased]: https://github.com/PHPCSStandards/PHPCSUtils/compare/stable...HEAD
[1.0.11]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.10...1.0.11
[1.0.10]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.9...1.0.10
[1.0.9]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.8...1.0.9
[1.0.8]: https://github.com/PHPCSStandards/PHPCSUtils/compare/1.0.7...1.0.8
Expand Down
144 changes: 142 additions & 2 deletions PHPCSUtils/BackCompat/BCFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
*
* Changelog for the PHPCS native function:
* - Introduced in PHPCS 0.0.5.
* - The upstream method has received no significant updates since PHPCS 3.9.0.
* - PHPCS 3.9.2: skip over closure use statements. PHPCS #421.
*
* @see \PHP_CodeSniffer\Files\File::getMethodProperties() Original source.
* @see \PHPCSUtils\Utils\FunctionDeclarations::getProperties() PHPCSUtils native improved version.
Expand All @@ -480,7 +480,147 @@ public static function getMethodParameters(File $phpcsFile, $stackPtr)
*/
public static function getMethodProperties(File $phpcsFile, $stackPtr)
{
return $phpcsFile->getMethodProperties($stackPtr);
$tokens = $phpcsFile->getTokens();

if ($tokens[$stackPtr]['code'] !== T_FUNCTION
&& $tokens[$stackPtr]['code'] !== T_CLOSURE
&& $tokens[$stackPtr]['code'] !== T_FN
) {
throw new RuntimeException('$stackPtr must be of type T_FUNCTION or T_CLOSURE or T_FN');
}

if ($tokens[$stackPtr]['code'] === T_FUNCTION) {
$valid = [
T_PUBLIC => T_PUBLIC,
T_PRIVATE => T_PRIVATE,
T_PROTECTED => T_PROTECTED,
T_STATIC => T_STATIC,
T_FINAL => T_FINAL,
T_ABSTRACT => T_ABSTRACT,
T_WHITESPACE => T_WHITESPACE,
T_COMMENT => T_COMMENT,
T_DOC_COMMENT => T_DOC_COMMENT,
];
} else {
$valid = [
T_STATIC => T_STATIC,
T_WHITESPACE => T_WHITESPACE,
T_COMMENT => T_COMMENT,
T_DOC_COMMENT => T_DOC_COMMENT,
];
}

$scope = 'public';
$scopeSpecified = false;
$isAbstract = false;
$isFinal = false;
$isStatic = false;

for ($i = ($stackPtr - 1); $i > 0; $i--) {
if (isset($valid[$tokens[$i]['code']]) === false) {
break;
}

switch ($tokens[$i]['code']) {
case T_PUBLIC:
$scope = 'public';
$scopeSpecified = true;
break;
case T_PRIVATE:
$scope = 'private';
$scopeSpecified = true;
break;
case T_PROTECTED:
$scope = 'protected';
$scopeSpecified = true;
break;
case T_ABSTRACT:
$isAbstract = true;
break;
case T_FINAL:
$isFinal = true;
break;
case T_STATIC:
$isStatic = true;
break;
}
}

$returnType = '';
$returnTypeToken = false;
$returnTypeEndToken = false;
$nullableReturnType = false;
$hasBody = true;
$returnTypeTokens = Collections::returnTypeTokens();

if (isset($tokens[$stackPtr]['parenthesis_closer']) === true) {
$scopeOpener = null;
if (isset($tokens[$stackPtr]['scope_opener']) === true) {
$scopeOpener = $tokens[$stackPtr]['scope_opener'];
}

for ($i = $tokens[$stackPtr]['parenthesis_closer']; $i < $phpcsFile->numTokens; $i++) {
if (($scopeOpener === null && $tokens[$i]['code'] === T_SEMICOLON)
|| ($scopeOpener !== null && $i === $scopeOpener)
) {
// End of function definition.
break;
}

if ($tokens[$i]['code'] === T_USE) {
// Skip over closure use statements.
for ($j = ($i + 1); $j < $phpcsFile->numTokens && isset(Tokens::$emptyTokens[$tokens[$j]['code']]) === true; $j++);
if ($tokens[$j]['code'] === T_OPEN_PARENTHESIS) {
if (isset($tokens[$j]['parenthesis_closer']) === false) {
// Live coding/parse error, stop parsing.
break;
}

$i = $tokens[$j]['parenthesis_closer'];
continue;
}
}

if ($tokens[$i]['code'] === T_NULLABLE) {
$nullableReturnType = true;
}

if (isset($returnTypeTokens[$tokens[$i]['code']]) === true) {
if ($returnTypeToken === false) {
$returnTypeToken = $i;
}

$returnType .= $tokens[$i]['content'];
$returnTypeEndToken = $i;
}
}

if ($tokens[$stackPtr]['code'] === T_FN) {
$bodyToken = T_FN_ARROW;
} else {
$bodyToken = T_OPEN_CURLY_BRACKET;
}

$end = $phpcsFile->findNext([$bodyToken, T_SEMICOLON], $tokens[$stackPtr]['parenthesis_closer']);
$hasBody = ($end !== false && $tokens[$end]['code'] === $bodyToken);
}

if ($returnType !== '' && $nullableReturnType === true) {
$returnType = '?' . $returnType;
}

return [
'scope' => $scope,
'scope_specified' => $scopeSpecified,
'return_type' => $returnType,
'return_type_token' => $returnTypeToken,
'return_type_end_token' => $returnTypeEndToken,
'nullable_return_type' => $nullableReturnType,
'is_abstract' => $isAbstract,
'is_final' => $isFinal,
'is_static' => $isStatic,
'has_body' => $hasBody,
];
}

/**
Expand Down
19 changes: 19 additions & 0 deletions PHPCSUtils/Utils/FunctionDeclarations.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,25 @@ public static function getProperties(File $phpcsFile, $stackPtr)
break;
}

if ($tokens[$i]['code'] === \T_USE) {
// Skip over closure use statements.
for (
$j = ($i + 1);
$j < $phpcsFile->numTokens && isset(Tokens::$emptyTokens[$tokens[$j]['code']]) === true;
$j++
);

if ($tokens[$j]['code'] === \T_OPEN_PARENTHESIS) {
if (isset($tokens[$j]['parenthesis_closer']) === false) {
// Live coding/parse error, stop parsing.
break;
}

$i = $tokens[$j]['parenthesis_closer'];
continue;
}
}

if ($tokens[$i]['code'] === \T_NULLABLE) {
$nullableReturnType = true;
}
Expand Down
2 changes: 1 addition & 1 deletion PHPCSUtils/Utils/NamingConventions.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,6 @@ public static function isEqual($nameA, $nameB)
}

// Comparing via strcasecmp will only compare ASCII letters case-insensitively.
return (strcasecmp($nameA, $nameB) === 0);
return (\strcasecmp($nameA, $nameB) === 0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

/* testParseError */
// Intentional parse error.
$incompleteUse = function(int $a, string $b = '') use(&$import,
54 changes: 54 additions & 0 deletions Tests/BackCompat/BCFile/GetMethodPropertiesParseError1Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php
/**
* PHPCSUtils, utility functions and classes for PHP_CodeSniffer sniff developers.
*
* @package PHPCSUtils
* @copyright 2019-2020 PHPCSUtils Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCSStandards/PHPCSUtils
*/

namespace PHPCSUtils\Tests\BackCompat\BCFile;

use PHPCSUtils\BackCompat\BCFile;
use PHPCSUtils\TestUtils\UtilityMethodTestCase;
use PHPCSUtils\Tokens\Collections;

/**
* Tests for the \PHPCSUtils\BackCompat\BCFile::getMethodProperties method.
*
* @covers \PHPCSUtils\BackCompat\BCFile::getMethodProperties
*
* @group functiondeclarations
*
* @since 1.0.11
*/
final class GetMethodPropertiesParseError1Test extends UtilityMethodTestCase
{

/**
* Test handling of closure declarations with an incomplete use clause.
*
* @return void
*/
public function testParseError()
{
$target = $this->getTargetToken('/* testParseError */', Collections::functionDeclarationTokens());
$result = BCFile::getMethodProperties(self::$phpcsFile, $target);

$expected = [
'scope' => 'public',
'scope_specified' => false,
'return_type' => '',
'return_type_token' => false,
'return_type_end_token' => false,
'nullable_return_type' => false,
'is_abstract' => false,
'is_final' => false,
'is_static' => false,
'has_body' => false,
];

$this->assertSame($expected, $result);
}
}
Loading

0 comments on commit c457da9

Please sign in to comment.