Skip to content

Commit

Permalink
Added a new comment syntax for PHPCS instructions; deprecates the exi…
Browse files Browse the repository at this point in the history
…sting @codingstandards format
  • Loading branch information
gsherwood committed Oct 30, 2017
1 parent 855fae3 commit 5325170
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 12 deletions.
15 changes: 15 additions & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@ http://pear.php.net/dtd/package-2.0.xsd">
</stability>
<license uri="https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt">BSD 3-Clause License</license>
<notes>
- This release deprecates the @codingStandards comment syntax used for sending commands to PHP_CodeSniffer
-- The existing sytax will continue to work in all version 3 releases, but will be removed in version 4
-- The comment formats have been replaced by a shorter syntax:
--- @codingStandardsIgnoreFile becomes phpcs:ignoreFile
--- @codingStandardsIgnoreStart becomes phpcs:disable
--- @codingStandardsIgnoreEnd becomes phpcs:enable
--- @codingStandardsIgnoreLine becomes phpcs:ignore
--- @codingStandardsChangeSetting becomes phpcs:set
-- Comments using the new syntax are assigned new comment token types to allow them to be detected:
--- phpcs:ignoreFile has the token T_PHPCS_IGNORE_FILE
--- phpcs:disable has the token T_PHPCS_DISABLE
--- phpcs:enable has the token T_PHPCS_ENABLE
--- phpcs:ignore has the token T_PHPCS_IGNORE
--- phpcs:set has the token T_PHPCS_SET

