From 4bb2eecdaf425824051f13947c10a3680a06c19b Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Mon, 18 May 2015 18:00:08 +1000 Subject: [PATCH] Add a linter rule for the instanceof operator Summary: The `instanceof` operator expects the first argument to be an object instance. See http://www.phpwtf.org/instanceof-smart. Test Plan: Added test case Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: Korvin, epriestley Differential Revision: https://secure.phabricator.com/D12856 --- src/lint/linter/ArcanistXHPASTLinter.php | 30 ++++++++++++++++++- .../xhpast/instanceof-operator.lint-test | 9 ++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 src/lint/linter/__tests__/xhpast/instanceof-operator.lint-test diff --git a/src/lint/linter/ArcanistXHPASTLinter.php b/src/lint/linter/ArcanistXHPASTLinter.php index 88e4ffea..593d588d 100644 --- a/src/lint/linter/ArcanistXHPASTLinter.php +++ b/src/lint/linter/ArcanistXHPASTLinter.php @@ -68,6 +68,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter { const LINT_CAST_SPACING = 66; const LINT_TOSTRING_EXCEPTION = 67; const LINT_LAMBDA_FUNC_FUNCTION = 68; + const LINT_INSTANCEOF_OPERATOR = 69; private $blacklistedFunctions = array(); private $naminghook; @@ -212,6 +213,8 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter { => pht('Throwing Exception in %s Method', '__toString'), self::LINT_LAMBDA_FUNC_FUNCTION => pht('%s Function', '__lambda_func'), + self::LINT_INSTANCEOF_OPERATOR + => pht('%s Operator', 'instanceof'), ); } @@ -332,7 +335,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter { public function getVersion() { // The version number should be incremented whenever a new rule is added. - return '30'; + return '31'; } protected function resolveFuture($path, Future $future) { @@ -427,6 +430,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter { 'lintCastSpacing' => self::LINT_CAST_SPACING, 'lintThrowExceptionInToStringMethod' => self::LINT_TOSTRING_EXCEPTION, 'lintLambdaFuncFunction' => self::LINT_LAMBDA_FUNC_FUNCTION, + 'lintInstanceOfOperator' => self::LINT_INSTANCEOF_OPERATOR, ); foreach ($method_codes as $method => $codes) { @@ -4196,6 +4200,30 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter { } } + private function lintInstanceOfOperator(XHPASTNode $root) { + $expressions = $root->selectDescendantsOfType('n_BINARY_EXPRESSION'); + + foreach ($expressions as $expression) { + $operator = $expression->getChildOfType(1, 'n_OPERATOR'); + + if (strtolower($operator->getConcreteString()) != 'instanceof') { + continue; + } + + $object = $expression->getChildByIndex(0); + + if ($object->isStaticScalar() || + $object->getTypeName() == 'n_SYMBOL_NAME') { + $this->raiseLintAtNode( + $object, + self::LINT_INSTANCEOF_OPERATOR, + pht( + '%s expects an object instance, constant given.', + 'instanceof')); + } + } + } + /** * Retrieve all calls to some specified function(s). diff --git a/src/lint/linter/__tests__/xhpast/instanceof-operator.lint-test b/src/lint/linter/__tests__/xhpast/instanceof-operator.lint-test new file mode 100644 index 00000000..ebf8423a --- /dev/null +++ b/src/lint/linter/__tests__/xhpast/instanceof-operator.lint-test @@ -0,0 +1,9 @@ +