Skip to content

Generic.WhiteSpace.ScopeIndent: false positives and destructive fixer for code nested inside property hook bodies #1493

Description

@TonnyJe

Describe the bug

Generic.WhiteSpace.ScopeIndent reports IncorrectExact false positives for any
statement wrapped in a nested scope (if, foreach, try, …) that lives inside
a PHP 8.4 property hook body. The same statements inside a regular method are
reported as correctly indented.

phpcbf then "fixes" the false positives by out-denting only the nested block,
leaving its sibling statements in the hook body untouched. The result is a file
with broken, internally inconsistent indentation.

The reported expected 4 spaces figure suggests the sniff does not register the
property hook's opening brace as a scope opener, so its expected-indent stack is
off for scope conditions nested inside the hook.

Code sample

<?php

class Foo
{
    public int $bar {
        set(int $value) {
            if ($value < 1) {
                $this->bar = 1;
            }
        }
    }
}

Custom ruleset

None required. Reproduced with the bundled Generic standard and a single sniff:

<?xml version="1.0"?>
<ruleset name="repro">
  <rule ref="Generic.WhiteSpace.ScopeIndent"/>
</ruleset>

To reproduce

  1. Save the code sample as test.php.
  2. Run phpcs -s --standard=Generic --sniffs=Generic.WhiteSpace.ScopeIndent test.php
FILE: /path/to/test.php
--------------------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 2 LINES
--------------------------------------------------------------------------------
 7 | ERROR | [x] Line indented incorrectly; expected 4 spaces, found 12
   |       |     (Generic.WhiteSpace.ScopeIndent.IncorrectExact)
 9 | ERROR | [x] Line indented incorrectly; expected 4 spaces, found 12
   |       |     (Generic.WhiteSpace.ScopeIndent.IncorrectExact)
--------------------------------------------------------------------------------
PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY
--------------------------------------------------------------------------------
  1. Run phpcbf --standard=Generic --sniffs=Generic.WhiteSpace.ScopeIndent test.php. The file becomes:
    public int $bar {
        set(int $value) {
    if ($value < 1) {
        $this->bar = 1;
    }
        }
    }

Contrast (not flagged)

Identical body in a normal method produces no errors:

<?php

class Foo
{
    public function setBar(int $value): void
    {
        if ($value < 1) {
            $this->bar = 1;
        }
    }
}

Expected behavior

Generic.WhiteSpace.ScopeIndent should treat a property hook body as an indent
scope, the same way it treats a method body. For the code sample, the if line
and its closing brace are correctly indented at 12 spaces and no error should be
reported. phpcbf should leave the file unchanged.

Versions (please complete the following information)

Operating System Alpine Linux v3.24 (official composer:2 Docker image)
PHP version 8.5.9
PHP_CodeSniffer version 4.0.4; also reproduced on the 4.x branch (4.0.5)
Standard Generic (single sniff Generic.WhiteSpace.ScopeIndent)
Install type Composer (local)

Additional context

  • Reproduces for get { … }, set { … } and set(Type $value) { … } full-body
    hooks. Short-arrow hooks (get => expr;) and full bodies without a nested
    scope are not affected.
  • Discovered via a real class whose hooks validate the assigned value
    (set(int $value) { if ($value < 1) { throw … } }). The destructive phpcbf
    behavior is the more serious half of this report: running the fixer over such a
    file corrupts it rather than skipping the unfixable case.

Please confirm

  • I have searched the issue list and am not opening a duplicate issue.
  • I have read the Contribution Guidelines and this is not a support question.
  • I confirm that this bug is a bug in PHP_CodeSniffer and not in one of the external standards.
  • I have verified the issue still exists in the 4.x branch of PHP_CodeSniffer.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions