Skip to content

Commit 22ab15e

Browse files
authored
Add checks for class properties (#77)
* Tests: wrap anonymous class fixtures in methods Previously they were creating an anonymous class in the global namespace outside a function, but this is an unrealistic usage and probably is being effected by #37. This modifies the fixtures to put the class as a return value of a class method. * Tests: cover private/protected class properties * Add check for class property definition * Tests: add 'private static' to anon class fixture * Tests: Add naked static, var to class properties * Treat `var` declarations as properties * Tests: add static function var to anon fixture * Allow bare static property declaration
1 parent 4f36541 commit 22ab15e

File tree

5 files changed

+72
-16
lines changed

5 files changed

+72
-16
lines changed

VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,38 @@ protected function checkForFunctionPrototype(File $phpcsFile, $stackPtr, $varNam
341341
return false;
342342
}
343343

344+
protected function checkForClassProperty(File $phpcsFile, $stackPtr, $varName, $currScope) {
345+
$propertyDeclarationKeywords = [
346+
T_PUBLIC,
347+
T_PRIVATE,
348+
T_PROTECTED,
349+
T_VAR,
350+
];
351+
$stopAtPtr = $stackPtr - 2;
352+
$visibilityPtr = $phpcsFile->findPrevious($propertyDeclarationKeywords, $stackPtr - 1, $stopAtPtr > 0 ? $stopAtPtr : 0);
353+
if ($visibilityPtr) {
354+
return true;
355+
}
356+
$staticPtr = $phpcsFile->findPrevious(T_STATIC, $stackPtr - 1, $stopAtPtr > 0 ? $stopAtPtr : 0);
357+
if (! $staticPtr) {
358+
return false;
359+
}
360+
$stopAtPtr = $staticPtr - 2;
361+
$visibilityPtr = $phpcsFile->findPrevious($propertyDeclarationKeywords, $staticPtr - 1, $stopAtPtr > 0 ? $stopAtPtr : 0);
362+
if ($visibilityPtr) {
363+
return true;
364+
}
365+
// it's legal to use `static` to define properties as well as to
366+
// define variables, so make sure we are not in a function before
367+
// assuming it's a property.
368+
$tokens = $phpcsFile->getTokens();
369+
$token = $tokens[$stackPtr];
370+
if ($token && !empty($token['conditions']) && end($token['conditions']) !== T_FUNCTION) {
371+
return Helpers::areAnyConditionsAClass($token['conditions']);
372+
}
373+
return false;
374+
}
375+
344376
protected function checkForCatchBlock(File $phpcsFile, $stackPtr, $varName, $currScope) {
345377
$tokens = $phpcsFile->getTokens();
346378
$token = $tokens[$stackPtr];
@@ -819,6 +851,11 @@ protected function processVariable(File $phpcsFile, $stackPtr) {
819851
return;
820852
}
821853

854+
if ($this->checkForClassProperty($phpcsFile, $stackPtr, $varName, $currScope)) {
855+
Helpers::debug('found class property definition');
856+
return;
857+
}
858+
822859
// Is the next non-whitespace an assignment?
823860
if ($this->checkForAssignment($phpcsFile, $stackPtr, $varName, $currScope)) {
824861
Helpers::debug('found assignment');

VariableAnalysis/Tests/CodeAnalysis/VariableAnalysisTest.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public function testClassWithMembersWarnings() {
157157
13,
158158
18,
159159
19,
160-
64,
160+
66,
161161
];
162162
$this->assertEquals($expectedWarnings, $lines);
163163
}
@@ -534,7 +534,9 @@ public function testAnonymousClassAllowPropertyDefinitions() {
534534
$phpcsFile = $this->prepareLocalFileForSniffs($this->getSniffFiles(), $fixtureFile);
535535
$phpcsFile->process();
536536
$lines = $this->getWarningLineNumbersFromFile($phpcsFile);
537-
$expectedWarnings = [];
537+
$expectedWarnings = [
538+
17,
539+
];
538540
$this->assertEquals($expectedWarnings, $lines);
539541
$lines = $this->getErrorLineNumbersFromFile($phpcsFile);
540542
$expectedErrors = [];
Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
<?php
22

3-
new class {
4-
public function sayHelloWorld() {
5-
echo 'Hello'.$this->getWorld();
6-
}
3+
class ClassWithAnonymousClass {
4+
public function getMyClass() {
5+
return new class {
6+
public function sayHelloWorld() {
7+
echo 'Hello'.$this->getWorld();
8+
}
79

8-
protected function getWorld() {
9-
return ' World!';
10+
protected function getWorld() {
11+
return ' World!';
12+
}
13+
};
1014
}
11-
};
15+
}
Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
<?php
22

3-
new class {
4-
protected $storedHello;
5-
public $helloOptions = [];
6-
public function sayHelloWorld() {
7-
echo "hello world";
8-
}
9-
};
3+
class ClassWithAnonymousClass {
4+
public function getAnonymousClass() {
5+
return new class {
6+
protected $storedHello;
7+
private static $storedHello2;
8+
private $storedHello3;
9+
public $helloOptions = [];
10+
static $aStaticOne;
11+
var $aVarOne;
12+
public function sayHelloWorld() {
13+
echo "hello world";
14+
}
1015

16+
public function methodWithStaticVar() {
17+
static $myStaticVar; // should trigger unused warning
18+
}
19+
};
20+
}
21+
}

VariableAnalysis/Tests/CodeAnalysis/fixtures/ClassWithMembersFixture.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ function method_with_member_var() {
4545

4646
class ClassWithMembers {
4747
public $member_var;
48+
private $private_member_var;
49+
protected $protected_member_var;
4850
static $static_member_var;
4951

5052
function method_with_member_var() {

0 commit comments

Comments
 (0)