Repository: tighten/tlint (php)

Issue:
False positive `OneLineBetweenClassVisibilityChanges` lint on properties near comments
The class below triggers the lint on the `public string $class` line. If I remove the comment lines above that line the lint doesn't show, so it's probably something to do with the comments.

```php
<?php

namespace App\Enums;

use App\Columns\IntegerColumn;
use App\Columns\StringColumn;
use BenSampo\Enum\Enum;
use InvalidArgumentException;

final class FieldType extends Enum
{
    const STRING = 'string';
    // const TEXT = 'text';
    const INTEGER = 'integer';
    // const DECIMAL = 'decimal';
    // const DATE = 'date';
    // const DATETIME = 'datetime';

    public string $class;

    public function __construct($enumValue)
    {
        parent::__construct($enumValue);

        $this->class = match ($enumValue) {
            self::STRING => StringColumn::class,
            // self::TEXT => StringColumn::class,
            self::INTEGER => IntegerColumn::class,
            // self::DECIMAL => StringColumn::class,
            // self::DATE => StringColumn::class,
            // self::DATETIME => StringColumn::class,
            default => throw new InvalidArgumentException("Unknown FieldType: '{$enumValue}'"),
        };
    }
}
```

Pull request:
Fix `OneLineBetweenClassVisibilityChanges` linter on nodes separated by comments
Fixes #262.