- Array properties specified in ruleset files now have their keys and values trimmed
-- This saves having to do this in individual sniffs, and stops errors introduced by whitespace in rulesets
-- Thanks to Juliette Reinders Folmer for the patch
Expand Down
41 changes: 35 additions & 6 deletions src/Files/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -320,26 +320,30 @@ public function process()
// Check for ignored lines.
if ($checkAnnotations === true
&& ($token['code'] === T_COMMENT
|| $token['code'] === T_PHPCS_IGNORE_FILE
|| $token['code'] === T_PHPCS_SET
|| $token['code'] === T_DOC_COMMENT_TAG
|| ($inTests === true && $token['code'] === T_INLINE_HTML))
) {
if (strpos($token['content'], '@codingStandards') !== false) {
if (strpos($token['content'], '@codingStandardsIgnoreFile') !== false) {
$commentText = ltrim($this->tokens[$stackPtr]['content'], ' /*');
$commentTextLower = strtolower($commentText);
if (strpos($commentText, '@codingStandards') !== false) {
if (strpos($commentText, '@codingStandardsIgnoreFile') !== false) {
// Ignoring the whole file, just a little late.
$this->errors = array();
$this->warnings = array();
$this->errorCount = 0;
$this->warningCount = 0;
$this->fixableCount = 0;
return;
} else if (strpos($token['content'], '@codingStandardsChangeSetting') !== false) {
$start = strpos($token['content'], '@codingStandardsChangeSetting');
$comment = substr($token['content'], ($start + 30));
} else if (strpos($commentText, '@codingStandardsChangeSetting') !== false) {
$start = strpos($commentText, '@codingStandardsChangeSetting');
$comment = substr($commentText, ($start + 30));
$parts = explode(' ', $comment);
if ($parts >= 3) {
$sniffParts = explode('.', $parts[0]);
if ($sniffParts >= 3) {
// If the sniff code is not know to us, it has not been registered in this run.
// If the sniff code is not known to us, it has not been registered in this run.
// But don't throw an error as it could be there for a different standard to use.
if (isset($this->ruleset->sniffCodes[$parts[0]]) === true) {
$listenerCode = array_shift($parts);
Expand All @@ -351,6 +355,31 @@ public function process()
}
}
}//end if
} else if (substr($commentTextLower, 0, 16) === 'phpcs:ignorefile') {
// Ignoring the whole file, just a little late.
$this->errors = array();
$this->warnings = array();
$this->errorCount = 0;
$this->warningCount = 0;
$this->fixableCount = 0;
return;
} else if (substr($commentTextLower, 0, 9) === 'phpcs:set') {
// Need to maintain case here, to get the correct sniff code.
$parts = explode(' ', substr($commentText, 10));
if ($parts >= 3) {
$sniffParts = explode('.', $parts[0]);
if ($sniffParts >= 3) {
// If the sniff code is not known to us, it has not been registered in this run.
// But don't throw an error as it could be there for a different standard to use.
if (isset($this->ruleset->sniffCodes[$parts[0]]) === true) {
$listenerCode = array_shift($parts);
$propertyCode = array_shift($parts);
$propertyValue = rtrim(implode(' ', $parts), " */\r\n");
$listenerClass = $this->ruleset->sniffCodes[$listenerCode];
$this->ruleset->setSniffProperty($listenerClass, $propertyCode, $propertyValue);
}
}
}
}//end if
}//end if

Expand Down
4 changes: 3 additions & 1 deletion src/Files/LocalFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ public function __construct($path, Ruleset $ruleset, Config $config)
$firstContent .= fgets($handle);
fclose($handle);

if (strpos($firstContent, '@codingStandardsIgnoreFile') !== false) {
if (strpos($firstContent, '@codingStandardsIgnoreFile') !== false
|| strpos(strtolower($firstContent), 'phpcs:ignorefile') !== false
) {
// We are ignoring the whole file.
$this->ignored = true;
return;
Expand Down
57 changes: 52 additions & 5 deletions src/Tokenizers/Tokenizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,25 +223,72 @@ private function createPositionMap()
|| $this->tokens[$i]['code'] === T_DOC_COMMENT_TAG
|| ($inTests === true && $this->tokens[$i]['code'] === T_INLINE_HTML))
) {
if (strpos($this->tokens[$i]['content'], '@codingStandards') !== false) {
$commentText = ltrim($this->tokens[$i]['content'], ' /*');
$commentTextLower = strtolower($commentText);
if (strpos($commentText, '@codingStandards') !== false) {
if ($ignoring === false
&& strpos($this->tokens[$i]['content'], '@codingStandardsIgnoreStart') !== false
&& strpos($commentText, '@codingStandardsIgnoreStart') !== false
) {
$ignoring = true;
} else if ($ignoring === true
&& strpos($this->tokens[$i]['content'], '@codingStandardsIgnoreEnd') !== false
&& strpos($commentText, '@codingStandardsIgnoreEnd') !== false
) {
$ignoring = false;
// Ignore this comment too.
$this->ignoredLines[$this->tokens[$i]['line']] = true;
} else if ($ignoring === false
&& strpos($this->tokens[$i]['content'], '@codingStandardsIgnoreLine') !== false
&& strpos($commentText, '@codingStandardsIgnoreLine') !== false
) {
$this->ignoredLines[($this->tokens[$i]['line'] + 1)] = true;
// Ignore this comment too.
$this->ignoredLines[$this->tokens[$i]['line']] = true;
}
}
} else if (substr($commentTextLower, 0, 6) === 'phpcs:') {
if (substr($commentTextLower, 0, 9) === 'phpcs:set') {
// Ignore standards for lines that change sniff settings.
$this->ignoredLines[$this->tokens[$i]['line']] = true;
$this->tokens[$i]['code'] = T_PHPCS_SET;
$this->tokens[$i]['type'] = 'T_PHPCS_SET';
} else if (substr($commentTextLower, 0, 16) === 'phpcs:ignorefile') {
// The whole file will be ignored, but at least set the correct token.
$this->tokens[$i]['code'] = T_PHPCS_IGNORE_FILE;
$this->tokens[$i]['type'] = 'T_PHPCS_IGNORE_FILE';
} else if ($ignoring === false
&& substr($commentTextLower, 0, 13) === 'phpcs:disable'
) {
$ignoring = true;
$this->tokens[$i]['code'] = T_PHPCS_DISABLE;
$this->tokens[$i]['type'] = 'T_PHPCS_DISABLE';
} else if ($ignoring === true
&& substr($commentTextLower, 0, 12) === 'phpcs:enable'
) {
$ignoring = false;
$this->ignoredLines[$this->tokens[$i]['line']] = true;
$this->tokens[$i]['code'] = T_PHPCS_ENABLE;
$this->tokens[$i]['type'] = 'T_PHPCS_ENABLE';
} else if ($ignoring === false
&& substr($commentTextLower, 0, 12) === 'phpcs:ignore'
) {
// If this comment is the only thing on the line, it tells us
// to ignore the following line. If the line contains other content
// then we are just ignoring this one single line.
$this->ignoredLines[$this->tokens[$i]['line']] = true;
for ($prev = ($i - 1); $prev >= 0; $prev--) {
if ($this->tokens[$prev]['code'] === T_WHITESPACE) {
continue;
}

break;
}

if ($this->tokens[$prev]['line'] !== $this->tokens[$i]['line']) {
$this->ignoredLines[($this->tokens[$i]['line'] + 1)] = true;
}

$this->tokens[$i]['code'] = T_PHPCS_IGNORE;
$this->tokens[$i]['type'] = 'T_PHPCS_IGNORE';
}//end if
}//end if
}//end if

if ($ignoring === true) {
Expand Down
17 changes: 17 additions & 0 deletions src/Util/Tokens.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@
define('T_DOC_COMMENT_CLOSE_TAG', 'PHPCS_T_DOC_COMMENT_CLOSE_TAG');
define('T_DOC_COMMENT_STRING', 'PHPCS_T_DOC_COMMENT_STRING');

// Tokens used for PHPCS instruction comments.
define('T_PHPCS_ENABLE', 'PHPCS_T_PHPCS_ENABLE');
define('T_PHPCS_DISABLE', 'PHPCS_T_PHPCS_DISABLE');
define('T_PHPCS_SET', 'PHPCS_T_PHPCS_SET');
define('T_PHPCS_IGNORE', 'PHPCS_T_PHPCS_IGNORE');
define('T_PHPCS_IGNORE_FILE', 'PHPCS_T_PHPCS_IGNORE_FILE');

final class Tokens
{

Expand Down Expand Up @@ -427,6 +434,11 @@ final class Tokens
T_DOC_COMMENT_OPEN_TAG => T_DOC_COMMENT_OPEN_TAG,
T_DOC_COMMENT_CLOSE_TAG => T_DOC_COMMENT_CLOSE_TAG,
T_DOC_COMMENT_STRING => T_DOC_COMMENT_STRING,
T_PHPCS_ENABLE => T_PHPCS_ENABLE,
T_PHPCS_DISABLE => T_PHPCS_DISABLE,
T_PHPCS_SET => T_PHPCS_SET,
T_PHPCS_IGNORE => T_PHPCS_IGNORE,
T_PHPCS_IGNORE_FILE => T_PHPCS_IGNORE_FILE,
);

/**
Expand All @@ -443,6 +455,11 @@ final class Tokens
T_DOC_COMMENT_OPEN_TAG => T_DOC_COMMENT_OPEN_TAG,
T_DOC_COMMENT_CLOSE_TAG => T_DOC_COMMENT_CLOSE_TAG,
T_DOC_COMMENT_STRING => T_DOC_COMMENT_STRING,
T_PHPCS_ENABLE => T_PHPCS_ENABLE,
T_PHPCS_DISABLE => T_PHPCS_DISABLE,
T_PHPCS_SET => T_PHPCS_SET,
T_PHPCS_IGNORE => T_PHPCS_IGNORE,
T_PHPCS_IGNORE_FILE => T_PHPCS_IGNORE_FILE,
);

/**
Expand Down

0 comments on commit 5325170

Please sign in to comment.