Skip to content

Commit bebe37e

Browse files
committed
[#15] Fixed false positives on variables prefixed with underscore.
Variables like `$_static_value` are now completely skipped from naming convention checks as they are commonly used for internal/special variables.
1 parent dc77cbf commit bebe37e

5 files changed

Lines changed: 86 additions & 1 deletion

File tree

src/DrevOps/Sniffs/NamingConventions/AbstractVariableNamingSniff.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,23 @@ protected function isReserved(string $name): bool {
6464
return in_array($name, $this->reservedVariables, TRUE);
6565
}
6666

67+
/**
68+
* Check if a variable name has a leading underscore.
69+
*
70+
* Variables with leading underscores (e.g., $_static_value) are typically
71+
* used as a naming convention for internal/special variables and should
72+
* be excluded from naming convention checks.
73+
*
74+
* @param string $name
75+
* Variable name (without $).
76+
*
77+
* @return bool
78+
* TRUE if has leading underscore, FALSE otherwise.
79+
*/
80+
protected function hasLeadingUnderscore(string $name): bool {
81+
return str_starts_with($name, '_');
82+
}
83+
6784
/**
6885
* Check if a variable name follows snake_case format.
6986
*

src/DrevOps/Sniffs/NamingConventions/LocalVariableNamingSniff.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ public function process(File $phpcsFile, $stackPtr): void {
3737
return;
3838
}
3939

40+
// Skip variables with leading underscores (e.g., $_static_value).
41+
if ($this->hasLeadingUnderscore($var_name)) {
42+
return;
43+
}
44+
4045
// Skip static property accesses (self::$prop, static::$prop, etc.).
4146
if ($this->isStaticPropertyAccess($phpcsFile, $stackPtr)) {
4247
return;

src/DrevOps/Sniffs/NamingConventions/ParameterNamingSniff.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ public function process(File $phpcsFile, $stackPtr): void {
3838
return;
3939
}
4040

41+
// Skip variables with leading underscores (e.g., $_static_value).
42+
if ($this->hasLeadingUnderscore($var_name)) {
43+
return;
44+
}
45+
4146
// Only process parameters (declaration only, not usage in body).
4247
// Local variables handled by LocalVariableNamingSniff.
4348
if (!$this->isParameter($phpcsFile, $stackPtr, FALSE)) {

tests/Fixtures/Valid.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,17 @@
77
function functionWithValidSnakeCaseParams($valid_param_one, $valid_param_two) {
88
$valid_local_variable = 100;
99
$another_valid_local = $valid_local_variable * $valid_param_two;
10-
return $valid_local_variable + $another_valid_local;
10+
// Variables with leading underscores should be skipped.
11+
$_static_value = 50;
12+
$_internalVar = 25;
13+
return $valid_local_variable + $another_valid_local + $_static_value + $_internalVar;
14+
}
15+
16+
/**
17+
* Function with underscore-prefixed parameter (should be skipped).
18+
*/
19+
function functionWithUnderscorePrefixedParam($_prefixed_param) {
20+
return $_prefixed_param * 2;
1121
}
1222

1323
class ClassWithValidSnakeCaseNaming {
@@ -16,7 +26,17 @@ class ClassWithValidSnakeCaseNaming {
1626

1727
public function methodWithValidSnakeCaseParam($valid_param) {
1828
$valid_local_variable = strtolower($valid_param);
29+
// Variables with leading underscores should be skipped.
30+
$_internal_cache = [];
31+
$_tempValue = NULL;
1932
return $valid_local_variable;
2033
}
2134

35+
/**
36+
* Method with underscore-prefixed parameter (should be skipped).
37+
*/
38+
public function methodWithUnderscorePrefixedParam($_prefixed_param) {
39+
return $_prefixed_param;
40+
}
41+
2242
}

tests/Unit/AbstractVariableNamingSniffTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,4 +683,42 @@ public function testToFormatThrowsExceptionForInvalidFormat(): void {
683683
$method->invoke($sniff, 'test');
684684
}
685685

686+
/**
687+
* Test leading underscore detection.
688+
*
689+
* @param string $name
690+
* The variable name to test.
691+
* @param bool $expected
692+
* Expected result.
693+
*/
694+
#[DataProvider('providerHasLeadingUnderscore')]
695+
public function testHasLeadingUnderscore(string $name, bool $expected): void {
696+
$sniff = new LocalVariableNamingSniff();
697+
$reflection = new \ReflectionClass($sniff);
698+
$method = $reflection->getMethod('hasLeadingUnderscore');
699+
700+
$result = $method->invoke($sniff, $name);
701+
$this->assertSame($expected, $result, 'Failed for: ' . $name);
702+
}
703+
704+
/**
705+
* Data provider for hasLeadingUnderscore tests.
706+
*
707+
* @return array<string, array<string|bool>>
708+
* Test cases.
709+
*/
710+
public static function providerHasLeadingUnderscore(): array {
711+
return [
712+
'leading_underscore_snake' => ['_static_value', TRUE],
713+
'leading_underscore_camel' => ['_staticValue', TRUE],
714+
'leading_underscore_only' => ['_', TRUE],
715+
'leading_double_underscore' => ['__internal', TRUE],
716+
'no_leading_underscore_snake' => ['static_value', FALSE],
717+
'no_leading_underscore_camel' => ['staticValue', FALSE],
718+
'underscore_in_middle' => ['static_value', FALSE],
719+
'trailing_underscore' => ['value_', FALSE],
720+
'single_letter' => ['a', FALSE],
721+
];
722+
}
723+
686724
}

0 commit comments

Comments
 (0)