Skip to content

Commit

Permalink
fix(ScopeIndent): Fix test fails on attributes on constructor promoti…
Browse files Browse the repository at this point in the history
…on properties (#3461148)
  • Loading branch information
klausi authored Dec 31, 2024
1 parent dfbd808 commit bf0dc2f
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 46 deletions.
168 changes: 122 additions & 46 deletions coder_sniffer/Drupal/Sniffs/WhiteSpace/ScopeIndentSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ public function register()
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void|int
* @return int
*/
public function process(File $phpcsFile, $stackPtr)
{
Expand All @@ -146,13 +146,14 @@ public function process(File $phpcsFile, $stackPtr)
}
}

$lastOpenTag = $stackPtr;
$lastCloseTag = null;
$openScopes = [];
$adjustments = [];
$setIndents = [];
$disableExactEnd = 0;
$tokenIndent = 0;
$lastOpenTag = $stackPtr;
$lastCloseTag = null;
$openScopes = [];
$adjustments = [];
$setIndents = [];
$disableExactStack = [];
$disableExactEnd = 0;
$tokenIndent = 0;

$tokens = $phpcsFile->getTokens();
$first = $phpcsFile->findFirstOnLine(T_INLINE_HTML, $stackPtr);
Expand Down Expand Up @@ -232,6 +233,7 @@ public function process(File $phpcsFile, $stackPtr)
if ($tokens[$i]['code'] === T_OPEN_PARENTHESIS
&& isset($tokens[$i]['parenthesis_closer']) === true
) {
$disableExactStack[$tokens[$i]['parenthesis_closer']] = $tokens[$i]['parenthesis_closer'];
$disableExactEnd = max($disableExactEnd, $tokens[$i]['parenthesis_closer']);
if ($this->debug === true) {
$line = $tokens[$i]['line'];
Expand Down Expand Up @@ -337,7 +339,14 @@ public function process(File $phpcsFile, $stackPtr)
echo "\t* open tag is inside condition; using open tag *".PHP_EOL;
}

$checkIndent = ($tokens[$lastOpenTag]['column'] - 1);
$first = $phpcsFile->findFirstOnLine([T_WHITESPACE, T_INLINE_HTML], $lastOpenTag, true);
if ($this->debug === true) {
$line = $tokens[$first]['line'];
$type = $tokens[$first]['type'];
echo "\t* first token on line $line is $first ($type) *".PHP_EOL;
}

$checkIndent = ($tokens[$first]['column'] - 1);
if (isset($adjustments[$condition]) === true) {
$checkIndent += $adjustments[$condition];
}
Expand Down Expand Up @@ -483,12 +492,7 @@ public function process(File $phpcsFile, $stackPtr)

$arrayOpener = $tokens[$arrayCloser]['bracket_opener'];
if ($tokens[$arrayCloser]['line'] !== $tokens[$arrayOpener]['line']) {
$first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $arrayOpener, true);
$checkIndent = ($tokens[$first]['column'] - 1);
if (isset($adjustments[$first]) === true) {
$checkIndent += $adjustments[$first];
}

$first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $arrayOpener, true);
$exact = false;

if ($this->debug === true) {
Expand Down Expand Up @@ -524,6 +528,11 @@ public function process(File $phpcsFile, $stackPtr)
$first = $phpcsFile->findNext(T_WHITESPACE, ($first + 1), null, true);
}

$checkIndent = ($tokens[$first]['column'] - 1);
if (isset($adjustments[$first]) === true) {
$checkIndent += $adjustments[$first];
}

