Skip to content

Commit 406bd5d

Browse files
committed
Merge remote-tracking branch 'origin/8.3.x' into case-semicolon
2 parents 6450298 + bf0dc2f commit 406bd5d

File tree

2 files changed

+140
-46
lines changed

2 files changed

+140
-46
lines changed

coder_sniffer/Drupal/Sniffs/WhiteSpace/ScopeIndentSniff.php

Lines changed: 122 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public function register()
126126
* @param int $stackPtr The position of the current token
127127
* in the stack passed in $tokens.
128128
*
129-
* @return void|int
129+
* @return int
130130
*/
131131
public function process(File $phpcsFile, $stackPtr)
132132
{
@@ -146,13 +146,14 @@ public function process(File $phpcsFile, $stackPtr)
146146
}
147147
}
148148

149-
$lastOpenTag = $stackPtr;
150-
$lastCloseTag = null;
151-
$openScopes = [];
152-
$adjustments = [];
153-
$setIndents = [];
154-
$disableExactEnd = 0;
155-
$tokenIndent = 0;
149+
$lastOpenTag = $stackPtr;
150+
$lastCloseTag = null;
151+
$openScopes = [];
152+
$adjustments = [];
153+
$setIndents = [];
154+
$disableExactStack = [];
155+
$disableExactEnd = 0;
156+
$tokenIndent = 0;
156157

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

340-
$checkIndent = ($tokens[$lastOpenTag]['column'] - 1);
342+
$first = $phpcsFile->findFirstOnLine([T_WHITESPACE, T_INLINE_HTML], $lastOpenTag, true);
343+
if ($this->debug === true) {
344+
$line = $tokens[$first]['line'];
345+
$type = $tokens[$first]['type'];
346+
echo "\t* first token on line $line is $first ($type) *".PHP_EOL;
347+
}
348+
349+
$checkIndent = ($tokens[$first]['column'] - 1);
341350
if (isset($adjustments[$condition]) === true) {
342351
$checkIndent += $adjustments[$condition];
343352
}
@@ -483,12 +492,7 @@ public function process(File $phpcsFile, $stackPtr)
483492

484493
$arrayOpener = $tokens[$arrayCloser]['bracket_opener'];
485494
if ($tokens[$arrayCloser]['line'] !== $tokens[$arrayOpener]['line']) {
486-
$first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $arrayOpener, true);
487-
$checkIndent = ($tokens[$first]['column'] - 1);
488-
if (isset($adjustments[$first]) === true) {
489-
$checkIndent += $adjustments[$first];
490-
}
491-
495+
$first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $arrayOpener, true);
492496
$exact = false;
493497

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

531+
$checkIndent = ($tokens[$first]['column'] - 1);
532+
if (isset($adjustments[$first]) === true) {
533+
$checkIndent += $adjustments[$first];
534+
}
535+
527536
if (isset($tokens[$first]['scope_closer']) === true
528537
&& $tokens[$first]['scope_closer'] === $first
529538
) {
@@ -609,11 +618,11 @@ public function process(File $phpcsFile, $stackPtr)
609618

610619
// Scope closers reset the required indent to the same level as the opening condition.
611620
if (($checkToken !== null
612-
&& isset($openScopes[$checkToken]) === true
621+
&& (isset($openScopes[$checkToken]) === true
613622
|| (isset($tokens[$checkToken]['scope_condition']) === true
614623
&& isset($tokens[$checkToken]['scope_closer']) === true
615624
&& $tokens[$checkToken]['scope_closer'] === $checkToken
616-
&& $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['scope_opener']]['line']))
625+
&& $tokens[$checkToken]['line'] !== $tokens[$tokens[$checkToken]['scope_opener']]['line'])))
617626
|| ($checkToken === null
618627
&& isset($openScopes[$i]) === true)
619628
) {
@@ -796,6 +805,19 @@ public function process(File $phpcsFile, $stackPtr)
796805
) {
797806
$exact = true;
798807

808+
if ($disableExactEnd > $checkToken) {
809+
foreach ($disableExactStack as $disableExactStackEnd) {
810+
if ($disableExactStackEnd < $checkToken) {
811+
continue;
812+
}
813+
814+
if ($tokens[$checkToken]['conditions'] === $tokens[$disableExactStackEnd]['conditions']) {
815+
$exact = false;
816+
break;
817+
}
818+
}
819+
}
820+
799821
$lastOpener = null;
800822
if (empty($openScopes) === false) {
801823
end($openScopes);
@@ -844,16 +866,34 @@ public function process(File $phpcsFile, $stackPtr)
844866
&& $tokens[($checkToken + 1)]['code'] !== T_DOUBLE_COLON
845867
) {
846868
$next = $phpcsFile->findNext(Tokens::$emptyTokens, ($checkToken + 1), null, true);
847-
if ($next === false || $tokens[$next]['code'] !== T_CLOSURE) {
848-
if ($this->debug === true) {
849-
$line = $tokens[$checkToken]['line'];
850-
$type = $tokens[$checkToken]['type'];
851-
echo "\t* method prefix ($type) found on line $line; indent set to exact *".PHP_EOL;
869+
if ($next === false
870+
|| ($tokens[$next]['code'] !== T_CLOSURE
871+
&& $tokens[$next]['code'] !== T_VARIABLE
872+
&& $tokens[$next]['code'] !== T_FN)
873+
) {
874+
$isMethodPrefix = true;
875+
if (isset($tokens[$checkToken]['nested_parenthesis']) === true) {
876+
$parenthesis = array_keys($tokens[$checkToken]['nested_parenthesis']);
877+
$deepestOpen = array_pop($parenthesis);
878+
if (isset($tokens[$deepestOpen]['parenthesis_owner']) === true
879+
&& $tokens[$tokens[$deepestOpen]['parenthesis_owner']]['code'] === T_FUNCTION
880+
) {
881+
// This is constructor property promotion and not a method prefix.
882+
$isMethodPrefix = false;
883+
}
852884
}
853885

854-
$exact = true;
855-
}
856-
}
886+
if ($isMethodPrefix === true) {
887+
if ($this->debug === true) {
888+
$line = $tokens[$checkToken]['line'];
889+
$type = $tokens[$checkToken]['type'];
890+
echo "\t* method prefix ($type) found on line $line; indent set to exact *".PHP_EOL;
891+
}
892+
893+
$exact = true;
894+
}
895+
}//end if
896+
}//end if
857897

858898
// JS property indentation has to be exact or else if will break
859899
// things like function and object indentation.
@@ -890,8 +930,6 @@ public function process(File $phpcsFile, $stackPtr)
890930
}
891931
}
892932
}
893-
894-
$checkIndent = (int) (ceil($checkIndent / $this->indent) * $this->indent);
895933
}//end if
896934

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

