mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-29 10:12:41 +01:00
Add a linter rule to ensure that namespace
is the first statement in a file
Summary: If a `namespace` is used within a PHP script, it must be the first statement. Test Plan: Added unit tests. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley, #blessed_reviewers Subscribers: Korvin Differential Revision: https://secure.phabricator.com/D14526
This commit is contained in:
parent
600dcf83dd
commit
eeaa176cfc
7 changed files with 82 additions and 0 deletions
|
@ -234,6 +234,8 @@ phutil_register_library_map(array(
|
||||||
'ArcanistMissingLinterException' => 'lint/linter/exception/ArcanistMissingLinterException.php',
|
'ArcanistMissingLinterException' => 'lint/linter/exception/ArcanistMissingLinterException.php',
|
||||||
'ArcanistModifierOrderingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistModifierOrderingXHPASTLinterRule.php',
|
'ArcanistModifierOrderingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistModifierOrderingXHPASTLinterRule.php',
|
||||||
'ArcanistModifierOrderingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistModifierOrderingXHPASTLinterRuleTestCase.php',
|
'ArcanistModifierOrderingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistModifierOrderingXHPASTLinterRuleTestCase.php',
|
||||||
|
'ArcanistNamespaceFirstStatementXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNamespaceFirstStatementXHPASTLinterRule.php',
|
||||||
|
'ArcanistNamespaceFirstStatementXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistNamespaceFirstStatementXHPASTLinterRuleTestCase.php',
|
||||||
'ArcanistNamingConventionsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNamingConventionsXHPASTLinterRule.php',
|
'ArcanistNamingConventionsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNamingConventionsXHPASTLinterRule.php',
|
||||||
'ArcanistNamingConventionsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistNamingConventionsXHPASTLinterRuleTestCase.php',
|
'ArcanistNamingConventionsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistNamingConventionsXHPASTLinterRuleTestCase.php',
|
||||||
'ArcanistNestedNamespacesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNestedNamespacesXHPASTLinterRule.php',
|
'ArcanistNestedNamespacesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNestedNamespacesXHPASTLinterRule.php',
|
||||||
|
@ -626,6 +628,8 @@ phutil_register_library_map(array(
|
||||||
'ArcanistMissingLinterException' => 'Exception',
|
'ArcanistMissingLinterException' => 'Exception',
|
||||||
'ArcanistModifierOrderingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistModifierOrderingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistModifierOrderingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistModifierOrderingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
|
'ArcanistNamespaceFirstStatementXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
|
'ArcanistNamespaceFirstStatementXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
'ArcanistNamingConventionsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistNamingConventionsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistNamingConventionsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
'ArcanistNamingConventionsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||||
'ArcanistNestedNamespacesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistNestedNamespacesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistNamespaceFirstStatementXHPASTLinterRule
|
||||||
|
extends ArcanistXHPASTLinterRule {
|
||||||
|
|
||||||
|
const ID = 98;
|
||||||
|
|
||||||
|
public function getLintName() {
|
||||||
|
return pht('`%s` Statement Must Be The First Statement', 'namespace');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function process(XHPASTNode $root) {
|
||||||
|
$namespaces = $root->selectDescendantsOfType('n_NAMESPACE');
|
||||||
|
|
||||||
|
if (!count($namespaces)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$statements = $root->getChildOfType(0, 'n_STATEMENT_LIST');
|
||||||
|
|
||||||
|
// Ignore the first statement, which should be `n_OPEN_TAG`.
|
||||||
|
$second_statement = $statements->getChildByIndex(1)->getChildByIndex(0);
|
||||||
|
|
||||||
|
if ($second_statement->getTypeName() != 'n_NAMESPACE') {
|
||||||
|
$this->raiseLintAtNode(
|
||||||
|
$second_statement,
|
||||||
|
pht(
|
||||||
|
'A script which contains a `%s` statement expects the very first '.
|
||||||
|
'statement to be a `%s` statement. Otherwise, a PHP fatal error '.
|
||||||
|
'will occur. %s',
|
||||||
|
'namespace',
|
||||||
|
'namespace', $second_statement->getTypeName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistNamespaceFirstStatementXHPASTLinterRuleTestCase
|
||||||
|
extends ArcanistXHPASTLinterRuleTestCase {
|
||||||
|
|
||||||
|
public function testLinter() {
|
||||||
|
$this->executeTestsInDirectory(
|
||||||
|
dirname(__FILE__).'/namespace-first-statement/');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
class X {}
|
||||||
|
namespace X;
|
||||||
|
~~~~~~~~~~
|
||||||
|
error:2:1
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is actually perfectly valid, for some unknown reason.
|
||||||
|
*
|
||||||
|
* TODO: Maybe fix the handling of this edge case.
|
||||||
|
*/
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
namespace X {
|
||||||
|
class C { }
|
||||||
|
echo 2;
|
||||||
|
}
|
||||||
|
~~~~~~~~~~
|
||||||
|
error:9:1
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
namespace X;
|
||||||
|
class X {}
|
||||||
|
|
||||||
|
namespace Y;
|
||||||
|
class Y {}
|
||||||
|
~~~~~~~~~~
|
|
@ -0,0 +1,3 @@
|
||||||
|
<?php
|
||||||
|
class X {}
|
||||||
|
~~~~~~~~~~
|
Loading…
Reference in a new issue