/PHP/CodeSniffer/Standards/Kohana/Sniffs/ControlStructures/SwitchSniff.php

https://github.com/acoulton/coding-standards · PHP · 147 lines · 83 code · 17 blank · 47 comment · 23 complexity · 4fe1b4a9743938220cfabc2203cdc929 MD5 · raw file

  1. <?php
  2. /**
  3. * Kohana_Sniffs_ControlStructures_SwitchSniff.
  4. *
  5. * PHP version 5
  6. *
  7. * @category PHP
  8. * @package PHP_CodeSniffer
  9. * @author Matthew Turland <matt@ishouldbecoding.com>
  10. * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
  11. * @version CVS: $Id$
  12. * @link http://pear.php.net/package/PHP_CodeSniffer
  13. */
  14. /**
  15. * Throws errors if switch structures do not conform to the coding standard.
  16. *
  17. * @category PHP
  18. * @package PHP_CodeSniffer
  19. * @author Matthew Turland <matt@ishouldbecoding.com>
  20. * @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
  21. * @version Release: @release_version@
  22. * @link http://pear.php.net/package/PHP_CodeSniffer
  23. */
  24. class Kohana_Sniffs_ControlStructures_SwitchSniff implements PHP_CodeSniffer_Sniff
  25. {
  26. /**
  27. * Returns an array of tokens this test wants to listen for.
  28. *
  29. * @return array
  30. */
  31. public function register()
  32. {
  33. return array(
  34. T_CASE,
  35. T_DEFAULT,
  36. T_BREAK
  37. );
  38. }
  39. /**
  40. * Processes this test, when one of its tokens is encountered.
  41. *
  42. * @param PHP_CodeSniffer_File $phpcsFile All the tokens found in the
  43. * document
  44. * @param int $stackPtr Position of the current token in the stack passed
  45. * in $tokens
  46. * @return void
  47. */
  48. public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
  49. {
  50. $tokens = $phpcsFile->getTokens();
  51. $line = $tokens[$stackPtr]['line'];
  52. $tokenCount = $phpcsFile->numTokens - 1;
  53. // Each case, break, and default should be on a separate line
  54. $start = $end = $stackPtr;
  55. while ($tokens[$start]['line'] == $line && $start > 0) {
  56. $start--;
  57. }
  58. while ($tokens[$end]['line'] == $line && $end < $tokenCount) {
  59. $end++;
  60. }
  61. $lineTokens = array_slice($tokens, $start, $end - $start + 1, true);
  62. foreach ($lineTokens as $tokenPtr => $token) {
  63. switch ($token['type']) {
  64. case 'T_CASE':
  65. case 'T_DEFAULT':
  66. case 'T_BREAK':
  67. if ($tokenPtr > $stackPtr) {
  68. $error = 'Each case, break, and default should be on a separate line';
  69. $phpcsFile->addError($error, $stackPtr);
  70. }
  71. }
  72. }
  73. if ($tokens[$stackPtr]['type'] == 'T_BREAK') {
  74. return;
  75. }
  76. // In this context the scope opener is either a colon or semicolon
  77. $stackPtrScopeOpener = $tokens[$stackPtr]['scope_opener'];
  78. // Account for typos using ; instead of : on case lines
  79. if ($tokens[$stackPtrScopeOpener]['type'] === 'T_SEMICOLON') {
  80. $error = 'Potential use of ; instead of : on a case line';
  81. $phpcsFile->addWarning($error, $stackPtr);
  82. return;
  83. }
  84. // Code inside case and default blocks should be indented
  85. for (
  86. $open = $tokens[$stackPtr]['scope_opener'];
  87. $tokens[$open]['line'] == $line;
  88. $open++
  89. );
  90. for (
  91. $close = $tokens[$stackPtr]['scope_closer'];
  92. $tokens[$close]['line'] == $tokens[$close + 1]['line'];
  93. $close--
  94. );
  95. $indent = $phpcsFile->getTokensAsString($start, $stackPtr - $start);
  96. $tabCount = substr_count($indent, "\t") + 1;
  97. $tabString = str_repeat("\t", $tabCount);
  98. foreach (range($open, $close) as $tokenPtr) {
  99. // The first condition checks that we're on a new line (so we can check the indent)
  100. // The second checks to see if there is sufficient indent
  101. if ($tokens[$tokenPtr]['line'] == $tokens[$tokenPtr - 1]['line'] + 1
  102. && substr($tokens[$tokenPtr]['content'], 0, $tabCount) != $tabString) {
  103. // Empty lines are exempt from the indentation rule
  104. $empty_line = TRUE;
  105. // We now need to have a look along the line and see if there're any case / default
  106. // tags in case we're allowing conditions to drop through
  107. for (
  108. $localTokenPtr = $tokenPtr;
  109. $tokens[$localTokenPtr]['line'] === $tokens[$localTokenPtr + 1]['line'];
  110. $localTokenPtr++
  111. ) {
  112. // If there's a break or default tag on this line then we need to move onto the next line
  113. if(in_array($tokens[$localTokenPtr]['type'], array('T_CASE', 'T_DEFAULT'))) {
  114. continue 2;
  115. }
  116. if($tokens[$localTokenPtr]['type'] !== 'T_WHITESPACE')
  117. {
  118. $empty_line = FALSE;
  119. }
  120. }
  121. // Empty lines are exempt from the indentation rules
  122. if( ! $empty_line)
  123. {
  124. $phpcsFile->addError('Code inside case and default blocks should be indented', $tokenPtr);
  125. }
  126. }
  127. }
  128. }
  129. }
  130. ?>