From f00d4219ddab116c29b929a2dc93802f60ea9900 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Thu, 14 May 2015 18:01:43 +1000 Subject: [PATCH] Add a linter rule for incorrect use of parent scope Summary: The following code is invalid: ``` final class MyClass { public function __construct() { parent::__construct(null); } } $x = new MyClass(); ``` Running the above code will produce a fatal error: ``` PHP Fatal error: Cannot access parent:: when current class scope has no parent ``` Test Plan: Added unit tests. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: Korvin, epriestley Differential Revision: https://secure.phabricator.com/D12420 --- src/lint/linter/ArcanistXHPASTLinter.php | 34 +++++++++++++++++++ .../xhpast/no-parent-scope.lint-test | 15 ++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/lint/linter/__tests__/xhpast/no-parent-scope.lint-test diff --git a/src/lint/linter/ArcanistXHPASTLinter.php b/src/lint/linter/ArcanistXHPASTLinter.php index f076ac96..248e4399 100644 --- a/src/lint/linter/ArcanistXHPASTLinter.php +++ b/src/lint/linter/ArcanistXHPASTLinter.php @@ -63,6 +63,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter { const LINT_LOWERCASE_FUNCTIONS = 61; const LINT_CLASS_NAME_LITERAL = 62; const LINT_USELESS_OVERRIDING_METHOD = 63; + const LINT_NO_PARENT_SCOPE = 64; private $blacklistedFunctions = array(); private $naminghook; @@ -197,6 +198,8 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter { => pht('Class Name Literal'), self::LINT_USELESS_OVERRIDING_METHOD => pht('Useless Overriding Method'), + self::LINT_NO_PARENT_SCOPE + => pht('No Parent Scope'), ); } @@ -405,6 +408,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter { 'lintLowercaseFunctions' => self::LINT_LOWERCASE_FUNCTIONS, 'lintClassNameLiteral' => self::LINT_CLASS_NAME_LITERAL, 'lintUselessOverridingMethods' => self::LINT_USELESS_OVERRIDING_METHOD, + 'lintNoParentScope' => self::LINT_NO_PARENT_SCOPE, ); foreach ($method_codes as $method => $codes) { @@ -3849,6 +3853,36 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter { } } + private function lintNoParentScope(XHPASTNode $root) { + $classes = $root->selectDescendantsOfType('n_CLASS_DECLARATION'); + + foreach ($classes as $class) { + $methods = $class->selectDescendantsOfType('n_METHOD_DECLARATION'); + + if ($class->getChildByIndex(2)->getTypeName() == 'n_EXTENDS_LIST') { + continue; + } + + foreach ($methods as $method) { + $static_accesses = $method + ->selectDescendantsOfType('n_CLASS_STATIC_ACCESS'); + + foreach ($static_accesses as $static_access) { + $called_class = $static_access->getChildOfType(0, 'n_CLASS_NAME'); + + if ($called_class->getConcreteString() == 'parent') { + $this->raiseLintAtNode( + $static_access, + self::LINT_NO_PARENT_SCOPE, + pht( + 'Cannot access %s when current class scope has no parent.', + 'parent::')); + } + } + } + } + } + /** * Retrieve all calls to some specified function(s). diff --git a/src/lint/linter/__tests__/xhpast/no-parent-scope.lint-test b/src/lint/linter/__tests__/xhpast/no-parent-scope.lint-test new file mode 100644 index 00000000..5251ea96 --- /dev/null +++ b/src/lint/linter/__tests__/xhpast/no-parent-scope.lint-test @@ -0,0 +1,15 @@ +