@@ -37,6 +37,29 @@ class LowerCaseConstantSniff implements Sniff
37
37
T_NULL => T_NULL ,
38
38
];
39
39
40
+ /**
41
+ * Token types which can be encountered in a property type declaration.
42
+ *
43
+ * @var array<int|string, int|string>
44
+ */
45
+ private $ propertyTypeTokens = [
46
+ T_CALLABLE => T_CALLABLE ,
47
+ T_SELF => T_SELF ,
48
+ T_PARENT => T_PARENT ,
49
+ T_FALSE => T_FALSE ,
50
+ T_TRUE => T_TRUE ,
51
+ T_NULL => T_NULL ,
52
+ T_STRING => T_STRING ,
53
+ T_NAME_QUALIFIED => T_NAME_QUALIFIED ,
54
+ T_NAME_FULLY_QUALIFIED => T_NAME_FULLY_QUALIFIED ,
55
+ T_NAME_RELATIVE => T_NAME_RELATIVE ,
56
+ T_NS_SEPARATOR => T_NS_SEPARATOR ,
57
+ T_NAMESPACE => T_NAMESPACE ,
58
+ T_TYPE_UNION => T_TYPE_UNION ,
59
+ T_TYPE_INTERSECTION => T_TYPE_INTERSECTION ,
60
+ T_NULLABLE => T_NULLABLE ,
61
+ ];
62
+
40
63
41
64
/**
42
65
* Returns an array of tokens this test wants to listen for.
@@ -47,7 +70,13 @@ public function register()
47
70
{
48
71
$ targets = $ this ->targets ;
49
72
50
- // Register function keywords to filter out type declarations.
73
+ // Register scope modifiers to filter out property type declarations.
74
+ $ targets += Tokens::$ scopeModifiers ;
75
+ $ targets [] = T_VAR ;
76
+ $ targets [] = T_STATIC ;
77
+ $ targets [] = T_READONLY ;
78
+
79
+ // Register function keywords to filter out param/return type declarations.
51
80
$ targets [] = T_FUNCTION ;
52
81
$ targets [] = T_CLOSURE ;
53
82
$ targets [] = T_FN ;
@@ -64,12 +93,43 @@ public function register()
64
93
* @param int $stackPtr The position of the current token in the
65
94
* stack passed in $tokens.
66
95
*
67
- * @return void|int
96
+ * @return void|int Optionally returns a stack pointer. The sniff will not be
97
+ * called again on the current file until the returned stack
98
+ * pointer is reached.
68
99
*/
69
100
public function process (File $ phpcsFile , $ stackPtr )
70
101
{
71
102
$ tokens = $ phpcsFile ->getTokens ();
72
103
104
+ /*
105
+ * Skip over type declarations for properties.
106
+ *
107
+ * Note: for other uses of the visibility modifiers (functions, constants, trait use),
108
+ * nothing relevant will be skipped as the next non-empty token will be an "non-skippable"
109
+ * one.
110
+ * Functions are handled separately below (and then skip to their scope opener), so
111
+ * this should also not cause any confusion for constructor property promotion.
112
+ *
113
+ * For other uses of the "static" keyword, it also shouldn't be problematic as the only
114
+ * time the next non-empty token will be a "skippable" token will be in return type
115
+ * declarations, in which case, it is correct to skip over them.
116
+ */
117
+
118
+ if (isset (Tokens::$ scopeModifiers [$ tokens [$ stackPtr ]['code ' ]]) === true
119
+ || $ tokens [$ stackPtr ]['code ' ] === T_VAR
120
+ || $ tokens [$ stackPtr ]['code ' ] === T_STATIC
121
+ || $ tokens [$ stackPtr ]['code ' ] === T_READONLY
122
+ ) {
123
+ $ skipOver = (Tokens::$ emptyTokens + $ this ->propertyTypeTokens );
124
+ $ skipTo = $ phpcsFile ->findNext ($ skipOver , ($ stackPtr + 1 ), null , true );
125
+ if ($ skipTo !== false ) {
126
+ return $ skipTo ;
127
+ }
128
+
129
+ // If we're at the end of the file, just return.
130
+ return ;
131
+ }
132
+
73
133
// Handle function declarations separately as they may contain the keywords in type declarations.
74
134
if ($ tokens [$ stackPtr ]['code ' ] === T_FUNCTION
75
135
|| $ tokens [$ stackPtr ]['code ' ] === T_CLOSURE
@@ -79,9 +139,15 @@ public function process(File $phpcsFile, $stackPtr)
79
139
return ;
80
140
}
81
141
142
+ // Make sure to skip over return type declarations.
82
143
$ end = $ tokens [$ stackPtr ]['parenthesis_closer ' ];
83
144
if (isset ($ tokens [$ stackPtr ]['scope_opener ' ]) === true ) {
84
145
$ end = $ tokens [$ stackPtr ]['scope_opener ' ];
146
+ } else {
147
+ $ skipTo = $ phpcsFile ->findNext ([T_SEMICOLON , T_OPEN_CURLY_BRACKET ], ($ end + 1 ), null , false , null , true );
148
+ if ($ skipTo !== false ) {
149
+ $ end = $ skipTo ;
150
+ }
85
151
}
86
152
87
153
// Do a quick check if any of the targets exist in the declaration.
@@ -114,21 +180,6 @@ public function process(File $phpcsFile, $stackPtr)
114
180
return $ end ;
115
181
}//end if
116
182
117
- // Handle property declarations separately as they may contain the keywords in type declarations.
118
- if (isset ($ tokens [$ stackPtr ]['conditions ' ]) === true ) {
119
- $ conditions = $ tokens [$ stackPtr ]['conditions ' ];
120
- $ lastCondition = end ($ conditions );
121
- if (isset (Tokens::$ ooScopeTokens [$ lastCondition ]) === true ) {
122
- // This can only be an OO constant or property declaration as methods are handled above.
123
- $ equals = $ phpcsFile ->findPrevious (T_EQUAL , ($ stackPtr - 1 ), null , false , null , true );
124
- if ($ equals !== false ) {
125
- $ this ->processConstant ($ phpcsFile , $ stackPtr );
126
- }
127
-
128
- return ;
129
- }
130
- }
131
-
132
183
// Handle everything else.
133
184
$ this ->processConstant ($ phpcsFile , $ stackPtr );
134
185
0 commit comments