Umherirrender has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/61178


Change subject: Add a SpacesAroundSomeTokensSniff
......................................................................

Add a SpacesAroundSomeTokensSniff

This sniff was used to find and fixed many spacing issues in mediawiki
core, see
https://gerrit.wikimedia.org/r/#/q/project:mediawiki/core+branch:master+topic:fix-spacing,n,z
for an overview.

This sniff has still false positive, so be carefully, when using.

Feel free to expand or rename it.

Change-Id: I2cbacf9b9987d23aec6b0f10a6d3f9e760126087
---
A MediaWiki/Sniffs/NamingConventions/SpacesAroundSomeTokensSniff.php
1 file changed, 427 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/tools/codesniffer 
refs/changes/78/61178/1

diff --git a/MediaWiki/Sniffs/NamingConventions/SpacesAroundSomeTokensSniff.php 
b/MediaWiki/Sniffs/NamingConventions/SpacesAroundSomeTokensSniff.php
new file mode 100644
index 0000000..23abd6c
--- /dev/null
+++ b/MediaWiki/Sniffs/NamingConventions/SpacesAroundSomeTokensSniff.php
@@ -0,0 +1,427 @@
+<?php
+/**
+ * Check, if there are correct number of spaces around some tokens
+ */
+class MediaWiki_Sniffs_NamingConventions_SpacesAroundSomeTokensSniff 
implements PHP_CodeSniffer_Sniff {
+
+       private $spaceOptions = array(
+               # string operations
+               T_STRING_CONCAT => array( // .
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_CONCAT_EQUAL => array( // .=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+
+               # logical operations
+               T_GREATER_THAN => array( // >
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_IS_GREATER_OR_EQUAL => array( // >=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_IS_EQUAL => array( // ==
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_IS_IDENTICAL => array( // ===
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_IS_NOT_EQUAL => array( // != or <>
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_IS_NOT_IDENTICAL => array( // !==
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_IS_SMALLER_OR_EQUAL => array( // <=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_LESS_THAN => array( // <
+                       'before' => 1,
+                       'after' => 1,
+               ),
+
+               # Shifting
+               T_SL => array( // <<
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_SL_EQUAL => array( // <<=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_SR => array( // >>
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_SR_EQUAL => array( // >>=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+
+               # operations
+               T_PLUS => array( // +
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_MINUS => array( // -
+                       'before' => 1, 'beforeOK' => T_OPEN_SQUARE_BRACKET, # 
okay as array index
+                       # no test after, because -1 standalone is okay
+               ),
+               T_MULTIPLY => array( // *
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_DIVIDE => array( // /
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_MODULUS => array( // %
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_POWER => array( // ^
+                       'before' => 1,
+                       'after' => 1,
+               ),
+
+               # operation and assignment
+               T_AND_EQUAL => array( // &=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_OR_EQUAL => array( // |=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_XOR_EQUAL => array( // ^=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_PLUS_EQUAL => array( // +=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_MINUS_EQUAL => array( // -=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_MUL_EQUAL => array( // *=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_DIV_EQUAL => array( // /=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_MOD_EQUAL => array( // %=
+                       'before' => 1,
+                       'after' => 1,
+               ),
+
+               # conditions
+               T_LOGICAL_AND => array( // and
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_LOGICAL_OR => array( // or
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_LOGICAL_XOR => array( // xor
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_BITWISE_AND => array( // &, also used as pass-by-references
+                       'before' => 1, 'beforeOK' => T_EQUAL, # OK: =&
+                       'after' => 1, 'afterOK' => array( T_VARIABLE, T_SELF, 
T_STRING ), # OK: &$var or &self:: or &functionName
+               ),
+               T_BITWISE_OR => array( // |
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_BOOLEAN_AND => array( // &&
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_BOOLEAN_OR => array( // ||
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_BOOLEAN_NOT => array( // !
+                       'before' => 1, 'beforeOK' => T_BOOLEAN_NOT, # some !! 
exists
+                       # TODO no testing after, because some ! have it
+               ),
+               T_TRUE => array( // true
+                       'before' => 1,
+                       'after' => 1, 'afterOK' => array( T_COMMA, T_SEMICOLON, 
T_COLON ), # OK: true, true; true:
+               ),
+               T_FALSE => array( // false
+                       'before' => 1,
+                       'after' => 1, 'afterOK' => array( T_COMMA, T_SEMICOLON, 
T_COLON ), # OK: false, false; false:
+               ),
+
+               # statements
+               T_IF => array( // if
+                       'before' => 1, 'beforeOK' => T_OPEN_TAG,
+                       'after' => 1,
+               ),
+               T_ELSEIF => array( // elseif
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_ELSE => array( // else
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_FOR => array( // for
+                       'before' => 1, 'beforeOK' => T_OPEN_TAG,
+                       'after' => 1,
+               ),
+               T_FOREACH => array( // foreach
+                       'before' => 1, 'beforeOK' => T_OPEN_TAG,
+                       'after' => 1,
+               ),
+               T_WHILE => array( // while
+                       'before' => 1, 'beforeOK' => T_OPEN_TAG,
+                       'after' => 1,
+               ),
+               T_DO => array( // do
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_SWITCH => array( // switch
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_TRY => array( // try
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_CATCH => array( // try
+                       'before' => 1,
+                       'after' => 1,
+               ),
+
+               # various
+               T_DOUBLE_ARROW => array( // => (array or foreach)
+                       'before' => 1, 'beforeOKin' => T_ARRAY, # TODO too many 
false positive in arrays at the moment
+                       'after' => 1, 'afterOKin' => T_ARRAY, # TODO too many 
false positive in arrays at the moment
+               ),
+               T_EQUAL => array( // =
+                       'before' => 1,
+                       'after' => 1, 'afterOK' => T_BITWISE_AND, # OK: =& 
(pass-by-references)
+               ),
+               T_AS => array( // as
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_NEW => array( // new
+                       'before' => 1,
+                       'after' => 1,
+               ),
+               T_ARRAY => array( // array
+                       'before' => 1, 'beforeOK' => T_OBJECT_CAST, # OK: 
(object)array()
+                       'after' => 0,
+               ),
+               T_LIST => array( // list
+                       'before' => 1, 'beforeOK' => T_ASPERAND, # OK: @list
+                       'after' => 0,
+               ),
+               T_ISSET => array( // isset
+                       'before' => 1, 'beforeOK' => array( T_BOOLEAN_NOT, 
T_OPEN_SQUARE_BRACKET ), # OK: !isset [isset
+                       'after' => 0,
+               ),
+               T_UNSET => array( // unset
+                       'before' => 1,
+                       'after' => 0,
+               ),
+               T_EXIT => array( // exit or die
+                       'before' => 1,
+                       'after' => 0,
+               ),
+               T_EMPTY => array( // empty
+                       'before' => 1, 'beforeOK' => array( T_BOOLEAN_NOT, 
T_OPEN_SQUARE_BRACKET ), # OK: !empty [empty
+                       'after' => 0,
+               ),
+               T_GLOBAL => array( // global
+                       'before' => 0, 'beforeOK' => T_OPEN_TAG,
+                       'after' => 1,
+               ),
+               T_RETURN => array( // return
+                       'before' => 0, 'beforeOK' => array( T_COLON, 
T_OPEN_TAG, T_OPEN_CURLY_BRACKET ), #OK: case ...: return
+                       'after' => 1, 'afterOK' => T_SEMICOLON, # OK: return;
+               ),
+               T_COMMA => array( // ,
+                       'before' => 0, 'beforeOKin' => T_LIST, # OK list( , , 
$var )
+                       'after' => 1, 'afterOKin' => T_ARRAY, # TODO too many 
false positive in arrays at the moment
+               ),
+               T_SEMICOLON => array( // ;
+                       'before' => 0, 'beforeOKin' => T_FOR, # OK: for ( ; 
...; ... )
+                       'after' => 0, 'afterOK' => array( T_CLOSE_TAG, 
T_CLOSE_CURLY_BRACKET ), # OK: ; ? >
+                       'afterOKin' => T_FOR, #OK: for ( ...; ...; ... )
+               ),
+               T_INLINE_THEN => array( // ?
+                       'before' => 1,
+                       'after' => 1, 'afterOK' => T_COLON, # OK: ?:
+               ),
+               T_COLON => array( // :
+                       # TODO before: 0 when used in T_SWITCH with T_CASE - 1 
when used in T_INLINE_THEN
+                       'after' => 1,
+               ),
+               T_DOUBLE_COLON => array( // ::
+                       'before' => 0,
+                       'after' => 0,
+               ),
+               T_OBJECT_OPERATOR => array( // ->
+                       'before' => 0,
+                       'after' => 0,
+               ),
+               T_CONSTANT_ENCAPSED_STRING => array( // "" or ''
+                       'before' => 1, 'beforeOK' => array( 
T_OPEN_SQUARE_BRACKET, T_CLOSE_SQUARE_BRACKET, T_CONSTANT_ENCAPSED_STRING ),
+                       'beforeOKin' => T_ARRAY, # TODO too many false positive 
at the moment with T_COMMA
+                       'after' => 1, 'afterOK' => array( 
T_OPEN_SQUARE_BRACKET, T_CLOSE_SQUARE_BRACKET, T_SEMICOLON, T_COMMA, T_COLON, 
T_CONSTANT_ENCAPSED_STRING ),
+                       'afterOKin' => T_ARRAY, # TODO too many false positive 
at the moment with T_COMMA
+               ),
+               T_ENCAPSED_AND_WHITESPACE => array( // "" or ''
+                       'before' => 1, 'beforeOK' => array( 
T_OPEN_SQUARE_BRACKET, T_CLOSE_SQUARE_BRACKET, T_BACKTICK, 
T_CONSTANT_ENCAPSED_STRING ),
+                       'beforeOKin' => T_ARRAY, # TODO too many false positive 
at the moment with T_COMMA
+                       'after' => 1, 'afterOK' => array( 
T_OPEN_SQUARE_BRACKET, T_CLOSE_SQUARE_BRACKET, T_SEMICOLON, T_COMMA, T_COLON, 
T_BACKTICK, T_CONSTANT_ENCAPSED_STRING ),
+                       'afterOKin' => T_ARRAY, # TODO too many false positive 
at the moment with T_COMMA
+               ),
+               T_OPEN_PARENTHESIS => array( // (
+                       # TODO before: 0 when T_STRING or other functions - 1 
when if foreach or conditions
+                       'after' => 1, 'afterOK' => T_CLOSE_PARENTHESIS, # OK: ()
+               ),
+               T_CLOSE_PARENTHESIS => array( // (
+                       'before' => 1, 'beforeOK' => array( T_OPEN_PARENTHESIS, 
T_CLOSE_PARENTHESIS ), # OK: () )))
+                       'beforeOKin' => T_ARRAY, # TODO too many false positive 
in arrays at the moment
+                       'after' => 1, 'afterOK' => array( T_SEMICOLON, T_COMMA, 
T_OBJECT_OPERATOR, T_CLOSE_SQUARE_BRACKET, T_CLOSE_PARENTHESIS ), # OK: ); ), 
)) )] )->
+               ),
+               T_OPEN_CURLY_BRACKET => array( // {
+                       'before' => 1, 'beforeOK' => array( T_OPEN_TAG, 
T_OBJECT_OPERATOR ),
+                       'after' => 1, 'afterOK' => array( 
T_CLOSE_CURLY_BRACKET, T_CLOSE_TAG ),
+               ),
+               T_CLOSE_CURLY_BRACKET => array( // }
+                       'before' => 1, 'beforeOK' => array( 
T_OPEN_CURLY_BRACKET, T_OPEN_TAG ),
+                       'after' => 1, 'afterOK' => array( T_COMMA, T_SEMICOLON, 
T_CLOSE_TAG ),
+               ),
+       );
+
+       public function register() {
+               return array_keys(
+                       $this->spaceOptions
+               );
+       }
+
+       public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) {
+               $tokens = $phpcsFile->getTokens();
+               $maxLength = count( $tokens );
+               $code = $tokens[$stackPtr]['code'];
+               $options = $this->spaceOptions[$code];
+               if ( isset( $options['before'] ) ) {
+                       $expectedSpacesBefore = $options['before'];
+                       $beforeOK = array( T_COMMENT, T_DOC_COMMENT ); //allow 
comments every time
+                       if ( isset( $options['beforeOK'] ) ) {
+                               if ( !is_array( $options['beforeOK'] ) ) {
+                                       $options['beforeOK'] = array( 
$options['beforeOK'] );
+                               }
+                               $beforeOK = array_merge( $beforeOK, 
$options['beforeOK'] );
+                       }
+                       $beforeOKin = array();
+                       if ( isset( $options['beforeOKin'] ) ) {
+                               $beforeOKin = $options['beforeOKin'];
+                               if ( !is_array( $beforeOKin ) ) {
+                                       $beforeOKin = array( $beforeOKin );
+                               }
+                       }
+
+                       $spaceBefore = 0;
+                       $tokenSpaceBefore = $stackPtr;
+                       while ( $tokenSpaceBefore > 0 && 
$tokens[$tokenSpaceBefore - 1]['code'] === T_WHITESPACE ) {
+                               $tokenSpaceBefore--;
+                               $spaceBefore += strlen( 
$tokens[$tokenSpaceBefore]['content'] );
+                       }
+
+                       //ignore multiline statements
+                       if ( $spaceBefore !== $expectedSpacesBefore &&
+                               $tokens[$tokenSpaceBefore]['content'] !== "\n" 
&&
+                               !in_array( $tokens[$tokenSpaceBefore - 
1]['code'], $beforeOK, true ) &&
+                               !$this->isInsideParenthesisOwner( $tokens, 
$stackPtr, $beforeOKin )
+                       ) {
+                               $error = 'Found %s space(s) before token 
\'%s\', expected %s space(s)';
+                               $type = 'SpaceBefore' . 
$this->getTokenInCamelCase( $tokens[$stackPtr]['type'] );
+                               $data = array( $spaceBefore, 
$tokens[$stackPtr]['content'], $expectedSpacesBefore );
+                               $phpcsFile->addError( $error, $stackPtr, $type, 
$data );
+                       }
+               }
+
+               if ( isset( $options['after'] ) ) {
+                       $expectedSpacesAfter = $options['after'];
+                       $afterOK = array( T_COMMENT, T_DOC_COMMENT ); //allow 
comments every time
+                       if ( isset( $options['afterOK'] ) ) {
+                               if ( !is_array( $options['afterOK'] ) ) {
+                                       $options['afterOK'] = array( 
$options['afterOK'] );
+                               }
+                               $afterOK = array_merge( $afterOK, 
$options['afterOK'] );
+                       }
+                       $afterOKin = array();
+                       if ( isset( $options['afterOKin'] ) ) {
+                               $afterOKin = $options['afterOKin'];
+                               if ( !is_array( $afterOKin ) ) {
+                                       $afterOKin = array( $afterOKin );
+                               }
+                       }
+
+                       $spaceAfter = 0;
+                       $tokenSpaceAfter = $stackPtr;
+                       while ( $tokenSpaceAfter + 1 < $maxLength && 
$tokens[$tokenSpaceAfter + 1]['code'] === T_WHITESPACE ) {
+                               $tokenSpaceAfter++;
+                               $spaceAfter += strlen( 
$tokens[$tokenSpaceAfter]['content'] );
+                       }
+
+                       //ignore multiline concatenation
+                       if ( $spaceAfter !== $expectedSpacesAfter &&
+                               $tokens[$stackPtr + 1]['content'] !== "\n" &&
+                               !in_array( $tokens[$tokenSpaceAfter + 
1]['code'], $afterOK, true ) &&
+                               !$this->isInsideParenthesisOwner( $tokens, 
$stackPtr, $afterOKin )
+                       ) {
+                               $error = 'Found %s space(s) after token \'%s\', 
expected %s space(s)';
+                               $type = 'SpaceAfter' . 
$this->getTokenInCamelCase( $tokens[$stackPtr]['type'] );
+                               $data = array( $spaceAfter, 
$tokens[$stackPtr]['content'], $expectedSpacesAfter );
+                               $phpcsFile->addError( $error, $stackPtr, $type, 
$data );
+                       }
+               }
+       }
+
+       private function isInsideParenthesisOwner( $tokens, $stackPtr, $codes ) 
{
+               if ( !isset( $tokens[$stackPtr]['nested_parenthesis'] ) || 
!count( $codes ) ) {
+                       return false;
+               }
+               $nestedParenthesis = $tokens[$stackPtr]['nested_parenthesis'];
+               foreach ( $nestedParenthesis as $open => $close ) {
+                       if ( isset( $tokens[$open]['parenthesis_owner'] ) ) {
+                               $parenthesisOwner = 
$tokens[$open]['parenthesis_owner'];
+                       } else {
+                               $parenthesisOwner = $open - 1; //maybe wrong 
due to T_WHITESPACE
+                       }
+                       if ( in_array( $tokens[$parenthesisOwner]['code'], 
$codes, true ) ) {
+                               return true;
+                       }
+               }
+       }
+
+       private function getTokenInCamelCase( $token ) {
+               $tokenArray = explode( '_', strtolower( $token ) );
+               array_shift( $tokenArray ); //remove T_
+               return implode( '', array_map( 'ucfirst', $tokenArray ) );
+       }
+}

-- 
To view, visit https://gerrit.wikimedia.org/r/61178
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I2cbacf9b9987d23aec6b0f10a6d3f9e760126087
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/tools/codesniffer
Gerrit-Branch: master
Gerrit-Owner: Umherirrender <umherirrender_de...@web.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to