mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-25 16:22:42 +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',
|
||||
'ArcanistModifierOrderingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistModifierOrderingXHPASTLinterRule.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',
|
||||
'ArcanistNamingConventionsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistNamingConventionsXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistNestedNamespacesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNestedNamespacesXHPASTLinterRule.php',
|
||||
|
@ -626,6 +628,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistMissingLinterException' => 'Exception',
|
||||
'ArcanistModifierOrderingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistModifierOrderingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistNamespaceFirstStatementXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistNamespaceFirstStatementXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistNamingConventionsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistNamingConventionsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'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