if (isset($tokens[$first]['scope_closer']) === true
&& $tokens[$first]['scope_closer'] === $first
) {
Expand Down Expand Up @@ -609,11 +618,11 @@ public function process(File $phpcsFile, $stackPtr)

// Scope closers reset the required indent to the same level as the opening condition.
if (($checkToken !== null
&& isset($openScopes[$checkToken]) === true
&& (isset($openScopes[$checkToken]) === true
|| (isset($tokens[$checkToken]['scope_condition']) === true
&& isset($tokens[$checkToken]['scope_closer']) === true
&& $tokens[$checkToken]['scope_closer'] === $checkToken
&& $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['scope_opener']]['line']))
&& $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['scope_opener']]['line'])))
|| ($checkToken === null
&& isset($openScopes[$i]) === true)
) {
Expand Down Expand Up @@ -796,6 +805,19 @@ public function process(File $phpcsFile, $stackPtr)
) {
$exact = true;

if ($disableExactEnd > $checkToken) {
foreach ($disableExactStack as $disableExactStackEnd) {
if ($disableExactStackEnd < $checkToken) {
continue;
}

if ($tokens[$checkToken]['conditions'] === $tokens[$disableExactStackEnd]['conditions']) {
$exact = false;
break;
}
}
}

$lastOpener = null;
if (empty($openScopes) === false) {
end($openScopes);
Expand Down Expand Up @@ -844,16 +866,34 @@ public function process(File $phpcsFile, $stackPtr)
&& $tokens[($checkToken + 1)]['code'] !== T_DOUBLE_COLON
) {
$next = $phpcsFile->findNext(Tokens::$emptyTokens, ($checkToken + 1), null, true);
if ($next === false || $tokens[$next]['code'] !== T_CLOSURE) {
if ($this->debug === true) {
$line = $tokens[$checkToken]['line'];
$type = $tokens[$checkToken]['type'];
echo "\t* method prefix ($type) found on line $line; indent set to exact *".PHP_EOL;
if ($next === false
|| ($tokens[$next]['code'] !== T_CLOSURE
&& $tokens[$next]['code'] !== T_VARIABLE
&& $tokens[$next]['code'] !== T_FN)
) {
$isMethodPrefix = true;
if (isset($tokens[$checkToken]['nested_parenthesis']) === true) {
$parenthesis = array_keys($tokens[$checkToken]['nested_parenthesis']);
$deepestOpen = array_pop($parenthesis);
if (isset($tokens[$deepestOpen]['parenthesis_owner']) === true
&& $tokens[$tokens[$deepestOpen]['parenthesis_owner']]['code'] === T_FUNCTION
) {
// This is constructor property promotion and not a method prefix.
$isMethodPrefix = false;
}
}

$exact = true;
}
}
if ($isMethodPrefix === true) {
if ($this->debug === true) {
$line = $tokens[$checkToken]['line'];
$type = $tokens[$checkToken]['type'];
echo "\t* method prefix ($type) found on line $line; indent set to exact *".PHP_EOL;
}

$exact = true;
}
}//end if
}//end if

// JS property indentation has to be exact or else if will break
// things like function and object indentation.
Expand Down Expand Up @@ -890,8 +930,6 @@ public function process(File $phpcsFile, $stackPtr)
}
}
}

$checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent);
}//end if

// Close tags needs to be indented to exact column positions.
Expand All @@ -911,7 +949,8 @@ public function process(File $phpcsFile, $stackPtr)
// Don't perform strict checking on chained method calls since they
// are often covered by custom rules.
if ($checkToken !== null
&& $tokens[$checkToken]['code'] === T_OBJECT_OPERATOR
&& ($tokens[$checkToken]['code'] === T_OBJECT_OPERATOR
|| $tokens[$checkToken]['code'] === T_NULLSAFE_OBJECT_OPERATOR)
&& $exact === true
) {
$exact = false;
Expand Down Expand Up @@ -988,18 +1027,38 @@ public function process(File $phpcsFile, $stackPtr)
}

if ($this->tabIndent === true) {
$error .= '%s tabs, found %s';
$data = [
floor($checkIndent / $this->tabWidth),
floor($tokenIndent / $this->tabWidth),
];
$expectedTabs = floor($checkIndent / $this->tabWidth);
$foundTabs = floor($tokenIndent / $this->tabWidth);
$foundSpaces = ($tokenIndent - ($foundTabs * $this->tabWidth));
if ($foundSpaces > 0) {
if ($foundTabs > 0) {
$error .= '%s tabs, found %s tabs and %s spaces';
$data = [
$expectedTabs,
$foundTabs,
$foundSpaces,
];
} else {
$error .= '%s tabs, found %s spaces';
$data = [
$expectedTabs,
$foundSpaces,
];
}
} else {
$error .= '%s tabs, found %s';
$data = [
$expectedTabs,
$foundTabs,
];
}//end if
} else {
$error .= '%s spaces, found %s';
$data = [
$checkIndent,
$tokenIndent,
];
}
}//end if

