public function process(PHP_CodeSniffer_File $phpcsFile, $classPointer)
{
$tokens = $phpcsFile->getTokens();
$classToken = $tokens[$classPointer];
$reportedProperties = $this->getProperties($phpcsFile, $tokens, $classToken);
$reportedMethods = $this->getMethods($phpcsFile, $tokens, $classToken);
if (count($reportedProperties) + count($reportedMethods) === 0) {
return;
}
$writeOnlyProperties = [];
$findUsagesStartTokenPointer = $classToken['scope_opener'] + 1;
while (($propertyAccessTokenPointer = $phpcsFile->findNext([T_VARIABLE, T_SELF, T_STATIC], $findUsagesStartTokenPointer, $classToken['scope_closer'])) !== false) {
$propertyAccessToken = $tokens[$propertyAccessTokenPointer];
if ($propertyAccessToken['content'] === '$this') {
$objectOperatorTokenPointer = TokenHelper::findNextEffective($phpcsFile, $propertyAccessTokenPointer + 1);
$objectOperatorToken = $tokens[$objectOperatorTokenPointer];
if ($objectOperatorToken['code'] !== T_OBJECT_OPERATOR) {
// $this not followed by ->
$findUsagesStartTokenPointer = $propertyAccessTokenPointer + 1;
continue;
}
$propertyNameTokenPointer = TokenHelper::findNextEffective($phpcsFile, $objectOperatorTokenPointer + 1);
$propertyNameToken = $tokens[$propertyNameTokenPointer];
$name = $propertyNameToken['content'];
if ($propertyNameToken['code'] !== T_STRING) {
// $this-> but not accessing a specific property (e. g. $this->$foo or $this->{$foo})
$findUsagesStartTokenPointer = $propertyNameTokenPointer + 1;
continue;
}
$methodCallTokenPointer = TokenHelper::findNextEffective($phpcsFile, $propertyNameTokenPointer + 1);
$methodCallToken = $tokens[$methodCallTokenPointer];
if ($methodCallToken['code'] === T_OPEN_PARENTHESIS) {
// calling a method on $this
$findUsagesStartTokenPointer = $methodCallTokenPointer + 1;
unset($reportedMethods[$name]);
continue;
}
$assignTokenPointer = TokenHelper::findNextEffective($phpcsFile, $propertyNameTokenPointer + 1);
$assignToken = $tokens[$assignTokenPointer];
if ($assignToken['code'] === T_EQUAL) {
// assigning value to a property - note possible write-only property
$findUsagesStartTokenPointer = $assignTokenPointer + 1;
$writeOnlyProperties[$name] = $propertyNameTokenPointer;
continue;
}
if (isset($reportedProperties[$name])) {
unset($reportedProperties[$name]);
}
$findUsagesStartTokenPointer = $propertyNameTokenPointer + 1;
} elseif (in_array($propertyAccessToken['code'], [T_SELF, T_STATIC], true)) {
$doubleColonTokenPointer = TokenHelper::findNextEffective($phpcsFile, $propertyAccessTokenPointer + 1);
$doubleColonToken = $tokens[$doubleColonTokenPointer];
if ($doubleColonToken['code'] !== T_DOUBLE_COLON) {
// self or static not followed by ::
$findUsagesStartTokenPointer = $doubleColonTokenPointer + 1;
continue;
}
$methodNameTokenPointer = TokenHelper::findNextEffective($phpcsFile, $doubleColonTokenPointer + 1);
$methodNameToken = $tokens[$methodNameTokenPointer];
if ($methodNameToken['code'] !== T_STRING) {
// self:: or static:: not followed by a string - possible static property access
$findUsagesStartTokenPointer = $methodNameTokenPointer + 1;
continue;
}
$methodCallTokenPointer = TokenHelper::findNextEffective($phpcsFile, $methodNameTokenPointer + 1);
$methodCallToken = $tokens[$methodCallTokenPointer];
if ($methodCallToken['code'] !== T_OPEN_PARENTHESIS) {
// self::string or static::string not followed by ( - possible constant access
$findUsagesStartTokenPointer = $methodCallTokenPointer + 1;
continue;
}
$name = $methodNameToken['content'];
if (isset($reportedMethods[$name])) {
unset($reportedMethods[$name]);
}
$findUsagesStartTokenPointer = $methodCallTokenPointer + 1;
} else {
$findUsagesStartTokenPointer = $propertyAccessTokenPointer + 1;
}
if (count($reportedProperties) + count($reportedMethods) === 0) {
return;
}
}
if (count($reportedProperties) + count($reportedMethods) === 0) {
return;
}
$classNamePointer = $phpcsFile->findNext(T_STRING, $classPointer);
$className = $tokens[$classNamePointer]['content'];
foreach ($reportedProperties as $name => $propertyTokenPointer) {
$phpcsFile->addError(sprintf('Class %s contains %s property: $%s', $className, isset($writeOnlyProperties[$name]) ? 'write-only' : 'unused', $name), $propertyTokenPointer, isset($writeOnlyProperties[$name]) ? self::CODE_WRITE_ONLY_PROPERTY : self::CODE_UNUSED_PROPERTY);
}
foreach ($reportedMethods as $name => $methodTokenPointer) {
$phpcsFile->addError(sprintf('Class %s contains unused private method: %s', $className, $name), $methodTokenPointer, self::CODE_UNUSED_METHOD);
}
}