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

Add a linter rule to prevent hardcoded class names

Summary: Add a linter rule to advise against the use of hardcoded class names. Hardcoded class names make the code harder to refactor and it is generally preferable to use the `__CLASS__` magic constant instead.

Test Plan: This works, but needs some polish.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin, epriestley

Differential Revision: https://secure.phabricator.com/D12605
This commit is contained in:
Joshua Spence 2015-05-13 06:50:30 +10:00
parent 73aca1f9f0
commit 9090efcb40
2 changed files with 69 additions and 1 deletions

View file

@ -61,6 +61,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
const LINT_INNER_FUNCTION = 59;
const LINT_DEFAULT_PARAMETERS = 60;
const LINT_LOWERCASE_FUNCTIONS = 61;
const LINT_CLASS_NAME_LITERAL = 62;
private $blacklistedFunctions = array();
private $naminghook;
@ -191,6 +192,8 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
=> pht('Default Parameters'),
self::LINT_LOWERCASE_FUNCTIONS
=> pht('Lowercase Functions'),
self::LINT_CLASS_NAME_LITERAL
=> pht('Class Name Literal'),
);
}
@ -240,6 +243,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
self::LINT_INNER_FUNCTION => $warning,
self::LINT_DEFAULT_PARAMETERS => $warning,
self::LINT_LOWERCASE_FUNCTIONS => $advice,
self::LINT_CLASS_NAME_LITERAL => $advice,
);
}
@ -307,7 +311,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
public function getVersion() {
// The version number should be incremented whenever a new rule is added.
return '24';
return '25';
}
protected function resolveFuture($path, Future $future) {
@ -395,6 +399,7 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
'lintInnerFunctions' => self::LINT_INNER_FUNCTION,
'lintDefaultParameters' => self::LINT_DEFAULT_PARAMETERS,
'lintLowercaseFunctions' => self::LINT_LOWERCASE_FUNCTIONS,
'lintClassNameLiteral' => self::LINT_CLASS_NAME_LITERAL,
);
foreach ($method_codes as $method => $codes) {
@ -3727,6 +3732,40 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
}
}
private function lintClassNameLiteral(XHPASTNode $root) {
$class_declarations = $root->selectDescendantsOfType('n_CLASS_DECLARATION');
foreach ($class_declarations as $class_declaration) {
$class_name = $class_declaration
->getChildOfType(1, 'n_CLASS_NAME')
->getConcreteString();
$strings = $class_declaration->selectDescendantsOfType('n_STRING_SCALAR');
foreach ($strings as $string) {
$contents = substr($string->getSemanticString(), 1, -1);
$replacement = null;
if ($contents == $class_name) {
$replacement = '__CLASS__';
}
$regex = '/\b'.preg_quote($class_name, '/').'\b/';
if (!preg_match($regex, $contents)) {
continue;
}
$this->raiseLintAtNode(
$string,
self::LINT_CLASS_NAME_LITERAL,
pht(
"Don't hard-code class names, use %s instead.",
'__CLASS__'),
$replacement);
}
}
}
/**
* Retrieve all calls to some specified function(s).
*

View file

@ -0,0 +1,29 @@
<?php
class MyClass {
public function someMethod() {
return 'MyClass';
}
public function someOtherMethod() {
$x = 'MyClass is awesome';
$y = 'MyClassIsAwesome';
return __CLASS__;
}
}
~~~~~~~~~~
error:2:7
advice:4:12
advice:8:10
~~~~~~~~~~
<?php
class MyClass {
public function someMethod() {
return __CLASS__;
}
public function someOtherMethod() {
$x = 'MyClass is awesome';
$y = 'MyClassIsAwesome';
return __CLASS__;
}
}