if ($this->debug === true) {
$line = $tokens[$checkToken]['line'];
Expand Down Expand Up @@ -1030,15 +1089,17 @@ public function process(File $phpcsFile, $stackPtr)

// Don't check indents exactly between arrays as they tend to have custom rules.
if ($tokens[$i]['code'] === T_OPEN_SHORT_ARRAY) {
$disableExactStack[$tokens[$i]['bracket_closer']] = $tokens[$i]['bracket_closer'];
$disableExactEnd = max($disableExactEnd, $tokens[$i]['bracket_closer']);
if ($this->debug === true) {
$line = $tokens[$i]['line'];
$type = $tokens[$disableExactEnd]['type'];
$line = $tokens[$i]['line'];
$type = $tokens[$disableExactEnd]['type'];
$endLine = $tokens[$disableExactEnd]['line'];
echo "Opening short array bracket found on line $line".PHP_EOL;
if ($disableExactEnd === $tokens[$i]['bracket_closer']) {
echo "\t=> disabling exact indent checking until $disableExactEnd ($type)".PHP_EOL;
echo "\t=> disabling exact indent checking until $disableExactEnd ($type) on line $endLine".PHP_EOL;
} else {
echo "\t=> continuing to disable exact indent checking until $disableExactEnd ($type)".PHP_EOL;
echo "\t=> continuing to disable exact indent checking until $disableExactEnd ($type) on line $endLine".PHP_EOL;
}
}
}
Expand All @@ -1050,7 +1111,6 @@ public function process(File $phpcsFile, $stackPtr)
) {
if ($this->debug === true) {
$line = $tokens[$i]['line'];
$type = $tokens[$disableExactEnd]['type'];
echo "Here/nowdoc found on line $line".PHP_EOL;
}

Expand All @@ -1074,8 +1134,11 @@ public function process(File $phpcsFile, $stackPtr)
if ($tokens[$i]['code'] === T_CONSTANT_ENCAPSED_STRING
|| $tokens[$i]['code'] === T_DOUBLE_QUOTED_STRING
) {
$i = $phpcsFile->findNext($tokens[$i]['code'], ($i + 1), null, true);
$i--;
$nextNonTextString = $phpcsFile->findNext($tokens[$i]['code'], ($i + 1), null, true);
if ($nextNonTextString !== false) {
$i = ($nextNonTextString - 1);
}

continue;
}

Expand Down Expand Up @@ -1162,7 +1225,7 @@ public function process(File $phpcsFile, $stackPtr)
if ($this->debug === true) {
$type = str_replace('_', ' ', strtolower(substr($tokens[$i]['type'], 2)));
$line = $tokens[$i]['line'];
echo "* ignoring single-line $type on line $line".PHP_EOL;
echo "* ignoring single-line $type on line $line *".PHP_EOL;
}

$i = $closer;
Expand Down Expand Up @@ -1232,14 +1295,24 @@ public function process(File $phpcsFile, $stackPtr)
if ($this->debug === true) {
$line = $tokens[$i]['line'];
$type = $tokens[$i]['type'];
echo "* ignoring single-line $type on line $line".PHP_EOL;
echo "* ignoring single-line $type on line $line *".PHP_EOL;
}

$i = $closer;
continue;
}

$condition = $tokens[$tokens[$i]['scope_condition']]['code'];
if ($condition === T_FN) {
if ($this->debug === true) {
$line = $tokens[$tokens[$i]['scope_condition']]['line'];
echo "* ignoring arrow function on line $line *".PHP_EOL;
}

$i = $closer;
continue;
}

if (isset(Tokens::$scopeOpeners[$condition]) === true
&& in_array($condition, $this->nonIndentingScopes, true) === false
) {
Expand Down Expand Up @@ -1279,7 +1352,7 @@ public function process(File $phpcsFile, $stackPtr)
if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
if ($this->debug === true) {
$line = $tokens[$i]['line'];
echo "* ignoring single-line JS object on line $line".PHP_EOL;
echo "* ignoring single-line JS object on line $line *".PHP_EOL;
}

$i = $closer;
Expand Down Expand Up @@ -1309,11 +1382,14 @@ public function process(File $phpcsFile, $stackPtr)
continue;
}//end if

// Closing an anon class or function.
// Closing an anon class, closure, or match.
// Each may be returned, which can confuse control structures that
// use return as a closer, like CASE statements.
if (isset($tokens[$i]['scope_condition']) === true
&& $tokens[$i]['scope_closer'] === $i
&& ($tokens[$tokens[$i]['scope_condition']]['code'] === T_CLOSURE
|| $tokens[$tokens[$i]['scope_condition']]['code'] === T_ANON_CLASS)
|| $tokens[$tokens[$i]['scope_condition']]['code'] === T_ANON_CLASS
|| $tokens[$tokens[$i]['scope_condition']]['code'] === T_MATCH)
) {
if ($this->debug === true) {
$type = str_replace('_', ' ', strtolower(substr($tokens[$tokens[$i]['scope_condition']]['type'], 2)));
Expand Down
18 changes: 18 additions & 0 deletions tests/Drupal/good/good.php
Original file line number Diff line number Diff line change
Expand Up @@ -1887,3 +1887,21 @@ public function foo() {
'#empty' => $this->t('No strings available.'),
'#attributes' => ['class' => ['locale-translate-edit-table']],
];

/**
* Implements hook_cron().
*/
#[Hook('cron')]
class CronHook {

public function __construct(
private readonly EntityTypeManagerInterface $entityTypeManager,
private readonly StreamWrapperManagerInterface $streamWrapperManager,
private readonly ConfigFactoryInterface $configFactory,
private readonly FileUsageInterface $fileUsage,
private readonly TimeInterface $time,
#[Autowire('@logger.channel.file')]
private readonly LoggerInterface $logger,
) {}

}

0 comments on commit bf0dc2f

Please sign in to comment.