Browse Source

CommentsAnalyzer - fix for declare before header comment

Kuba Werłos 5 years ago
parent
commit
b27f23f2ae

+ 0 - 4
php-cs-fixer

@@ -11,10 +11,6 @@
  * with this source code in the file LICENSE.
  */
 
-/**
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
- */
 if (getenv('PHP_CS_FIXER_FUTURE_MODE')) {
     error_reporting(-1);
 }

+ 22 - 4
src/Tokenizer/Analyzer/CommentsAnalyzer.php

@@ -40,9 +40,28 @@ final class CommentsAnalyzer
             throw new \InvalidArgumentException('Given index must point to a comment.');
         }
 
-        $prevIndex = $tokens->getPrevMeaningfulToken($index);
+        if (null === $tokens->getNextMeaningfulToken($index)) {
+            return false;
+        }
+
+        $prevIndex = $tokens->getPrevNonWhitespace($index);
+
+        if ($tokens[$prevIndex]->equals(';')) {
+            $braceCloseIndex = $tokens->getPrevMeaningfulToken($prevIndex);
+            if (!$tokens[$braceCloseIndex]->equals(')')) {
+                return false;
+            }
+
+            $braceOpenIndex = $tokens->findBlockStart(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $braceCloseIndex);
+            $declareIndex = $tokens->getPrevMeaningfulToken($braceOpenIndex);
+            if (!$tokens[$declareIndex]->isGivenKind(T_DECLARE)) {
+                return false;
+            }
+
+            $prevIndex = $tokens->getPrevNonWhitespace($declareIndex);
+        }
 
-        return $tokens[$prevIndex]->isGivenKind(T_OPEN_TAG) && null !== $tokens->getNextMeaningfulToken($index);
+        return $tokens[$prevIndex]->isGivenKind(T_OPEN_TAG);
     }
 
     /**
@@ -224,8 +243,7 @@ final class CommentsAnalyzer
 
         $endKind = $tokens[$languageConstructIndex]->isGivenKind(CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN)
             ? [CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE]
-            : ')'
-        ;
+            : ')';
 
         $endIndex = $tokens->getNextTokenOfKind($languageConstructIndex, [$endKind]);
 

+ 40 - 6
tests/Tokenizer/Analyzer/CommentsAnalyzerTest.php

@@ -157,20 +157,54 @@ $bar;',
         $analyzer->isHeaderComment($tokens, 2);
     }
 
-    public function testHeaderComment()
+    /**
+     * @param string $code
+     * @param int    $index
+     *
+     * @dataProvider provideHeaderCommentCases
+     */
+    public function testHeaderComment($code, $index)
     {
-        $tokens = Tokens::fromCode('<?php /* This is header */ namespace Foo;');
+        $tokens = Tokens::fromCode($code);
         $analyzer = new CommentsAnalyzer();
 
-        static::assertTrue($analyzer->isHeaderComment($tokens, 1));
+        static::assertTrue($analyzer->isHeaderComment($tokens, $index));
     }
 
-    public function testNotHeaderComment()
+    public function provideHeaderCommentCases()
     {
-        $tokens = Tokens::fromCode('<?php /* This is not header */');
+        return [
+            ['<?php /* Comment */ namespace Foo;', 1],
+            ['<?php /** Comment */ namespace Foo;', 1],
+            ['<?php declare(strict_types=1); /* Comment */ namespace Foo;', 9],
+            ['<?php /* We test this one */ /* Foo */ namespace Bar;', 1],
+        ];
+    }
+
+    /**
+     * @param string $code
+     * @param int    $index
+     *
+     * @dataProvider provideNotHeaderCommentCases
+     */
+    public function testNotHeaderComment($code, $index)
+    {
+        $tokens = Tokens::fromCode($code);
         $analyzer = new CommentsAnalyzer();
 
-        static::assertFalse($analyzer->isHeaderComment($tokens, 1));
+        static::assertFalse($analyzer->isHeaderComment($tokens, $index));
+    }
+
+    public function provideNotHeaderCommentCases()
+    {
+        return [
+            ['<?php $foo; /* Comment */ $bar;', 4],
+            ['<?php foo(); /* Comment */ $bar;', 6],
+            ['<?php namespace Foo; /* Comment */ class Bar {};', 6],
+            ['<?php /* It is not header when no content after */', 1],
+            ['<?php /* Foo */ /* We test this one */ namespace Bar;', 3],
+            ['<?php /* Foo */ declare(strict_types=1); /* We test this one */ namespace Bar;', 11],
+        ];
     }
 
     public function testPhpdocCandidateAcceptsOnlyComments()