diff --git a/assets/config_levels/3.xml b/assets/config_levels/3.xml
index 3a0f196b9..430afa70b 100644
--- a/assets/config_levels/3.xml
+++ b/assets/config_levels/3.xml
@@ -20,7 +20,9 @@
+
+
diff --git a/assets/config_levels/4.xml b/assets/config_levels/4.xml
index 1d8c55a30..46b1d1565 100644
--- a/assets/config_levels/4.xml
+++ b/assets/config_levels/4.xml
@@ -20,7 +20,9 @@
+
+
diff --git a/assets/config_levels/5.xml b/assets/config_levels/5.xml
index b8c1beeb4..e2d840f8a 100644
--- a/assets/config_levels/5.xml
+++ b/assets/config_levels/5.xml
@@ -20,7 +20,9 @@
+
+
diff --git a/assets/config_levels/6.xml b/assets/config_levels/6.xml
index 65cdbc417..e5c09d44a 100644
--- a/assets/config_levels/6.xml
+++ b/assets/config_levels/6.xml
@@ -20,7 +20,9 @@
+
+
diff --git a/assets/config_levels/7.xml b/assets/config_levels/7.xml
index cb46b6819..64ca7e289 100644
--- a/assets/config_levels/7.xml
+++ b/assets/config_levels/7.xml
@@ -20,7 +20,9 @@
+
+
diff --git a/assets/config_levels/8.xml b/assets/config_levels/8.xml
index 9c357aaa5..5c54a0bef 100644
--- a/assets/config_levels/8.xml
+++ b/assets/config_levels/8.xml
@@ -20,7 +20,9 @@
+
+
diff --git a/config.xsd b/config.xsd
index b10a52224..1974495a2 100644
--- a/config.xsd
+++ b/config.xsd
@@ -117,9 +117,11 @@
+
+
diff --git a/docs/issues.md b/docs/issues.md
index 56c85e07f..9812399f6 100644
--- a/docs/issues.md
+++ b/docs/issues.md
@@ -80,6 +80,19 @@ class A {}
new A();
```
+### DeprecatedConstant
+
+Emitted when referring to a deprecated constant:
+
+```php
+class A {
+ /** @deprecated */
+ const FOO = 'foo';
+}
+
+echo A::FOO;
+```
+
### DeprecatedInterface
Emitted when referring to a deprecated interface
@@ -118,6 +131,18 @@ class A {
(new A())->foo = 5;
```
+### DeprecatedTrait
+
+Emitted when referring to a deprecated trait:
+
+```php
+/** @deprecated */
+trait T {}
+class A {
+ use T;
+}
+```
+
### DocblockTypeContradiction
Emitted when conditional doesn't make sense given the docblock types supplied.
diff --git a/src/Psalm/Checker/ClassChecker.php b/src/Psalm/Checker/ClassChecker.php
index ed161bae3..e1812a15c 100644
--- a/src/Psalm/Checker/ClassChecker.php
+++ b/src/Psalm/Checker/ClassChecker.php
@@ -10,6 +10,7 @@ use Psalm\Config;
use Psalm\Context;
use Psalm\Issue\DeprecatedClass;
use Psalm\Issue\DeprecatedInterface;
+use Psalm\Issue\DeprecatedTrait;
use Psalm\Issue\InaccessibleMethod;
use Psalm\Issue\MissingConstructor;
use Psalm\Issue\MissingPropertyType;
@@ -687,6 +688,20 @@ class ClassChecker extends ClassLikeChecker
continue;
}
+ $trait_storage = $codebase->classlike_storage_provider->get($fq_trait_name);
+
+ if ($trait_storage->deprecated) {
+ if (IssueBuffer::accepts(
+ new DeprecatedTrait(
+ 'Trait ' . $fq_trait_name . ' is deprecated',
+ new CodeLocation($this, $trait_name)
+ ),
+ array_merge($storage->suppressed_issues, $this->getSuppressedIssues())
+ )) {
+ return false;
+ }
+ }
+
$trait_file_checker = $project_checker->getFileCheckerForClassLike($fq_trait_name);
$trait_node = $codebase->classlikes->getTraitNode($fq_trait_name);
$trait_aliases = $codebase->classlikes->getTraitAliases($fq_trait_name);
diff --git a/src/Psalm/Checker/Statements/Expression/Fetch/ConstFetchChecker.php b/src/Psalm/Checker/Statements/Expression/Fetch/ConstFetchChecker.php
index ea2ec7ff4..2557a4d32 100644
--- a/src/Psalm/Checker/Statements/Expression/Fetch/ConstFetchChecker.php
+++ b/src/Psalm/Checker/Statements/Expression/Fetch/ConstFetchChecker.php
@@ -9,6 +9,7 @@ use Psalm\Checker\TraitChecker;
use Psalm\Codebase;
use Psalm\CodeLocation;
use Psalm\Context;
+use Psalm\Issue\DeprecatedConstant;
use Psalm\Issue\InaccessibleClassConstant;
use Psalm\Issue\ParentNotFound;
use Psalm\Issue\UndefinedConstant;
@@ -204,6 +205,20 @@ class ConstFetchChecker
return false;
}
+ $class_const_storage = $codebase->classlike_storage_provider->get($fq_class_name);
+
+ if (isset($class_const_storage->deprecated_constants[$stmt->name->name])) {
+ if (IssueBuffer::accepts(
+ new DeprecatedConstant(
+ 'Constant ' . $const_id . ' is deprecated',
+ new CodeLocation($statements_checker->getSource(), $stmt)
+ ),
+ $statements_checker->getSuppressedIssues()
+ )) {
+ // fall through
+ }
+ }
+
if (isset($class_constants[$stmt->name->name]) && $first_part_lc !== 'static') {
$stmt->inferredType = clone $class_constants[$stmt->name->name];
} else {
diff --git a/src/Psalm/Issue/DeprecatedConstant.php b/src/Psalm/Issue/DeprecatedConstant.php
new file mode 100644
index 000000000..c536f4e98
--- /dev/null
+++ b/src/Psalm/Issue/DeprecatedConstant.php
@@ -0,0 +1,6 @@
+
+ */
+ public $deprecated_constants = [];
+
/**
* @var bool
*/
diff --git a/src/Psalm/Visitor/DependencyFinderVisitor.php b/src/Psalm/Visitor/DependencyFinderVisitor.php
index 240a5d6d4..21e368676 100644
--- a/src/Psalm/Visitor/DependencyFinderVisitor.php
+++ b/src/Psalm/Visitor/DependencyFinderVisitor.php
@@ -1766,6 +1766,18 @@ class DependencyFinderVisitor extends PhpParser\NodeVisitorAbstract implements P
+ $storage->private_class_constants
+ $storage->public_class_constants;
+ $comment = $stmt->getDocComment();
+ $deprecated = false;
+ $config = $this->config;
+
+ if ($comment && $comment->getText() && ($config->use_docblock_types || $config->use_docblock_property_types)) {
+ $comments = CommentChecker::parseDocComment($comment->getText(), 0);
+
+ if (isset($comments['specials']['deprecated'])) {
+ $deprecated = true;
+ }
+ }
+
foreach ($stmt->consts as $const) {
$const_type = StatementsChecker::getSimpleType(
$this->codebase,
@@ -1797,6 +1809,10 @@ class DependencyFinderVisitor extends PhpParser\NodeVisitorAbstract implements P
$storage->aliases = $this->aliases;
}
+
+ if ($deprecated) {
+ $storage->deprecated_constants[$const->name->name] = true;
+ }
}
}