From cb63f4f70f86a8026e2bb0ef553b6b4fc1818f44 Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Fri, 10 Aug 2018 13:25:25 -0400 Subject: [PATCH] Add support for checking DeprecatedTrait and DeprecatedConstant --- assets/config_levels/3.xml | 2 ++ assets/config_levels/4.xml | 2 ++ assets/config_levels/5.xml | 2 ++ assets/config_levels/6.xml | 2 ++ assets/config_levels/7.xml | 2 ++ assets/config_levels/8.xml | 2 ++ config.xsd | 2 ++ docs/issues.md | 25 +++++++++++++++++++ src/Psalm/Checker/ClassChecker.php | 15 +++++++++++ .../Expression/Fetch/ConstFetchChecker.php | 15 +++++++++++ src/Psalm/Issue/DeprecatedConstant.php | 6 +++++ src/Psalm/Issue/DeprecatedTrait.php | 6 +++++ src/Psalm/Storage/ClassLikeStorage.php | 5 ++++ src/Psalm/Visitor/DependencyFinderVisitor.php | 16 ++++++++++++ 14 files changed, 102 insertions(+) create mode 100644 src/Psalm/Issue/DeprecatedConstant.php create mode 100644 src/Psalm/Issue/DeprecatedTrait.php 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; + } } }