Seditio Source
Root |
./othercms/croogo-4.0.7/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php
<?php
/**
 * Checks the declaration of the class and its inheritance is correct.
 *
 * @author    Greg Sherwood <gsherwood@squiz.net>
 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
 * @license   https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
 */

namespace PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes;

use
PHP_CodeSniffer\Files\File;
use
PHP_CodeSniffer\Standards\PEAR\Sniffs\Classes\ClassDeclarationSniff as PEARClassDeclarationSniff;
use
PHP_CodeSniffer\Util\Tokens;

class
ClassDeclarationSniff extends PEARClassDeclarationSniff
{

   
/**
     * The number of spaces code should be indented.
     *
     * @var integer
     */
   
public $indent = 4;


   
/**
     * Processes this test, when one of its tokens is encountered.
     *
     * @param \PHP_CodeSniffer\Files\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(File $phpcsFile, $stackPtr)
    {
       
// We want all the errors from the PEAR standard, plus some of our own.
       
parent::process($phpcsFile, $stackPtr);

       
// Just in case.
       
$tokens = $phpcsFile->getTokens();
        if (isset(
$tokens[$stackPtr]['scope_opener']) === false) {
            return;
        }

       
$this->processOpen($phpcsFile, $stackPtr);
       
$this->processClose($phpcsFile, $stackPtr);

    }
//end process()


    /**
     * Processes the opening section of a class declaration.
     *
     * @param \PHP_CodeSniffer\Files\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 processOpen(File $phpcsFile, $stackPtr)
    {
       
$tokens       = $phpcsFile->getTokens();
       
$stackPtrType = strtolower($tokens[$stackPtr]['content']);

       
// Check alignment of the keyword and braces.
       
if ($tokens[($stackPtr - 1)]['code'] === T_WHITESPACE) {
           
$prevContent = $tokens[($stackPtr - 1)]['content'];
            if (
$prevContent !== $phpcsFile->eolChar) {
               
$blankSpace = substr($prevContent, strpos($prevContent, $phpcsFile->eolChar));
               
$spaces     = strlen($blankSpace);

                if (
in_array($tokens[($stackPtr - 2)]['code'], [T_ABSTRACT, T_FINAL], true) === true
                   
&& $spaces !== 1
               
) {
                   
$prevContent = strtolower($tokens[($stackPtr - 2)]['content']);
                   
$error       = 'Expected 1 space between %s and %s keywords; %s found';
                   
$data        = [
                       
$prevContent,
                       
$stackPtrType,
                       
$spaces,
                    ];

                   
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceBeforeKeyword', $data);
                    if (
$fix === true) {
                       
$phpcsFile->fixer->replaceToken(($stackPtr - 1), ' ');
                    }
                }
            } else if (
$tokens[($stackPtr - 2)]['code'] === T_ABSTRACT
               
|| $tokens[($stackPtr - 2)]['code'] === T_FINAL
           
) {
               
$prevContent = strtolower($tokens[($stackPtr - 2)]['content']);
               
$error       = 'Expected 1 space between %s and %s keywords; newline found';
               
$data        = [
                   
$prevContent,
                   
$stackPtrType,
                ];

               
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'NewlineBeforeKeyword', $data);
                if (
$fix === true) {
                   
$phpcsFile->fixer->replaceToken(($stackPtr - 1), ' ');
                }
            }
//end if
       
}//end if

        // We'll need the indent of the class/interface declaration for later.
       
$classIndent = 0;
        for (
$i = ($stackPtr - 1); $i > 0; $i--) {
            if (
$tokens[$i]['line'] === $tokens[$stackPtr]['line']) {
                continue;
            }

           
// We changed lines.
           
if ($tokens[($i + 1)]['code'] === T_WHITESPACE) {
               
$classIndent = $tokens[($i + 1)]['length'];
            }

            break;
        }

       
$className    = null;
       
$checkSpacing = true;

        if (
$tokens[$stackPtr]['code'] !== T_ANON_CLASS) {
           
$className = $phpcsFile->findNext(T_STRING, $stackPtr);
        } else {
           
// Ignore the spacing check if this is a simple anon class.
           
$next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true);
            if (
$next === $tokens[$stackPtr]['scope_opener']
                &&
$tokens[$next]['line'] > $tokens[$stackPtr]['line']
            ) {
               
$checkSpacing = false;
            }
        }

        if (
$checkSpacing === true) {
           
// Spacing of the keyword.
           
if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) {
               
$gap = 0;
            } else if (
$tokens[($stackPtr + 2)]['line'] !== $tokens[$stackPtr]['line']) {
               
$gap = 'newline';
            } else {
               
$gap = $tokens[($stackPtr + 1)]['length'];
            }

            if (
$gap !== 1) {
               
$error = 'Expected 1 space after %s keyword; %s found';
               
$data  = [
                   
$stackPtrType,
                   
$gap,
                ];

               
$fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceAfterKeyword', $data);
                if (
$fix === true) {
                    if (
$gap === 0) {
                       
$phpcsFile->fixer->addContent($stackPtr, ' ');
                    } else {
                       
$phpcsFile->fixer->replaceToken(($stackPtr + 1), ' ');
                    }
                }
            }
        }
//end if

        // Check after the class/interface name.
       
if ($className !== null
           
&& $tokens[($className + 2)]['line'] === $tokens[$className]['line']
        ) {
           
$gap = $tokens[($className + 1)]['content'];
            if (
strlen($gap) !== 1) {
               
$found = strlen($gap);
               
$error = 'Expected 1 space after %s name; %s found';
               
$data  = [
                   
$stackPtrType,
                   
$found,
                ];

               
$fix = $phpcsFile->addFixableError($error, $className, 'SpaceAfterName', $data);
                if (
$fix === true) {
                   
$phpcsFile->fixer->replaceToken(($className + 1), ' ');
                }
            }
        }

       
$openingBrace = $tokens[$stackPtr]['scope_opener'];

       
// Check positions of the extends and implements keywords.
       
$compareToken = $stackPtr;
       
$compareType  = 'name';
        if (
$tokens[$stackPtr]['code'] === T_ANON_CLASS) {
            if (isset(
$tokens[$stackPtr]['parenthesis_opener']) === true) {
               
$compareToken = $tokens[$stackPtr]['parenthesis_closer'];
               
$compareType  = 'closing parenthesis';
            } else {
               
$compareType = 'keyword';
            }
        }

        foreach ([
'extends', 'implements'] as $keywordType) {
           
$keyword = $phpcsFile->findNext(constant('T_'.strtoupper($keywordType)), ($compareToken + 1), $openingBrace);
            if (
$keyword !== false) {
                if (
$tokens[$keyword]['line'] !== $tokens[$compareToken]['line']) {
                   
$error = 'The '.$keywordType.' keyword must be on the same line as the %s '.$compareType;
                   
$data  = [$stackPtrType];
                   
$fix   = $phpcsFile->addFixableError($error, $keyword, ucfirst($keywordType).'Line', $data);
                    if (
$fix === true) {
                       
$phpcsFile->fixer->beginChangeset();
                       
$comments = [];

                        for (
$i = ($compareToken + 1); $i < $keyword; ++$i) {
                            if (
$tokens[$i]['code'] === T_COMMENT) {
                               
$comments[] = trim($tokens[$i]['content']);
                            }

                            if (
$tokens[$i]['code'] === T_WHITESPACE
                               
|| $tokens[$i]['code'] === T_COMMENT
                           
) {
                               
$phpcsFile->fixer->replaceToken($i, ' ');
                            }
                        }

                       
$phpcsFile->fixer->addContent($compareToken, ' ');
                        if (empty(
$comments) === false) {
                           
$i = $keyword;
                            while (
$tokens[($i + 1)]['line'] === $tokens[$keyword]['line']) {
                                ++
$i;
                            }

                           
$phpcsFile->fixer->addContentBefore($i, ' '.implode(' ', $comments));
                        }

                       
$phpcsFile->fixer->endChangeset();
                    }
//end if
               
} else {
                   
// Check the whitespace before. Whitespace after is checked
                    // later by looking at the whitespace before the first class name
                    // in the list.
                   
$gap = $tokens[($keyword - 1)]['length'];
                    if (
$gap !== 1) {
                       
$error = 'Expected 1 space before '.$keywordType.' keyword; %s found';
                       
$data  = [$gap];
                       
$fix   = $phpcsFile->addFixableError($error, $keyword, 'SpaceBefore'.ucfirst($keywordType), $data);
                        if (
$fix === true) {
                           
$phpcsFile->fixer->replaceToken(($keyword - 1), ' ');
                        }
                    }
                }
//end if
           
}//end if
       
}//end foreach

        // Check each of the extends/implements class names. If the extends/implements
        // keyword is the last content on the line, it means we need to check for
        // the multi-line format, so we do not include the class names
        // from the extends/implements list in the following check.
        // Note that classes can only extend one other class, so they can't use a
        // multi-line extends format, whereas an interface can extend multiple
        // other interfaces, and so uses a multi-line extends format.
       
if ($tokens[$stackPtr]['code'] === T_INTERFACE) {
           
$keywordTokenType = T_EXTENDS;
        } else {
           
$keywordTokenType = T_IMPLEMENTS;
        }

       
$implements          = $phpcsFile->findNext($keywordTokenType, ($stackPtr + 1), $openingBrace);
       
$multiLineImplements = false;
        if (
$implements !== false) {
           
$prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($openingBrace - 1), $implements, true);
            if (
$tokens[$prev]['line'] !== $tokens[$implements]['line']) {
               
$multiLineImplements = true;
            }
        }

       
$find = [
           
T_STRING,
           
$keywordTokenType,
        ];

        if (
$className !== null) {
           
$start = $className;
        } else if (isset(
$tokens[$stackPtr]['parenthesis_closer']) === true) {
           
$start = $tokens[$stackPtr]['parenthesis_closer'];
        } else {
           
$start = $stackPtr;
        }

       
$classNames = [];
       
$nextClass  = $phpcsFile->findNext($find, ($start + 2), ($openingBrace - 1));
        while (
$nextClass !== false) {
           
$classNames[] = $nextClass;
           
$nextClass    = $phpcsFile->findNext($find, ($nextClass + 1), ($openingBrace - 1));
        }

       
$classCount         = count($classNames);
       
$checkingImplements = false;
       
$implementsToken    = null;
        foreach (
$classNames as $n => $className) {
            if (
$tokens[$className]['code'] === $keywordTokenType) {
               
$checkingImplements = true;
               
$implementsToken    = $className;

                continue;
            }

            if (
$checkingImplements === true
               
&& $multiLineImplements === true
               
&& ($tokens[($className - 1)]['code'] !== T_NS_SEPARATOR
               
|| $tokens[($className - 2)]['code'] !== T_STRING)
            ) {
               
$prev = $phpcsFile->findPrevious(
                    [
                       
T_NS_SEPARATOR,
                       
T_WHITESPACE,
                    ],
                    (
$className - 1),
                   
$implements,
                   
true
               
);

                if (
$prev === $implementsToken && $tokens[$className]['line'] !== ($tokens[$prev]['line'] + 1)) {
                    if (
$keywordTokenType === T_EXTENDS) {
                       
$error = 'The first item in a multi-line extends list must be on the line following the extends keyword';
                       
$fix   = $phpcsFile->addFixableError($error, $className, 'FirstExtendsInterfaceSameLine');
                    } else {
                       
$error = 'The first item in a multi-line implements list must be on the line following the implements keyword';
                       
$fix   = $phpcsFile->addFixableError($error, $className, 'FirstInterfaceSameLine');
                    }

                    if (
$fix === true) {
                       
$phpcsFile->fixer->beginChangeset();
                        for (
$i = ($prev + 1); $i < $className; $i++) {
                            if (
$tokens[$i]['code'] !== T_WHITESPACE) {
                                break;
                            }

                           
$phpcsFile->fixer->replaceToken($i, '');
                        }

                       
$phpcsFile->fixer->addNewline($prev);
                       
$phpcsFile->fixer->endChangeset();
                    }
                } else if (
$tokens[$prev]['line'] !== ($tokens[$className]['line'] - 1)) {
                    if (
$keywordTokenType === T_EXTENDS) {
                       
$error = 'Only one interface may be specified per line in a multi-line extends declaration';
                       
$fix   = $phpcsFile->addFixableError($error, $className, 'ExtendsInterfaceSameLine');
                    } else {
                       
$error = 'Only one interface may be specified per line in a multi-line implements declaration';
                       
$fix   = $phpcsFile->addFixableError($error, $className, 'InterfaceSameLine');
                    }

                    if (
$fix === true) {
                       
$phpcsFile->fixer->beginChangeset();
                        for (
$i = ($prev + 1); $i < $className; $i++) {
                            if (
$tokens[$i]['code'] !== T_WHITESPACE) {
                                break;
                            }

                           
$phpcsFile->fixer->replaceToken($i, '');
                        }

                       
$phpcsFile->fixer->addNewline($prev);
                       
$phpcsFile->fixer->endChangeset();
                    }
                } else {
                   
$prev = $phpcsFile->findPrevious(T_WHITESPACE, ($className - 1), $implements);
                    if (
$tokens[$prev]['line'] !== $tokens[$className]['line']) {
                       
$found = 0;
                    } else {
                       
$found = $tokens[$prev]['length'];
                    }

                   
$expected = ($classIndent + $this->indent);
                    if (
$found !== $expected) {
                       
$error = 'Expected %s spaces before interface name; %s found';
                       
$data  = [
                           
$expected,
                           
$found,
                        ];
                       
$fix   = $phpcsFile->addFixableError($error, $className, 'InterfaceWrongIndent', $data);
                        if (
$fix === true) {
                           
$padding = str_repeat(' ', $expected);
                            if (
$found === 0) {
                               
$phpcsFile->fixer->addContent($prev, $padding);
                            } else {
                               
$phpcsFile->fixer->replaceToken($prev, $padding);
                            }
                        }
                    }
                }
//end if
           
} else if ($tokens[($className - 1)]['code'] !== T_NS_SEPARATOR
               
|| $tokens[($className - 2)]['code'] !== T_STRING
           
) {
               
// Not part of a longer fully qualified class name.
               
if ($tokens[($className - 1)]['code'] === T_COMMA
                   
|| ($tokens[($className - 1)]['code'] === T_NS_SEPARATOR
                   
&& $tokens[($className - 2)]['code'] === T_COMMA)
                ) {
                   
$error = 'Expected 1 space before "%s"; 0 found';
                   
$data  = [$tokens[$className]['content']];
                   
$fix   = $phpcsFile->addFixableError($error, ($nextComma + 1), 'NoSpaceBeforeName', $data);
                    if (
$fix === true) {
                       
$phpcsFile->fixer->addContentBefore(($nextComma + 1), ' ');
                    }
                } else {
                    if (
$tokens[($className - 1)]['code'] === T_NS_SEPARATOR) {
                       
$prev = ($className - 2);
                    } else {
                       
$prev = ($className - 1);
                    }

                   
$last    = $phpcsFile->findPrevious(T_WHITESPACE, $prev, null, true);
                   
$content = $phpcsFile->getTokensAsString(($last + 1), ($prev - $last));
                    if (
$content !== ' ') {
                       
$found = strlen($content);

                       
$error = 'Expected 1 space before "%s"; %s found';
                       
$data  = [
                           
$tokens[$className]['content'],
                           
$found,
                        ];

                       
$fix = $phpcsFile->addFixableError($error, $className, 'SpaceBeforeName', $data);
                        if (
$fix === true) {
                            if (
$tokens[$prev]['code'] === T_WHITESPACE) {
                               
$phpcsFile->fixer->beginChangeset();
                               
$phpcsFile->fixer->replaceToken($prev, ' ');
                                while (
$tokens[--$prev]['code'] === T_WHITESPACE) {
                                   
$phpcsFile->fixer->replaceToken($prev, ' ');
                                }

                               
$phpcsFile->fixer->endChangeset();
                            } else {
                               
$phpcsFile->fixer->addContent($prev, ' ');
                            }
                        }
                    }
//end if
               
}//end if
           
}//end if

           
if ($checkingImplements === true
               
&& $tokens[($className + 1)]['code'] !== T_NS_SEPARATOR
               
&& $tokens[($className + 1)]['code'] !== T_COMMA
           
) {
                if (
$n !== ($classCount - 1)) {
                   
// This is not the last class name, and the comma
                    // is not where we expect it to be.
                   
if ($tokens[($className + 2)]['code'] !== $keywordTokenType) {
                       
$error = 'Expected 0 spaces between "%s" and comma; %s found';
                       
$data  = [
                           
$tokens[$className]['content'],
                           
$tokens[($className + 1)]['length'],
                        ];

                       
$fix = $phpcsFile->addFixableError($error, $className, 'SpaceBeforeComma', $data);
                        if (
$fix === true) {
                           
$phpcsFile->fixer->replaceToken(($className + 1), '');
                        }
                    }
                }

               
$nextComma = $phpcsFile->findNext(T_COMMA, $className);
            } else {
               
$nextComma = ($className + 1);
            }
//end if
       
}//end foreach

   
}//end processOpen()


    /**
     * Processes the closing section of a class declaration.
     *
     * @param \PHP_CodeSniffer\Files\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 processClose(File $phpcsFile, $stackPtr)
    {
       
$tokens = $phpcsFile->getTokens();

       
// Check that the closing brace comes right after the code body.
       
$closeBrace  = $tokens[$stackPtr]['scope_closer'];
       
$prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($closeBrace - 1), null, true);
        if (
$prevContent !== $tokens[$stackPtr]['scope_opener']
            &&
$tokens[$prevContent]['line'] !== ($tokens[$closeBrace]['line'] - 1)
        ) {
           
$error = 'The closing brace for the %s must go on the next line after the body';
           
$data  = [$tokens[$stackPtr]['content']];
           
$fix   = $phpcsFile->addFixableError($error, $closeBrace, 'CloseBraceAfterBody', $data);

            if (
$fix === true) {
               
$phpcsFile->fixer->beginChangeset();
                for (
$i = ($prevContent + 1); $i < $closeBrace; $i++) {
                   
$phpcsFile->fixer->replaceToken($i, '');
                }

                if (
strpos($tokens[$prevContent]['content'], $phpcsFile->eolChar) === false) {
                   
$phpcsFile->fixer->replaceToken($closeBrace, $phpcsFile->eolChar.$tokens[$closeBrace]['content']);
                }

               
$phpcsFile->fixer->endChangeset();
            }
        }
//end if

       
if ($tokens[$stackPtr]['code'] !== T_ANON_CLASS) {
           
// Check the closing brace is on it's own line, but allow
            // for comments like "//end class".
           
$ignoreTokens   = Tokens::$phpcsCommentTokens;
           
$ignoreTokens[] = T_WHITESPACE;
           
$ignoreTokens[] = T_COMMENT;
           
$ignoreTokens[] = T_SEMICOLON;
           
$ignoreTokens[] = T_COMMA;
           
$nextContent    = $phpcsFile->findNext($ignoreTokens, ($closeBrace + 1), null, true);
            if (
$tokens[$nextContent]['content'] !== $phpcsFile->eolChar
               
&& $tokens[$nextContent]['line'] === $tokens[$closeBrace]['line']
            ) {
               
$type  = strtolower($tokens[$stackPtr]['content']);
               
$error = 'Closing %s brace must be on a line by itself';
               
$data  = [$type];
               
$phpcsFile->addError($error, $closeBrace, 'CloseBraceSameLine', $data);
            }
        }

    }
//end processClose()


}//end class