Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic.WhiteSpace.ScopeIndent false positive with nested match-es #3875

Closed
3 tasks done
andrey-yantsen opened this issue Aug 14, 2023 · 2 comments · Fixed by PHPCSStandards/PHP_CodeSniffer#502
Closed
3 tasks done

Comments

@andrey-yantsen
Copy link

Describe the bug

The ScopeIndent sniff suggests a quite strange indentation when processing multi-nested match-statements

Code sample

<?php

echo match (1) {
    0 => match (2) {
        2 => match (3) {
            3 => 3,
            default => -1,
        },
    },
    1 => match (2) {
        1 => match (3) {
            3 => 3,
            default => -1,
        },
        2 => match (3) {
            3 => 3,
            default => -1,
        },
    },
};

How that code will look if formatted as suggested

<?php

echo match (1) {
    0 => match (2) {
        2 => match (3) {
            3 => 3,
            default => -1,
        },
    },
    1 => match (2) {
        1 => match (3) {
            3 => 3,
            default => -1,
        },
            2 => match (3) {
                3 => 3,
                default => -1,
            },
    },
};

Custom ruleset

N/A — reproducible with PSR12

To reproduce

Steps to reproduce the behavior:

  1. Create a file called test.php with the code sample above
  2. Run phpcs -s --standard=psr12 test.php
  3. See errors displayed
------------------------------------------------------------------------------------------------------------------------------
FOUND 4 ERRORS AFFECTING 4 LINES
------------------------------------------------------------------------------------------------------------------------------
 15 | ERROR | [x] Line indented incorrectly; expected at least 12 spaces, found 8
    |       |     (Generic.WhiteSpace.ScopeIndent.Incorrect)
 16 | ERROR | [x] Line indented incorrectly; expected at least 16 spaces, found 12
    |       |     (Generic.WhiteSpace.ScopeIndent.Incorrect)
 17 | ERROR | [x] Line indented incorrectly; expected at least 16 spaces, found 12
    |       |     (Generic.WhiteSpace.ScopeIndent.Incorrect)
 18 | ERROR | [x] Line indented incorrectly; expected 12 spaces, found 8 (Generic.WhiteSpace.ScopeIndent.IncorrectExact)
------------------------------------------------------------------------------------------------------------------------------
PHPCBF CAN FIX THE 4 MARKED SNIFF VIOLATIONS AUTOMATICALLY
------------------------------------------------------------------------------------------------------------------------------

Expected behavior

No indentation errors.

Versions (please complete the following information)

Operating System macOS 12.5
PHP version 8.0
PHP_CodeSniffer version 3.7.2
Standard PSR2
Install type Local composer

Additional context

none

Please confirm:

  • I have searched the issue list and am not opening a duplicate issue.
  • 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 master branch of PHP_CodeSniffer.
@jrfnl
Copy link
Contributor

jrfnl commented Aug 14, 2023

Tested & confirmed.

@DannyvdSluijs
Copy link

In trying to provide more information to this bug, taking the file and the suggested command I can reproduce as well (as @jrfnl had already pointed out.) I also ran the command with the $debug enabled which returns the full reasoning about how the indenting level was computed. The full output is the code block in the bottom but I wanted to highlight the following from the output which seems to give some hints:

Close scope (T_MATCH) on line 14
        => removed open scope 81 (T_MATCH) on line 11
        * first token is 77 (T_LNUMBER) on line 11 *
        => indent set to 8 by token 107 (T_CLOSE_CURLY_BRACKET)
Close match on line 14
        * token is inside condition 68 (T_MATCH) on line 10 *
        * using condition *
        * previous token is T_MATCH on line 10 *
        * first token on line 10 is 64 (T_LNUMBER) *
        * amended previous is T_CLOSE_CURLY_BRACKET on line 8 *
        * amended first token is 56 (T_CLOSE_CURLY_BRACKET) on line 8 *
        * first token is a scope closer *
        * ignoring scope closer *
        => indent set to 12 by token 56 (T_CLOSE_CURLY_BRACKET)

