From 807c10cc5690d4fca494ae650ace2748509faa9f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 31 Aug 2020 20:44:07 +0200 Subject: [PATCH] Tokenizer: support hash comment for ignore annotations Until now, for the PHPCS native ignore annotations, only `//` slash or `/* */` star-style comments were supported. This adds support for PHPCS native ignore annotations using `#` hash-style comments. Includes unit tests and syncing of the `ltrim()` used in `File::process()` with the `ltrim()` used in `Tokenizer::createPositionMap()`. --- src/Files/File.php | 2 +- src/Tokenizers/Tokenizer.php | 2 +- tests/Core/ErrorSuppressionTest.php | 170 +++++++++++++++++++++++++++- 3 files changed, 169 insertions(+), 5 deletions(-) diff --git a/src/Files/File.php b/src/Files/File.php index ca01f37e95..e4056bc8f8 100644 --- a/src/Files/File.php +++ b/src/Files/File.php @@ -356,7 +356,7 @@ public function process() || $token['code'] === T_DOC_COMMENT_TAG || ($inTests === true && $token['code'] === T_INLINE_HTML)) ) { - $commentText = ltrim($this->tokens[$stackPtr]['content'], ' /*'); + $commentText = ltrim($this->tokens[$stackPtr]['content'], " \t/*#"); $commentTextLower = strtolower($commentText); if (strpos($commentText, '@codingStandards') !== false) { if (strpos($commentText, '@codingStandardsIgnoreFile') !== false) { diff --git a/src/Tokenizers/Tokenizer.php b/src/Tokenizers/Tokenizer.php index a229d6979e..4c5d391340 100644 --- a/src/Tokenizers/Tokenizer.php +++ b/src/Tokenizers/Tokenizer.php @@ -250,7 +250,7 @@ private function createPositionMap() || $this->tokens[$i]['code'] === T_DOC_COMMENT_TAG || ($inTests === true && $this->tokens[$i]['code'] === T_INLINE_HTML) ) { - $commentText = ltrim($this->tokens[$i]['content'], " \t/*"); + $commentText = ltrim($this->tokens[$i]['content'], " \t/*#"); $commentText = rtrim($commentText, " */\t\r\n"); $commentTextLower = strtolower($commentText); if (strpos($commentText, '@codingStandards') !== false) { diff --git a/tests/Core/ErrorSuppressionTest.php b/tests/Core/ErrorSuppressionTest.php index f031b334bb..a11399d6c5 100644 --- a/tests/Core/ErrorSuppressionTest.php +++ b/tests/Core/ErrorSuppressionTest.php @@ -81,6 +81,46 @@ public function testSuppressError() $this->assertEquals(0, $numErrors); $this->assertCount(0, $errors); + // Process with inline hash comment suppression. + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(0, $numErrors); + $this->assertCount(0, $errors); + + // Process with multi-line inline hash comment suppression, tab-indented. + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(0, $numErrors); + $this->assertCount(0, $errors); + + // Process with inline hash @ comment suppression. + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(0, $numErrors); + $this->assertCount(0, $errors); + + // Process with inline hash comment suppression mixed case. + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(0, $numErrors); + $this->assertCount(0, $errors); + // Process with inline comment suppression (deprecated syntax). $content = 'assertEquals(1, $numErrors); $this->assertCount(1, $errors); + // Process with suppression (hash comment). + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(1, $numErrors); + $this->assertCount(1, $errors); + + // Process with @ suppression (hash comment). + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(1, $numErrors); + $this->assertCount(1, $errors); + // Process with suppression (deprecated syntax). $content = 'assertEquals(1, $numErrors); $this->assertCount(1, $errors); + // Process with suppression on line before (hash comment). + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(1, $numErrors); + $this->assertCount(1, $errors); + + // Process with @ suppression on line before (hash comment). + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(1, $numErrors); + $this->assertCount(1, $errors); + // Process with suppression on line before. $content = 'assertEquals(1, $numErrors); $this->assertCount(1, $errors); + // Process with suppression on same line (hash comment). + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(1, $numErrors); + $this->assertCount(1, $errors); + + // Process with @ suppression on same line (hash comment). + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(1, $numErrors); + $this->assertCount(1, $errors); + // Process with suppression on same line (deprecated syntax). $content = 'assertEquals(0, $numErrors); $this->assertCount(0, $errors); + // Process with disable/enable suppression and no single line suppression (hash comment). + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(0, $numErrors); + $this->assertCount(0, $errors); + // Process with disable/enable suppression and no single line suppression (deprecated syntax). $content = 'assertEquals(0, $numErrors); $this->assertCount(0, $errors); + // Process with line @ suppression nested within disable/enable @ suppression (hash comment). + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(0, $numErrors); + $this->assertCount(0, $errors); + // Process with line suppression nested within disable/enable suppression (deprecated syntax). $content = 'assertEquals(0, $numErrors); $this->assertCount(0, $errors); + // Process with suppression (hash comment). + $content = 'foo();'.PHP_EOL.'}'.PHP_EOL.'}'; + $file = new DummyFile($content, $ruleset, $config); + $file->process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $this->assertEquals(0, $numErrors); + $this->assertCount(0, $errors); + // Process with suppression. $content = 'foo();'.PHP_EOL.'}'.PHP_EOL.'}'; $file = new DummyFile($content, $ruleset, $config); @@ -647,6 +777,26 @@ public function testSuppressFile() $this->assertEquals(0, $numWarnings); $this->assertCount(0, $warnings); + // Process with suppression (hash comment). + $content = 'process(); + + $warnings = $file->getWarnings(); + $numWarnings = $file->getWarningCount(); + $this->assertEquals(0, $numWarnings); + $this->assertCount(0, $warnings); + + // Process with @ suppression (hash comment). + $content = 'process(); + + $warnings = $file->getWarnings(); + $numWarnings = $file->getWarningCount(); + $this->assertEquals(0, $numWarnings); + $this->assertCount(0, $warnings); + // Process with suppression (deprecated syntax). $content = 'assertEquals(0, $numWarnings); $this->assertCount(0, $warnings); + // Suppress a single sniff with reason (hash comment). + $content = 'process(); + + $errors = $file->getErrors(); + $numErrors = $file->getErrorCount(); + $warnings = $file->getWarnings(); + $numWarnings = $file->getWarningCount(); + $this->assertEquals(1, $numErrors); + $this->assertCount(1, $errors); + $this->assertEquals(0, $numWarnings); + $this->assertCount(0, $warnings); + // Suppress multiple sniffs. $content = 'assertCount(1, $warnings); // Suppress multiple sniffs and re-enable one. - $content = 'process(); @@ -998,7 +1162,7 @@ public function testEnableSelected() $this->assertCount(1, $warnings); // Suppress a category and re-enable a whole standard. - $content = 'process(); @@ -1143,7 +1307,7 @@ public function testIgnoreSelected() $this->assertCount(0, $warnings); // Suppress a category of sniffs. - $content = 'process();