mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-22 14:52:40 +01:00
Add a linter rule for abstract
methods containing a body
Summary: `abstract` methods cannot contain a body. ``` PHP Fatal error: Abstract function X::Y() cannot contain body in /home/josh/workspace/github.com/phacility/arcanist/test.php on line 4 ``` Test Plan: Added unit tests. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D14560
This commit is contained in:
parent
37571d8839
commit
72d9013d29
8 changed files with 88 additions and 28 deletions
|
@ -9,6 +9,8 @@
|
|||
phutil_register_library_map(array(
|
||||
'__library_version__' => 2,
|
||||
'class' => array(
|
||||
'ArcanistAbstractMethodBodyXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistAbstractMethodBodyXHPASTLinterRule.php',
|
||||
'ArcanistAbstractMethodBodyXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistAbstractMethodBodyXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistAbstractPrivateMethodXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistAbstractPrivateMethodXHPASTLinterRule.php',
|
||||
'ArcanistAbstractPrivateMethodXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistAbstractPrivateMethodXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistAliasFunctionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistAliasFunctionXHPASTLinterRule.php',
|
||||
|
@ -395,6 +397,8 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'function' => array(),
|
||||
'xmap' => array(
|
||||
'ArcanistAbstractMethodBodyXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistAbstractMethodBodyXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistAbstractPrivateMethodXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistAbstractPrivateMethodXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistAliasFunctionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
|
|
|
@ -225,6 +225,34 @@ abstract class ArcanistXHPASTLinterRule extends Phobject {
|
|||
return AASTNodeList::newFromTreeAndNodes($root->getTree(), $nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class/method modifiers.
|
||||
*
|
||||
* @param XHPASTNode A node of type `n_CLASS_DECLARATION` or
|
||||
* `n_METHOD_DECLARATION`.
|
||||
* @return map<string, bool> Class/method modifiers.
|
||||
*/
|
||||
final protected function getModifiers(XHPASTNode $node) {
|
||||
$modifier_list = $node->getChildByIndex(0);
|
||||
|
||||
switch ($modifier_list->getTypeName()) {
|
||||
case 'n_CLASS_ATTRIBUTES':
|
||||
case 'n_METHOD_MODIFIER_LIST':
|
||||
break;
|
||||
|
||||
default:
|
||||
return array();
|
||||
}
|
||||
|
||||
$modifiers = array();
|
||||
|
||||
foreach ($modifier_list->selectDescendantsOfType('n_STRING') as $modifier) {
|
||||
$modifiers[strtolower($modifier->getConcreteString())] = true;
|
||||
}
|
||||
|
||||
return $modifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get PHP superglobals.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistAbstractMethodBodyXHPASTLinterRule
|
||||
extends ArcanistXHPASTLinterRule {
|
||||
|
||||
const ID = 108;
|
||||
|
||||
public function getLintName() {
|
||||
return pht('`%s` Method Cannot Contain Body', 'abstract');
|
||||
}
|
||||
|
||||
public function process(XHPASTNode $root) {
|
||||
$methods = $root->selectDescendantsOfType('n_METHOD_DECLARATION');
|
||||
|
||||
foreach ($methods as $method) {
|
||||
$modifiers = $this->getModifiers($method);
|
||||
$body = $method->getChildByIndex(5);
|
||||
|
||||
if (idx($modifiers, 'abstract') && $body->getTypeName() != 'n_EMPTY') {
|
||||
$this->raiseLintAtNode(
|
||||
$body,
|
||||
pht(
|
||||
'`%s` methods cannot contain a body. This construct will '.
|
||||
'cause a fatal error.',
|
||||
'abstract'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -43,32 +43,4 @@ final class ArcanistClassMustBeDeclaredAbstractXHPASTLinterRule
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class/method modifiers.
|
||||
*
|
||||
* @param XHPASTNode A node of type `n_CLASS_DECLARATION` or
|
||||
* `n_METHOD_DECLARATION`.
|
||||
* @return map<string, bool> Class/method modifiers.
|
||||
*/
|
||||
private function getModifiers(XHPASTNode $node) {
|
||||
$modifier_list = $node->getChildByIndex(0);
|
||||
|
||||
switch ($modifier_list->getTypeName()) {
|
||||
case 'n_CLASS_ATTRIBUTES':
|
||||
case 'n_METHOD_MODIFIER_LIST':
|
||||
break;
|
||||
|
||||
default:
|
||||
return array();
|
||||
}
|
||||
|
||||
$modifiers = array();
|
||||
|
||||
foreach ($modifier_list->selectDescendantsOfType('n_STRING') as $modifier) {
|
||||
$modifiers[strtolower($modifier->getConcreteString())] = true;
|
||||
}
|
||||
|
||||
return $modifiers;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistAbstractMethodBodyXHPASTLinterRuleTestCase
|
||||
extends ArcanistXHPASTLinterRuleTestCase {
|
||||
|
||||
public function testLinter() {
|
||||
$this->executeTestsInDirectory(dirname(__FILE__).'/abstract-method-body/');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
abstract class SomeClass {
|
||||
abstract public function someMethod() {}
|
||||
}
|
||||
~~~~~~~~~~
|
||||
error:3:41
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
abstract class SomeClass {
|
||||
abstract public function someMethod();
|
||||
}
|
||||
~~~~~~~~~~
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
abstract class SomeClass {
|
||||
public function someMethod() {}
|
||||
}
|
||||
~~~~~~~~~~
|
Loading…
Reference in a new issue