ReservedWordsSniff.php 3.28 KB
Newer Older
Ketan's avatar
Ketan committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace Magento\Sniffs\NamingConventions;

use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Files\File;

/**
 * Validates that class name is not reserved word.
 */
class ReservedWordsSniff implements Sniff
{
    /**
     * The following words cannot be used to name a class, interface or trait,
     * and they are also prohibited from being used in namespaces.
     *
     * @link http://php.net/manual/en/reserved.other-reserved-words.php
     *
     * @var string[]
     */
    protected $reservedWords = [
        'int' => '7',
        'float' => '7',
        'bool' => '7',
        'string' => '7',
        'true' => '7',
        'false' => '7',
        'null' => '7',
        'void' => '7.1',
        'iterable' => '7.1',
        'resource' => '7',
        'object' => '7',
        'mixed' => '7',
        'numeric' => '7',
    ];

    /**
     * @inheritdoc
     */
    public function register()
    {
        return [T_CLASS, T_INTERFACE, T_TRAIT, T_NAMESPACE];
    }

    /**
     * Check all namespace parts
     *
     * @param File $sourceFile
     * @param int $stackPtr
     * @return void
     */
    protected function validateNamespace(File $sourceFile, $stackPtr)
    {
        $stackPtr += 2;
        $tokens = $sourceFile->getTokens();
        while ($stackPtr < $sourceFile->numTokens && $tokens[$stackPtr]['code'] !== T_SEMICOLON) {
            if ($tokens[$stackPtr]['code'] === T_WHITESPACE || $tokens[$stackPtr]['code'] === T_NS_SEPARATOR) {
                $stackPtr++; //skip "namespace" and whitespace
                continue;
            }
            $namespacePart = $tokens[$stackPtr]['content'];
            if (isset($this->reservedWords[strtolower($namespacePart)])) {
                $sourceFile->addError(
                    'Cannot use "%s" in namespace as it is reserved since PHP %s',
                    $stackPtr,
                    'Namespace',
                    [$namespacePart, $this->reservedWords[strtolower($namespacePart)]]
                );
            }
            $stackPtr++;
        }
    }

    /**
     * Check class name not having reserved words
     *
     * @param File $sourceFile
     * @param int $stackPtr
     * @return void
     */
    protected function validateClass(File $sourceFile, $stackPtr)
    {
        $tokens = $sourceFile->getTokens();
        $stackPtr += 2; //skip "class" and whitespace
        $className = strtolower($tokens[$stackPtr]['content']);
        if (isset($this->reservedWords[$className])) {
            $sourceFile->addError(
                'Cannot use "%s" as class name as it is reserved since PHP %s',
                $stackPtr,
                'Class',
                [$className, $this->reservedWords[$className]]
            );
        }
    }

    /**
     * @inheritdoc
     */
    public function process(File $sourceFile, $stackPtr)
    {
        $tokens = $sourceFile->getTokens();
        switch ($tokens[$stackPtr]['code']) {
            case T_CLASS:
            case T_INTERFACE:
            case T_TRAIT:
                $this->validateClass($sourceFile, $stackPtr);
                break;
            case T_NAMESPACE:
                $this->validateNamespace($sourceFile, $stackPtr);
                break;
        }
    }
}