@@ -126,7 +126,7 @@ public function register()
126
126
* @param int $stackPtr The position of the current token
127
127
* in the stack passed in $tokens.
128
128
*
129
- * @return void| int
129
+ * @return int
130
130
*/
131
131
public function process (File $ phpcsFile , $ stackPtr )
132
132
{
@@ -146,13 +146,14 @@ public function process(File $phpcsFile, $stackPtr)
146
146
}
147
147
}
148
148
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 ;
156
157
157
158
$ tokens = $ phpcsFile ->getTokens ();
158
159
$ first = $ phpcsFile ->findFirstOnLine (T_INLINE_HTML , $ stackPtr );
@@ -232,6 +233,7 @@ public function process(File $phpcsFile, $stackPtr)
232
233
if ($ tokens [$ i ]['code ' ] === T_OPEN_PARENTHESIS
233
234
&& isset ($ tokens [$ i ]['parenthesis_closer ' ]) === true
234
235
) {
236
+ $ disableExactStack [$ tokens [$ i ]['parenthesis_closer ' ]] = $ tokens [$ i ]['parenthesis_closer ' ];
235
237
$ disableExactEnd = max ($ disableExactEnd , $ tokens [$ i ]['parenthesis_closer ' ]);
236
238
if ($ this ->debug === true ) {
237
239
$ line = $ tokens [$ i ]['line ' ];
@@ -337,7 +339,14 @@ public function process(File $phpcsFile, $stackPtr)
337
339
echo "\t* open tag is inside condition; using open tag * " .PHP_EOL ;
338
340
}
339
341
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 );
341
350
if (isset ($ adjustments [$ condition ]) === true ) {
342
351
$ checkIndent += $ adjustments [$ condition ];
343
352
}
@@ -483,12 +492,7 @@ public function process(File $phpcsFile, $stackPtr)
483
492
484
493
$ arrayOpener = $ tokens [$ arrayCloser ]['bracket_opener ' ];
485
494
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 );
492
496
$ exact = false ;
493
497
494
498
if ($ this ->debug === true ) {
@@ -524,6 +528,11 @@ public function process(File $phpcsFile, $stackPtr)
524
528
$ first = $ phpcsFile ->findNext (T_WHITESPACE , ($ first + 1 ), null , true );
525
529
}
526
530
531
+ $ checkIndent = ($ tokens [$ first ]['column ' ] - 1 );
532
+ if (isset ($ adjustments [$ first ]) === true ) {
533
+ $ checkIndent += $ adjustments [$ first ];
534
+ }
535
+
527
536
if (isset ($ tokens [$ first ]['scope_closer ' ]) === true
528
537
&& $ tokens [$ first ]['scope_closer ' ] === $ first
529
538
) {
@@ -609,11 +618,11 @@ public function process(File $phpcsFile, $stackPtr)
609
618
610
619
// Scope closers reset the required indent to the same level as the opening condition.
611
620
if (($ checkToken !== null
612
- && isset ($ openScopes [$ checkToken ]) === true
621
+ && ( isset ($ openScopes [$ checkToken ]) === true
613
622
|| (isset ($ tokens [$ checkToken ]['scope_condition ' ]) === true
614
623
&& isset ($ tokens [$ checkToken ]['scope_closer ' ]) === true
615
624
&& $ 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 ' ])))
617
626
|| ($ checkToken === null
618
627
&& isset ($ openScopes [$ i ]) === true )
619
628
) {
@@ -796,6 +805,19 @@ public function process(File $phpcsFile, $stackPtr)
796
805
) {
797
806
$ exact = true ;
798
807
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
+
799
821
$ lastOpener = null ;
800
822
if (empty ($ openScopes ) === false ) {
801
823
end ($ openScopes );
@@ -844,16 +866,34 @@ public function process(File $phpcsFile, $stackPtr)
844
866
&& $ tokens [($ checkToken + 1 )]['code ' ] !== T_DOUBLE_COLON
845
867
) {
846
868
$ 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
+ }
852
884
}
853
885
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
857
897
858
898
// JS property indentation has to be exact or else if will break
859
899
// things like function and object indentation.
@@ -890,8 +930,6 @@ public function process(File $phpcsFile, $stackPtr)
890
930
}
891
931
}
892
932
}
893
-
894
- $ checkIndent = (int ) (ceil ($ checkIndent / $ this ->indent ) * $ this ->indent );
895
933
}//end if
896
934
897
935
// Close tags needs to be indented to exact column positions.
@@ -911,7 +949,8 @@ public function process(File $phpcsFile, $stackPtr)
911
949
// Don't perform strict checking on chained method calls since they
912
950
// are often covered by custom rules.
913
951
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 )
915
954
&& $ exact === true
916
955
) {
917
956
$ exact = false ;
@@ -988,18 +1027,38 @@ public function process(File $phpcsFile, $stackPtr)
988
1027
}
989
1028
990
1029
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
996
1055
} else {
997
1056
$ error .= '%s spaces, found %s ' ;
998
1057
$ data = [
999
1058
$ checkIndent ,
1000
1059
$ tokenIndent ,
1001
1060
];
1002
- }
1061
+ }//end if
1003
1062
1004
1063
if ($ this ->debug === true ) {
1005
1064
$ line = $ tokens [$ checkToken ]['line ' ];
@@ -1030,15 +1089,17 @@ public function process(File $phpcsFile, $stackPtr)
1030
1089
1031
1090
// Don't check indents exactly between arrays as they tend to have custom rules.
1032
1091
if ($ tokens [$ i ]['code ' ] === T_OPEN_SHORT_ARRAY ) {
1092
+ $ disableExactStack [$ tokens [$ i ]['bracket_closer ' ]] = $ tokens [$ i ]['bracket_closer ' ];
1033
1093
$ disableExactEnd = max ($ disableExactEnd , $ tokens [$ i ]['bracket_closer ' ]);
1034
1094
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 ' ];
1037
1098
echo "Opening short array bracket found on line $ line " .PHP_EOL ;
1038
1099
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 ;
1040
1101
} 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 ;
1042
1103
}
1043
1104
}
1044
1105
}
@@ -1050,7 +1111,6 @@ public function process(File $phpcsFile, $stackPtr)
1050
1111
) {
1051
1112
if ($ this ->debug === true ) {
1052
1113
$ line = $ tokens [$ i ]['line ' ];
1053
- $ type = $ tokens [$ disableExactEnd ]['type ' ];
1054
1114
echo "Here/nowdoc found on line $ line " .PHP_EOL ;
1055
1115
}
1056
1116
@@ -1074,8 +1134,11 @@ public function process(File $phpcsFile, $stackPtr)
1074
1134
if ($ tokens [$ i ]['code ' ] === T_CONSTANT_ENCAPSED_STRING
1075
1135
|| $ tokens [$ i ]['code ' ] === T_DOUBLE_QUOTED_STRING
1076
1136
) {
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
+
1079
1142
continue ;
1080
1143
}
1081
1144
@@ -1162,7 +1225,7 @@ public function process(File $phpcsFile, $stackPtr)
1162
1225
if ($ this ->debug === true ) {
1163
1226
$ type = str_replace ('_ ' , ' ' , strtolower (substr ($ tokens [$ i ]['type ' ], 2 )));
1164
1227
$ 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 ;
1166
1229
}
1167
1230
1168
1231
$ i = $ closer ;
@@ -1232,14 +1295,24 @@ public function process(File $phpcsFile, $stackPtr)
1232
1295
if ($ this ->debug === true ) {
1233
1296
$ line = $ tokens [$ i ]['line ' ];
1234
1297
$ 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 ;
1236
1299
}
1237
1300
1238
1301
$ i = $ closer ;
1239
1302
continue ;
1240
1303
}
1241
1304
1242
1305
$ 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
+
1243
1316
if (isset (Tokens::$ scopeOpeners [$ condition ]) === true
1244
1317
&& in_array ($ condition , $ this ->nonIndentingScopes , true ) === false
1245
1318
) {
@@ -1279,7 +1352,7 @@ public function process(File $phpcsFile, $stackPtr)
1279
1352
if ($ tokens [$ i ]['line ' ] === $ tokens [$ closer ]['line ' ]) {
1280
1353
if ($ this ->debug === true ) {
1281
1354
$ 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 ;
1283
1356
}
1284
1357
1285
1358
$ i = $ closer ;
@@ -1309,11 +1382,14 @@ public function process(File $phpcsFile, $stackPtr)
1309
1382
continue ;
1310
1383
}//end if
1311
1384
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.
1313
1388
if (isset ($ tokens [$ i ]['scope_condition ' ]) === true
1314
1389
&& $ tokens [$ i ]['scope_closer ' ] === $ i
1315
1390
&& ($ 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 )
1317
1393
) {
1318
1394
if ($ this ->debug === true ) {
1319
1395
$ type = str_replace ('_ ' , ' ' , strtolower (substr ($ tokens [$ tokens [$ i ]['scope_condition ' ]]['type ' ], 2 )));
0 commit comments