9901029
if ($this->tabIndent === true) {
991-
$error .= '%s tabs, found %s';
992-
$data = [
993-
floor($checkIndent / $this->tabWidth),
994-
floor($tokenIndent / $this->tabWidth),
995-
];
1030+
$expectedTabs = floor($checkIndent / $this->tabWidth);
1031+
$foundTabs = floor($tokenIndent / $this->tabWidth);
1032+
$foundSpaces = ($tokenIndent - ($foundTabs * $this->tabWidth));
1033+
if ($foundSpaces > 0) {
1034+
if ($foundTabs > 0) {
1035+
$error .= '%s tabs, found %s tabs and %s spaces';
1036+
$data = [
1037+
$expectedTabs,
1038+
$foundTabs,
1039+
$foundSpaces,
1040+
];
1041+
} else {
1042+
$error .= '%s tabs, found %s spaces';
1043+
$data = [
1044+
$expectedTabs,
1045+
$foundSpaces,
1046+
];
1047+
}
1048+
} else {
1049+
$error .= '%s tabs, found %s';
1050+
$data = [
1051+
$expectedTabs,
1052+
$foundTabs,
1053+
];
1054+
}//end if
9961055
} else {
9971056
$error .= '%s spaces, found %s';
9981057
$data = [
9991058
$checkIndent,
10001059
$tokenIndent,
10011060
];
1002-
}
1061+
}//end if
10031062

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