Patch:
diff --git a/composer.json b/composer.json
index 60e7208..16996e1 100644
--- a/composer.json
+++ b/composer.json
@@ -18,7 +18,8 @@
         "symfony/process": "^4.3 || ^5.0"
     },
     "require-dev": {
-        "phpunit/phpunit": "^9.3"
+        "phpunit/phpunit": "^9.3",
+        "symfony/var-dumper": "^5.3"
     },
     "autoload": {
         "psr-4": {
diff --git a/readme.md b/readme.md
index 48f5ba0..fe5d7a2 100644
--- a/readme.md
+++ b/readme.md
@@ -195,7 +195,6 @@ The default configuration is "tighten", but you may change this by adding a `tfo
 | `ClassThingsOrder` | Class "things" should follow the ordering presented in the [handbook](https://gist.github.com/mattstauffer/1178946cb585b17a3941dd0edcbce0c4). |
 | `ConcatenationNoSpacing` | There should be no space around `.` concatenations, and additional lines should always start with a `.` |
 | `ConcatenationSpacing` | There should be 1 space around `.` concatenations, and additional lines should always start with a `.` |
-| `FullyQualifiedFacades` | Import facades using their full namespace. |
 | `ImportFacades` | Import facades (don't use aliases). |
 | `MailableMethodsInBuild` | Mailable values (from and subject etc) should be set in build(). |
 | `ModelMethodOrder` | Model method order should be: booting > boot > booted > custom_static > relationships > scopes > accessors > mutators > custom |
@@ -204,7 +203,7 @@ The default configuration is "tighten", but you may change this by adding a `tfo
 | `NoDatesPropertyOnModels` | The `$dates` property was deprecated in Laravel 8. Use `$casts` instead. |
 | `NoDocBlocksForMigrationUpDown` | Remove doc blocks from the up and down method in migrations. |
 | `NoDump` | There should be no calls to `dd()`, `dump()`, `ray()`, or `var_dump()` |
-| `NoInlineVarDocs` | No /** @var ClassName $var */ inline docs. [ref](https://github.com/tighten/tlint/issues/108) |
+| `NoInlineVarDocs` | No /\*_ @var ClassName $var _/ inline docs. [ref](https://github.com/tighten/tlint/issues/108) |
 | `NoJsonDirective` | Use blade `{{ $model }}` auto escaping for models, and double quotes via json_encode over @json blade directive: `<vue-comp :values='@json($var)'>` -> `<vue-comp :values="{{ $model }}">` OR `<vue-comp :values="{{ json_encode($var) }}">` |
 | `NoLeadingSlashesOnRoutePaths` | No leading slashes on route paths. |
 | `NoMethodVisibilityInTests` | There should be no method visibility in test methods. [ref](https://github.com/tighten/tlint/issues/106#issuecomment-537952774) |
@@ -254,7 +253,6 @@ The default configuration is "tighten", but you may change this by adding a `tfo
 
 - `ApplyMiddlewareInRoutes`
 - `ArrayParametersOverViewWith`
-- `FullyQualifiedFacades`
 - `ImportFacades`
 - `MailableMethodsInBuild`
 - `NoLeadingSlashesOnRoutePaths`
@@ -284,7 +282,7 @@ The default configuration is "tighten", but you may change this by adding a `tfo
 | --- | --- |
 | `AlphabeticalImports` | Alphabetizes import statements. |
 | `ExcessSpaceBetweenAndAfterImports` | Removes excess newlines around use statements. |
-| `FullyQualifiedFacades` | Import facades using their full namespace. |
+| `ImportFacades` | Import facades using their full namespace. |
 | `NewLineAtEndOfFile` | Applies a newline at the end of files. |
 | `NoDatesPropertyOnModels` | Use `$casts` instead of `$dates` on Eloquent models. |
 | `NoDocBlocksForMigrationUpDown` | Removes doc blocks from the up and down method in migrations. |
@@ -300,7 +298,7 @@ The default configuration is "tighten", but you may change this by adding a `tfo
 
 ### Laravel
 
-- `FullyQualifiedFacades`
+- `ImportFacades`
 - `NoDatesPropertyOnModels`
 - `NoDocBlocksForMigrationUpDown`
 - `UseAnonymousMigrations`
diff --git a/src/Formatters/FullyQualifiedFacades.php b/src/Formatters/ImportFacades.php
similarity index 56%
rename from src/Formatters/FullyQualifiedFacades.php
rename to src/Formatters/ImportFacades.php
index 1d48576..0990203 100644
--- a/src/Formatters/FullyQualifiedFacades.php
+++ b/src/Formatters/ImportFacades.php
@@ -5,7 +5,6 @@ namespace Tighten\TLint\Formatters;
 use PhpParser\Lexer;
 use PhpParser\Node;
 use PhpParser\Node\Name;
-use PhpParser\Node\Stmt\Namespace_;
 use PhpParser\Node\Stmt\Use_;
 use PhpParser\Node\Stmt\UseUse;
 use PhpParser\NodeTraverser;
@@ -15,7 +14,7 @@ use PhpParser\PrettyPrinter\Standard;
 use Tighten\TLint\BaseFormatter;
 use Tighten\TLint\Concerns\IdentifiesFacades;
 
-class FullyQualifiedFacades extends BaseFormatter
+class ImportFacades extends BaseFormatter
 {
     use IdentifiesFacades;
 
@@ -26,23 +25,10 @@ class FullyQualifiedFacades extends BaseFormatter
         $traverser = new NodeTraverser;
         $traverser->addVisitor(new CloningVisitor);
 
-        $oldStmts = $parser->parse($this->code);
-        $oldTokens = $lexer->getTokens();
+        $originalStatements = $parser->parse($this->code);
+        $tokens = $lexer->getTokens();
 
-        $newStmts = $traverser->traverse($oldStmts);
-
-        if (count($newStmts) && $newStmts[0] instanceof Namespace_) {
-            $newStmts[0]->stmts = $this->transformFacadesToFullyQualified($newStmts[0]->stmts);
-        } else {
-            $newStmts = $this->transformFacadesToFullyQualified($newStmts);
-        }
-
-        return (new Standard)->printFormatPreserving($newStmts, $oldStmts, $oldTokens);
-    }
-
-    private function transformFacadesToFullyQualified(array $stmts)
-    {
-        return array_map(function (Node $node) {
+        $statements = array_map(function (Node $node) {
             if (
                 $node instanceof Use_
                 && array_key_exists((string) $node->uses[0]->name, static::$aliases)
@@ -51,6 +37,8 @@ class FullyQualifiedFacades extends BaseFormatter
             }
 
             return $node;
-        }, $stmts);
+        }, $traverser->traverse($originalStatements));
+
+        return (new Standard)->printFormatPreserving($statements, $originalStatements, $tokens);
     }
 }
diff --git a/src/Linters/FullyQualifiedFacades.php b/src/Linters/FullyQualifiedFacades.php
deleted file mode 100644
index 1b5093f..0000000
--- a/src/Linters/FullyQualifiedFacades.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-
-namespace Tighten\TLint\Linters;
-
-use PhpParser\Node;
-use PhpParser\NodeTraverser;
-use PhpParser\NodeVisitor\FindingVisitor;
-use PhpParser\Parser;
-use Tighten\TLint\BaseLinter;
-use Tighten\TLint\Concerns\IdentifiesFacades;
-
-class FullyQualifiedFacades extends BaseLinter
-{
-    use IdentifiesFacades;
-
-    public const description = "Import facades using their full namespace.";
-
-    public function lint(Parser $parser)
-    {
-        $traverser = new NodeTraverser;
-
-        $visitor = new FindingVisitor(function (Node $node) {
-            static $groupUse = [];
-
-            /**
-             * Build an array of group use statement classes (groups use FQNs)
-             * Illuminate\Support\Facades\{Config, Hash} => ['Config', 'Hash']
-             */
-            if ($node instanceof Node\Stmt\GroupUse) {
-                foreach ($node->uses as $use) {
-                    $groupUse[] = $use->name->toString();
-                }
-            }
-
-            /**
-             * Check if the node is a use statement and not a group use statement
-             * Return if use statement is a facade or not
-             */
-            if ($node instanceof Node\Stmt\UseUse && ! in_array($node->name->toString(), $groupUse)) {
-                return in_array($node->name->toString(), array_keys(static::$aliases));
-            }
-
-            return false;
-        });
-
-        $traverser->addVisitor($visitor);
-
-        $traverser->traverse($parser->parse($this->code));
-
-        return $visitor->getFoundNodes();
-    }
-}
diff --git a/src/Linters/OneLineBetweenClassVisibilityChanges.php b/src/Linters/OneLineBetweenClassVisibilityChanges.php
index 0d5d9eb..b27a197 100644
--- a/src/Linters/OneLineBetweenClassVisibilityChanges.php
+++ b/src/Linters/OneLineBetweenClassVisibilityChanges.php
@@ -21,24 +21,51 @@ class OneLineBetweenClassVisibilityChanges extends BaseLinter
 
         $visitor = new FindingVisitor(function (Node $node) use (&$notSeparatedByBlankLine) {
             if ($node instanceof Class_) {
-                $prev = null;
-
-                foreach (array_filter($node->stmts, function ($stmt) {
-                    return in_array(get_class($stmt), [
-                        Node\Stmt\ClassConst::class,
-                        Node\Stmt\Property::class,
-                    ]);
-                }) as $stmt) {
-                    if (! is_null($prev)) {
-                        if ($prev->flags !== $stmt->flags &&
-                            (($stmt->getStartLine() - $prev->getEndLine() !== 2 && ! (bool) $stmt->getDocComment()) ||
-                            ((bool) $stmt->getDocComment() && $stmt->getDocComment()->getStartLine() - $prev->getEndLine() !== 2 ))
-                            ) {
-                            $notSeparatedByBlankLine[] = $stmt;
+                $previousNode = null;
+
+                $constAndPropertyNodes = array_filter($node->stmts, function ($stmt) {
+                    return in_array(get_class($stmt), [Node\Stmt\ClassConst::class, Node\Stmt\Property::class]);
+                });
+
+                foreach ($constAndPropertyNodes as $node) {
+                    // Ignore the very first node
+                    if (is_null($previousNode)) {
+                        $previousNode = $node;
+                        continue;
+                    }
+
+                    // Ignore nodes with exactly the same visibility
+                    if ($previousNode->flags === $node->flags) {
+                        $previousNode = $node;
+                        continue;
+                    }
+
+                    // Ignore nodes separated by exactly one blank line and no comments
+                    if ($node->getStartLine() - $previousNode->getEndLine() === 2 && empty($node->getComments())) {
+                        $previousNode = $node;
+                        continue;
+                    }
+
+                    if (! empty($comments = $node->getComments())) {
+                        // Get the line numbers of all lines between this node and the previous one
+                        $allLinesBetweenNodes = range($previousNode->getEndLine() + 1, $node->getStartLine() - 1);
+
+                        // Get the line numbers of all lines between this node and the previous one that are part of any comment
+                        $commentLines = array_merge(...array_map(function ($comment) {
+                            return range($comment->getStartLine(), $comment->getEndLine());
+                        }, $comments));
+
+                        // Diff <all the lines> and <the commented lines> to find the lines between these two nodes that are blank
+                        // Ignore nodes separated by comments when there is exactly one blank line within the comments
+                        if (count(array_diff($allLinesBetweenNodes, $commentLines)) === 1) {
+                            $previousNode = $node;
+                            continue;
                         }
                     }
 
-                    $prev = $stmt;
+                    $notSeparatedByBlankLine[] = $node;
+
+                    $previousNode = $node;
                 }
             }
 
diff --git a/src/Presets/LaravelPreset.php b/src/Presets/LaravelPreset.php
index 729286d..2b37638 100644
--- a/src/Presets/LaravelPreset.php
+++ b/src/Presets/LaravelPreset.php
@@ -15,6 +15,7 @@ class LaravelPreset implements PresetInterface
             Linters\ArrayParametersOverViewWith::class,
             Linters\ClassThingsOrder::class,
             Linters\ConcatenationNoSpacing::class,
+            Linters\ImportFacades::class,
             Linters\MailableMethodsInBuild::class,
             Linters\NewLineAtEndOfFile::class,
             Linters\NoCompact::class,
diff --git a/src/Presets/TightenPreset.php b/src/Presets/TightenPreset.php
index c140ab9..0a47585 100644
--- a/src/Presets/TightenPreset.php
+++ b/src/Presets/TightenPreset.php
@@ -15,6 +15,7 @@ class TightenPreset implements PresetInterface
             Linters\ArrayParametersOverViewWith::class,
             Linters\ClassThingsOrder::class,
             Linters\ConcatenationSpacing::class,
+            Linters\ImportFacades::class,
             Linters\MailableMethodsInBuild::class,
             Linters\NewLineAtEndOfFile::class,
             Linters\NoCompact::class,


Test patch:
diff --git a/tests/Formatting/Formatters/FullyQualifiedFacadesTest.php b/tests/Formatting/Formatters/FullyQualifiedFacadesTest.php
deleted file mode 100644
index 4292c22..0000000
--- a/tests/Formatting/Formatters/FullyQualifiedFacadesTest.php
+++ /dev/null
@@ -1,210 +0,0 @@
-<?php
-
-namespace Tests\Formatting\Formatters;
-
-use PHPUnit\Framework\TestCase;
-use Tighten\TLint\Formatters\FullyQualifiedFacades;
-use Tighten\TLint\TFormat;
-
-class FullyQualifiedFacadesTest extends TestCase
-{
-    /** @test */
-    public function fixes_facade_aliases()
-    {
-        $file = <<<'file'
-<?php
-
-namespace Test;
-
-use DB;
-use Storage;
-
-file;
-
-        $formatted = (new TFormat)->format(new FullyQualifiedFacades($file));
-
-        $expected = <<<'file'
-<?php
-
-namespace Test;
-
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Storage;
-
-file;
-
-        $this->assertSame($expected, $formatted);
-    }
-
-    /** @test */
-    public function fixes_facade_aliases_when_file_not_namespaced()
-    {
-        $file = <<<'file'
-<?php
-
-use DB;
-use Storage;
-
-file;
-
-        $formatted = (new TFormat)->format(new FullyQualifiedFacades($file));
-
-        $expected = <<<'file'
-<?php
-
-use Illuminate\Support\Facades\DB;
-use Illuminate\Support\Facades\Storage;
-
-file;
-
-        $this->assertSame($expected, $formatted);
-    }
-
-    /** @test */
-    public function fixes_facade_aliases_mixed_with_valid_use_statements()
-    {
-        $file = <<<'file'
-<?php
-
-namespace Test;
-
-use DB;
-use Illuminate\Http\Request;
-use Illuminate\Support\Facades\Schema;
-use Storage;
-use Tests\TestCase;
-
-file;
-
-        $formatted = (new TFormat)->format(new FullyQualifiedFacades($file));
-
-        $expected = <<<'file'
-<?php
-
-namespace Test;
-
-use Illuminate\Support\Facades\DB;
-use Illuminate\Http\Request;
-use Illuminate\Support\Facades\Schema;
-use Illuminate\Support\Facades\Storage;
-use Tests\TestCase;
-
-file;
-
-        $this->assertSame($expected, $formatted);
-    }
-
-    /** @test */
-    public function fixes_facade_aliases_after_group_use_when_file_not_namespaced()
-    {
-        $file = <<<'file'
-<?php
-
-use Illuminate\Support\Facades\{Config, Hash};
-use Illuminate\Http\Request;
-use Illuminate\Support\Facades\Schema;
-use Storage;
-use Tests\TestCase;
-
-file;
-
-        $formatted = (new TFormat)->format(new FullyQualifiedFacades($file));
-
-        $expected = <<<'file'
-<?php
-
-use Illuminate\Support\Facades\{Config, Hash};
-use Illuminate\Http\Request;
-use Illuminate\Support\Facades\Schema;
-use Illuminate\Support\Facades\Storage;
-use Tests\TestCase;
-
-file;
-
-        $this->assertSame($expected, $formatted);
-    }
-
-    /** @test */
-    public function fixes_str_and_arr_helpers()
-    {
-        $file = <<<'file'
-<?php
-
-namespace Test;
-
-use Arr;
-use Str;
-
-file;
-
-        $formatted = (new TFormat)->format(new FullyQualifiedFacades($file));
-
-        $expected = <<<'file'
-<?php
-
-namespace Test;
-
-use Illuminate\Support\Arr;
-use Illuminate\Support\Str;
-
-file;
-
-        $this->assertSame($expected, $formatted);
-    }
-
-    /** @test */
-    public function ignores_grouped_imports()
-    {
-        $file = <<<'file'
-<?php
-
-namespace Test;
-
-use App\{ User, Post };
-
-file;
-
-        $formatted = (new TFormat)->format(new FullyQualifiedFacades($file));
-
-        $this->assertSame($file, $formatted);
-    }
-
-    /** @test */
-    public function ignores_unknown_aliases()
-    {
-        $file = <<<'file'
-<?php
-
-namespace Test;
-
-use Shortcut;
-
-file;
-
-        $formatted = (new TFormat)->format(new FullyQualifiedFacades($file));
-
-        $this->assertSame($file, $formatted);
-    }
-
-    /** @test */
-    public function ignores_files_in_same_directory_with_same_name_as_facade_alias()
-    {
-        $file = <<<'file'
-<?php
-
-namespace App\Utilities;
-
-class Stuff
-{
-    public function doStuff()
-    {
-        return File::otherStuff();
-    }
-}
-file;
-
-        $formatted = (new TFormat)->format(new FullyQualifiedFacades($file));
-
-        $this->assertSame($file, $formatted);
-    }
-}
diff --git a/tests/Formatting/Formatters/ImportFacadesTest.php b/tests/Formatting/Formatters/ImportFacadesTest.php
new file mode 100644
index 0000000..96443b6
--- /dev/null
+++ b/tests/Formatting/Formatters/ImportFacadesTest.php
@@ -0,0 +1,126 @@
+<?php
+
+namespace Tests\Formatting\Formatters;
+
+use PHPUnit\Framework\TestCase;
+use Tighten\TLint\Formatters\ImportFacades;
+use Tighten\TLint\TFormat;
+
+class ImportFacadesTest extends TestCase
+{
+    /** @test */
+    function fixes_facade_aliases()
+    {
+        $file = <<<'file'
+<?php
+
+use DB;
+use Storage;
+
+return true;
+file;
+
+        $formatted = (new TFormat)->format(new ImportFacades($file));
+
+        $expected = <<<'file'
+<?php
+
+use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Storage;
+
+return true;
+file;
+
+        $this->assertSame($expected, $formatted);
+    }
+
+    /** @test */
+    function fixes_facade_aliases_mixed_with_valid_use_statements()
+    {
+        $file = <<<'file'
+<?php
+
+use DB;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Schema;
+use Storage;
+use Tests\TestCase;
+
+return true;
+file;
+
+        $formatted = (new TFormat)->format(new ImportFacades($file));
+
+        $expected = <<<'file'
+<?php
+
+use Illuminate\Support\Facades\DB;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Support\Facades\Storage;
+use Tests\TestCase;
+
+return true;
+file;
+
+        $this->assertSame($expected, $formatted);
+    }
+
+    /** @test */
+    function fixes_str_and_arr_helpers()
+    {
+        $file = <<<'file'
+<?php
+
+use Arr;
+use Str;
+
+return true;
+file;
+
+        $formatted = (new TFormat)->format(new ImportFacades($file));
+
+        $expected = <<<'file'
+<?php
+
+use Illuminate\Support\Arr;
+use Illuminate\Support\Str;
+
+return true;
+file;
+
+        $this->assertSame($expected, $formatted);
+    }
+
+    /** @test */
+    function ignores_grouped_imports()
+    {
+        $file = <<<'file'
+<?php
+
+use App\{ User, Post };
+
+return true;
+file;
+
+        $formatted = (new TFormat)->format(new ImportFacades($file));
+
+        $this->assertSame($file, $formatted);
+    }
+
+    /** @test */
+    function ignores_unknown_aliases()
+    {
+        $file = <<<'file'
+<?php
+
+use Shortcut;
+
+return true;
+file;
+
+        $formatted = (new TFormat)->format(new ImportFacades($file));
+
+        $this->assertSame($file, $formatted);
+    }
+}
diff --git a/tests/Linting/Linters/FullyQualifiedFacadesTest.php b/tests/Linting/Linters/FullyQualifiedFacadesTest.php
deleted file mode 100644
index 4c8bd8b..0000000
--- a/tests/Linting/Linters/FullyQualifiedFacadesTest.php
+++ /dev/null
@@ -1,201 +0,0 @@
-<?php
-
-namespace Tests\Linting\Linters;
-
-use PHPUnit\Framework\TestCase;
-use Tighten\TLint\Linters\FullyQualifiedFacades;
-use Tighten\TLint\TLint;
-
-class FullyQualifiedFacadesTest extends TestCase
-{
-    /** @test */
-    public function it_triggers_on_namespaced_file()
-    {
-        $file = <<<file
-<?php
-
-namespace Test;
-
-use Cache;
-
-file;
-
-        $lints = (new TLint)->lint(
-            new FullyQualifiedFacades($file)
-        );
-
-        $this->assertEquals(5, $lints[0]->getNode()->getLine());
-    }
-
-    /** @test */
-    public function it_triggers_on_non_namespaced_file()
-    {
-        $file = <<<file
-<?php
-
-use Cache;
-
-file;
-
-        $lints = (new TLint)->lint(
-            new FullyQualifiedFacades($file)
-        );
-
-        $this->assertEquals(3, $lints[0]->getNode()->getLine());
-    }
-
-    /** @test */
-    public function it_triggers_on_aliased_facade()
-    {
-        $file = <<<file
-<?php
-
-use Cache as Store;
-
-file;
-
-        $lints = (new TLint)->lint(
-            new FullyQualifiedFacades($file)
-        );
-
-        $this->assertEquals(3, $lints[0]->getNode()->getLine());
-    }
-
-    /** @test */
-    public function does_not_trigger_on_a_fully_qualified_facade()
-    {
-        $file = <<<file
-<?php
-
-namespace Test;
-
-use Illuminate\Support\Facades\Hash;
-
-file;
-
-        $lints = (new TLint)->lint(
-            new FullyQualifiedFacades($file)
-        );
-
-        $this->assertEmpty($lints);
-    }
-
-    /** @test */
-    public function does_not_trigger_on_custom_class_aliased_to_facade_name()
-    {
-        $file = <<<file
-<?php
-
-namespace Test;
-
-use MyNamespace\MyClass as Config;
-
-file;
-
-        $lints = (new TLint)->lint(
-            new FullyQualifiedFacades($file)
-        );
-
-        $this->assertEmpty($lints);
-    }
-
-    /** @test */
-    public function does_not_trigger_on_facade_usage_with_grouped_import()
-    {
-        $file = <<<file
-<?php
-
-namespace Test;
-
-use Illuminate\Support\Facades\{Config, Hash};
-
-file;
-
-        $lints = (new TLint)->lint(
-            new FullyQualifiedFacades($file)
-        );
-
-        $this->assertEmpty($lints);
-    }
-
-    /** @test */
-    public function does_not_trigger_on_facade_usage_with_grouped_import_and_renamed_imports()
-    {
-        $file = <<<file
-<?php
-
-namespace Test;
-
-use Illuminate\Support\Facades\{Config, Hash};
-use Some\Othere\Namespace\{Config as OtherConfig};
-use Some\Other\Namespace\File;
-
-file;
-
-        $lints = (new TLint)->lint(
-            new FullyQualifiedFacades($file)
-        );
-
-        $this->assertEmpty($lints);
-    }
-
-    /** @test */
-    public function ignores_unknown_aliases_in_namespaced_file()
-    {
-        $file = <<<'file'
-<?php
-
-namespace Test;
-
-use Shortcut;
-
-file;
-
-        $lints = (new TLint)->lint(
-            new FullyQualifiedFacades($file)
-        );
-
-        $this->assertEmpty($lints);
-    }
-
-    /** @test */
-    public function ignores_unknown_aliases_in_non_namespaced_file()
-    {
-        $file = <<<'file'
-<?php
-
-use Shortcut;
-
-file;
-
-        $lints = (new TLint)->lint(
-            new FullyQualifiedFacades($file)
-        );
-
-        $this->assertEmpty($lints);
-    }
-
-    /** @test */
-    public function ignores_files_in_same_directory_with_same_name_as_facade_alias()
-    {
-        $file = <<<'file'
-<?php
-
-namespace App\Utilities;
-
-class Stuff
-{
-    public function doStuff()
-    {
-        return File::otherStuff();
-    }
-}
-file;
-
-        $lints = (new TLint)->lint(
-            new FullyQualifiedFacades($file)
-        );
-
-        $this->assertEmpty($lints);
-    }
-}
diff --git a/tests/Linting/Linters/OneLineBetweenClassVisibilityChangesTest.php b/tests/Linting/Linters/OneLineBetweenClassVisibilityChangesTest.php
index 33c873e..196d086 100644
--- a/tests/Linting/Linters/OneLineBetweenClassVisibilityChangesTest.php
+++ b/tests/Linting/Linters/OneLineBetweenClassVisibilityChangesTest.php
@@ -80,4 +80,155 @@ file;
 
         $this->assertEmpty($lints);
     }
+
+    /** @test */
+    function catches_missing_line_between_visibility_changes_with_comment()
+    {
+        $file = <<<'file'
+<?php
+
+namespace App;
+
+class Thing
+{
+    protected const OK = 1;
+    // Note to self
+    private $ok;
+}
+file;
+
+        $lints = (new TLint)->lint(
+            new OneLineBetweenClassVisibilityChanges($file)
+        );
+
+        $this->assertEquals(9, $lints[0]->getNode()->getLine());
+    }
+
+    /** @test */
+    function catches_missing_line_between_visibility_changes_with_two_comments()
+    {
+        $file = <<<'file'
+<?php
+
+namespace App;
+
+class Thing
+{
+    protected const OK = 1;
+    // Note to self
+    // Another
+    private $ok;
+}
+file;
+
+        $lints = (new TLint)->lint(
+            new OneLineBetweenClassVisibilityChanges($file)
+        );
+
+        $this->assertEquals(10, $lints[0]->getNode()->getLine());
+    }
+
+    /** @test */
+    function catches_missing_line_between_visibility_changes_with_many_comments()
+    {
+        $file = <<<'file'
+<?php
+
+namespace App;
+
+class Thing
+{
+    protected const OK = 1;
+    // Note to self
+    // Another
+    // And another
+    // And another one
+    private $ok;
+}
+file;
+
+        $lints = (new TLint)->lint(
+            new OneLineBetweenClassVisibilityChanges($file)
+        );
+
+        $this->assertEquals(12, $lints[0]->getNode()->getLine());
+    }
+
+    /** @test */
+    function ignores_comment_below_space_between_visibility_changes()
+    {
+        $file = <<<'file'
+<?php
+
+namespace App;
+
+class Thing
+{
+    protected const OK = 1;
+
+    // TODO
+    private $ok;
+}
+file;
+
+        $lints = (new TLint)->lint(
+            new OneLineBetweenClassVisibilityChanges($file)
+        );
+
+        $this->assertEmpty($lints);
+    }
+
+    /** @test */
+    function ignores_comment_above_space_between_visibility_changes()
+    {
+        $file = <<<'file'
+<?php
+
+namespace App;
+
+class Thing
+{
+    protected const OK = 1;
+    // public const NOT_OK = 2;
+
+    private $ok;
+}
+file;
+
+        $lints = (new TLint)->lint(
+            new OneLineBetweenClassVisibilityChanges($file)
+        );
+
+        $this->assertEmpty($lints);
+    }
+
+    /** @test */
+    function ignores_many_comments_between_visibility_changes()
+    {
+        $file = <<<'file'
+<?php
+
+namespace App;
+
+class Thing
+{
+    protected const OK = 1;
+    // public const NOT_OK = 2;
+
+    // another one
+    /**
+     * docblock!
+     */
+    // Hi there
+    //
+    private $ok;
+}
+file;
+
+        $lints = (new TLint)->lint(
+            new OneLineBetweenClassVisibilityChanges($file)
+        );
+
+        $this->assertEmpty($lints);
+    }
 }