Full debug output:

Start with token 0 on line 1 with indent 0
Opening parenthesis found on line 3
        => disabling exact indent checking until 8 (T_CLOSE_PARENTHESIS)
Closing parenthesis found on line 3
         * ignoring single-line definition *
Open scope (T_MATCH) on line 3
        => added open scope 148 (T_CLOSE_CURLY_BRACKET) on line 20, pointing to condition 4 (T_MATCH) on line 3
        => indent set to 4 by token 10 (T_OPEN_CURLY_BRACKET)
Opening parenthesis found on line 4
        => disabling exact indent checking until 21 (T_CLOSE_PARENTHESIS)
Closing parenthesis found on line 4
         * ignoring single-line definition *
Open scope (T_MATCH) on line 4
        => added open scope 60 (T_CLOSE_CURLY_BRACKET) on line 9, pointing to condition 17 (T_MATCH) on line 4
        => indent set to 8 by token 23 (T_OPEN_CURLY_BRACKET)
Opening parenthesis found on line 5
        => disabling exact indent checking until 34 (T_CLOSE_PARENTHESIS)
Closing parenthesis found on line 5
         * ignoring single-line definition *
Open scope (T_MATCH) on line 5
        => added open scope 56 (T_CLOSE_CURLY_BRACKET) on line 8, pointing to condition 30 (T_MATCH) on line 5
        => indent set to 12 by token 36 (T_OPEN_CURLY_BRACKET)
Close scope (T_MATCH) on line 8
        => removed open scope 30 (T_MATCH) on line 5
        * first token is 26 (T_LNUMBER) on line 5 *
        => indent set to 8 by token 56 (T_CLOSE_CURLY_BRACKET)
Close match on line 8
        * token is inside condition 17 (T_MATCH) on line 4 *
        * using condition *
        * previous token is T_MATCH on line 4 *
        * first token on line 4 is 13 (T_LNUMBER) *
        => indent set to 8 by token 13 (T_LNUMBER)
Close scope (T_MATCH) on line 9
        => removed open scope 17 (T_MATCH) on line 4
        * first token is 13 (T_LNUMBER) on line 4 *
        => indent set to 4 by token 60 (T_CLOSE_CURLY_BRACKET)
Close match on line 9
        * token is inside condition 4 (T_MATCH) on line 3 *
        * using condition *
        * previous token is T_MATCH on line 3 *
        * first token on line 3 is 2 (T_ECHO) *
        => indent set to 4 by token 2 (T_ECHO)
Opening parenthesis found on line 10
        => disabling exact indent checking until 72 (T_CLOSE_PARENTHESIS)
Closing parenthesis found on line 10
         * ignoring single-line definition *
Open scope (T_MATCH) on line 10
        => added open scope 145 (T_CLOSE_CURLY_BRACKET) on line 19, pointing to condition 68 (T_MATCH) on line 10
        => indent set to 8 by token 74 (T_OPEN_CURLY_BRACKET)
Opening parenthesis found on line 11
        => disabling exact indent checking until 85 (T_CLOSE_PARENTHESIS)
Closing parenthesis found on line 11
         * ignoring single-line definition *
Open scope (T_MATCH) on line 11
        => added open scope 107 (T_CLOSE_CURLY_BRACKET) on line 14, pointing to condition 81 (T_MATCH) on line 11
        => indent set to 12 by token 87 (T_OPEN_CURLY_BRACKET)
Close scope (T_MATCH) on line 14
        => removed open scope 81 (T_MATCH) on line 11
        * first token is 77 (T_LNUMBER) on line 11 *
        => indent set to 8 by token 107 (T_CLOSE_CURLY_BRACKET)
