Skip to content

Commit b01bca1

Browse files
committed
Constants/ConstantString: prevent more false positives
The `define()` and `defined()` functions expect the name of a constant as a text string to be passed as the first parameter. This sniff is intended to guard against a coding mistake where the name of the constant would be passed as a_constant_. While passing the name of the constant as a constant _could_ be perfectly valid when that constant contains the name of another constant as a text string, more often than not, it will be a coding error. As things were, the sniff did not handle parameters build up using more than one token into account. It also did not handle valid situations, like passing the constant name as a text string via a variable to the functions, correctly. As outlined in #422 (comment) (Proposal 1), this limits the sniff to _only_ trigger an error when a plain constant has been passed as the "constant name" parameter and ignore all other cases. Note: The current implementation of this fix, uses the WPCS `get_function_call_parameter()` method to retrieve the stack pointer to the start and end of the parameter. Once PHPCSUtils is in place, this function call should be replaced by using the PHPCSUtils version of that method. Fixes 422 Fixes 480
1 parent 7c6dc07 commit b01bca1

File tree

3 files changed

+38
-15
lines changed

3 files changed

+38
-15
lines changed

WordPressVIPMinimum/Sniffs/Constants/ConstantStringSniff.php

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,26 @@ public function process_token( $stackPtr ) {
5555
return;
5656
}
5757

58-
$nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextToken + 1, null, true, null, true );
59-
$nextNextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextToken + 1, null, true, null, true );
60-
61-
if ( T_NS_C === $this->tokens[ $nextToken ]['code'] && T_STRING_CONCAT === $this->tokens[ $nextNextToken ]['code'] ) {
62-
// Namespacing being used, skip to next.
63-
$nextToken = $this->phpcsFile->findNext( Tokens::$emptyTokens, $nextNextToken + 1, null, true, null, true );
58+
$param = $this->get_function_call_parameter( $stackPtr, 1 );
59+
if ( $param === false ) {
60+
// Target parameter not found.
61+
return;
6462
}
6563

66-
if ( $this->tokens[ $nextToken ]['code'] !== T_CONSTANT_ENCAPSED_STRING ) {
67-
$message = 'Constant name, as a string, should be used along with `%s()`.';
68-
$data = [ $this->tokens[ $stackPtr ]['content'] ];
69-
$this->phpcsFile->addError( $message, $nextToken, 'NotCheckingConstantName', $data );
64+
$search = Tokens::$emptyTokens;
65+
$search[ T_STRING ] = T_STRING;
66+
67+
$has_only_tstring = $this->phpcsFile->findNext( $search, $param['start'], $param['end'] + 1, true );
68+
if ( $has_only_tstring !== false ) {
69+
// Came across something other than a T_STRING token. Ignore.
7070
return;
7171
}
72+
73+
$tstring_token = $this->phpcsFile->findNext( T_STRING, $param['start'], $param['end'] + 1 );
74+
75+
$message = 'Constant name, as a string, should be used along with `%s()`.';
76+
$data = [ $this->tokens[ $stackPtr ]['content'] ];
77+
$this->phpcsFile->addError( $message, $tstring_token, 'NotCheckingConstantName', $data );
7278
}
7379

7480
}

WordPressVIPMinimum/Tests/Constants/ConstantStringUnitTest.inc

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,29 @@ if ( ! defined( 'WPCOM_VIP' ) ) { // Okay.
55
}
66

77
if ( ! defined( WPCOM_VIP ) ) { // Error.
8-
define( WPCOM_VIP ); // Error.
8+
define( WPCOM_VIP, true ); // Error.
99
}
1010

1111
namespace Foo\Bar;
1212
const REST_ALLOWED_META_PREFIXES = [ 'foo-', 'bar-', 'baz-' ];
1313
if ( defined( __NAMESPACE__ . '\REST_ALLOWED_META_PREFIXES' ) && in_array( 'foo-', REST_ALLOWED_META_PREFIXES, true ) ) { // Ok.
14-
define( __NAMESPACE__ . REST_ALLOWED_META_PREFIXES ); // Error.
14+
define( __NAMESPACE__ . '\\' . REST_ALLOWED_META_PREFIXES[1], $value ); // OK.
1515
}
16+
17+
define( __NAMESPACE__ . '\PLUGIN_URL', \plugins_url( '/', __FILE__ ) ); // OK.
18+
if ( defined( __NAMESPACE__ . '\\LOADED' ) ) {} // OK.
19+
20+
if ( defined( $obj->constant_name_property ) === false ) { // OK.
21+
define( $variable_containing_constant_name, $constant_value ); // OK.
22+
}
23+
24+
if ( defined( MY_PREFIX . '_CONSTANT_NAME' ) === false ) { // OK.
25+
define( 'PREFIX_' . $variable_part, $constant_value ); // OK.
26+
}
27+
28+
if ( ! defined($generator->get()) { // OK.
29+
define( $generator->getLast(), 'value'); // OK.
30+
}
31+
32+
$defined = defined(); // OK, ignore.
33+
$defined = defined( /*comment*/ ); // OK, ignore.

WordPressVIPMinimum/Tests/Constants/ConstantStringUnitTest.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@ class ConstantStringUnitTest extends AbstractSniffUnitTest {
2525
*/
2626
public function getErrorList() {
2727
return [
28-
7 => 1,
29-
8 => 1,
30-
14 => 1,
28+
7 => 1,
29+
8 => 1,
3130
];
3231
}
3332

0 commit comments

Comments
 (0)