diff --git a/assets/config_levels/4.xml b/assets/config_levels/4.xml
index 4dae788fc..b78613cbd 100644
--- a/assets/config_levels/4.xml
+++ b/assets/config_levels/4.xml
@@ -39,6 +39,5 @@
-
diff --git a/assets/config_levels/5.xml b/assets/config_levels/5.xml
index 28b1447b8..8ab5a5e20 100644
--- a/assets/config_levels/5.xml
+++ b/assets/config_levels/5.xml
@@ -39,7 +39,6 @@
-
diff --git a/config.xsd b/config.xsd
index 812e83df4..98bed198d 100644
--- a/config.xsd
+++ b/config.xsd
@@ -188,8 +188,8 @@
-
+
@@ -219,6 +219,7 @@
+
diff --git a/psalm.xml b/psalm.xml
index 9b2c9070a..9c97adff7 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -25,12 +25,19 @@
-
+
-
+
+
+
+
+
+
+
+
@@ -55,6 +62,9 @@
+
+
+
diff --git a/src/Psalm/Checker/ClassLikeChecker.php b/src/Psalm/Checker/ClassLikeChecker.php
index ac5dfeafa..33b9cdcd5 100644
--- a/src/Psalm/Checker/ClassLikeChecker.php
+++ b/src/Psalm/Checker/ClassLikeChecker.php
@@ -1378,33 +1378,6 @@ abstract class ClassLikeChecker extends SourceChecker implements StatementsSourc
}
}
- /**
- * @param string $class_name
- * @param mixed $visibility
- *
- * @return array
- */
- 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
*
diff --git a/src/Psalm/Checker/FunctionLikeChecker.php b/src/Psalm/Checker/FunctionLikeChecker.php
index c95b612c7..029ed521e 100644
--- a/src/Psalm/Checker/FunctionLikeChecker.php
+++ b/src/Psalm/Checker/FunctionLikeChecker.php
@@ -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()
diff --git a/src/Psalm/Checker/ProjectChecker.php b/src/Psalm/Checker/ProjectChecker.php
index acc0bbfd4..6b36be74f 100644
--- a/src/Psalm/Checker/ProjectChecker.php
+++ b/src/Psalm/Checker/ProjectChecker.php
@@ -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
}
diff --git a/src/Psalm/Issue/CodeIssue.php b/src/Psalm/Issue/CodeIssue.php
index 9c259c0fe..c99972b15 100644
--- a/src/Psalm/Issue/CodeIssue.php
+++ b/src/Psalm/Issue/CodeIssue.php
@@ -61,6 +61,8 @@ abstract class CodeIssue
/**
* @return string
+ *
+ * @psalm-suppress PossiblyUnusedMethod for convenience
*/
public function getFileName()
{
diff --git a/src/Psalm/Issue/PossiblyUnusedParam.php b/src/Psalm/Issue/PossiblyUnusedParam.php
new file mode 100644
index 000000000..d15c38053
--- /dev/null
+++ b/src/Psalm/Issue/PossiblyUnusedParam.php
@@ -0,0 +1,6 @@
+|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;
}
diff --git a/src/Psalm/Provider/ParserCacheProvider.php b/src/Psalm/Provider/ParserCacheProvider.php
index 8367f5aac..6587330c7 100644
--- a/src/Psalm/Provider/ParserCacheProvider.php
+++ b/src/Psalm/Provider/ParserCacheProvider.php
@@ -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();
diff --git a/src/Psalm/Provider/StatementsProvider.php b/src/Psalm/Provider/StatementsProvider.php
index fef2f026c..3151726a6 100644
--- a/src/Psalm/Provider/StatementsProvider.php
+++ b/src/Psalm/Provider/StatementsProvider.php
@@ -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
diff --git a/src/Psalm/Type/Union.php b/src/Psalm/Type/Union.php
index 694ba4009..052c4f6fa 100644
--- a/src/Psalm/Type/Union.php
+++ b/src/Psalm/Type/Union.php
@@ -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
*/
diff --git a/tests/Provider/FakeParserCacheProvider.php b/tests/Provider/FakeParserCacheProvider.php
index b0961d413..ae767a4cc 100644
--- a/tests/Provider/FakeParserCacheProvider.php
+++ b/tests/Provider/FakeParserCacheProvider.php
@@ -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|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;
}