Skip to content
Permalink
Browse files

Track method param uses between diff runs

  • Loading branch information...
muglug committed Apr 29, 2019
1 parent 0824ca3 commit b6e9fba8e6d860af123c848ce75e37a6ecd604e2
@@ -820,10 +820,19 @@ function (FunctionLikeParameter $p) {
}
}
if ($storage instanceof MethodStorage && $class_storage) {
if ($storage instanceof MethodStorage
&& $class_storage
&& $storage->visibility !== ClassLikeAnalyzer::VISIBILITY_PRIVATE
) {
$method_id_lc = strtolower($this->getMethodId());
foreach ($storage->params as $i => $_) {
if (!isset($storage->unused_params[$i])) {
$storage->used_params[$i] = true;
$codebase->file_reference_provider->addMethodParamUse(
$method_id_lc,
$i,
$method_id_lc
);
/** @var ClassMethod $this->function */
$method_name_lc = strtolower($storage->cased_name);
@@ -833,9 +842,11 @@ function (FunctionLikeParameter $p) {
}
foreach ($class_storage->overridden_method_ids[$method_name_lc] as $parent_method_id) {
$parent_method_storage = $codebase->methods->getStorage($parent_method_id);
$parent_method_storage->used_params[$i] = true;
$codebase->file_reference_provider->addMethodParamUse(
strtolower($parent_method_id),
$i,
$method_id_lc
);
}
}
}
@@ -42,6 +42,7 @@
* file_manipulations: array<string, FileManipulation[]>,
* method_references_to_class_members: array<string, array<string,bool>>,
* method_references_to_missing_class_members: array<string, array<string,bool>>,
* method_param_uses: array<string, array<int, array<string, bool>>>,
* analyzed_methods: array<string, array<string, int>>,
* file_maps: array<
* string,
@@ -288,6 +289,7 @@ function () {
=> $file_reference_provider->getAllFileReferencesToMissingClassMembers(),
'method_references_to_missing_class_members'
=> $file_reference_provider->getAllMethodReferencesToMissingClassMembers(),
'method_param_uses' => $file_reference_provider->getAllMethodParamUses(),
'mixed_member_names' => $analyzer->getMixedMemberNames(),
'file_manipulations' => FileManipulationBuffer::getAll(),
'mixed_counts' => $analyzer->getMixedCounts(),
@@ -336,6 +338,9 @@ function () {
$codebase->file_reference_provider->addMethodReferencesToMissingClassMembers(
$pool_data['method_references_to_missing_class_members']
);
$codebase->file_reference_provider->addMethodParamUses(
$pool_data['method_param_uses']
);
$this->addMixedMemberNames(
$pool_data['mixed_member_names']
);
@@ -449,6 +454,8 @@ public function loadCachedResults(ProjectAnalyzer $project_analyzer)
$file_references_to_classes = $file_reference_provider->getAllFileReferencesToClasses();
$method_param_uses = $file_reference_provider->getAllMethodParamUses();
$file_references_to_class_members
= $file_reference_provider->getAllFileReferencesToClassMembers();
$file_references_to_missing_class_members
@@ -511,6 +518,7 @@ public function loadCachedResults(ProjectAnalyzer $project_analyzer)
unset($method_references_to_missing_class_members[$member_id]);
unset($file_references_to_missing_class_members[$member_id]);
unset($references_to_mixed_member_names[$member_id]);
unset($method_param_uses[$member_id]);
$member_stub = preg_replace('/::.*$/', '::*', $member_id);
@@ -540,6 +548,12 @@ public function loadCachedResults(ProjectAnalyzer $project_analyzer)
foreach ($references_to_mixed_member_names as &$references) {
unset($references[$method_id]);
}
foreach ($method_param_uses as &$references) {
foreach ($references as &$method_refs) {
unset($method_refs[$method_id]);
}
}
}
foreach ($this->analyzed_methods as $file_path => $analyzed_methods) {
@@ -626,6 +640,13 @@ function (array $a) : bool {
}
);
$method_param_uses = array_filter(
$method_param_uses,
function (array $a) : bool {
return !!$a;
}
);
$file_reference_provider->setCallingMethodReferencesToClassMembers(
$method_references_to_class_members
);
@@ -649,6 +670,10 @@ function (array $a) : bool {
$file_reference_provider->setFileReferencesToClasses(
$file_references_to_classes
);
$file_reference_provider->setMethodParamUses(
$method_param_uses
);
}
/**
@@ -937,7 +937,9 @@ private function checkMethodReferences(ClassLikeStorage $classlike_storage, Meth
}
}
if (!$has_parent_references && !isset($method_storage->used_params[$offset])) {
if (!$has_parent_references
&& !$this->file_reference_provider->isMethodParamUsed(strtolower($method_id), $offset)
) {
if (IssueBuffer::accepts(
new PossiblyUnusedParam(
'Param #' . $offset . ' is never referenced in this method',
@@ -41,6 +41,7 @@ class FileReferenceCacheProvider
const METHOD_MISSING_MEMBER_CACHE_NAME = 'method_missing_member';
const FILE_MISSING_MEMBER_CACHE_NAME = 'file_missing_member';
const UNKNOWN_MEMBER_CACHE_NAME = 'unknown_member_references';
const METHOD_PARAM_USE_CACHE_NAME = 'method_param_uses';
/**
* @var Config
@@ -263,6 +264,35 @@ public function getCachedMixedMemberNameReferences()
return $cache;
}
/**
* @return ?array
*
* @psalm-suppress MixedAssignment
* @psalm-suppress MixedTypeCoercion
*/
public function getCachedMethodParamUses()
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return null;
}
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME;
if (!is_readable($cache_location)) {
return null;
}
$cache = unserialize((string) file_get_contents($cache_location));
if (!is_array($cache)) {
throw new \UnexpectedValueException('The method param use cache must be an array');
}
return $cache;
}
/**
* @return ?array
*
@@ -404,6 +434,22 @@ public function setCachedMixedMemberNameReferences(array $references)
file_put_contents($cache_location, serialize($references));
}
/**
* @return void
*/
public function setCachedMethodParamUses(array $references)
{
$cache_directory = $this->config->getCacheDirectory();
if (!$cache_directory) {
return;
}
$cache_location = $cache_directory . DIRECTORY_SEPARATOR . self::METHOD_PARAM_USE_CACHE_NAME;
file_put_contents($cache_location, serialize($references));
}
/**
* @return void
*/
@@ -133,6 +133,11 @@ class FileReferenceProvider
*/
private static $mixed_counts = [];
/**
* @var array<string, array<int, array<string, bool>>>
*/
private static $method_param_uses = [];
/**
* @var ?FileReferenceCacheProvider
*/
@@ -267,6 +272,14 @@ public function addFileInheritanceToClass($source_file, $fq_class_name_lc)
self::$files_inheriting_classes[$fq_class_name_lc][$source_file] = true;
}
/**
* @return void
*/
public function addMethodParamUse(string $method_id, int $offset, string $referencing_method_id)
{
self::$method_param_uses[$method_id][$offset][$referencing_method_id] = true;
}
/**
* @param string $file
*
@@ -375,6 +388,14 @@ public function getAllReferencesToMixedMemberNames()
return self::$references_to_mixed_member_names;
}
/**
* @return array<string, array<int, array<string, bool>>>
*/
public function getAllMethodParamUses()
{
return self::$method_param_uses;
}
/**
* @param bool $force_reload
* @return bool
@@ -458,6 +479,14 @@ public function loadReferenceCache($force_reload = true)
self::$issues = $issues;
$method_param_uses = $this->cache->getCachedMethodParamUses();
if ($method_param_uses === null) {
return false;
}
self::$method_param_uses = $method_param_uses;
$mixed_counts = $this->cache->getTypeCoverage();
if ($mixed_counts === false) {
@@ -510,6 +539,7 @@ public function updateReferenceCache(Codebase $codebase, array $visited_files)
$this->cache->setCachedMethodMissingMemberReferences(self::$method_references_to_missing_class_members);
$this->cache->setCachedFileMissingMemberReferences(self::$file_references_to_missing_class_members);
$this->cache->setCachedMixedMemberNameReferences(self::$references_to_mixed_member_names);
$this->cache->setCachedMethodParamUses(self::$method_param_uses);
$this->cache->setCachedIssues(self::$issues);
$this->cache->setFileMapCache(self::$file_maps);
$this->cache->setTypeCoverage(self::$mixed_counts);
@@ -594,6 +624,11 @@ public function isClassReferenced(string $fq_class_name_lc) : bool
return isset(self::$file_references_to_classes[$fq_class_name_lc]);
}
public function isMethodParamUsed(string $method_id, int $offset) : bool
{
return !empty(self::$method_param_uses[$method_id][$offset]);
}
/**
* @param array<string, array<string,bool>> $references
* @psalm-suppress MixedTypeCoercion
@@ -681,6 +716,20 @@ public function addMethodReferencesToMissingClassMembers(array $references)
);
}
/**
* @param array<string, array<int, array<string, bool>>> $references
* @psalm-suppress MixedTypeCoercion
*
* @return void
*/
public function addMethodParamUses(array $references)
{
self::$method_param_uses = array_merge_recursive(
$references,
self::$method_param_uses
);
}
/**
* @param array<string, array<string,bool>> $references
* @psalm-suppress MixedTypeCoercion
@@ -736,6 +785,17 @@ public function setReferencesToMixedMemberNames(array $references)
self::$references_to_mixed_member_names = $references;
}
/**
* @param array<string, array<int, array<string, bool>>> $references
* @psalm-suppress MixedTypeCoercion
*
* @return void
*/
public function setMethodParamUses(array $references)
{
self::$method_param_uses = $references;
}
/**
* @param array<string, array<int, CodeLocation>> $references
* @psalm-suppress MixedTypeCoercion
@@ -912,5 +972,6 @@ public static function clearCache()
self::$analyzed_methods = [];
self::$issues = [];
self::$file_maps = [];
self::$method_param_uses = [];
}
}
@@ -690,6 +690,68 @@ public function foo() : void {}
],
'error_message' => 'PossiblyUnusedMethod',
],
'unusedStaticMethodReferencedInFile' => [
'file_stages' => [
[
getcwd() . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'A.php' => '<?php
namespace Foo;
class A {
public static function foo() : void {}
public static function bar() : void {}
}',
getcwd() . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'B.php' => '<?php
\Foo\A::foo();
\Foo\A::bar();',
],
[
getcwd() . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'A.php' => '<?php
namespace Foo;
class A {
public static function foo() : void {}
public static function bar() : void {}
}',
getcwd() . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'B.php' => '<?php
\Foo\A::bar();',
],
],
'error_message' => 'PossiblyUnusedMethod',
],
'unusedParamReferencedInFile' => [
'file_stages' => [
[
getcwd() . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'A.php' => '<?php
namespace Foo;
class A {
public function foo(string $s) : void {}
}
class B extends A {
public function foo(string $s) : void {
echo $s;
}
}
(new B)->foo("hello");',
],
[
getcwd() . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'A.php' => '<?php
namespace Foo;
class A {
public function foo(string $s) : void {}
}
class B extends A {
}
(new B)->foo("hello");',
],
],
'error_message' => 'PossiblyUnusedParam',
],
'unusedMethodReferencedInMethod' => [
'file_stages' => [
[

0 comments on commit b6e9fba

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