mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-26 00:32:41 +01:00
Add a linter rule for detecting empty files
Summary: Adds two different linter rules (one general purpose and another PHP specific) to prevent empty files from being added to a repository. For some unknown reason, people seem to like to do this. Test Plan: Added test cases. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: avivey, cburroughs, Korvin Differential Revision: https://secure.phabricator.com/D13881
This commit is contained in:
parent
a5304e472d
commit
6fa2de5ff8
8 changed files with 83 additions and 0 deletions
|
@ -90,6 +90,7 @@ phutil_register_library_map(array(
|
|||
'ArcanistDuplicateSwitchCaseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDuplicateSwitchCaseXHPASTLinterRule.php',
|
||||
'ArcanistDynamicDefineXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDynamicDefineXHPASTLinterRule.php',
|
||||
'ArcanistElseIfUsageXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistElseIfUsageXHPASTLinterRule.php',
|
||||
'ArcanistEmptyFileXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistEmptyFileXHPASTLinterRule.php',
|
||||
'ArcanistEmptyStatementXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistEmptyStatementXHPASTLinterRule.php',
|
||||
'ArcanistEventType' => 'events/constant/ArcanistEventType.php',
|
||||
'ArcanistExitExpressionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistExitExpressionXHPASTLinterRule.php',
|
||||
|
@ -375,6 +376,7 @@ phutil_register_library_map(array(
|
|||
'ArcanistDuplicateSwitchCaseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistDynamicDefineXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistElseIfUsageXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistEmptyFileXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistEmptyStatementXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistEventType' => 'PhutilEventType',
|
||||
'ArcanistExitExpressionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
|
|
|
@ -13,6 +13,7 @@ final class ArcanistTextLinter extends ArcanistLinter {
|
|||
const LINT_TRAILING_WHITESPACE = 6;
|
||||
const LINT_BOF_WHITESPACE = 8;
|
||||
const LINT_EOF_WHITESPACE = 9;
|
||||
const LINT_EMPTY_FILE = 10;
|
||||
|
||||
private $maxLineLength = 80;
|
||||
|
||||
|
@ -85,16 +86,23 @@ final class ArcanistTextLinter extends ArcanistLinter {
|
|||
self::LINT_TRAILING_WHITESPACE => pht('Trailing Whitespace'),
|
||||
self::LINT_BOF_WHITESPACE => pht('Leading Whitespace at BOF'),
|
||||
self::LINT_EOF_WHITESPACE => pht('Trailing Whitespace at EOF'),
|
||||
self::LINT_EMPTY_FILE => pht('Empty File'),
|
||||
);
|
||||
}
|
||||
|
||||
public function lintPath($path) {
|
||||
$this->lintEmptyFile($path);
|
||||
|
||||
if (!strlen($this->getData($path))) {
|
||||
// If the file is empty, don't bother; particularly, don't require
|
||||
// the user to add a newline.
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->didStopAllLinters()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->lintNewlines($path);
|
||||
$this->lintTabs($path);
|
||||
|
||||
|
@ -116,6 +124,29 @@ final class ArcanistTextLinter extends ArcanistLinter {
|
|||
$this->lintEOFWhitespace($path);
|
||||
}
|
||||
|
||||
protected function lintEmptyFile($path) {
|
||||
$data = $this->getData($path);
|
||||
|
||||
// It is reasonable for certain file types to be completely empty,
|
||||
// so they are excluded here.
|
||||
switch ($filename = basename($this->getActivePath())) {
|
||||
case '__init__.py':
|
||||
return;
|
||||
|
||||
default:
|
||||
if (strlen($filename) && $filename[0] == '.') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('/^\s*$/', $data)) {
|
||||
$this->raiseLintAtPath(
|
||||
self::LINT_EMPTY_FILE,
|
||||
pht("Empty files usually don't serve any useful purpose."));
|
||||
$this->stopAllLinters();
|
||||
}
|
||||
}
|
||||
|
||||
protected function lintNewlines($path) {
|
||||
$data = $this->getData($path);
|
||||
$pos = strpos($this->getData($path), "\r");
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
|
||||
|
||||
~~~~~~~~~~
|
||||
error::
|
3
src/lint/linter/__tests__/xhpast/empty.lint-test
Normal file
3
src/lint/linter/__tests__/xhpast/empty.lint-test
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php ?>
|
||||
~~~~~~~~~~
|
||||
warning::
|
4
src/lint/linter/__tests__/xhpast/not-empty.lint-test
Normal file
4
src/lint/linter/__tests__/xhpast/not-empty.lint-test
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
|
||||
// This file is not empty.
|
||||
~~~~~~~~~~
|
|
@ -1,6 +1,7 @@
|
|||
<?
|
||||
|
||||
~~~~~~~~~~
|
||||
warning::
|
||||
error:1:1
|
||||
~~~~~~~~~~
|
||||
<?php
|
||||
|
|
|
@ -146,6 +146,10 @@ abstract class ArcanistXHPASTLinterRule extends Phobject {
|
|||
$replace);
|
||||
}
|
||||
|
||||
final protected function raiseLintAtPath($desc) {
|
||||
return $this->linter->raiseLintAtPath($this->getLintID(), $desc);
|
||||
}
|
||||
|
||||
final protected function raiseLintAtToken(
|
||||
XHPASTToken $token,
|
||||
$desc,
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistEmptyFileXHPASTLinterRule
|
||||
extends ArcanistXHPASTLinterRule {
|
||||
|
||||
const ID = 82;
|
||||
|
||||
public function getLintName() {
|
||||
return pht('Empty File');
|
||||
}
|
||||
|
||||
public function getLintSeverity() {
|
||||
return ArcanistLintSeverity::SEVERITY_WARNING;
|
||||
}
|
||||
|
||||
public function process(XHPASTNode $root) {
|
||||
$tokens = $root->getTokens();
|
||||
|
||||
foreach ($tokens as $token) {
|
||||
switch ($token->getTypeName()) {
|
||||
case 'T_OPEN_TAG':
|
||||
case 'T_CLOSE_TAG':
|
||||
case 'T_WHITESPACE':
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->raiseLintAtPath(
|
||||
pht("Empty files usually don't serve any useful purpose."));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue