@@ -16,6 +16,8 @@ class FunctionCommentSniff extends PEARFunctionCommentSniff
1616 /**
1717 * @param File $phpcsFile
1818 * @param int $stackPtr
19+ *
20+ * @return void
1921 */
2022 public function process (File $ phpcsFile , $ stackPtr ): void
2123 {
@@ -68,10 +70,7 @@ public function process(File $phpcsFile, $stackPtr): void
6870 }
6971 } else {
7072 // No comment but maybe a method prefix
71- $ methodPrefixes = $ phpcsFile ->findFirstOnLine (
72- Tokens::$ methodPrefixes ,
73- $ stackPtr
74- );
73+ $ methodPrefixes = $ phpcsFile ->findFirstOnLine (Tokens::$ methodPrefixes , $ stackPtr );
7574
7675 if (false !== $ methodPrefixes ) {
7776 $ commentStart = $ methodPrefixes ;
@@ -107,58 +106,56 @@ public function process(File $phpcsFile, $stackPtr): void
107106 * @param int $stackPtr
108107 * @param int|null $commentStart
109108 * @param bool $hasComment
109+ *
110+ * @return void
110111 */
111112 protected function processReturn (File $ phpcsFile , $ stackPtr , $ commentStart , $ hasComment = true ): void
112113 {
113- // Check for inheritDoc if there is comment
114- if ($ hasComment && $ this ->isInheritDoc ($ phpcsFile , $ stackPtr )) {
114+ if (!$ hasComment ) {
115+ $ phpcsFile ->addError ('Missing @return tag in function comment ' , $ stackPtr , 'MissingReturn ' );
116+
117+ return ;
118+ }
119+
120+ // Check for inheritDoc
121+ if ($ this ->isInheritDoc ($ phpcsFile , $ stackPtr )) {
115122 return ;
116123 }
117124
118125 $ tokens = $ phpcsFile ->getTokens ();
119126
120- // Only check for a return comment if a non-void return statement exists
121- if (isset ($ tokens [$ stackPtr ]['scope_opener ' ])) {
122- // Start inside the function
123- $ start = $ phpcsFile ->findNext (
124- T_OPEN_CURLY_BRACKET ,
125- $ stackPtr ,
126- $ tokens [$ stackPtr ]['scope_closer ' ]
127- );
128-
129- for ($ i = $ start ; $ i < $ tokens [$ stackPtr ]['scope_closer ' ]; ++$ i ) {
130- // Skip closures
131- if (T_CLOSURE === $ tokens [$ i ]['code ' ]) {
132- $ i = $ tokens [$ i ]['scope_closer ' ];
133- continue ;
127+ $ return = null ;
128+ foreach ($ tokens [$ commentStart ]['comment_tags ' ] as $ tag ) {
129+ if ('@return ' === $ tokens [$ tag ]['content ' ]) {
130+ if (null !== $ return ) {
131+ $ error = 'Only 1 @return tag is allowed in a function comment ' ;
132+ $ phpcsFile ->addError ($ error , $ tag , 'DuplicateReturn ' );
133+
134+ return ;
134135 }
135136
136- // Found a return not in a closure statement
137- // Run the check on the first which is not only 'return;'
138- if (T_RETURN === $ tokens [$ i ]['code ' ]
139- && $ this ->isMatchingReturn ($ tokens , $ i )
140- ) {
141- if ($ hasComment ) {
142- parent ::processReturn ($ phpcsFile , $ stackPtr , $ commentStart );
143- } else {
144- // There is no doc and we need one with @return
145- $ phpcsFile ->addError (
146- 'Missing @return tag in function comment ' ,
147- $ stackPtr ,
148- 'MissingReturn '
149- );
150- }
137+ $ return = $ tag ;
138+ }
139+ }
151140
152- break ;
153- }
141+ if (null !== $ return ) {
142+ $ content = $ tokens [($ return + 2 )]['content ' ];
143+ if (!$ content || T_DOC_COMMENT_STRING !== $ tokens [($ return + 2 )]['code ' ]) {
144+ $ error = 'Return type missing for @return tag in function comment ' ;
145+ $ phpcsFile ->addError ($ error , $ return , 'MissingReturnType ' );
154146 }
147+ } else {
148+ $ error = 'Missing @return tag in function comment ' ;
149+ $ phpcsFile ->addError ($ error , $ tokens [$ commentStart ]['comment_closer ' ], 'MissingReturn ' );
155150 }
156151 }
157152
158153 /**
159154 * @param File $phpcsFile
160155 * @param int $stackPtr
161156 * @param int $commentStart
157+ *
158+ * @return void
162159 */
163160 protected function processThrows (File $ phpcsFile , $ stackPtr , $ commentStart ): void
164161 {
@@ -181,28 +178,15 @@ protected function processThrows(File $phpcsFile, $stackPtr, $commentStart): voi
181178 }
182179 }
183180
184- if (null !== $ throw ) {
185- $ exception = null ;
186- if (T_DOC_COMMENT_STRING === $ tokens [$ throw + 2 ]['code ' ]) {
187- $ matches = [];
188- preg_match ('/([^\s]+)(?:\s+(.*))?/ ' , $ tokens [$ throw + 2 ]['content ' ], $ matches );
189- $ exception = $ matches [1 ];
190- }
191-
192- if (null === $ exception ) {
193- $ phpcsFile ->addError (
194- 'Exception type missing for @throws tag in function comment ' ,
195- $ throw ,
196- 'InvalidThrows '
197- );
198- }
199- }
181+ parent ::processThrows ($ phpcsFile , $ stackPtr , $ commentStart );
200182 }
201183
202184 /**
203185 * @param File $phpcsFile
204186 * @param int $stackPtr
205187 * @param int $commentStart
188+ *
189+ * @return void
206190 */
207191 protected function processParams (File $ phpcsFile , $ stackPtr , $ commentStart ): void
208192 {
@@ -226,21 +210,6 @@ private function isInheritDoc(File $phpcsFile, int $stackPtr): bool
226210
227211 $ content = $ phpcsFile ->getTokensAsString ($ start , ($ end - $ start ));
228212
229- return preg_match ('#{@inheritdoc}#i ' , $ content ) === 1 ;
230- }
231-
232- /**
233- * @param array $tokens
234- * @param int $returnPos
235- *
236- * @return bool
237- */
238- private function isMatchingReturn (array $ tokens , int $ returnPos ): bool
239- {
240- do {
241- $ returnPos ++;
242- } while (T_WHITESPACE === $ tokens [$ returnPos ]['code ' ]);
243-
244- return T_SEMICOLON !== $ tokens [$ returnPos ]['code ' ];
213+ return preg_match ('#@inheritdoc|{@inheritdoc}#i ' , $ content ) === 1 ;
245214 }
246215}
0 commit comments