Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify handling static variables #32

Merged
merged 5 commits into from
Feb 8, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 77 additions & 49 deletions VariableAnalysis/Sniffs/CodeAnalysis/VariableAnalysisSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -511,48 +511,83 @@ protected function checkForStaticMember(File $phpcsFile, $stackPtr, $varName, $c
$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];

// Are we a static member?
$doubleColonPtr = $stackPtr - 1;
if ($tokens[$doubleColonPtr]['code'] !== T_DOUBLE_COLON) {
return false;
}
$classNamePtr = $stackPtr - 2;
if (($tokens[$classNamePtr]['code'] !== T_STRING)
&& ($tokens[$classNamePtr]['code'] !== T_SELF)
&& ($tokens[$classNamePtr]['code'] !== T_STATIC)) {
$staticReferences = [
T_STRING,
T_SELF,
T_STATIC,
];
if (! in_array($tokens[$classNamePtr]['code'], $staticReferences, true)) {
return false;
}
return true;
}

protected function checkForStaticOutsideClass(File $phpcsFile, $stackPtr, $varName, $currScope) {
// Are we refering to self:: outside a class?
// TODO: not sure this is our business or should be some other sniff.
if (($tokens[$classNamePtr]['code'] === T_SELF) || ($tokens[$classNamePtr]['code'] === T_STATIC)) {
if ($tokens[$classNamePtr]['code'] === T_SELF) {
$err_class = 'SelfOutsideClass';
$err_desc = 'self::';
} else {
$err_class = 'StaticOutsideClass';
$err_desc = 'static::';

$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];

$doubleColonPtr = $stackPtr - 1;
if ($tokens[$doubleColonPtr]['code'] !== T_DOUBLE_COLON) {
return false;
}
$classNamePtr = $stackPtr - 2;
$code = $tokens[$classNamePtr]['code'];
$staticReferences = [
T_SELF,
T_STATIC,
];
if (! in_array($code, $staticReferences, true)) {
return false;
}
$errorClass = $code === T_SELF ? 'SelfOutsideClass' : 'StaticOutsideClass';
$staticRefType = $code === T_SELF ? 'self::' : 'static::';
if (!empty($token['conditions'])) {
if ($this->areAnyConditionsAClosure($phpcsFile, $token['conditions'])) {
$phpcsFile->addError("Use of {$staticRefType}%s inside closure.", $stackPtr, $errorClass, ["\${$varName}"]);
return true;
}
if (!empty($token['conditions'])) {
foreach (array_reverse($token['conditions'], true) as $scopePtr => $scopeCode) {
// self within a closure is invalid
// Note: have to fetch code from $tokens, T_CLOSURE isn't set for conditions codes.
if ($tokens[$scopePtr]['code'] === T_CLOSURE) {
$phpcsFile->addError("Use of {$err_desc}%s inside closure.", $stackPtr, $err_class, ["\${$varName}"]);
return true;
}
if ($scopeCode === T_CLASS) {
return true;
}
}
if ($this->areAnyConditionsAClass($token['conditions'])) {
return true;
}
$phpcsFile->addError("Use of {$err_desc}%s outside class definition.", $stackPtr, $err_class, ["\${$varName}"]);
return true;
}

$phpcsFile->addError(
"Use of {$staticRefType}%s outside class definition.",
$stackPtr,
$errorClass,
["\${$varName}"]
);
return true;
}

protected function areAnyConditionsAClosure($phpcsFile, $conditions) {
// self within a closure is invalid
$tokens = $phpcsFile->getTokens();
foreach (array_reverse($conditions, true) as $scopePtr => $scopeCode) {
// Note: have to fetch code from $tokens, T_CLOSURE isn't set for conditions codes.
if ($tokens[$scopePtr]['code'] === T_CLOSURE) {
return true;
}
}
return false;
}

protected function areAnyConditionsAClass($conditions) {
foreach (array_reverse($conditions, true) as $scopePtr => $scopeCode) {
if ($scopeCode === T_CLASS) {
return true;
}
}
return false;
}

protected function checkForAssignment(File $phpcsFile, $stackPtr, $varName, $currScope) {
$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];
Expand Down Expand Up @@ -773,18 +808,6 @@ protected function checkForSymbolicObjectProperty(File $phpcsFile, $stackPtr, $v
return true;
}

/**
* Called to process class member vars.
*
* @param File $phpcsFile The PHP_CodeSniffer file where this token was found.
* @param int $stackPtr The position where the token was found.
*/
protected function processMemberVar(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];
// TODO: don't care for now
}

/**
* Called to process normal member vars.
*
Expand Down Expand Up @@ -846,6 +869,11 @@ protected function processVariable(File $phpcsFile, $stackPtr) {
return;
}

// Check for static members used outside a class
if ($this->checkForStaticOutsideClass($phpcsFile, $stackPtr, $varName, $currScope)) {
return;
}

// $var part of class::$var static member
if ($this->checkForStaticMember($phpcsFile, $stackPtr, $varName, $currScope)) {
return;
Expand Down Expand Up @@ -1015,27 +1043,27 @@ protected function processScopeCloseForVariable($phpcsFile, $varInfo) {
// of "unused variable" warnings.
return;
}
if (isset($varInfo->firstDeclared)) {
$stackPtr = $this->getStackPtrIfVariableIsUnused($varInfo);
if ($stackPtr) {
$phpcsFile->addWarning(
"Unused %s %s.",
$varInfo->firstDeclared,
$stackPtr,
'UnusedVariable',
[
VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType],
"\${$varInfo->name}",
]
);
}
}

protected function getStackPtrIfVariableIsUnused($varInfo) {
if (isset($varInfo->firstDeclared)) {
return $varInfo->firstDeclared;
}
if (isset($varInfo->firstInitialized)) {
$phpcsFile->addWarning(
"Unused %s %s.",
$varInfo->firstInitialized,
'UnusedVariable',
[
VariableInfo::$scopeTypeDescriptions[$varInfo->scopeType],
"\${$varInfo->name}",
]
);
return $varInfo->firstInitialized;
}
return null;
}
}