<commit_before><?php

namespace Tighten\TLint\Linters;

use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\FindingVisitor;
use PhpParser\Parser;
use Tighten\TLint\BaseLinter;

class OneLineBetweenClassVisibilityChanges extends BaseLinter
{
    public const description = 'Class members of differing visibility must be separated by a blank line';

    public function lint(Parser $parser)
    {
        $traverser = new NodeTraverser;

        $notSeparatedByBlankLine = [];

        $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)) {
                        // dump($stmt);
                        if ($prev->flags !== $stmt->flags &&
                            (($stmt->getStartLine() - $prev->getEndLine() !== 2 && ! (bool) $stmt->getDocComment()  && empty($stmt->getComments())) ||
                            ((bool) $stmt->getDocComment() && $stmt->getDocComment()->getStartLine() - $prev->getEndLine() !== 2 ) ||
                            (! empty($stmt->getComments()) && ($stmt->getComments()[0]->getStartLine() - $prev->getEndLine() !== 2 && $stmt->getStartLine() - $stmt->getComments()[0]->getEndLine() !== 2)))
                            ) {
                            $notSeparatedByBlankLine[] = $stmt;
                        }
                    }

                    $prev = $stmt;
                }
            }

            return false;
        });

        $traverser->addVisitor($visitor);

        $traverser->traverse($parser->parse($this->code));
<commit_msg>Refactor checks for comments and blank lines<commit_after><?php

namespace Tighten\TLint\Linters;

use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\FindingVisitor;
use PhpParser\Parser;
use Tighten\TLint\BaseLinter;

class OneLineBetweenClassVisibilityChanges extends BaseLinter
{
    public const description = 'Class members of differing visibility must be separated by a blank line';

    public function lint(Parser $parser)
    {
        $traverser = new NodeTraverser;

        $notSeparatedByBlankLine = [];

        $visitor = new FindingVisitor(function (Node $node) use (&$notSeparatedByBlankLine) {
            if ($node instanceof Class_) {
                $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 const/property
                    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 all lines between these nodes that are part of any comment
                        $commentLines = array_merge(...array_map(function ($comment) {
                            return range($comment->getStartLine(), $comment->getEndLine());
                        }, $comments));

                        // Get all lines between these nodes
                        $allLinesBetweenNodes = range($previousNode->getEndLine() + 1, $node->getStartLine() - 1);

                        // 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;
                        }
                    }

                    $notSeparatedByBlankLine[] = $node;

                    $previousNode = $node;
                }
            }

            return false;
        });

        $traverser->addVisitor($visitor);

        $traverser->traverse($parser->parse($this->code));

{'fraction_non_alphanumeric': 0.11599757918095623, 'fraction_numerical': 0.0020173492031470646, 'mean_word_length': 1.617740232312566, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 40, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5895639', 'n_tokens_mistral': 1293, 'n_tokens_neox': 1200, 'n_words': 275}