1<?php 2/** 3 * Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff. 4 * 5 * PHP version 5 6 * 7 * @category PHP 8 * @package PHP_CodeSniffer 9 * @author Greg Sherwood <gsherwood@squiz.net> 10 * @author Marc McIntyre <mmcintyre@squiz.net> 11 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 12 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 13 * @link http://pear.php.net/package/PHP_CodeSniffer 14 */ 15 16/** 17 * Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff. 18 * 19 * Throws errors if tabs are used for indentation. 20 * 21 * @category PHP 22 * @package PHP_CodeSniffer 23 * @author Greg Sherwood <gsherwood@squiz.net> 24 * @author Marc McIntyre <mmcintyre@squiz.net> 25 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 26 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 27 * @version Release: @package_version@ 28 * @link http://pear.php.net/package/PHP_CodeSniffer 29 */ 30class Generic_Sniffs_WhiteSpace_DisallowTabIndentSniff implements PHP_CodeSniffer_Sniff 31{ 32 33 /** 34 * A list of tokenizers this sniff supports. 35 * 36 * @var array 37 */ 38 public $supportedTokenizers = array( 39 'PHP', 40 'JS', 41 'CSS', 42 ); 43 44 45 /** 46 * Returns an array of tokens this test wants to listen for. 47 * 48 * @return array 49 */ 50 public function register() 51 { 52 return array(T_OPEN_TAG); 53 54 }//end register() 55 56 57 /** 58 * Processes this test, when one of its tokens is encountered. 59 * 60 * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. 61 * @param int $stackPtr The position of the current token in 62 * the stack passed in $tokens. 63 * 64 * @return void 65 */ 66 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 67 { 68 $tokens = $phpcsFile->getTokens(); 69 $error = 'Spaces must be used to indent lines; tabs are not allowed'; 70 $errorCode = 'TabsUsed'; 71 72 $checkTokens = array( 73 T_WHITESPACE => true, 74 T_INLINE_HTML => true, 75 T_DOC_COMMENT_WHITESPACE => true, 76 T_DOC_COMMENT_STRING => true, 77 ); 78 79 for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { 80 if (isset($checkTokens[$tokens[$i]['code']]) === false) { 81 continue; 82 } 83 84 // If tabs are being converted to spaces by the tokeniser, the 85 // original content should be checked instead of the converted content. 86 if (isset($tokens[$i]['orig_content']) === true) { 87 $content = $tokens[$i]['orig_content']; 88 } else { 89 $content = $tokens[$i]['content']; 90 } 91 92 if ($content === '') { 93 continue; 94 } 95 96 if ($tokens[$i]['code'] === T_DOC_COMMENT_WHITESPACE && $content === ' ') { 97 // Ignore file/class-level DocBlock, especially for recording metrics. 98 continue; 99 } 100 101 $tabFound = false; 102 if ($tokens[$i]['column'] === 1) { 103 if ($content[0] === "\t") { 104 $phpcsFile->recordMetric($i, 'Line indent', 'tabs'); 105 $tabFound = true; 106 } else if ($content[0] === ' ') { 107 if (strpos($content, "\t") !== false) { 108 $phpcsFile->recordMetric($i, 'Line indent', 'mixed'); 109 $tabFound = true; 110 } else { 111 $phpcsFile->recordMetric($i, 'Line indent', 'spaces'); 112 } 113 } 114 } else { 115 // Look for tabs so we can report and replace, but don't 116 // record any metrics about them because they aren't 117 // line indent tokens. 118 if (strpos($content, "\t") !== false) { 119 $tabFound = true; 120 $error = 'Spaces must be used for alignment; tabs are not allowed'; 121 $errorCode = 'NonIndentTabsUsed'; 122 } 123 }//end if 124 125 if ($tabFound === false) { 126 continue; 127 } 128 129 $fix = $phpcsFile->addFixableError($error, $i, $errorCode); 130 if ($fix === true) { 131 if (isset($tokens[$i]['orig_content']) === true) { 132 // Use the replacement that PHPCS has already done. 133 $phpcsFile->fixer->replaceToken($i, $tokens[$i]['content']); 134 } else { 135 // Replace tabs with spaces, using an indent of 4 spaces. 136 // Other sniffs can then correct the indent if they need to. 137 $newContent = str_replace("\t", ' ', $tokens[$i]['content']); 138 $phpcsFile->fixer->replaceToken($i, $newContent); 139 } 140 } 141 }//end for 142 143 // Ignore the rest of the file. 144 return ($phpcsFile->numTokens + 1); 145 146 }//end process() 147 148 149}//end class 150