1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-22 06:42:41 +01:00

Add a linter rule to detect unnecessary semicolons

Summary:
Ref T7409. Adds a rule to detect unnecessary semicolons. The most common scenario I've seen in the wild is the use of semicolons after a class definition:

```lang=php
class MyClass {
  // ...
};
```

Test Plan: Added unit tests.

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: Korvin, epriestley

Maniphest Tasks: T7409

Differential Revision: https://secure.phabricator.com/D12139
This commit is contained in:
Joshua Spence 2015-04-07 07:24:20 +10:00
parent 92713cf922
commit c5df885d7b
2 changed files with 34 additions and 1 deletions

View file

@ -55,6 +55,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
const LINT_CALL_TIME_PASS_BY_REF = 53; const LINT_CALL_TIME_PASS_BY_REF = 53;
const LINT_FORMATTED_STRING = 54; const LINT_FORMATTED_STRING = 54;
const LINT_UNNECESSARY_FINAL_MODIFIER = 55; const LINT_UNNECESSARY_FINAL_MODIFIER = 55;
const LINT_UNNECESSARY_SEMICOLON = 56;
private $blacklistedFunctions = array(); private $blacklistedFunctions = array();
private $naminghook; private $naminghook;
@ -123,6 +124,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
self::LINT_CALL_TIME_PASS_BY_REF => 'Call-Time Pass-By-Reference', self::LINT_CALL_TIME_PASS_BY_REF => 'Call-Time Pass-By-Reference',
self::LINT_FORMATTED_STRING => 'Formatted String', self::LINT_FORMATTED_STRING => 'Formatted String',
self::LINT_UNNECESSARY_FINAL_MODIFIER => 'Unnecessary Final Modifier', self::LINT_UNNECESSARY_FINAL_MODIFIER => 'Unnecessary Final Modifier',
self::LINT_UNNECESSARY_SEMICOLON => 'Unnecessary Semicolon',
); );
} }
@ -166,6 +168,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
self::LINT_CONSTRUCTOR_PARENTHESES => $advice, self::LINT_CONSTRUCTOR_PARENTHESES => $advice,
self::LINT_IMPLICIT_VISIBILITY => $advice, self::LINT_IMPLICIT_VISIBILITY => $advice,
self::LINT_UNNECESSARY_FINAL_MODIFIER => $advice, self::LINT_UNNECESSARY_FINAL_MODIFIER => $advice,
self::LINT_UNNECESSARY_SEMICOLON => $advice,
); );
} }
@ -233,7 +236,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
public function getVersion() { public function getVersion() {
// The version number should be incremented whenever a new rule is added. // The version number should be incremented whenever a new rule is added.
return '17'; return '18';
} }
protected function resolveFuture($path, Future $future) { protected function resolveFuture($path, Future $future) {
@ -312,6 +315,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
'lintCallTimePassByReference' => self::LINT_CALL_TIME_PASS_BY_REF, 'lintCallTimePassByReference' => self::LINT_CALL_TIME_PASS_BY_REF,
'lintFormattedString' => self::LINT_FORMATTED_STRING, 'lintFormattedString' => self::LINT_FORMATTED_STRING,
'lintUnnecessaryFinalModifier' => self::LINT_UNNECESSARY_FINAL_MODIFIER, 'lintUnnecessaryFinalModifier' => self::LINT_UNNECESSARY_FINAL_MODIFIER,
'lintUnnecessarySemicolons' => self::LINT_UNNECESSARY_SEMICOLON,
); );
foreach ($method_codes as $method => $codes) { foreach ($method_codes as $method => $codes) {
@ -3229,6 +3233,24 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
} }
} }
private function lintUnnecessarySemicolons(XHPASTNode $root) {
$statements = $root->selectDescendantsOfType('n_STATEMENT');
foreach ($statements as $statement) {
if ($statement->getParentNode()->getTypeName() == 'n_DECLARE') {
continue;
}
if ($statement->getSemanticString() == ';') {
$this->raiseLintAtNode(
$statement,
self::LINT_UNNECESSARY_SEMICOLON,
pht('Unnecessary semicolons after statement.'),
'');
}
}
}
public function getSuperGlobalNames() { public function getSuperGlobalNames() {
return array( return array(
'$GLOBALS', '$GLOBALS',

View file

@ -0,0 +1,11 @@
<?php
final class Foo {};
$x = null;;
~~~~~~~~~~
error:2:13 XHP19
advice:2:19
advice:3:11
~~~~~~~~~~
<?php
final class Foo {}
$x = null;