10311090
// Don't check indents exactly between arrays as they tend to have custom rules.
10321091
if ($tokens[$i]['code'] === T_OPEN_SHORT_ARRAY) {
1092+
$disableExactStack[$tokens[$i]['bracket_closer']] = $tokens[$i]['bracket_closer'];
10331093
$disableExactEnd = max($disableExactEnd, $tokens[$i]['bracket_closer']);
10341094
if ($this->debug === true) {
1035-
$line = $tokens[$i]['line'];
1036-
$type = $tokens[$disableExactEnd]['type'];
1095+
$line = $tokens[$i]['line'];
1096+
$type = $tokens[$disableExactEnd]['type'];
1097+
$endLine = $tokens[$disableExactEnd]['line'];
10371098
echo "Opening short array bracket found on line $line".PHP_EOL;
10381099
if ($disableExactEnd === $tokens[$i]['bracket_closer']) {
1039-
echo "\t=> disabling exact indent checking until $disableExactEnd ($type)".PHP_EOL;
1100+
echo "\t=> disabling exact indent checking until $disableExactEnd ($type) on line $endLine".PHP_EOL;
10401101
} else {
1041-
echo "\t=> continuing to disable exact indent checking until $disableExactEnd ($type)".PHP_EOL;
1102+
echo "\t=> continuing to disable exact indent checking until $disableExactEnd ($type) on line $endLine".PHP_EOL;
10421103
}
10431104
}
10441105
}
@@ -1050,7 +1111,6 @@ public function process(File $phpcsFile, $stackPtr)
10501111
) {
10511112
if ($this->debug === true) {
10521113
$line = $tokens[$i]['line'];
1053-
$type = $tokens[$disableExactEnd]['type'];
10541114
echo "Here/nowdoc found on line $line".PHP_EOL;
10551115
}
10561116

@@ -1074,8 +1134,11 @@ public function process(File $phpcsFile, $stackPtr)
10741134
if ($tokens[$i]['code'] === T_CONSTANT_ENCAPSED_STRING
10751135
|| $tokens[$i]['code'] === T_DOUBLE_QUOTED_STRING
10761136
) {
1077-
$i = $phpcsFile->findNext($tokens[$i]['code'], ($i + 1), null, true);
1078-
$i--;
1137+
$nextNonTextString = $phpcsFile->findNext($tokens[$i]['code'], ($i + 1), null, true);
1138+
if ($nextNonTextString !== false) {
1139+
$i = ($nextNonTextString - 1);
1140+
}
1141+
10791142
continue;
10801143
}
10811144

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

11681231
$i = $closer;
@@ -1232,14 +1295,24 @@ public function process(File $phpcsFile, $stackPtr)
12321295
if ($this->debug === true) {
12331296
$line = $tokens[$i]['line'];
12341297
$type = $tokens[$i]['type'];
1235-
echo "* ignoring single-line $type on line $line".PHP_EOL;
1298+
echo "* ignoring single-line $type on line $line *".PHP_EOL;
12361299
}
12371300

12381301
$i = $closer;
12391302
continue;
12401303
}
12411304

12421305
$condition = $tokens[$tokens[$i]['scope_condition']]['code'];
1306+
if ($condition === T_FN) {
1307+
if ($this->debug === true) {
1308+
$line = $tokens[$tokens[$i]['scope_condition']]['line'];
1309+
echo "* ignoring arrow function on line $line *".PHP_EOL;
1310+
}
1311+
1312+
$i = $closer;
1313+
continue;
1314+
}
1315+
12431316
if (isset(Tokens::$scopeOpeners[$condition]) === true
12441317
&& in_array($condition, $this->nonIndentingScopes, true) === false
12451318
) {
@@ -1279,7 +1352,7 @@ public function process(File $phpcsFile, $stackPtr)
12791352
if ($tokens[$i]['line'] === $tokens[$closer]['line']) {
12801353
if ($this->debug === true) {
12811354
$line = $tokens[$i]['line'];
1282-
echo "* ignoring single-line JS object on line $line".PHP_EOL;
1355+
echo "* ignoring single-line JS object on line $line *".PHP_EOL;
12831356
}
12841357

12851358
$i = $closer;
@@ -1309,11 +1382,14 @@ public function process(File $phpcsFile, $stackPtr)
13091382
continue;
13101383
}//end if
13111384

1312-
// Closing an anon class or function.
1385+
// Closing an anon class, closure, or match.
1386+
// Each may be returned, which can confuse control structures that
1387+
// use return as a closer, like CASE statements.
13131388
if (isset($tokens[$i]['scope_condition']) === true
13141389
&& $tokens[$i]['scope_closer'] === $i
13151390
&& ($tokens[$tokens[$i]['scope_condition']]['code'] === T_CLOSURE
1316-
|| $tokens[$tokens[$i]['scope_condition']]['code'] === T_ANON_CLASS)
1391+
|| $tokens[$tokens[$i]['scope_condition']]['code'] === T_ANON_CLASS
1392+
|| $tokens[$tokens[$i]['scope_condition']]['code'] === T_MATCH)
13171393
) {
13181394
if ($this->debug === true) {
13191395
$type = str_replace('_', ' ', strtolower(substr($tokens[$tokens[$i]['scope_condition']]['type'], 2)));

tests/Drupal/good/good.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,3 +1887,21 @@ public function foo() {
18871887
'#empty' => $this->t('No strings available.'),
18881888
'#attributes' => ['class' => ['locale-translate-edit-table']],
18891889
];
1890+
1891+
/**
1892+
* Implements hook_cron().
1893+
*/
1894+
#[Hook('cron')]
1895+
class CronHook {
1896+
1897+
public function __construct(
1898+
private readonly EntityTypeManagerInterface $entityTypeManager,
1899+
private readonly StreamWrapperManagerInterface $streamWrapperManager,
1900+
private readonly ConfigFactoryInterface $configFactory,
1901+
private readonly FileUsageInterface $fileUsage,
1902+
private readonly TimeInterface $time,
1903+
#[Autowire('@logger.channel.file')]
1904+
private readonly LoggerInterface $logger,
1905+
) {}
1906+
1907+
}

0 commit comments

Comments
 (0)