Close match on line 14
        * token is inside condition 68 (T_MATCH) on line 10 *
        * using condition *
        * previous token is T_MATCH on line 10 *
        * first token on line 10 is 64 (T_LNUMBER) *
        * amended previous is T_CLOSE_CURLY_BRACKET on line 8 *
        * amended first token is 56 (T_CLOSE_CURLY_BRACKET) on line 8 *
        * first token is a scope closer *
        * ignoring scope closer *
        => indent set to 12 by token 56 (T_CLOSE_CURLY_BRACKET)
[Line 15] Line indented incorrectly; expected at least 12 spaces, found 8
        => add adjustment of 4 for token 111 (T_LNUMBER) on line 15
Opening parenthesis found on line 15
        => disabling exact indent checking until 119 (T_CLOSE_PARENTHESIS)
Closing parenthesis found on line 15
         * ignoring single-line definition *
Open scope (T_MATCH) on line 15
        => added open scope 141 (T_CLOSE_CURLY_BRACKET) on line 18, pointing to condition 115 (T_MATCH) on line 15
        => indent set to 16 by token 121 (T_OPEN_CURLY_BRACKET)
Indent adjusted to 16 for T_LNUMBER on line 16
        => add adjustment of 4 for token 124 (T_LNUMBER) on line 16
[Line 16] Line indented incorrectly; expected at least 16 spaces, found 12
        => add adjustment of 4 for token 124 (T_LNUMBER) on line 16
Indent adjusted to 16 for T_MATCH_DEFAULT on line 17
        => add adjustment of 4 for token 132 (T_MATCH_DEFAULT) on line 17
[Line 17] Line indented incorrectly; expected at least 16 spaces, found 12
        => add adjustment of 4 for token 132 (T_MATCH_DEFAULT) on line 17
Close scope (T_MATCH) on line 18
        => removed open scope 115 (T_MATCH) on line 15
        * first token is 111 (T_LNUMBER) on line 15 *
        => indent set to 12 by token 141 (T_CLOSE_CURLY_BRACKET)
[Line 18] Line indented incorrectly; expected 12 spaces, found 8
        => add adjustment of 4 for token 141 (T_CLOSE_CURLY_BRACKET) on line 18
Close match on line 18
        * token is inside condition 68 (T_MATCH) on line 10 *
        * using condition *
        * previous token is T_MATCH on line 10 *
        * first token on line 10 is 64 (T_LNUMBER) *
        * amended previous is T_CLOSE_CURLY_BRACKET on line 8 *
        * amended first token is 56 (T_CLOSE_CURLY_BRACKET) on line 8 *
        * first token is a scope closer *
        * ignoring scope closer *
        => indent set to 12 by token 56 (T_CLOSE_CURLY_BRACKET)
Close scope (T_MATCH) on line 19
        => removed open scope 68 (T_MATCH) on line 10
        * first token is 64 (T_LNUMBER) on line 10 *
        => indent set to 4 by token 145 (T_CLOSE_CURLY_BRACKET)
Close match on line 19
        * token is inside condition 4 (T_MATCH) on line 3 *
        * using condition *
        * previous token is T_MATCH on line 3 *
        * first token on line 3 is 2 (T_ECHO) *
        => indent set to 4 by token 2 (T_ECHO)
Close scope (T_MATCH) on line 20
        => removed open scope 4 (T_MATCH) on line 3
        * first token is 2 (T_ECHO) on line 3 *
        => indent set to 0 by token 148 (T_CLOSE_CURLY_BRACKET)
Close match on line 20
        * could not find a previous T_EQUAL or T_RETURN token; will use current token *
        * previous token is T_CLOSE_CURLY_BRACKET on line 20 *
        * first token on line 20 is 148 (T_CLOSE_CURLY_BRACKET) *
        * amended previous is T_ECHO on line 3 *
        * amended first token is 2 (T_ECHO) on line 3 *
        => indent set to 0 by token 2 (T_ECHO)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants