Skip to content
Permalink
Browse files

Prevent removing properties on classes with variable assignment

  • Loading branch information...
muglug committed Apr 18, 2019
1 parent 4807ebe commit d6de6ca5d581119867525b1ee29b7a07bbc01045
@@ -830,6 +830,10 @@ public static function analyzeStatic(
$prop_name = $stmt->name;
if (!$prop_name instanceof PhpParser\Node\Identifier) {
if ($fq_class_name) {
$codebase->analyzer->addMixedMemberName(strtolower($fq_class_name) . '::$');
}
return;
}
@@ -565,6 +565,18 @@ public static function analyze(
if (ExpressionAnalyzer::analyze($statements_analyzer, $assign_var->var, $context) === false) {
return false;
}
if (isset($assign_var->var->inferredType)) {
$stmt_var_type = $assign_var->var->inferredType;
if ($stmt_var_type->hasObjectType()) {
foreach ($stmt_var_type->getTypes() as $type) {
if ($type instanceof Type\Atomic\TNamedObject) {
$codebase->analyzer->addMixedMemberName(strtolower($type->value) . '::$');
}
}
}
}
}
if ($var_id) {
@@ -292,6 +292,14 @@ public static function analyzeInstance(
}
if (!$prop_name) {
if ($stmt_var_type->hasObjectType()) {
foreach ($stmt_var_type->getTypes() as $type) {
if ($type instanceof Type\Atomic\TNamedObject) {
$codebase->analyzer->addMixedMemberName(strtolower($type->value) . '::$');
}
}
}
return null;
}
@@ -806,125 +814,134 @@ public static function analyzeStatic(
$prop_name = null;
}
if ($fq_class_name &&
$context->check_classes &&
$context->check_variables &&
$prop_name &&
!ExpressionAnalyzer::isMock($fq_class_name)
) {
$var_id = ExpressionAnalyzer::getVarId(
$stmt,
$context->self ?: $statements_analyzer->getFQCLN(),
$statements_analyzer
);
if (!$prop_name) {
if ($fq_class_name) {
$codebase->analyzer->addMixedMemberName(strtolower($fq_class_name) . '::$');
}
$property_id = $fq_class_name . '::$' . $prop_name;
return null;
}
if ($codebase->store_node_types) {
$codebase->analyzer->addNodeReference(
$statements_analyzer->getFilePath(),
$stmt->name,
$property_id
);
}
if (!$fq_class_name
|| !$context->check_classes
|| !$context->check_variables
|| ExpressionAnalyzer::isMock($fq_class_name)
) {
return null;
}
if ($var_id && $context->hasVariable($var_id, $statements_analyzer)) {
// we don't need to check anything
$stmt->inferredType = $context->vars_in_scope[$var_id];
$var_id = ExpressionAnalyzer::getVarId(
$stmt,
$context->self ?: $statements_analyzer->getFQCLN(),
$statements_analyzer
);
if ($context->collect_references) {
// log the appearance
$codebase->properties->propertyExists(
$property_id,
false,
$statements_analyzer,
$context,
new CodeLocation($statements_analyzer->getSource(), $stmt)
);
}
$property_id = $fq_class_name . '::$' . $prop_name;
if ($codebase->store_node_types
&& (!$context->collect_initializations
&& !$context->collect_mutations)
&& isset($stmt->inferredType)
) {
$codebase->analyzer->addNodeType(
$statements_analyzer->getFilePath(),
$stmt->name,
(string) $stmt->inferredType
);
}
if ($codebase->store_node_types) {
$codebase->analyzer->addNodeReference(
$statements_analyzer->getFilePath(),
$stmt->name,
$property_id
);
}
return null;
if ($var_id && $context->hasVariable($var_id, $statements_analyzer)) {
// we don't need to check anything
$stmt->inferredType = $context->vars_in_scope[$var_id];
if ($context->collect_references) {
// log the appearance
$codebase->properties->propertyExists(
$property_id,
false,
$statements_analyzer,
$context,
new CodeLocation($statements_analyzer->getSource(), $stmt)
);
}
if (!$codebase->properties->propertyExists(
$property_id,
false,
$statements_analyzer,
$context,
$context->collect_references ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null
)
if ($codebase->store_node_types
&& (!$context->collect_initializations
&& !$context->collect_mutations)
&& isset($stmt->inferredType)
) {
if (IssueBuffer::accepts(
new UndefinedPropertyFetch(
'Static property ' . $property_id . ' is not defined',
new CodeLocation($statements_analyzer->getSource(), $stmt),
$property_id
),
$statements_analyzer->getSuppressedIssues()
)) {
// fall through
}
return;
$codebase->analyzer->addNodeType(
$statements_analyzer->getFilePath(),
$stmt->name,
(string) $stmt->inferredType
);
}
if (ClassLikeAnalyzer::checkPropertyVisibility(
$property_id,
$context,
$statements_analyzer,
new CodeLocation($statements_analyzer->getSource(), $stmt),
return null;
}
if (!$codebase->properties->propertyExists(
$property_id,
false,
$statements_analyzer,
$context,
$context->collect_references ? new CodeLocation($statements_analyzer->getSource(), $stmt) : null
)
) {
if (IssueBuffer::accepts(
new UndefinedPropertyFetch(
'Static property ' . $property_id . ' is not defined',
new CodeLocation($statements_analyzer->getSource(), $stmt),
$property_id
),
$statements_analyzer->getSuppressedIssues()
) === false) {
return false;
)) {
// fall through
}
$declaring_property_class = $codebase->properties->getDeclaringClassForProperty(
$fq_class_name . '::$' . $prop_name,
true
);
return;
}
$class_storage = $codebase->classlike_storage_provider->get((string)$declaring_property_class);
$property = $class_storage->properties[$prop_name];
if (ClassLikeAnalyzer::checkPropertyVisibility(
$property_id,
$context,
$statements_analyzer,
new CodeLocation($statements_analyzer->getSource(), $stmt),
$statements_analyzer->getSuppressedIssues()
) === false) {
return false;
}
if ($var_id) {
if ($property->type) {
$context->vars_in_scope[$var_id] = ExpressionAnalyzer::fleshOutType(
$codebase,
clone $property->type,
$declaring_property_class,
$declaring_property_class
);
} else {
$context->vars_in_scope[$var_id] = Type::getMixed();
}
$declaring_property_class = $codebase->properties->getDeclaringClassForProperty(
$fq_class_name . '::$' . $prop_name,
true
);
$stmt->inferredType = clone $context->vars_in_scope[$var_id];
$class_storage = $codebase->classlike_storage_provider->get((string)$declaring_property_class);
$property = $class_storage->properties[$prop_name];
if ($codebase->store_node_types
&& (!$context->collect_initializations
&& !$context->collect_mutations)
) {
$codebase->analyzer->addNodeType(
$statements_analyzer->getFilePath(),
$stmt->name,
(string) $stmt->inferredType
);
}
if ($var_id) {
if ($property->type) {
$context->vars_in_scope[$var_id] = ExpressionAnalyzer::fleshOutType(
$codebase,
clone $property->type,
$declaring_property_class,
$declaring_property_class
);
} else {
$stmt->inferredType = Type::getMixed();
$context->vars_in_scope[$var_id] = Type::getMixed();
}
$stmt->inferredType = clone $context->vars_in_scope[$var_id];
if ($codebase->store_node_types
&& (!$context->collect_initializations
&& !$context->collect_mutations)
) {
$codebase->analyzer->addNodeType(
$statements_analyzer->getFilePath(),
$stmt->name,
(string) $stmt->inferredType
);
}
} else {
$stmt->inferredType = Type::getMixed();
}
return null;
@@ -961,6 +961,9 @@ private function checkPropertyReferences(ClassLikeStorage $classlike_storage)
if ($property_storage->stmt_location
&& isset($project_analyzer->getIssuesToFix()['PossiblyUnusedProperty'])
&& !$codebase->analyzer->hasMixedMemberName('$' . $property_name)
&& !$codebase->analyzer->hasMixedMemberName(
strtolower($classlike_storage->name) . '::$'
)
&& !IssueBuffer::isSuppressed($issue, $classlike_storage->suppressed_issues)
) {
FileManipulationBuffer::addForCodeLocation(
@@ -989,6 +992,9 @@ private function checkPropertyReferences(ClassLikeStorage $classlike_storage)
if ($property_storage->stmt_location
&& isset($project_analyzer->getIssuesToFix()['UnusedProperty'])
&& !$codebase->analyzer->hasMixedMemberName('$' . $property_name)
&& !$codebase->analyzer->hasMixedMemberName(
strtolower($classlike_storage->name) . '::$'
)
&& !IssueBuffer::isSuppressed($issue, $classlike_storage->suppressed_issues)
) {
FileManipulationBuffer::addForCodeLocation(
@@ -1772,7 +1772,7 @@ class A {
['PossiblyUnusedProperty'],
true,
],
'removePossiblyUnusedPropertyMixedUse' => [
'dontRemovePossiblyUnusedPropertyWithMixedUse' => [
'<?php
class A {
public $foo = "hello";
@@ -1793,6 +1793,90 @@ function foo($a) {
['PossiblyUnusedProperty'],
true,
],
'dontRemovePossiblyUnusedPropertyWithVariableFetch' => [
'<?php
class A {
public $foo = "hello";
}
function foo(A $a, string $var) {
echo $a->$var;
}',
'<?php
class A {
public $foo = "hello";
}
function foo(A $a, string $var) {
echo $a->$var;
}',
'7.1',
['PossiblyUnusedProperty'],
true,
],
'dontRemovePossiblyUnusedPropertyWithStaticVariableFetch' => [
'<?php
class A {
public static $foo = "hello";
}
function foo(string $var) {
echo A::$$var;
}',
'<?php
class A {
public static $foo = "hello";
}
function foo(string $var) {
echo A::$$var;
}',
'7.1',
['PossiblyUnusedProperty'],
true,
],
'dontRemovePossiblyUnusedPropertyWithVariableAssignment' => [
'<?php
class A {
public $foo = "hello";
}
function foo(A $a, string $var) {
$a->$var = "hello";
}',
'<?php
class A {
public $foo = "hello";
}
function foo(A $a, string $var) {
$a->$var = "hello";
}',
'7.1',
['PossiblyUnusedProperty'],
true,
],
'dontRemovePossiblyUnusedPropertyWithStaticVariableAssignment' => [
'<?php
class A {
public static $foo = "hello";
}
function foo(string $var) {
A::$$var = "hello";
}',
'<?php
class A {
public static $foo = "hello";
}
function foo(string $var) {
A::$$var = "hello";
}',
'7.1',
['PossiblyUnusedProperty'],
true,
],
'removeUnusedPropertyWithDocblock' => [
'<?php
class A {

0 comments on commit d6de6ca

Please sign in to comment.
You can’t perform that action at this time.