diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6d64a8bc7b..557b9df281 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,29 @@ This projects adheres to [Semantic Versioning](http://semver.org/) and [Keep a C
`get_category_by_slug()`, `get_cat_ID()`, `count_user_posts()`, and `wp_old_slug_redirect()`
to the list of restricted functions in the `WordPress.VIP.RestrictedFunctions` sniff.
+## [0.7.0] - 2015-08-30
+
+### Added
+- Automatic error fixing to the `WordPress.Arrays.ArrayKeySpacingRestrictions` sniff.
+- Functions and closures to the control structures checked by the `WordPress.WhiteSpace.ControlStructureSpacing`
+sniff.
+- Sniffing and fixing for extra spacing in the `WordPress.WhiteSpace.ControlStructureSpacing`
+sniff. (Previously it only checked for insufficient spacing.)
+- `.twig` files to the default ignored files.
+- `esc_url_raw()` and `hash_equals()` to the list of sanitizing functions.
+- `intval()` and `boolval()` to list of unslashing functions.
+- `do_shortcode()` to the list of auto-escaped functions.
+
+### Removed
+- `WordPress.Functions.FunctionDeclarationArgumentSpacing` in favor of the upstream
+sniff `Squiz.Functions.FunctionDeclarationArgumentSpacing`.
+
+### Fixed
+- Reference to incorrect issue in the inline docs of the `WordPress.VIP.SessionVariableUsage`
+sniff.
+- `WordPress.XSS.EscapeOutput` sniff incorrectly handling ternary conditions in
+`echo` statements without parentheses in some cases.
+
## [0.6.0] - 2015-06-30
### Added
diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml
index f228bd90f3..4a74646b84 100644
--- a/WordPress-Core/ruleset.xml
+++ b/WordPress-Core/ruleset.xml
@@ -72,13 +72,20 @@
0
+
+
+
+
+
+
+
+
-
diff --git a/WordPress/Sniff.php b/WordPress/Sniff.php
index 4bc0042898..d6a9f0a448 100644
--- a/WordPress/Sniff.php
+++ b/WordPress/Sniff.php
@@ -117,6 +117,7 @@ abstract class WordPress_Sniff implements PHP_CodeSniffer_Sniff {
'comments_rss_link' => true,
'delete_get_calendar_cache' => true,
'disabled' => true,
+ 'do_shortcode' => true,
'do_shortcode_tag' => true,
'edit_bookmark_link' => true,
'edit_comment_link' => true,
@@ -236,8 +237,10 @@ abstract class WordPress_Sniff implements PHP_CodeSniffer_Sniff {
*/
public static $sanitizingFunctions = array(
'absint' => true,
+ 'esc_url_raw' => true,
'filter_input' => true,
'filter_var' => true,
+ 'hash_equals' => true,
'in_array' => true,
'intval' => true,
'is_array' => true,
@@ -280,6 +283,8 @@ abstract class WordPress_Sniff implements PHP_CodeSniffer_Sniff {
*/
public static $unslashingSanitizingFunctions = array(
'absint' => true,
+ 'boolval' => true,
+ 'intval' => true,
'is_array' => true,
'sanitize_key' => true,
);
@@ -1036,6 +1041,40 @@ protected function is_comparison( $stackPtr ) {
return false;
}
+
+ /**
+ * Check what type of 'use' statement a token is part of.
+ *
+ * The T_USE token has multiple different uses:
+ *
+ * 1. In a closure: function () use ( $var ) {}
+ * 2. In a class, to import a trait: use Trait_Name
+ * 3. In a namespace, to import a class: use Some\Class;
+ *
+ * This function will check the token and return 'closure', 'trait', or 'class',
+ * based on which of these uses the use is being used for.
+ *
+ * @param int $stackPtr The position of the token to check.
+ *
+ * @return string The type of use.
+ */
+ protected function get_use_type( $stackPtr ) {
+
+ // USE keywords inside closures.
+ $next = $this->phpcsFile->findNext( T_WHITESPACE, $stackPtr + 1, null, true );
+
+ if ( T_OPEN_PARENTHESIS === $this->tokens[ $next ]['code'] ) {
+ return 'closure';
+ }
+
+ // USE keywords for traits.
+ if ( $this->phpcsFile->hasCondition( $stackPtr, array( T_CLASS, T_TRAIT ) ) ) {
+ return 'trait';
+ }
+
+ // USE keywords for classes to import to a namespace.
+ return 'class';
+ }
}
// EOF
diff --git a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php
index 02d4dbcef7..0eb3fc97e9 100644
--- a/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php
+++ b/WordPress/Sniffs/Arrays/ArrayKeySpacingRestrictionsSniff.php
@@ -55,11 +55,27 @@ public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr )
// It should have spaces only if it only has strings or numbers as the key
if ( $need_spaces && ! ( $spaced1 && $spaced2 ) ) {
$error = 'Array keys must be surrounded by spaces unless they contain a string or an integer.';
- $phpcsFile->addError( $error, $stackPtr, 'NoSpacesAroundArrayKeys' );
+ $fix = $phpcsFile->addFixableError( $error, $stackPtr, 'NoSpacesAroundArrayKeys' );
+ if ( $fix ) {
+ if ( ! $spaced1 ) {
+ $phpcsFile->fixer->addContentBefore( $stackPtr + 1, ' ' );
+ }
+ if ( ! $spaced2 ) {
+ $phpcsFile->fixer->addContentBefore( $token['bracket_closer'], ' ' );
+ }
+ }
}
elseif( ! $need_spaces && ( $spaced1 || $spaced2 ) ) {
$error = 'Array keys must NOT be surrounded by spaces if they only contain a string or an integer.';
- $phpcsFile->addError( $error, $stackPtr, 'SpacesAroundArrayKeys' );
+ $fix = $phpcsFile->addFixableError( $error, $stackPtr, 'SpacesAroundArrayKeys' );
+ if ( $fix ) {
+ if ( $spaced1 ) {
+ $phpcsFile->fixer->replaceToken( $stackPtr + 1, '' );
+ }
+ if ( $spaced2 ) {
+ $phpcsFile->fixer->replaceToken( $token['bracket_closer'] - 1, '' );
+ }
+ }
}
}//end process()
diff --git a/WordPress/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php b/WordPress/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php
deleted file mode 100644
index 7efe868750..0000000000
--- a/WordPress/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php
+++ /dev/null
@@ -1,184 +0,0 @@
-
- * @author Greg Sherwood
- * @author Marc McIntyre
- */
-
-/**
- * Enforces WordPress array format
- *
- * @category PHP
- * @package PHP_CodeSniffer
- * @author John Godley
- * @author Greg Sherwood
- * @author Marc McIntyre
- */
-class WordPress_Sniffs_Functions_FunctionDeclarationArgumentSpacingSniff implements PHP_CodeSniffer_Sniff
-{
-
-
- /**
- * Returns an array of tokens this test wants to listen for.
- *
- * @return array
- */
- public function register()
- {
- return array(T_FUNCTION);
-
- }//end register()
-
-
- /**
- * Processes this test, when one of its tokens is encountered.
- *
- * @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
- * @param int $stackPtr The position of the current token in the
- * stack passed in $tokens.
- *
- * @return void
- */
- public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
- {
- $tokens = $phpcsFile->getTokens();
-
- $functionName = $phpcsFile->findNext(array(T_STRING), $stackPtr);
- $openBracket = $tokens[$stackPtr]['parenthesis_opener'];
- $closeBracket = $tokens[$stackPtr]['parenthesis_closer'];
-
- $multiLine = ($tokens[$openBracket]['line'] !== $tokens[$closeBracket]['line']);
-
- $nextParam = $openBracket;
- $params = array();
-
- while (($nextParam = $phpcsFile->findNext(T_VARIABLE, ($nextParam + 1), $closeBracket)) !== false) {
- $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($nextParam + 1), ($closeBracket + 1), true);
- if ($nextToken === false) {
- break;
- }
-
- $nextCode = $tokens[$nextToken]['code'];
-
- if ($nextCode === T_EQUAL) {
- // Check parameter default spacing.
- if (($nextToken - $nextParam) !== 2) {
- $gap = strlen($tokens[($nextParam + 1)]['content']);
- $arg = $tokens[$nextParam]['content'];
- $error = "Expected 1 space between argument \"$arg\" and equals sign; ".($gap - 1)." found";
- $phpcsFile->addError($error, $nextToken, 'SpaceBeforeEquals');
- }
-
- if ($tokens[($nextToken + 1)]['code'] !== T_WHITESPACE) {
- $gap = strlen($tokens[($nextToken + 1)]['content']);
- $arg = $tokens[$nextParam]['content'];
- $error = "Expected 1 space between default value and equals sign for argument \"$arg\";";
- $phpcsFile->addError($error, $nextToken, 'SpaceAfterEquals');
- }
- }
-
- // Find and check the comma (if there is one).
- $nextComma = $phpcsFile->findNext(T_COMMA, ($nextParam + 1), $closeBracket);
- if ($nextComma !== false) {
- // Comma found.
- if ($tokens[($nextComma - 1)]['code'] === T_WHITESPACE) {
- $space = strlen($tokens[($nextComma - 1)]['content']);
- $arg = $tokens[$nextParam]['content'];
- $error = "Expected 0 spaces between argument \"$arg\" and comma; $space found";
- $phpcsFile->addError($error, $nextToken, 'SpaceBeforeComma');
- }
- }
-
- // Take references into account when expecting the
- // location of whitespace.
- if ($phpcsFile->isReference(($nextParam - 1)) === true) {
- $whitespace = $tokens[($nextParam - 2)];
- } else {
- $whitespace = $tokens[($nextParam - 1)];
- }
-
- if (empty($params) === false) {
- // This is not the first argument in the function declaration.
- $arg = $tokens[$nextParam]['content'];
-
- if ($whitespace['code'] === T_WHITESPACE) {
- $gap = strlen($whitespace['content']);
-
- // Before we throw an error, make sure there is no type hint.
- $comma = $phpcsFile->findPrevious(T_COMMA, ($nextParam - 1));
- $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($comma + 1), null, true);
- if ($phpcsFile->isReference($nextToken) === true) {
- $nextToken++;
- }
-
- if ($nextToken !== $nextParam) {
- // There was a type hint, so check the spacing between
- // the hint and the variable as well.
- $hint = $tokens[$nextToken]['content'];
-
- if ($gap !== 1) {
- $error = "Expected 1 space between type hint and argument \"$arg\"; $gap found";
- $phpcsFile->addError($error, $nextToken, 'SpacingAfterHint');
- }
-
- if ($multiLine === false) {
- if ($tokens[($comma + 1)]['code'] !== T_WHITESPACE) {
- $error = "Expected 1 space between comma and type hint \"$hint\"; 0 found";
- $phpcsFile->addError($error, $nextToken, 'NoSpaceBeforeHint');
- } else {
- $gap = strlen($tokens[($comma + 1)]['content']);
- if ($gap !== 1) {
- $error = "Expected 1 space between comma and type hint \"$hint\"; $gap found";
- $phpcsFile->addError($error, $nextToken, 'SpacingBeforeHint');
- }
- }
- }
- } else if ($multiLine === false && $gap !== 1) {
- $error = "Expected 1 space between comma and argument \"$arg\"; $gap found";
- $phpcsFile->addError($error, $nextToken, 'SpacingBeforeArg');
- }//end if
- } else {
- $error = "Expected 1 space between comma and argument \"$arg\"; 0 found";
- $phpcsFile->addError($error, $nextToken, 'NoSpaceBeforeArg');
- }//end if
- } else {
- // First argument in function declaration.
- if ($whitespace['code'] === T_WHITESPACE) {
- $gap = strlen($whitespace['content']);
- $arg = $tokens[$nextParam]['content'];
-
- // Before we throw an error, make sure there is no type hint.
- $bracket = $phpcsFile->findPrevious(T_OPEN_PARENTHESIS, ($nextParam - 1));
- $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($bracket + 1), null, true);
- if ($phpcsFile->isReference($nextToken) === true) {
- $nextToken++;
- }
-
- if ($nextToken !== $nextParam) {
- // There was a type hint, so check the spacing between
- // the hint and the variable as well.
- $hint = $tokens[$nextToken]['content'];
-
- if ($gap !== 1) {
- $error = "Expected 1 space between type hint and argument \"$arg\"; $gap found";
- $phpcsFile->addError($error, $nextToken, 'SpacingAfterHint');
- }
- }
- }//end if
- }//end if
-
- $params[] = $nextParam;
- }//end while
-
- }//end process()
-
-
-}//end class
-
-?>
diff --git a/WordPress/Sniffs/VIP/SessionVariableUsageSniff.php b/WordPress/Sniffs/VIP/SessionVariableUsageSniff.php
index aa6db76d18..8641b52a08 100644
--- a/WordPress/Sniffs/VIP/SessionVariableUsageSniff.php
+++ b/WordPress/Sniffs/VIP/SessionVariableUsageSniff.php
@@ -2,12 +2,13 @@
/**
* WordPress_Sniffs_VIP_SessionVariableUsageSniff
*
- * Discourages the use of the session variable
+ * Discourages the use of the session variable.
+ * Creating a session writes a file to the server and is unreliable in a multi-server environment.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Shady Sharaf
- * @link https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/issues/69
+ * @link https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/issues/75
*/
class WordPress_Sniffs_VIP_SessionVariableUsageSniff extends Generic_Sniffs_PHP_ForbiddenFunctionsSniff
{
diff --git a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php
index 58f70d86ae..22605be5d5 100644
--- a/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php
+++ b/WordPress/Sniffs/WhiteSpace/ControlStructureSpacingSniff.php
@@ -22,8 +22,7 @@
* @author Greg Sherwood
* @author Marc McIntyre
*/
-class WordPress_Sniffs_WhiteSpace_ControlStructureSpacingSniff implements PHP_CodeSniffer_Sniff
-{
+class WordPress_Sniffs_WhiteSpace_ControlStructureSpacingSniff extends WordPress_Sniff {
/**
* A list of tokenizers this sniff supports.
@@ -52,6 +51,16 @@ class WordPress_Sniffs_WhiteSpace_ControlStructureSpacingSniff implements PHP_Co
*/
public $space_before_colon = 'required';
+ /**
+ * How many spaces should be between a T_CLOSURE and T_OPEN_PARENTHESIS.
+ *
+ * function[*]() {...}
+ *
+ * @since 0.7.0
+ *
+ * @var int
+ */
+ public $spaces_before_closure_open_paren = 1;
/**
* Returns an array of tokens this test wants to listen for.
@@ -69,6 +78,9 @@ public function register()
T_DO,
T_ELSE,
T_ELSEIF,
+ T_FUNCTION,
+ T_CLOSURE,
+ T_USE,
);
}//end register()
@@ -90,8 +102,11 @@ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
$tokens = $phpcsFile->getTokens();
+ $this->init( $phpcsFile );
+
if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE
&& ! ( $tokens[$stackPtr]['code'] === T_ELSE && $tokens[($stackPtr + 1)]['code'] === T_COLON )
+ && ! ( T_CLOSURE === $tokens[ $stackPtr ]['code'] && 0 === (int) $this->spaces_before_closure_open_paren )
) {
$error = 'Space after opening control structure is required';
if (isset($phpcsFile->fixer) === true) {
@@ -106,12 +121,19 @@ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
}
}
- if (isset($tokens[$stackPtr]['scope_closer']) === false) {
- return;
- }
+ if ( isset( $tokens[ $stackPtr ]['scope_closer'] ) === false ) {
- $scopeOpener = $tokens[$stackPtr]['scope_opener'];
- $scopeCloser = $tokens[$stackPtr]['scope_closer'];
+ if ( T_USE === $tokens[ $stackPtr ]['code'] && 'closure' === $this->get_use_type( $stackPtr ) ) {
+ $scopeOpener = $phpcsFile->findNext( T_OPEN_CURLY_BRACKET, $stackPtr + 1 );
+ $scopeCloser = $tokens[ $scopeOpener ]['scope_closer'];
+ } else {
+ return;
+ }
+
+ } else {
+ $scopeOpener = $tokens[ $stackPtr ]['scope_opener'];
+ $scopeCloser = $tokens[ $stackPtr ]['scope_closer'];
+ }
// alternative syntax
if ( $tokens[$scopeOpener]['code'] === T_COLON ) {
@@ -156,21 +178,128 @@ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
$parenthesisOpener = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, ($stackPtr + 1), null, true);
- if (($stackPtr + 1) === $parenthesisOpener && $tokens[$parenthesisOpener]['code'] !== T_COLON) {
- // Checking this: $value = my_function[*](...).
- $error = 'No space before opening parenthesis is prohibited';
- if (isset($phpcsFile->fixer) === true) {
- $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoSpaceBeforeOpenParenthesis');
- if ($fix === true) {
- $phpcsFile->fixer->beginChangeset();
- $phpcsFile->fixer->addContent($stackPtr, ' ');
- $phpcsFile->fixer->endChangeset();
+ // If this is a function declaration.
+ if ( $tokens[ $stackPtr ]['code'] === T_FUNCTION ) {
+
+ if ( $tokens[ $parenthesisOpener ]['code'] === T_STRING ) {
+
+ $function_name_ptr = $parenthesisOpener;
+
+ } elseif ( $tokens[ $parenthesisOpener ]['code'] === T_BITWISE_AND ) {
+
+ // This function returns by reference (function &function_name() {}).
+ $function_name_ptr = $parenthesisOpener = $phpcsFile->findNext(
+ PHP_CodeSniffer_Tokens::$emptyTokens,
+ $parenthesisOpener + 1,
+ null,
+ true
+ );
+ }
+
+ $parenthesisOpener = $phpcsFile->findNext(
+ PHP_CodeSniffer_Tokens::$emptyTokens,
+ $parenthesisOpener + 1,
+ null,
+ true
+ );
+
+ // Checking this: function my_function[*](...) {}
+ if ( $parenthesisOpener !== $function_name_ptr + 1 ) {
+
+ $error = 'Space between function name and opening parenthesis is prohibited.';
+ $fix = $phpcsFile->addFixableError(
+ $error,
+ $stackPtr,
+ 'SpaceBeforeFunctionOpenParenthesis',
+ $tokens[ $function_name_ptr + 1 ]['content']
+ );
+
+ if ( true === $fix ) {
+ $phpcsFile->fixer->beginChangeset();
+ $phpcsFile->fixer->replaceToken( $function_name_ptr + 1, '' );
+ $phpcsFile->fixer->endChangeset();
+ }
+ }
+
+ } elseif ( T_CLOSURE === $tokens[ $stackPtr ]['code'] ) {
+
+ // Check if there is a use () statement.
+ if ( isset( $tokens[ $parenthesisOpener ]['parenthesis_closer'] ) ) {
+
+ $usePtr = $phpcsFile->findNext(
+ PHP_CodeSniffer_Tokens::$emptyTokens,
+ $tokens[ $parenthesisOpener ]['parenthesis_closer'] + 1,
+ null,
+ true,
+ null,
+ true
+ );
+
+ // If it is, we set that as the "scope opener".
+ if ( T_USE === $tokens[ $usePtr ]['code'] ) {
+ $scopeOpener = $usePtr;
+ }
+ }
+ }
+
+ if (
+ T_COLON !== $tokens[ $parenthesisOpener ]['code']
+ && T_FUNCTION !== $tokens[ $stackPtr ]['code']
+ ) {
+
+ if (
+ T_CLOSURE === $tokens[ $stackPtr ]['code']
+ && 0 === (int) $this->spaces_before_closure_open_paren
+ ) {
+
+ if ( ($stackPtr + 1) !== $parenthesisOpener ) {
+ // Checking this: function[*](...) {}.
+ $error = 'Space before closure opening parenthesis is prohibited';
+ $fix = $phpcsFile->addFixableError( $error, $stackPtr, 'SpaceBeforeClosureOpenParenthesis' );
+ if ( $fix === true ) {
+ $phpcsFile->fixer->beginChangeset();
+ $phpcsFile->fixer->replaceToken( $stackPtr + 1, '' );
+ $phpcsFile->fixer->endChangeset();
+ }
+ }
+
+ } elseif ( ($stackPtr + 1) === $parenthesisOpener ) {
+
+ // Checking this: if[*](...) {}.
+ $error = 'No space before opening parenthesis is prohibited';
+ if ( isset( $phpcsFile->fixer ) === true ) {
+ $fix = $phpcsFile->addFixableError( $error, $stackPtr, 'NoSpaceBeforeOpenParenthesis' );
+ if ( $fix === true ) {
+ $phpcsFile->fixer->beginChangeset();
+ $phpcsFile->fixer->addContent( $stackPtr, ' ' );
+ $phpcsFile->fixer->endChangeset();
+ }
+ } else {
+ $phpcsFile->addError( $error, $stackPtr, 'NoSpaceBeforeOpenParenthesis' );
}
- } else {
- $phpcsFile->addError($error, $stackPtr, 'NoSpaceBeforeOpenParenthesis');
}
}
+ if (
+ T_WHITESPACE === $tokens[ $stackPtr + 1 ]['code']
+ && ' ' !== $tokens[ $stackPtr + 1 ]['content']
+ ) {
+ // Checking this: if [*](...) {}.
+ $error = 'Expected exactly one space before opening parenthesis; "%s" found.';
+ $fix = $phpcsFile->addFixableError(
+ $error,
+ $stackPtr,
+ 'ExtraSpaceBeforeOpenParenthesis',
+ $tokens[ $stackPtr + 1 ]['content']
+ );
+
+ if ( true === $fix ) {
+ $phpcsFile->fixer->beginChangeset();
+ $phpcsFile->fixer->replaceToken( $stackPtr + 1, ' ' );
+ $phpcsFile->fixer->endChangeset();
+ }
+ }
+
if ($tokens[($parenthesisOpener + 1)]['code'] !== T_WHITESPACE
&& $tokens[($parenthesisOpener + 1)]['code'] !== T_CLOSE_PARENTHESIS
) {
@@ -188,22 +317,45 @@ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
}
}
- if (isset($tokens[$parenthesisOpener]['parenthesis_closer']) === true) {
+ if ( isset($tokens[$parenthesisOpener]['parenthesis_closer']) === true ) {
+
$parenthesisCloser = $tokens[$parenthesisOpener]['parenthesis_closer'];
- if ($tokens[($parenthesisCloser - 1)]['code'] !== T_WHITESPACE) {
- $error = 'No space before closing parenthesis is prohibited';
- if (isset($phpcsFile->fixer) === true) {
- $fix = $phpcsFile->addFixableError($error, $parenthesisCloser, 'NoSpaceBeforeCloseParenthesis');
- if ($fix === true) {
- $phpcsFile->fixer->beginChangeset();
- $phpcsFile->fixer->addContentBefore($parenthesisCloser, ' ');
- $phpcsFile->fixer->endChangeset();
- }
- } else {
- $phpcsFile->addError($error, $parenthesisCloser, 'NoSpaceBeforeCloseParenthesis');
- }
- }
+ if ( $tokens[($parenthesisOpener + 1)]['code'] !== T_CLOSE_PARENTHESIS ) {
+
+ if ($tokens[($parenthesisCloser - 1)]['code'] !== T_WHITESPACE) {
+ $error = 'No space before closing parenthesis is prohibited';
+ if (isset($phpcsFile->fixer) === true) {
+ $fix = $phpcsFile->addFixableError($error, $parenthesisCloser, 'NoSpaceBeforeCloseParenthesis');
+ if ($fix === true) {
+ $phpcsFile->fixer->beginChangeset();
+ $phpcsFile->fixer->addContentBefore($parenthesisCloser, ' ');
+ $phpcsFile->fixer->endChangeset();
+ }
+ } else {
+ $phpcsFile->addError($error, $parenthesisCloser, 'NoSpaceBeforeCloseParenthesis');
+ }
+ }
+
+ if (
+ $tokens[ $parenthesisCloser + 1 ]['code'] !== T_WHITESPACE
+ && $tokens[ $scopeOpener ]['code'] !== T_COLON
+ ) {
+ $error = 'Space between opening control structure and closing parenthesis is required';
+
+ if ( isset( $phpcsFile->fixer ) === true ) {
+ $fix = $phpcsFile->addFixableError( $error, $scopeOpener, 'NoSpaceAfterCloseParenthesis' );
+
+ if ( $fix === true ) {
+ $phpcsFile->fixer->beginChangeset();
+ $phpcsFile->fixer->addContentBefore( $scopeOpener, ' ' );
+ $phpcsFile->fixer->endChangeset();
+ }
+ } else {
+ $phpcsFile->addError( $error, $stackPtr, 'NoSpaceAfterCloseParenthesis' );
+ }
+ }
+ }
if (isset($tokens[$parenthesisOpener]['parenthesis_owner']) === true
&& $tokens[$parenthesisCloser]['line'] !== $tokens[$scopeOpener]['line']
@@ -218,7 +370,6 @@ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
$phpcsFile->fixer->replaceToken($i, '');
}
- // TODO: Should be a separate check for spacing between ")" and "{" only (when they are on same line).
$phpcsFile->fixer->addContent($parenthesisCloser, ' ');
$phpcsFile->fixer->endChangeset();
}
@@ -226,7 +377,27 @@ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
$phpcsFile->addError($error, $parenthesisOpener, 'OpenBraceNotSameLine');
}//end if
return;
- }//end if
+
+ } elseif (
+ T_WHITESPACE === $tokens[ $parenthesisCloser + 1 ]['code']
+ && ' ' !== $tokens[ $parenthesisCloser + 1 ]['content']
+ ) {
+
+ // Checking this: if (...) [*]{}
+ $error = 'Expected exactly one space between closing parenthesis and opening control structure; "%s" found.';
+ $fix = $phpcsFile->addFixableError(
+ $error,
+ $stackPtr,
+ 'ExtraSpaceAfterCloseParenthesis',
+ $tokens[ $parenthesisCloser + 1 ]['content']
+ );
+
+ if ( true === $fix ) {
+ $phpcsFile->fixer->beginChangeset();
+ $phpcsFile->fixer->replaceToken( $parenthesisCloser + 1, ' ' );
+ $phpcsFile->fixer->endChangeset();
+ }
+ }
}//end if
if ($this->blank_line_check === true) {
diff --git a/WordPress/Sniffs/XSS/EscapeOutputSniff.php b/WordPress/Sniffs/XSS/EscapeOutputSniff.php
index 3096e85ff2..0becada3c7 100644
--- a/WordPress/Sniffs/XSS/EscapeOutputSniff.php
+++ b/WordPress/Sniffs/XSS/EscapeOutputSniff.php
@@ -172,16 +172,8 @@ public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr )
$ternary = $phpcsFile->findNext( T_INLINE_THEN, $stackPtr, $end_of_statement );
// If there is a ternary skip over the part before the ?. However, if
- // there is a closing parenthesis ending the statement, we only do
- // this when the opening parenthesis comes after the ternary. If the
- // ternary is within the parentheses, it will be handled in the loop.
- if (
- $ternary
- && (
- T_CLOSE_PARENTHESIS !== $tokens[ $last_token ]['code']
- || $ternary < $tokens[ $last_token ]['parenthesis_opener']
- )
- ) {
+ // the ternary is within parentheses, it will be handled in the loop.
+ if ( $ternary && empty( $tokens[ $ternary ]['nested_parenthesis'] ) ) {
$stackPtr = $ternary;
}
}
diff --git a/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed
new file mode 100644
index 0000000000..791e58c351
--- /dev/null
+++ b/WordPress/Tests/Arrays/ArrayKeySpacingRestrictionsUnitTest.inc.fixed
@@ -0,0 +1,31 @@
+
- * @author Greg Sherwood
- * @author Marc McIntyre
- * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
- * @link http://pear.php.net/package/PHP_CodeSniffer
- */
-
-/**
- * Unit test class for the FunctionDeclarationArgumentSpacing sniff.
- *
- * A sniff unit test checks a .inc file for expected violations of a single
- * coding standard. Expected errors and warnings are stored in this class.
- *
- * @category PHP
- * @package PHP_CodeSniffer
- * @author Akeda Bagus
- * @author Greg Sherwood
- * @author Marc McIntyre
- * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
- * @version Release: @package_version@
- * @link http://pear.php.net/package/PHP_CodeSniffer
- */
-class WordPress_Tests_Functions_FunctionDeclarationArgumentSpacingUnitTest extends AbstractSniffUnitTest
-{
-
-
- /**
- * Returns the lines where errors should occur.
- *
- * The key of the array should represent the line number and the value
- * should represent the number of errors that should occur on that line.
- *
- * @return array(int => int)
- */
- public function getErrorList()
- {
- return array(
- 3 => 2,
- 5 => 1,
- 9 => 1,
- );
-
- }//end getErrorList()
-
-
- /**
- * Returns the lines where warnings should occur.
- *
- * The key of the array should represent the line number and the value
- * should represent the number of warnings that should occur on that line.
- *
- * @return array(int => int)
- */
- public function getWarningList()
- {
- return array();
-
- }//end getWarningList()
-
-
-}//end class
-
-?>
diff --git a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.inc b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.inc
index 957a3f6767..821c40ae01 100644
--- a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.inc
+++ b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.inc
@@ -45,3 +45,57 @@ endif;
if ( false ) :
else :
endif;
+
+function($arg){} // Bad
+function ( $arg ) {
+ // OK
+}
+
+function () {
+ // OK
+}
+
+function something($arg){} // Bad
+function foo( $arg ) {
+ // OK
+}
+
+function no_params() {
+ // OK
+}
+
+function another () {} // Bad, space before open parenthesis prohibited.
+function and_another() {} // Bad, space before function name prohibited.
+function
+bar() {} // Bad
+function baz() {} // Bad
+function test()
+{} // Bad
+
+function &return_by_ref() {} // OK
+
+// @codingStandardsChangeSetting WordPress.WhiteSpace.ControlStructureSpacing spaces_before_closure_open_paren 0
+
+function() {} // OK
+function( $arg ) {} // OK
+function($arg){} // Bad
+function () {} // Bad
+
+$closureWithArgsAndVars = function( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // OK
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // Bad
+
+// @codingStandardsChangeSetting WordPress.WhiteSpace.ControlStructureSpacing spaces_before_closure_open_paren 1
+
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // OK
+
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use( $var1, $var2 ) {}; // Bad, no space before open parenthesis prohibited.
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // Bad, expected exactly one space before opening parenthesis.
+
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ){}; // Bad, space between closing parenthesis and control structure required.
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // Bad, expected exactly one space between closing parenthesis and control structure.
+
+$closureWithArgsAndVars = function ( $arg1, $arg2 )use ( $var1, $var2 ) {}; // Bad, expected exactly one space between closing parenthesis and control structure.
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // Bad, expected exactly one space between closing parenthesis and control structure.
+
+// Namespaces.
+use Foo\Admin;
diff --git a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.inc.fixed b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.inc.fixed
index 56168f5d31..22617542e2 100644
--- a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.inc.fixed
+++ b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.inc.fixed
@@ -14,7 +14,7 @@ if ( true ) {
}
// bad
-if ( 'update' === $option_operation['operation'] ) {
+if ( 'update' === $option_operation['operation'] ) {
update_option( $option_operation['option_name'], $option_operation['old_value'] );
}
@@ -25,7 +25,7 @@ if ( 'update' === $option_operation['operation'] ) {
}
// bad
-if ( true ){}
+if ( true ) {}
if ( true ) {
@@ -43,3 +43,55 @@ endif;
if ( false ) :
else :
endif;
+
+function ( $arg ) {} // Bad
+function ( $arg ) {
+ // OK
+}
+
+function () {
+ // OK
+}
+
+function something( $arg ) {} // Bad
+function foo( $arg ) {
+ // OK
+}
+
+function no_params() {
+ // OK
+}
+
+function another() {} // Bad, space before open parenthesis prohibited.
+function and_another() {} // Bad, space before function name prohibited.
+function bar() {} // Bad
+function baz() {} // Bad
+function test() {} // Bad
+
+function &return_by_ref() {} // OK
+
+// @codingStandardsChangeSetting WordPress.WhiteSpace.ControlStructureSpacing spaces_before_closure_open_paren 0
+
+function() {} // OK
+function( $arg ) {} // OK
+function( $arg ) {} // Bad
+function() {} // Bad
+
+$closureWithArgsAndVars = function( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // OK
+$closureWithArgsAndVars = function( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // Bad
+
+// @codingStandardsChangeSetting WordPress.WhiteSpace.ControlStructureSpacing spaces_before_closure_open_paren 1
+
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // OK
+
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // Bad, no space before open parenthesis prohibited.
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // Bad, expected exactly one space before opening parenthesis.
+
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // Bad, space between closing parenthesis and control structure required.
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // Bad, expected exactly one space between closing parenthesis and control structure.
+
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // Bad, expected exactly one space between closing parenthesis and control structure.
+$closureWithArgsAndVars = function ( $arg1, $arg2 ) use ( $var1, $var2 ) {}; // Bad, expected exactly one space between closing parenthesis and control structure.
+
+// Namespaces.
+use Foo\Admin;
diff --git a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php
index 672b688fed..7d732713cd 100644
--- a/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php
+++ b/WordPress/Tests/WhiteSpace/ControlStructureSpacingUnitTest.php
@@ -44,11 +44,27 @@ public function getErrorList()
{
$ret = array(
4 => 2,
- 17 => 1,
- 29 => 4,
+ 17 => 2,
+ 29 => 5,
37 => 1,
41 => 1,
42 => 1,
+ 49 => 5,
+ 58 => 3,
+ 67 => 1,
+ 68 => 1,
+ 69 => 1,
+ 71 => 1,
+ 72 => 1,
+ 81 => 3,
+ 82 => 1,
+ 85 => 1,
+ 91 => 2,
+ 92 => 1,
+ 94 => 1,
+ 95 => 1,
+ 97 => 1,
+ 98 => 1,
);
// Uncomment when "$blank_line_check" parameter will be "true" by default.
diff --git a/WordPress/Tests/XSS/EscapeOutputUnitTest.inc b/WordPress/Tests/XSS/EscapeOutputUnitTest.inc
index 5b76af1b20..bcff315caa 100644
--- a/WordPress/Tests/XSS/EscapeOutputUnitTest.inc
+++ b/WordPress/Tests/XSS/EscapeOutputUnitTest.inc
@@ -157,3 +157,10 @@ echo sprintf( 'Howdy, %s', esc_html( $name ? $name : __( 'Partner' ) ) ); // OK
_e( 'Something' ); // Bad
esc_html_e( 'Something' ); // OK
+
+echo $something // Bad
+ . esc_attr( 'baz-' // Rest is OK
+ . $r
+ . ( $r === $active_round ? ' foo' : '' )
+ . ( $r < $active_round ? ' bar' : '' )
+ ) . 'something';
diff --git a/WordPress/Tests/XSS/EscapeOutputUnitTest.php b/WordPress/Tests/XSS/EscapeOutputUnitTest.php
index 9124c7d141..abf7634354 100644
--- a/WordPress/Tests/XSS/EscapeOutputUnitTest.php
+++ b/WordPress/Tests/XSS/EscapeOutputUnitTest.php
@@ -75,6 +75,7 @@ public function getErrorList()
148 => 1,
151 => 2,
158 => 1,
+ 161 => 1,
);
}//end getErrorList()
diff --git a/project.ruleset.xml.example b/project.ruleset.xml.example
index 8f1ef1f41c..894879b79d 100644
--- a/project.ruleset.xml.example
+++ b/project.ruleset.xml.example
@@ -8,6 +8,7 @@
/docroot/index.php
/docroot/xmlrpc.php
/docroot/wp-content/plugins/*
+ *.twig