@@ -48,106 +48,136 @@ public function process(File $phpcsFile, $stackPtr)
4848 {
4949 $ tokens = $ phpcsFile ->getTokens ();
5050
51- switch ($ tokens [$ stackPtr ]['type ' ]) {
52- // Detect `something();;`.
53- case 'T_SEMICOLON ' :
54- $ prevNonEmpty = $ phpcsFile ->findPrevious (Tokens::$ emptyTokens , ($ stackPtr - 1 ), null , true );
55-
56- if ($ tokens [$ prevNonEmpty ]['code ' ] !== T_SEMICOLON
57- && $ tokens [$ prevNonEmpty ]['code ' ] !== T_OPEN_TAG
58- && $ tokens [$ prevNonEmpty ]['code ' ] !== T_OPEN_TAG_WITH_ECHO
51+ if ($ tokens [$ stackPtr ]['code ' ] === T_SEMICOLON ) {
52+ $ this ->processSemicolon ($ phpcsFile , $ stackPtr );
53+ } else {
54+ $ this ->processCloseTag ($ phpcsFile , $ stackPtr );
55+ }
56+
57+ }//end process()
58+
59+
60+ /**
61+ * Detect `something();;`.
62+ *
63+ * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
64+ * @param int $stackPtr The position of the current token
65+ * in the stack passed in $tokens.
66+ *
67+ * @return void
68+ */
69+ private function processSemicolon (File $ phpcsFile , $ stackPtr )
70+ {
71+ $ tokens = $ phpcsFile ->getTokens ();
72+
73+ $ prevNonEmpty = $ phpcsFile ->findPrevious (Tokens::$ emptyTokens , ($ stackPtr - 1 ), null , true );
74+ if ($ tokens [$ prevNonEmpty ]['code ' ] !== T_SEMICOLON
75+ && $ tokens [$ prevNonEmpty ]['code ' ] !== T_OPEN_TAG
76+ && $ tokens [$ prevNonEmpty ]['code ' ] !== T_OPEN_TAG_WITH_ECHO
77+ ) {
78+ if (isset ($ tokens [$ prevNonEmpty ]['scope_condition ' ]) === false ) {
79+ return ;
80+ }
81+
82+ if ($ tokens [$ prevNonEmpty ]['scope_opener ' ] !== $ prevNonEmpty
83+ && $ tokens [$ prevNonEmpty ]['code ' ] !== T_CLOSE_CURLY_BRACKET
5984 ) {
60- if (isset ($ tokens [$ prevNonEmpty ]['scope_condition ' ]) === false ) {
61- return ;
62- }
85+ return ;
86+ }
6387
64- if ($ tokens [$ prevNonEmpty ]['scope_opener ' ] !== $ prevNonEmpty
65- && $ tokens [$ prevNonEmpty ]['code ' ] !== T_CLOSE_CURLY_BRACKET
66- ) {
67- return ;
68- }
88+ $ scopeOwner = $ tokens [$ tokens [$ prevNonEmpty ]['scope_condition ' ]]['code ' ];
89+ if ($ scopeOwner === T_CLOSURE || $ scopeOwner === T_ANON_CLASS || $ scopeOwner === T_MATCH ) {
90+ return ;
91+ }
6992
70- $ scopeOwner = $ tokens [$ tokens [$ prevNonEmpty ]['scope_condition ' ]]['code ' ];
71- if ($ scopeOwner === T_CLOSURE || $ scopeOwner === T_ANON_CLASS || $ scopeOwner === T_MATCH ) {
72- return ;
73- }
93+ // Else, it's something like `if (foo) {};` and the semicolon is not needed.
94+ }
7495
75- // Else, it's something like `if (foo) {};` and the semicolon is not needed.
96+ if (isset ($ tokens [$ stackPtr ]['nested_parenthesis ' ]) === true ) {
97+ $ nested = $ tokens [$ stackPtr ]['nested_parenthesis ' ];
98+ $ lastCloser = array_pop ($ nested );
99+ if (isset ($ tokens [$ lastCloser ]['parenthesis_owner ' ]) === true
100+ && $ tokens [$ tokens [$ lastCloser ]['parenthesis_owner ' ]]['code ' ] === T_FOR
101+ ) {
102+ // Empty for() condition.
103+ return ;
76104 }
105+ }
77106
78- if (isset ($ tokens [$ stackPtr ]['nested_parenthesis ' ]) === true ) {
79- $ nested = $ tokens [$ stackPtr ]['nested_parenthesis ' ];
80- $ lastCloser = array_pop ($ nested );
81- if (isset ($ tokens [$ lastCloser ]['parenthesis_owner ' ]) === true
82- && $ tokens [$ tokens [$ lastCloser ]['parenthesis_owner ' ]]['code ' ] === T_FOR
83- ) {
84- // Empty for() condition.
85- return ;
107+ $ fix = $ phpcsFile ->addFixableWarning (
108+ 'Empty PHP statement detected: superfluous semicolon. ' ,
109+ $ stackPtr ,
110+ 'SemicolonWithoutCodeDetected '
111+ );
112+
113+ if ($ fix === true ) {
114+ $ phpcsFile ->fixer ->beginChangeset ();
115+
116+ if ($ tokens [$ prevNonEmpty ]['code ' ] === T_OPEN_TAG
117+ || $ tokens [$ prevNonEmpty ]['code ' ] === T_OPEN_TAG_WITH_ECHO
118+ ) {
119+ // Check for superfluous whitespace after the semicolon which should be
120+ // removed as the `<?php ` open tag token already contains whitespace,
121+ // either a space or a new line.
122+ if ($ tokens [($ stackPtr + 1 )]['code ' ] === T_WHITESPACE ) {
123+ $ replacement = str_replace (' ' , '' , $ tokens [($ stackPtr + 1 )]['content ' ]);
124+ $ phpcsFile ->fixer ->replaceToken (($ stackPtr + 1 ), $ replacement );
86125 }
87126 }
88127
89- $ fix = $ phpcsFile ->addFixableWarning (
90- 'Empty PHP statement detected: superfluous semicolon. ' ,
91- $ stackPtr ,
92- 'SemicolonWithoutCodeDetected '
93- );
94- if ($ fix === true ) {
95- $ phpcsFile ->fixer ->beginChangeset ();
96-
97- if ($ tokens [$ prevNonEmpty ]['code ' ] === T_OPEN_TAG
98- || $ tokens [$ prevNonEmpty ]['code ' ] === T_OPEN_TAG_WITH_ECHO
128+ for ($ i = $ stackPtr ; $ i > $ prevNonEmpty ; $ i --) {
129+ if ($ tokens [$ i ]['code ' ] !== T_SEMICOLON
130+ && $ tokens [$ i ]['code ' ] !== T_WHITESPACE
99131 ) {
100- // Check for superfluous whitespace after the semicolon which will be
101- // removed as the `<?php ` open tag token already contains whitespace,
102- // either a space or a new line.
103- if ($ tokens [($ stackPtr + 1 )]['code ' ] === T_WHITESPACE ) {
104- $ replacement = str_replace (' ' , '' , $ tokens [($ stackPtr + 1 )]['content ' ]);
105- $ phpcsFile ->fixer ->replaceToken (($ stackPtr + 1 ), $ replacement );
106- }
132+ break ;
107133 }
108134
109- for ($ i = $ stackPtr ; $ i > $ prevNonEmpty ; $ i --) {
110- if ($ tokens [$ i ]['code ' ] !== T_SEMICOLON
111- && $ tokens [$ i ]['code ' ] !== T_WHITESPACE
112- ) {
113- break ;
114- }
135+ $ phpcsFile ->fixer ->replaceToken ($ i , '' );
136+ }
115137
116- $ phpcsFile ->fixer ->replaceToken ( $ i , '' );
117- }
138+ $ phpcsFile ->fixer ->endChangeset ( );
139+ } //end if
118140
119- $ phpcsFile ->fixer ->endChangeset ();
120- }//end if
121- break ;
141+ }//end processSemicolon()
122142
123- // Detect `<?php ? >`.
124- case 'T_CLOSE_TAG ' :
125- $ prevNonEmpty = $ phpcsFile ->findPrevious (T_WHITESPACE , ($ stackPtr - 1 ), null , true );
126143
127- if ($ tokens [$ prevNonEmpty ]['code ' ] !== T_OPEN_TAG
128- && $ tokens [$ prevNonEmpty ]['code ' ] !== T_OPEN_TAG_WITH_ECHO
129- ) {
130- return ;
131- }
144+ /**
145+ * Detect `<?php ? >`.
146+ *
147+ * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
148+ * @param int $stackPtr The position of the current token
149+ * in the stack passed in $tokens.
150+ *
151+ * @return void
152+ */
153+ private function processCloseTag (File $ phpcsFile , $ stackPtr )
154+ {
155+ $ tokens = $ phpcsFile ->getTokens ();
132156
133- $ fix = $ phpcsFile ->addFixableWarning (
134- 'Empty PHP open/close tag combination detected. ' ,
135- $ prevNonEmpty ,
136- 'EmptyPHPOpenCloseTagsDetected '
137- );
138- if ($ fix === true ) {
139- $ phpcsFile ->fixer ->beginChangeset ();
157+ $ prevNonEmpty = $ phpcsFile ->findPrevious (T_WHITESPACE , ($ stackPtr - 1 ), null , true );
158+ if ($ tokens [$ prevNonEmpty ]['code ' ] !== T_OPEN_TAG
159+ && $ tokens [$ prevNonEmpty ]['code ' ] !== T_OPEN_TAG_WITH_ECHO
160+ ) {
161+ return ;
162+ }
140163
141- for ($ i = $ prevNonEmpty ; $ i <= $ stackPtr ; $ i ++) {
142- $ phpcsFile ->fixer ->replaceToken ($ i , '' );
143- }
164+ $ fix = $ phpcsFile ->addFixableWarning (
165+ 'Empty PHP open/close tag combination detected. ' ,
166+ $ prevNonEmpty ,
167+ 'EmptyPHPOpenCloseTagsDetected '
168+ );
144169
145- $ phpcsFile ->fixer ->endChangeset ();
170+ if ($ fix === true ) {
171+ $ phpcsFile ->fixer ->beginChangeset ();
172+
173+ for ($ i = $ prevNonEmpty ; $ i <= $ stackPtr ; $ i ++) {
174+ $ phpcsFile ->fixer ->replaceToken ($ i , '' );
146175 }
147- break ;
148- }//end switch
149176
150- }//end process()
177+ $ phpcsFile ->fixer ->endChangeset ();
178+ }
179+
180+ }//end processCloseTag()
151181
152182
153183}//end class
0 commit comments