Skip to content

Commit

Permalink
Merge pull request #1855 from WordPress/develop
Browse files Browse the repository at this point in the history
Release version 2.2.1
  • Loading branch information
jrfnl committed Feb 4, 2020
2 parents f90e869 + 9822816 commit b5a4532
Show file tree
Hide file tree
Showing 16 changed files with 155 additions and 62 deletions.
8 changes: 4 additions & 4 deletions .travis.yml
Expand Up @@ -8,8 +8,7 @@ cache:
# Cache directory for more recent Composer versions.
- $HOME/.cache/composer/files

language:
- php
language: php

php:
- 5.4
Expand All @@ -19,7 +18,8 @@ php:
- 7.1
- 7.2
- 7.3
- "7.4snapshot"
- 7.4
- "nightly"

env:
# `master` is now 3.x.
Expand Down Expand Up @@ -114,7 +114,7 @@ jobs:

allow_failures:
# Allow failures for unstable builds.
- php: "7.4snapshot"
- php: "nightly"

before_install:
# Speed up build time by disabling Xdebug.
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,20 @@ This projects adheres to [Semantic Versioning](https://semver.org/) and [Keep a

_No documentation available about unreleased changes as of yet._

## [2.2.1] - 2020-02-04

### Added
- Metrics to the `WordPress.Arrays.CommaAfterArrayItem` sniff. These can be displayed using `--report=info`.
- The `sanitize_hex_color()` and the `sanitize_hex_color_no_hash()` functions to the `escapingFunctions` list used by the `WordPress.Security.EscapeOutput` sniff.

### Changed
- The recommended version of the suggested DealerDirect PHPCS Composer plugin is now `^0.6`.

### Fixed
- `WordPress.PHP.NoSilencedErrors`: depending on the custom properties set, the metrics would be different.
- `WordPress.WhiteSpace.ControlStructureSpacing`: fixed undefined index notice for closures with `use`.
- `WordPress.WP.GlobalVariablesOverride`: fixed undefined offset notice when the `treat_files_as_scoped` property would be set to `true`.
- `WordPress.WP.I18n`: fixed a _Trying to access array offset on value of type null_ error when the sniff was run on PHP 7.4 and would encounter a translation function expecting singular and plural texts for which one of these arguments was missing.

## [2.2.0] - 2019-11-11

Expand Down Expand Up @@ -1148,6 +1162,7 @@ See the comparison for full list.
Initial tagged release.

[Unreleased]: https://github.com/WordPress/WordPress-Coding-Standards/compare/master...HEAD
[2.2.1]: https://github.com/WordPress/WordPress-Coding-Standards/compare/2.2.0...2.2.1
[2.2.0]: https://github.com/WordPress/WordPress-Coding-Standards/compare/2.1.1...2.2.0
[2.1.1]: https://github.com/WordPress/WordPress-Coding-Standards/compare/2.1.0...2.1.1
[2.1.0]: https://github.com/WordPress/WordPress-Coding-Standards/compare/2.0.0...2.1.0
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -82,7 +82,7 @@ When installing the WordPress Coding Standards as a dependency in a larger proje

There are two actively maintained Composer plugins which can handle the registration of standards with PHP_CodeSniffer for you:
* [composer-phpcodesniffer-standards-plugin](https://github.com/higidi/composer-phpcodesniffer-standards-plugin)
* [phpcodesniffer-composer-installer](https://github.com/DealerDirect/phpcodesniffer-composer-installer):"^0.5.0"
* [phpcodesniffer-composer-installer](https://github.com/DealerDirect/phpcodesniffer-composer-installer):"^0.6"

It is strongly suggested to `require` one of these plugins in your project to handle the registration of external standards with PHPCS for you.

Expand Down
70 changes: 36 additions & 34 deletions WordPress/Sniff.php
Expand Up @@ -132,40 +132,42 @@ abstract class Sniff implements PHPCS_Sniff {
* @var array
*/
protected $escapingFunctions = array(
'absint' => true,
'esc_attr__' => true,
'esc_attr_e' => true,
'esc_attr_x' => true,
'esc_attr' => true,
'esc_html__' => true,
'esc_html_e' => true,
'esc_html_x' => true,
'esc_html' => true,
'esc_js' => true,
'esc_sql' => true,
'esc_textarea' => true,
'esc_url_raw' => true,
'esc_url' => true,
'filter_input' => true,
'filter_var' => true,
'floatval' => true,
'highlight_string' => true,
'intval' => true,
'json_encode' => true,
'like_escape' => true,
'number_format' => true,
'rawurlencode' => true,
'sanitize_html_class' => true,
'sanitize_key' => true,
'sanitize_user_field' => true,
'tag_escape' => true,
'urlencode_deep' => true,
'urlencode' => true,
'wp_json_encode' => true,
'wp_kses_allowed_html' => true,
'wp_kses_data' => true,
'wp_kses_post' => true,
'wp_kses' => true,
'absint' => true,
'esc_attr__' => true,
'esc_attr_e' => true,
'esc_attr_x' => true,
'esc_attr' => true,
'esc_html__' => true,
'esc_html_e' => true,
'esc_html_x' => true,
'esc_html' => true,
'esc_js' => true,
'esc_sql' => true,
'esc_textarea' => true,
'esc_url_raw' => true,
'esc_url' => true,
'filter_input' => true,
'filter_var' => true,
'floatval' => true,
'highlight_string' => true,
'intval' => true,
'json_encode' => true,
'like_escape' => true,
'number_format' => true,
'rawurlencode' => true,
'sanitize_hex_color' => true,
'sanitize_hex_color_no_hash' => true,
'sanitize_html_class' => true,
'sanitize_key' => true,
'sanitize_user_field' => true,
'tag_escape' => true,
'urlencode_deep' => true,
'urlencode' => true,
'wp_json_encode' => true,
'wp_kses_allowed_html' => true,
'wp_kses_data' => true,
'wp_kses_post' => true,
'wp_kses' => true,
);

/**
Expand Down
14 changes: 14 additions & 0 deletions WordPress/Sniffs/Arrays/CommaAfterArrayItemSniff.php
Expand Up @@ -103,6 +103,12 @@ public function process_token( $stackPtr ) {
*/
if ( true === $single_line && $item_index === $array_item_count ) {

$this->phpcsFile->recordMetric(
$stackPtr,
'Single line array - comma after last item',
( true === $is_comma ? 'yes' : 'no' )
);

if ( true === $is_comma ) {
$fix = $this->phpcsFile->addFixableError(
'Comma not allowed after last value in single-line array declaration',
Expand Down Expand Up @@ -153,6 +159,14 @@ public function process_token( $stackPtr ) {
}
}

if ( false === $single_line && $item_index === $array_item_count ) {
$this->phpcsFile->recordMetric(
$stackPtr,
'Multi-line array - comma after last item',
( true === $is_comma ? 'yes' : 'no' )
);
}

if ( false === $is_comma ) {
// Can't check spacing around the comma if there is no comma.
continue;
Expand Down
36 changes: 19 additions & 17 deletions WordPress/Sniffs/PHP/NoSilencedErrorsSniff.php
Expand Up @@ -179,22 +179,24 @@ public function process_token( $stackPtr ) {
$this->custom_whitelist = $this->merge_custom_array( $this->custom_whitelist, array(), false );
$this->custom_whitelist = array_map( 'strtolower', $this->custom_whitelist );

if ( true === $this->use_default_whitelist || ! empty( $this->custom_whitelist ) ) {
/*
* Check if the error silencing is done for one of the whitelisted functions.
*/
$next_non_empty = $this->phpcsFile->findNext( $this->empty_tokens, ( $stackPtr + 1 ), null, true, null, true );
if ( false !== $next_non_empty && \T_STRING === $this->tokens[ $next_non_empty ]['code'] ) {
$has_parenthesis = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $next_non_empty + 1 ), null, true, null, true );
if ( false !== $has_parenthesis && \T_OPEN_PARENTHESIS === $this->tokens[ $has_parenthesis ]['code'] ) {
$function_name = strtolower( $this->tokens[ $next_non_empty ]['content'] );
if ( ( true === $this->use_default_whitelist
&& isset( $this->function_whitelist[ $function_name ] ) === true )
|| in_array( $function_name, $this->custom_whitelist, true ) === true
) {
$this->phpcsFile->recordMetric( $stackPtr, 'Error silencing', 'whitelisted function call: ' . $function_name );
return;
}
/*
* Check if the error silencing is done for one of the whitelisted functions.
*
* @internal The function call name determination is done even when there is no whitelist active
* to allow the metrics to be more informative.
*/
$next_non_empty = $this->phpcsFile->findNext( $this->empty_tokens, ( $stackPtr + 1 ), null, true, null, true );
if ( false !== $next_non_empty && \T_STRING === $this->tokens[ $next_non_empty ]['code'] ) {
$has_parenthesis = $this->phpcsFile->findNext( Tokens::$emptyTokens, ( $next_non_empty + 1 ), null, true, null, true );
if ( false !== $has_parenthesis && \T_OPEN_PARENTHESIS === $this->tokens[ $has_parenthesis ]['code'] ) {
$function_name = strtolower( $this->tokens[ $next_non_empty ]['content'] );
if ( ( true === $this->use_default_whitelist
&& isset( $this->function_whitelist[ $function_name ] ) === true )
|| ( ! empty( $this->custom_whitelist )
&& in_array( $function_name, $this->custom_whitelist, true ) === true )
) {
$this->phpcsFile->recordMetric( $stackPtr, 'Error silencing', 'whitelisted function call: ' . $function_name );
return;
}
}
}
Expand Down Expand Up @@ -228,7 +230,7 @@ public function process_token( $stackPtr ) {
);

if ( isset( $function_name ) ) {
$this->phpcsFile->recordMetric( $stackPtr, 'Error silencing', $function_name );
$this->phpcsFile->recordMetric( $stackPtr, 'Error silencing', '@' . $function_name );
} else {
$this->phpcsFile->recordMetric( $stackPtr, 'Error silencing', $found );
}
Expand Down
2 changes: 1 addition & 1 deletion WordPress/Sniffs/WP/GlobalVariablesOverrideSniff.php
Expand Up @@ -351,7 +351,7 @@ protected function process_global_statement( $stackPtr, $in_function_scope ) {
$end = $this->tokens[ $scope_cond ]['scope_closer'];
} else {
// Global statement in the global namespace with file is being treated as scoped.
$end = ( $this->phpcsFile->numTokens + 1 );
$end = $this->phpcsFile->numTokens;
}

for ( $ptr = $start; $ptr < $end; $ptr++ ) {
Expand Down
12 changes: 10 additions & 2 deletions WordPress/Sniffs/WP/I18nSniff.php
Expand Up @@ -390,8 +390,16 @@ public function process_matched_token( $stack_ptr, $group_name, $matched_content
$this->check_argument_tokens( $argument_assertion_context );
}

// For _n*() calls, compare the singular and plural strings.
if ( false !== strpos( $this->i18n_functions[ $matched_content ], 'number' ) ) {
/*
* For _n*() calls, compare the singular and plural strings.
* If either of the arguments is missing, empty or has more than 1 token, skip out.
* An error for that will already have been reported via the `check_argument_tokens()` method.
*/
if ( false !== strpos( $this->i18n_functions[ $matched_content ], 'number' )
&& isset( $argument_assertions[0]['tokens'], $argument_assertions[1]['tokens'] )
&& count( $argument_assertions[0]['tokens'] ) === 1
&& count( $argument_assertions[1]['tokens'] ) === 1
) {
$single_context = $argument_assertions[0];
$plural_context = $argument_assertions[1];

Expand Down
3 changes: 2 additions & 1 deletion WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php
Expand Up @@ -346,7 +346,8 @@ public function process_token( $stackPtr ) {
if ( \T_WHITESPACE !== $this->tokens[ ( $parenthesisCloser + 1 ) ]['code']
&& ! ( // Do NOT flag : immediately following ) for return types declarations.
\T_COLON === $this->tokens[ ( $parenthesisCloser + 1 ) ]['code']
&& in_array( $this->tokens[ $this->tokens[ $parenthesisCloser ]['parenthesis_owner'] ]['code'], array( \T_FUNCTION, \T_CLOSURE ), true )
&& ( isset( $this->tokens[ $parenthesisCloser ]['parenthesis_owner'] ) === false
|| in_array( $this->tokens[ $this->tokens[ $parenthesisCloser ]['parenthesis_owner'] ]['code'], array( \T_FUNCTION, \T_CLOSURE ), true ) )
)
&& ( isset( $scopeOpener ) && \T_COLON !== $this->tokens[ $scopeOpener ]['code'] )
) {
Expand Down
7 changes: 7 additions & 0 deletions WordPress/Tests/WP/GlobalVariablesOverrideUnitTest.6.inc
@@ -0,0 +1,7 @@
<?php

// phpcs:set WordPress.WP.GlobalVariablesOverride treat_files_as_scoped true

global $post;

// phpcs:set WordPress.WP.GlobalVariablesOverride treat_files_as_scoped false
6 changes: 6 additions & 0 deletions WordPress/Tests/WP/I18nUnitTest.1.inc
Expand Up @@ -177,5 +177,11 @@ $offset_or_tz = _x( '0', 'default GMT offset or timezone string', 'my-slug' );
$test = __( '%1$s %2$s', 'my-slug' ); // OK(ish), placeholder order may change depending on language.
$test = __( ' %s ', 'my-slug' ); // Bad, no translatable content.

// Missing plural argument.
_n_noop($singular); // Bad x 3.

// This test is needed to verify that the missing plural argument above does not cause an internal error, stopping the run.
_n_noop( 'I have %d cat.', 'I have %d cats.' ); // Bad.

// phpcs:set WordPress.WP.I18n text_domain[]
// phpcs:set WordPress.WP.I18n check_translator_comments true
6 changes: 6 additions & 0 deletions WordPress/Tests/WP/I18nUnitTest.1.inc.fixed
Expand Up @@ -177,5 +177,11 @@ $offset_or_tz = _x( '0', 'default GMT offset or timezone string', 'my-slug' );
$test = __( '%1$s %2$s', 'my-slug' ); // OK(ish), placeholder order may change depending on language.
$test = __( ' %s ', 'my-slug' ); // Bad, no translatable content.

// Missing plural argument.
_n_noop($singular); // Bad x 3.

// This test is needed to verify that the missing plural argument above does not cause an internal error, stopping the run.
_n_noop( 'I have %d cat.', 'I have %d cats.' ); // Bad.

// phpcs:set WordPress.WP.I18n text_domain[]
// phpcs:set WordPress.WP.I18n check_translator_comments true
2 changes: 2 additions & 0 deletions WordPress/Tests/WP/I18nUnitTest.php
Expand Up @@ -114,6 +114,8 @@ public function getErrorList( $testFile = '' ) {
153 => 1,
157 => 1,
178 => 1,
181 => 3,
184 => 1,
);

case 'I18nUnitTest.2.inc':
Expand Down
15 changes: 15 additions & 0 deletions WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.1.inc
Expand Up @@ -290,3 +290,18 @@ $returntype = function ( string $input ): string {}; // Ok.
$returntype = function ( string $input ) : string {}; // Ok.
$returntype = function ( string $input, array $inputs ): string {}; // Ok.
$returntype = function ( string $input, array $inputs ) : string {}; // Ok.

// Issue 1792.
$matching_options = array_filter(
$imported_options,
function ( $option ) use ( $option_id ): bool {
return $option['id'] === $option_id;
}
);

$matching_options = array_filter(
$imported_options,
function ( $option ) use ( $option_id ) : bool {
return $option['id'] === $option_id;
}
);
Expand Up @@ -279,3 +279,18 @@ $returntype = function ( string $input ): string {}; // Ok.
$returntype = function ( string $input ) : string {}; // Ok.
$returntype = function ( string $input, array $inputs ): string {}; // Ok.
$returntype = function ( string $input, array $inputs ) : string {}; // Ok.

// Issue 1792.
$matching_options = array_filter(
$imported_options,
function ( $option ) use ( $option_id ): bool {
return $option['id'] === $option_id;
}
);

$matching_options = array_filter(
$imported_options,
function ( $option ) use ( $option_id ) : bool {
return $option['id'] === $option_id;
}
);
4 changes: 2 additions & 2 deletions composer.json
Expand Up @@ -19,12 +19,12 @@
"squizlabs/php_codesniffer": "^3.3.1"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0",
"dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6",
"phpcompatibility/php-compatibility": "^9.0",
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
},
"suggest": {
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
"dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
},
"minimum-stability": "RC",
"scripts": {
Expand Down

0 comments on commit b5a4532

Please sign in to comment.