1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-12-23 22:10:54 +01:00

Add a linter rule for abstract methods within an interface

Summary:
`interface`s cannot contain `abstract` methods. This construct will cause a PHP fatal error:

```
Access type for interface method SomeInterface::someMethod() must be omitted
```

Test Plan: Added test cases.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: Korvin

Differential Revision: https://secure.phabricator.com/D14562
This commit is contained in:
Joshua Spence 2015-11-26 07:21:29 +11:00
parent 8183a45804
commit b323ad4d64
5 changed files with 62 additions and 0 deletions

View file

@ -178,6 +178,8 @@ phutil_register_library_map(array(
'ArcanistInstallCertificateWorkflow' => 'workflow/ArcanistInstallCertificateWorkflow.php', 'ArcanistInstallCertificateWorkflow' => 'workflow/ArcanistInstallCertificateWorkflow.php',
'ArcanistInstanceOfOperatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInstanceOfOperatorXHPASTLinterRule.php', 'ArcanistInstanceOfOperatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInstanceOfOperatorXHPASTLinterRule.php',
'ArcanistInstanceofOperatorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInstanceofOperatorXHPASTLinterRuleTestCase.php', 'ArcanistInstanceofOperatorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInstanceofOperatorXHPASTLinterRuleTestCase.php',
'ArcanistInterfaceAbstractMethodXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInterfaceAbstractMethodXHPASTLinterRule.php',
'ArcanistInterfaceAbstractMethodXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInterfaceAbstractMethodXHPASTLinterRuleTestCase.php',
'ArcanistInterfaceMethodBodyXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInterfaceMethodBodyXHPASTLinterRule.php', 'ArcanistInterfaceMethodBodyXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInterfaceMethodBodyXHPASTLinterRule.php',
'ArcanistInterfaceMethodBodyXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInterfaceMethodBodyXHPASTLinterRuleTestCase.php', 'ArcanistInterfaceMethodBodyXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInterfaceMethodBodyXHPASTLinterRuleTestCase.php',
'ArcanistInvalidDefaultParameterXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInvalidDefaultParameterXHPASTLinterRule.php', 'ArcanistInvalidDefaultParameterXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInvalidDefaultParameterXHPASTLinterRule.php',
@ -568,6 +570,8 @@ phutil_register_library_map(array(
'ArcanistInstallCertificateWorkflow' => 'ArcanistWorkflow', 'ArcanistInstallCertificateWorkflow' => 'ArcanistWorkflow',
'ArcanistInstanceOfOperatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistInstanceOfOperatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInstanceofOperatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistInstanceofOperatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInterfaceAbstractMethodXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInterfaceAbstractMethodXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInterfaceMethodBodyXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistInterfaceMethodBodyXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInterfaceMethodBodyXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistInterfaceMethodBodyXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInvalidDefaultParameterXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistInvalidDefaultParameterXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',

View file

@ -0,0 +1,34 @@
<?php
final class ArcanistInterfaceAbstractMethodXHPASTLinterRule
extends ArcanistXHPASTLinterRule {
const ID = 114;
public function getLintName() {
return pht('`%s` Methods Cannot Be Marked `%s`', 'interface', 'abstract');
}
public function process(XHPASTNode $root) {
$interfaces = $root->selectDescendantsOfType('n_INTERFACE_DECLARATION');
foreach ($interfaces as $interface) {
$methods = $interface->selectDescendantsOfType('n_METHOD_DECLARATION');
foreach ($methods as $method) {
$modifiers = $this->getModifiers($method);
if (idx($modifiers, 'abstract')) {
$this->raiseLintAtNode(
$method,
pht(
'`%s` methods cannot be marked as `%s`. This construct will '.
'cause a fatal error.',
'interface',
'abstract'));
}
}
}
}
}

View file

@ -0,0 +1,11 @@
<?php
final class ArcanistInterfaceAbstractMethodXHPASTLinterRuleTestCase
extends ArcanistXHPASTLinterRuleTestCase {
public function testLinter() {
$this->executeTestsInDirectory(
dirname(__FILE__).'/interface-abstract-method/');
}
}

View file

@ -0,0 +1,7 @@
<?php
interface SomeInterface {
abstract public function someMethod();
}
~~~~~~~~~~
error:4:3

View file

@ -0,0 +1,6 @@
<?php
interface SomeInterface {
public function someMethod();
}
~~~~~~~~~~