Skip to content

Commit e9d9698

Browse files
authored
Merge pull request #863 from Automattic/feature/functions-restrictedfunctions-sniff-review
2 parents 1438761 + ce82266 commit e9d9698

File tree

3 files changed

+37
-38
lines changed

3 files changed

+37
-38
lines changed

WordPressVIPMinimum/Sniffs/Functions/RestrictedFunctionsSniff.php

Lines changed: 18 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -303,47 +303,27 @@ public function getGroups() {
303303
* @return bool
304304
*/
305305
public function is_targetted_token( $stackPtr ) {
306-
// Exclude function definitions, class methods, and namespaced calls.
307-
if ( $this->tokens[ $stackPtr ]['code'] === \T_STRING && isset( $this->tokens[ $stackPtr - 1 ] ) ) {
308-
// Check if this is really a function.
309-
$next = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true );
310-
if ( $next !== false && $this->tokens[ $next ]['code'] !== T_OPEN_PARENTHESIS ) {
311-
return false;
312-
}
306+
if ( empty( $this->groups[ $this->tokens[ $stackPtr ]['content'] ]['object_var'] ) ) {
307+
return parent::is_targetted_token( $stackPtr );
308+
}
313309

314-
$prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $stackPtr - 1, null, true );
315-
if ( $prev !== false ) {
310+
// Start difference to parent class method.
311+
// Check to see if the token is a method call on a specific object variable.
312+
$next = $this->phpcsFile->findNext( Tokens::$emptyTokens, $stackPtr + 1, null, true );
313+
if ( $next === false || $this->tokens[ $next ]['code'] !== T_OPEN_PARENTHESIS ) {
314+
return false;
315+
}
316316

317-
// Start difference to parent class method.
318-
// Check to see if function is a method on a specific object variable.
319-
if ( ! empty( $this->groups[ $this->tokens[ $stackPtr ]['content'] ]['object_var'] ) ) {
320-
$prevPrev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $stackPtr - 2, null, true );
317+
$prev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $stackPtr - 1, null, true );
318+
if ( $this->tokens[ $prev ]['code'] !== T_OBJECT_OPERATOR
319+
&& $this->tokens[ $prev ]['code'] !== T_NULLSAFE_OBJECT_OPERATOR
320+
) {
321+
return false;
322+
}
321323

322-
return $this->tokens[ $prev ]['code'] === \T_OBJECT_OPERATOR && isset( $this->groups[ $this->tokens[ $stackPtr ]['content'] ]['object_var'][ $this->tokens[ $prevPrev ]['content'] ] );
323-
} // End difference to parent class method.
324+
$prevPrev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $prev - 1, null, true );
324325

325-
// Skip sniffing if calling a same-named method, or on function definitions.
326-
$skipped = [
327-
\T_FUNCTION => \T_FUNCTION,
328-
\T_CLASS => \T_CLASS,
329-
\T_AS => \T_AS, // Use declaration alias.
330-
\T_DOUBLE_COLON => \T_DOUBLE_COLON,
331-
\T_OBJECT_OPERATOR => \T_OBJECT_OPERATOR,
332-
\T_NEW => \T_NEW,
333-
];
334-
if ( isset( $skipped[ $this->tokens[ $prev ]['code'] ] ) ) {
335-
return false;
336-
}
337-
// Skip namespaced functions, ie: `\foo\bar()` not `\bar()`.
338-
if ( $this->tokens[ $prev ]['code'] === \T_NS_SEPARATOR ) {
339-
$pprev = $this->phpcsFile->findPrevious( Tokens::$emptyTokens, $prev - 1, null, true );
340-
if ( $pprev !== false && $this->tokens[ $pprev ]['code'] === \T_STRING ) {
341-
return false;
342-
}
343-
}
344-
}
345-
return true;
346-
}
347-
return false;
326+
return $this->tokens[ $prevPrev ]['code'] === T_VARIABLE
327+
&& isset( $this->groups[ $this->tokens[ $stackPtr ]['content'] ]['object_var'][ $this->tokens[ $prevPrev ]['content'] ] );
348328
}
349329
}

WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.inc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,19 @@ $popular = custom_stats_get_csv( 'postviews', [ 'days' => 2, 'limit' => 20 ]
230230

231231
$foo = new Link; // OK, class, not function.
232232
$foo = new Mail(); // OK, class, not function.
233+
234+
class ReturnByRef {
235+
function &chmod($a) {} // OK, method declaration, not function call.
236+
}
237+
238+
// Class instantiations in PHP 8.0+ attributes are not function calls.
239+
class AttributesShouldBeIgnored {
240+
#[WP_Is_Mobile()] // OK.
241+
public function foo() {}
242+
}
243+
244+
$wp_rewrite->flush_rules; // OK, property access, not function call.
245+
$wp_rewrite /*comment*/ -> /*comment*/ flush_rules(); // Error.
246+
$wp_rewrite?->flush_rules(); // Error.
247+
248+
array_walk($roles, add_role(...)); // Error. PHP 8.1 first class callable.

WordPressVIPMinimum/Tests/Functions/RestrictedFunctionsUnitTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ public function getErrorList() {
9797
199 => 1,
9898
200 => 1,
9999
228 => 1,
100+
245 => 1,
101+
246 => 1,
102+
248 => 1,
100103
];
101104
}
102105

0 commit comments

Comments
 (0)