mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Improve dead code detection, reducing false positives for params
This commit is contained in:
parent
8efc939a5f
commit
875bb8c072
@ -39,6 +39,5 @@
|
||||
<PossiblyNullPropertyFetch errorLevel="info" />
|
||||
<PossiblyNullReference errorLevel="info" />
|
||||
<PossiblyUndefinedVariable errorLevel="info" />
|
||||
<PossiblyUnusedVariable errorLevel="info" />
|
||||
</issueHandlers>
|
||||
</psalm>
|
||||
|
@ -39,7 +39,6 @@
|
||||
<PossiblyNullPropertyFetch errorLevel="info" />
|
||||
<PossiblyNullReference errorLevel="info" />
|
||||
<PossiblyUndefinedVariable errorLevel="info" />
|
||||
<PossiblyUnusedVariable errorLevel="info" />
|
||||
|
||||
<!-- level 5 issues - should be avoided at mosts costs... -->
|
||||
|
||||
|
@ -188,8 +188,8 @@
|
||||
<xs:element name="PossiblyUndefinedMethod" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="PossiblyUndefinedGlobalVariable" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="PossiblyUndefinedVariable" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="PossiblyUnusedVariable" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="PossiblyUnusedMethod" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="PossiblyUnusedParam" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="PropertyNotSetInConstructor" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="RawObjectIteration" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="RedundantCondition" type="IssueHandlerType" minOccurs="0" />
|
||||
@ -219,6 +219,7 @@
|
||||
<xs:element name="UnresolvableInclude" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="UnevaluatedCode" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="UnusedVariable" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="UnusedParam" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="UnusedClass" type="IssueHandlerType" minOccurs="0" />
|
||||
<xs:element name="UnusedMethod" type="IssueHandlerType" minOccurs="0" />
|
||||
</xs:choice>
|
||||
|
14
psalm.xml
14
psalm.xml
@ -25,12 +25,19 @@
|
||||
<MissingConstructor errorLevel="suppress" />
|
||||
<DeprecatedProperty errorLevel="suppress" />
|
||||
|
||||
<PossiblyUnusedVariable>
|
||||
<UnusedParam>
|
||||
<errorLevel type="suppress">
|
||||
<file name="src/Psalm/Plugin.php" />
|
||||
<directory name="examples" />
|
||||
</errorLevel>
|
||||
</PossiblyUnusedVariable>
|
||||
</UnusedParam>
|
||||
|
||||
<PossiblyUnusedParam>
|
||||
<errorLevel type="suppress">
|
||||
<file name="src/Psalm/Plugin.php" />
|
||||
<directory name="examples" />
|
||||
</errorLevel>
|
||||
</PossiblyUnusedParam>
|
||||
|
||||
<UnusedVariable>
|
||||
<errorLevel type="suppress">
|
||||
@ -55,6 +62,9 @@
|
||||
<errorLevel type="suppress">
|
||||
<directory name="tests" />
|
||||
<directory name="examples" />
|
||||
<file name="src/Psalm/Type/Atomic/GenericTrait.php" />
|
||||
<file name="src/Psalm/TraitSource.php" />
|
||||
<file name="src/Psalm/FileManipulation/FileManipulationBuffer.php" />
|
||||
</errorLevel>
|
||||
</PossiblyUnusedMethod>
|
||||
|
||||
|
@ -1378,33 +1378,6 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class_name
|
||||
* @param mixed $visibility
|
||||
*
|
||||
* @return array<string, PropertyStorage>
|
||||
*/
|
||||
public static function getPropertiesForClass(ProjectChecker $project_checker, $class_name, $visibility)
|
||||
{
|
||||
$storage = $project_checker->classlike_storage_provider->get($class_name);
|
||||
|
||||
$properties = [];
|
||||
|
||||
foreach ($storage->properties as $property_name => $property) {
|
||||
if (!$property->is_static) {
|
||||
if ($visibility === ReflectionProperty::IS_PRIVATE ||
|
||||
$property->visibility === ClassLikeChecker::VISIBILITY_PUBLIC ||
|
||||
($property->visibility === ClassLikeChecker::VISIBILITY_PROTECTED &&
|
||||
$visibility === ReflectionProperty::IS_PROTECTED)
|
||||
) {
|
||||
$properties[$property_name] = $property;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Psalm type from a particular value
|
||||
*
|
||||
|
@ -26,8 +26,9 @@ use Psalm\Issue\MixedInferredReturnType;
|
||||
use Psalm\Issue\MoreSpecificImplementedReturnType;
|
||||
use Psalm\Issue\MoreSpecificReturnType;
|
||||
use Psalm\Issue\OverriddenMethodAccess;
|
||||
use Psalm\Issue\PossiblyUnusedVariable;
|
||||
use Psalm\Issue\PossiblyUnusedParam;
|
||||
use Psalm\Issue\UntypedParam;
|
||||
use Psalm\Issue\UnusedParam;
|
||||
use Psalm\Issue\UnusedVariable;
|
||||
use Psalm\IssueBuffer;
|
||||
use Psalm\StatementsSource;
|
||||
@ -129,6 +130,10 @@ abstract class FunctionLikeChecker extends SourceChecker implements StatementsSo
|
||||
|
||||
$implemented_docblock_param_types = [];
|
||||
|
||||
$project_checker = $this->file_checker->project_checker;
|
||||
|
||||
$classlike_storage_provider = $project_checker->classlike_storage_provider;
|
||||
|
||||
if ($this->function instanceof ClassMethod) {
|
||||
$real_method_id = (string)$this->getMethodId();
|
||||
|
||||
@ -162,10 +167,6 @@ abstract class FunctionLikeChecker extends SourceChecker implements StatementsSo
|
||||
|
||||
$fq_class_name = (string)$context->self;
|
||||
|
||||
$project_checker = $this->file_checker->project_checker;
|
||||
|
||||
$classlike_storage_provider = $project_checker->classlike_storage_provider;
|
||||
|
||||
$class_storage = $classlike_storage_provider->get($fq_class_name);
|
||||
|
||||
$storage = MethodChecker::getStorage($project_checker, $declaring_method_id);
|
||||
@ -473,10 +474,7 @@ abstract class FunctionLikeChecker extends SourceChecker implements StatementsSo
|
||||
$original_location = $statements_checker->getFirstAppearance($var_name);
|
||||
|
||||
if (!isset($context->referenced_var_ids[$var_name]) && $original_location) {
|
||||
if (!isset($storage->param_types[substr($var_name, 1)]) ||
|
||||
!$storage instanceof MethodStorage ||
|
||||
$storage->visibility === ClassLikeChecker::VISIBILITY_PRIVATE
|
||||
) {
|
||||
if (!array_key_exists(substr($var_name, 1), $storage->param_types)) {
|
||||
if (IssueBuffer::accepts(
|
||||
new UnusedVariable(
|
||||
'Variable ' . $var_name . ' is never referenced',
|
||||
@ -486,10 +484,40 @@ abstract class FunctionLikeChecker extends SourceChecker implements StatementsSo
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
} else {
|
||||
} elseif (!$storage instanceof MethodStorage
|
||||
|| $storage->visibility === ClassLikeChecker::VISIBILITY_PRIVATE
|
||||
) {
|
||||
if (IssueBuffer::accepts(
|
||||
new PossiblyUnusedVariable(
|
||||
'Variable ' . $var_name . ' is never referenced in this method',
|
||||
new UnusedParam(
|
||||
'Param ' . $var_name . ' is never referenced in this method',
|
||||
$original_location
|
||||
),
|
||||
$this->getSuppressedIssues()
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
} else {
|
||||
if (!$class_storage || $storage->abstract) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var ClassMethod $this->function */
|
||||
$method_name_lc = strtolower((string)$this->function->name);
|
||||
$parent_method_id = end($class_storage->overridden_method_ids[$method_name_lc]);
|
||||
|
||||
if ($parent_method_id) {
|
||||
list($parent_fq_class_name) = explode('::', $parent_method_id);
|
||||
|
||||
$parent_method_class_storage = $classlike_storage_provider->get($parent_fq_class_name);
|
||||
|
||||
if (!$parent_method_class_storage->abstract) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (IssueBuffer::accepts(
|
||||
new PossiblyUnusedParam(
|
||||
'Param ' . $var_name . ' is never referenced in this method',
|
||||
$original_location
|
||||
),
|
||||
$this->getSuppressedIssues()
|
||||
|
@ -920,6 +920,8 @@ class ProjectChecker
|
||||
* @param string $file_path
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @psalm-suppress UnusedParam
|
||||
*/
|
||||
function ($i, $file_path) use ($filetype_handlers) {
|
||||
$file_checker = $this->getFile($file_path, $filetype_handlers, true);
|
||||
@ -1117,11 +1119,9 @@ class ProjectChecker
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Psalm\Storage\ClassLikeStorage $classlike_storage
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function checkMethodReferences($classlike_storage)
|
||||
protected static function checkMethodReferences(\Psalm\Storage\ClassLikeStorage $classlike_storage)
|
||||
{
|
||||
foreach ($classlike_storage->methods as $method_name => $method_storage) {
|
||||
if (($method_storage->referencing_locations === null
|
||||
@ -1137,7 +1137,8 @@ class ProjectChecker
|
||||
new PossiblyUnusedMethod(
|
||||
'Cannot find public calls to method ' . $method_id,
|
||||
$method_storage->location
|
||||
)
|
||||
),
|
||||
$method_storage->suppressed_issues
|
||||
)) {
|
||||
// fall through
|
||||
}
|
||||
|
@ -61,6 +61,8 @@ abstract class CodeIssue
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*
|
||||
* @psalm-suppress PossiblyUnusedMethod for convenience
|
||||
*/
|
||||
public function getFileName()
|
||||
{
|
||||
|
6
src/Psalm/Issue/PossiblyUnusedParam.php
Normal file
6
src/Psalm/Issue/PossiblyUnusedParam.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class PossiblyUnusedParam extends CodeError
|
||||
{
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class PossiblyUnusedVariable extends CodeError
|
||||
{
|
||||
}
|
6
src/Psalm/Issue/UnusedParam.php
Normal file
6
src/Psalm/Issue/UnusedParam.php
Normal file
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace Psalm\Issue;
|
||||
|
||||
class UnusedParam extends CodeError
|
||||
{
|
||||
}
|
@ -6,14 +6,13 @@ use PhpParser;
|
||||
class NoParserCacheProvider extends \Psalm\Provider\ParserCacheProvider
|
||||
{
|
||||
/**
|
||||
* @param string $file_path
|
||||
* @param string $file_content_hash
|
||||
* @param string $file_cache_key
|
||||
* @param mixed $file_modified_time
|
||||
*
|
||||
* @return array<int, PhpParser\Node\Stmt>|null
|
||||
*/
|
||||
public function loadStatementsFromCache($file_path, $file_modified_time, $file_content_hash, $file_cache_key)
|
||||
public function loadStatementsFromCache($file_modified_time, $file_content_hash, $file_cache_key)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ class ParserCacheProvider
|
||||
public $use_igbinary = false;
|
||||
|
||||
/**
|
||||
* @param string $file_path
|
||||
* @param string $file_content_hash
|
||||
* @param string $file_cache_key
|
||||
* @param mixed $file_modified_time
|
||||
@ -35,7 +34,7 @@ class ParserCacheProvider
|
||||
*
|
||||
* @psalm-suppress UndefinedFunction
|
||||
*/
|
||||
public function loadStatementsFromCache($file_path, $file_modified_time, $file_content_hash, $file_cache_key)
|
||||
public function loadStatementsFromCache($file_modified_time, $file_content_hash, $file_cache_key)
|
||||
{
|
||||
$root_cache_directory = Config::getInstance()->getCacheDirectory();
|
||||
|
||||
|
@ -35,7 +35,6 @@ class StatementsProvider
|
||||
$file_cache_key = $cache_provider->getParserCacheKey($file_path);
|
||||
|
||||
$stmts = $cache_provider->loadStatementsFromCache(
|
||||
$file_path,
|
||||
$modified_time,
|
||||
$file_content_hash,
|
||||
$file_cache_key
|
||||
|
@ -165,14 +165,6 @@ class Union
|
||||
return isset($this->types['array']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasObjectLike()
|
||||
{
|
||||
return isset($this->types['array']) && $this->types['array'] instanceof Atomic\ObjectLike;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
@ -301,18 +293,6 @@ class Union
|
||||
return isset($this->types['empty']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function removeObjects()
|
||||
{
|
||||
foreach ($this->types as $key => $type) {
|
||||
if ($type instanceof Atomic\TNamedObject) {
|
||||
unset($this->types[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
|
@ -6,14 +6,13 @@ use PhpParser;
|
||||
class FakeParserCacheProvider extends \Psalm\Provider\ParserCacheProvider
|
||||
{
|
||||
/**
|
||||
* @param string $file_path
|
||||
* @param string $file_content_hash
|
||||
* @param string $file_cache_key
|
||||
* @param mixed $file_modified_time
|
||||
*
|
||||
* @return array<int, PhpParser\Node\Stmt>|null
|
||||
*/
|
||||
public function loadStatementsFromCache($file_path, $file_modified_time, $file_content_hash, $file_cache_key)
|
||||
public function loadStatementsFromCache($file_modified_time, $file_content_hash, $file_cache_key)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user