LowPHPCSSniff.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <?php
  2. /**
  3. * PHPCompatibility, an external standard for PHP_CodeSniffer.
  4. *
  5. * @package PHPCompatibility
  6. * @copyright 2012-2019 PHPCompatibility Contributors
  7. * @license https://opensource.org/licenses/LGPL-3.0 LGPL3
  8. * @link https://github.com/PHPCompatibility/PHPCompatibility
  9. */
  10. namespace PHPCompatibility\Sniffs\Upgrade;
  11. use PHPCompatibility\Sniff;
  12. use PHPCompatibility\PHPCSHelper;
  13. use PHP_CodeSniffer_File as File;
  14. /**
  15. * Add a notification for users of low PHPCS versions.
  16. *
  17. * Originally PHPCompatibility supported PHPCS 1.5.x, 2.x and since PHPCompatibility 8.0.0, 3.x.
  18. * Support for PHPCS < 2.3.0 has been dropped in PHPCompatibility 9.0.0.
  19. *
  20. * The standard will - up to a point - still work for users of lower
  21. * PHPCS versions, but will give less accurate results and may throw
  22. * notices and warnings (or even fatal out).
  23. *
  24. * This sniff adds an explicit error/warning for users of the standard
  25. * using a PHPCS version below the recommended version.
  26. *
  27. * @link https://github.com/PHPCompatibility/PHPCompatibility/issues/688
  28. * @link https://github.com/PHPCompatibility/PHPCompatibility/issues/835
  29. *
  30. * @since 8.2.0
  31. */
  32. class LowPHPCSSniff extends Sniff
  33. {
  34. /**
  35. * The minimum supported PHPCS version.
  36. *
  37. * Users on PHPCS versions below this will see an ERROR message.
  38. *
  39. * @since 8.2.0
  40. * @since 9.3.0 Changed from $minSupportedVersion property to a constant.
  41. *
  42. * @var string
  43. */
  44. const MIN_SUPPORTED_VERSION = '2.3.0';
  45. /**
  46. * The minimum recommended PHPCS version.
  47. *
  48. * Users on PHPCS versions below this will see a WARNING.
  49. *
  50. * @since 8.2.0
  51. * @since 9.3.0 Changed from $minRecommendedVersion property to a constant.
  52. *
  53. * @var string
  54. */
  55. const MIN_RECOMMENDED_VERSION = '2.6.0';
  56. /**
  57. * Keep track of whether this sniff needs to actually run.
  58. *
  59. * This will be set to `false` when either a high enough PHPCS
  60. * version is detected or once the error/warning has been thrown,
  61. * to make sure that the notice will only be thrown once per run.
  62. *
  63. * @since 8.2.0
  64. *
  65. * @var bool
  66. */
  67. private $examine = true;
  68. /**
  69. * Returns an array of tokens this test wants to listen for.
  70. *
  71. * @since 8.2.0
  72. *
  73. * @return array
  74. */
  75. public function register()
  76. {
  77. return array(
  78. \T_OPEN_TAG,
  79. );
  80. }
  81. /**
  82. * Processes this test, when one of its tokens is encountered.
  83. *
  84. * @since 8.2.0
  85. *
  86. * @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
  87. * @param int $stackPtr The position of the current token in the
  88. * stack passed in $tokens.
  89. *
  90. * @return int|void Integer stack pointer to skip forward or void to continue
  91. * normal file processing.
  92. */
  93. public function process(File $phpcsFile, $stackPtr)
  94. {
  95. // Don't do anything if the warning has already been thrown or is not necessary.
  96. if ($this->examine === false) {
  97. return ($phpcsFile->numTokens + 1);
  98. }
  99. $phpcsVersion = PHPCSHelper::getVersion();
  100. // Don't do anything if the PHPCS version used is above the minimum recommended version.
  101. if (version_compare($phpcsVersion, self::MIN_RECOMMENDED_VERSION, '>=')) {
  102. $this->examine = false;
  103. return ($phpcsFile->numTokens + 1);
  104. }
  105. if (version_compare($phpcsVersion, self::MIN_SUPPORTED_VERSION, '<')) {
  106. $isError = true;
  107. $message = 'IMPORTANT: Please be advised that the minimum PHP_CodeSniffer version the PHPCompatibility standard supports is %s. You are currently using PHP_CodeSniffer %s. Please upgrade your PHP_CodeSniffer installation. The recommended version of PHP_CodeSniffer for PHPCompatibility is %s or higher.';
  108. $errorCode = 'Unsupported_' . $this->stringToErrorCode(self::MIN_SUPPORTED_VERSION);
  109. $replacements = array(
  110. self::MIN_SUPPORTED_VERSION,
  111. $phpcsVersion,
  112. self::MIN_RECOMMENDED_VERSION,
  113. $errorCode,
  114. );
  115. } else {
  116. $isError = false;
  117. $message = 'IMPORTANT: Please be advised that for the most reliable PHPCompatibility results, PHP_CodeSniffer %s or higher should be used. Support for lower versions will be dropped in the foreseeable future. You are currently using PHP_CodeSniffer %s. Please upgrade your PHP_CodeSniffer installation to version %s or higher.';
  118. $errorCode = 'BelowRecommended_' . $this->stringToErrorCode(self::MIN_RECOMMENDED_VERSION);
  119. $replacements = array(
  120. self::MIN_RECOMMENDED_VERSION,
  121. $phpcsVersion,
  122. self::MIN_RECOMMENDED_VERSION,
  123. $errorCode,
  124. );
  125. }
  126. /*
  127. * Figure out the report width to determine how long the delimiter lines should be.
  128. *
  129. * This is not an exact calculation as there are a number of unknowns at the time the
  130. * notice is thrown (whether there are other notices for the file, whether those are
  131. * warnings or errors, whether there are auto-fixable issues etc).
  132. *
  133. * In other words, this is just an approximation to get a reasonably stable and
  134. * readable message layout format.
  135. *
  136. * {@internal
  137. * PHPCS has had some changes as to how the messages display over the years.
  138. * Most significantly in 2.4.0 it was attempted to solve an issue with messages
  139. * containing new lines. Unfortunately, that solution is buggy.
  140. * An improved version has been pulled upstream and will hopefully make it
  141. * into PHPCS 3.3.1/3.4.0.
  142. *
  143. * Anyway, this means that instead of new lines, delimiter lines will be used to improved
  144. * the readability of the (long) message.
  145. *
  146. * Also, as of PHPCS 2.2.0, the report width when using the `-s` option is 8 wider than
  147. * it should be. A patch for that is included in the same upstream PR.
  148. *
  149. * If/when the upstream PR has been merged and the minimum supported/recommended version
  150. * of PHPCompatibility would go beyond that, the below code should be adjusted.}
  151. */
  152. $reportWidth = PHPCSHelper::getCommandLineData($phpcsFile, 'reportWidth');
  153. if (empty($reportWidth)) {
  154. $reportWidth = 80;
  155. }
  156. $showSources = PHPCSHelper::getCommandLineData($phpcsFile, 'showSources');
  157. if ($showSources === true) {
  158. $reportWidth += 6;
  159. }
  160. $messageWidth = ($reportWidth - 15); // 15 is length of " # | WARNING | ".
  161. $delimiterLine = str_repeat('-', ($messageWidth));
  162. $disableNotice = 'To disable this notice, add --exclude=PHPCompatibility.Upgrade.LowPHPCS to your command or add <exclude name="PHPCompatibility.Upgrade.LowPHPCS.%s"/> to your custom ruleset. ';
  163. $thankYou = 'Thank you for using PHPCompatibility!';
  164. $message .= ' ' . $delimiterLine;
  165. $message .= ' ' . $disableNotice;
  166. $message .= ' ' . $delimiterLine;
  167. $message .= ' ' . $thankYou;
  168. $this->addMessage($phpcsFile, $message, 0, $isError, $errorCode, $replacements);
  169. $this->examine = false;
  170. }
  171. }