1<?php 2/** 3 * PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff. 4 * 5 * PHP version 5 6 * 7 * @category PHP 8 * @package PHP_CodeSniffer 9 * @author Greg Sherwood <gsherwood@squiz.net> 10 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 11 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 12 * @link http://pear.php.net/package/PHP_CodeSniffer 13 */ 14 15/** 16 * PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff. 17 * 18 * Checks that object operators are indented 4 spaces if they are the first 19 * thing on a line. 20 * 21 * @category PHP 22 * @package PHP_CodeSniffer 23 * @author Greg Sherwood <gsherwood@squiz.net> 24 * @copyright 2006-2014 Squiz Pty Ltd (ABN 77 084 670 600) 25 * @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence 26 * @version Release: @package_version@ 27 * @link http://pear.php.net/package/PHP_CodeSniffer 28 */ 29class PEAR_Sniffs_WhiteSpace_ObjectOperatorIndentSniff implements PHP_CodeSniffer_Sniff 30{ 31 32 /** 33 * The number of spaces code should be indented. 34 * 35 * @var int 36 */ 37 public $indent = 4; 38 39 40 /** 41 * Returns an array of tokens this test wants to listen for. 42 * 43 * @return array 44 */ 45 public function register() 46 { 47 return array(T_OBJECT_OPERATOR); 48 49 }//end register() 50 51 52 /** 53 * Processes this test, when one of its tokens is encountered. 54 * 55 * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the document. 56 * @param int $stackPtr The position of the current token 57 * in the stack passed in $tokens. 58 * 59 * @return void 60 */ 61 public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr) 62 { 63 $tokens = $phpcsFile->getTokens(); 64 65 // Make sure this is the first object operator in a chain of them. 66 $varToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); 67 if ($varToken === false || $tokens[$varToken]['code'] !== T_VARIABLE) { 68 return; 69 } 70 71 // Make sure this is a chained call. 72 $next = $phpcsFile->findNext( 73 T_OBJECT_OPERATOR, 74 ($stackPtr + 1), 75 null, 76 false, 77 null, 78 true 79 ); 80 81 if ($next === false) { 82 // Not a chained call. 83 return; 84 } 85 86 // Determine correct indent. 87 for ($i = ($varToken - 1); $i >= 0; $i--) { 88 if ($tokens[$i]['line'] !== $tokens[$varToken]['line']) { 89 $i++; 90 break; 91 } 92 } 93 94 $requiredIndent = 0; 95 if ($i >= 0 && $tokens[$i]['code'] === T_WHITESPACE) { 96 $requiredIndent = strlen($tokens[$i]['content']); 97 } 98 99 $requiredIndent += $this->indent; 100 101 // Determine the scope of the original object operator. 102 $origBrackets = null; 103 if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { 104 $origBrackets = $tokens[$stackPtr]['nested_parenthesis']; 105 } 106 107 $origConditions = null; 108 if (isset($tokens[$stackPtr]['conditions']) === true) { 109 $origConditions = $tokens[$stackPtr]['conditions']; 110 } 111 112 // Check indentation of each object operator in the chain. 113 // If the first object operator is on a different line than 114 // the variable, make sure we check its indentation too. 115 if ($tokens[$stackPtr]['line'] > $tokens[$varToken]['line']) { 116 $next = $stackPtr; 117 } 118 119 while ($next !== false) { 120 // Make sure it is in the same scope, otherwise don't check indent. 121 $brackets = null; 122 if (isset($tokens[$next]['nested_parenthesis']) === true) { 123 $brackets = $tokens[$next]['nested_parenthesis']; 124 } 125 126 $conditions = null; 127 if (isset($tokens[$next]['conditions']) === true) { 128 $conditions = $tokens[$next]['conditions']; 129 } 130 131 if ($origBrackets === $brackets && $origConditions === $conditions) { 132 // Make sure it starts a line, otherwise dont check indent. 133 $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($next - 1), $stackPtr, true); 134 $indent = $tokens[($next - 1)]; 135 if ($tokens[$prev]['line'] !== $tokens[$next]['line'] 136 && $indent['code'] === T_WHITESPACE 137 ) { 138 if ($indent['line'] === $tokens[$next]['line']) { 139 $foundIndent = strlen($indent['content']); 140 } else { 141 $foundIndent = 0; 142 } 143 144 if ($foundIndent !== $requiredIndent) { 145 $error = 'Object operator not indented correctly; expected %s spaces but found %s'; 146 $data = array( 147 $requiredIndent, 148 $foundIndent, 149 ); 150 151 $fix = $phpcsFile->addFixableError($error, $next, 'Incorrect', $data); 152 if ($fix === true) { 153 $spaces = str_repeat(' ', $requiredIndent); 154 if ($foundIndent === 0) { 155 $phpcsFile->fixer->addContentBefore($next, $spaces); 156 } else { 157 $phpcsFile->fixer->replaceToken(($next - 1), $spaces); 158 } 159 } 160 } 161 }//end if 162 163 // It cant be the last thing on the line either. 164 $content = $phpcsFile->findNext(T_WHITESPACE, ($next + 1), null, true); 165 if ($tokens[$content]['line'] !== $tokens[$next]['line']) { 166 $error = 'Object operator must be at the start of the line, not the end'; 167 $fix = $phpcsFile->addFixableError($error, $next, 'StartOfLine'); 168 if ($fix === true) { 169 $phpcsFile->fixer->beginChangeset(); 170 for ($x = ($next + 1); $x < $content; $x++) { 171 $phpcsFile->fixer->replaceToken($x, ''); 172 } 173 174 $phpcsFile->fixer->addNewlineBefore($next); 175 $phpcsFile->fixer->endChangeset(); 176 } 177 } 178 }//end if 179 180 $next = $phpcsFile->findNext( 181 T_OBJECT_OPERATOR, 182 ($next + 1), 183 null, 184 false, 185 null, 186 true 187 ); 188 }//end while 189 190 }//end process() 191 192 193}//end class 194