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

Add a linter rule for *val functions

Summary: Type casts should be used instead of calls to the `*val` functions as function calls impose additional overhead.

Test Plan: Added unit tests.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin

Differential Revision: https://secure.phabricator.com/D14572
This commit is contained in:
Joshua Spence 2015-11-30 07:32:43 +11:00
parent 4f1141d0c5
commit 578f540a92
5 changed files with 99 additions and 0 deletions

View file

@ -145,6 +145,8 @@ phutil_register_library_map(array(
'ArcanistFlake8LinterTestCase' => 'lint/linter/__tests__/ArcanistFlake8LinterTestCase.php', 'ArcanistFlake8LinterTestCase' => 'lint/linter/__tests__/ArcanistFlake8LinterTestCase.php',
'ArcanistFormattedStringXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistFormattedStringXHPASTLinterRule.php', 'ArcanistFormattedStringXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistFormattedStringXHPASTLinterRule.php',
'ArcanistFormattedStringXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistFormattedStringXHPASTLinterRuleTestCase.php', 'ArcanistFormattedStringXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistFormattedStringXHPASTLinterRuleTestCase.php',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRule.php',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase.php',
'ArcanistFutureLinter' => 'lint/linter/ArcanistFutureLinter.php', 'ArcanistFutureLinter' => 'lint/linter/ArcanistFutureLinter.php',
'ArcanistGeneratedLinter' => 'lint/linter/ArcanistGeneratedLinter.php', 'ArcanistGeneratedLinter' => 'lint/linter/ArcanistGeneratedLinter.php',
'ArcanistGeneratedLinterTestCase' => 'lint/linter/__tests__/ArcanistGeneratedLinterTestCase.php', 'ArcanistGeneratedLinterTestCase' => 'lint/linter/__tests__/ArcanistGeneratedLinterTestCase.php',
@ -539,6 +541,8 @@ phutil_register_library_map(array(
'ArcanistFlake8LinterTestCase' => 'ArcanistExternalLinterTestCase', 'ArcanistFlake8LinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistFormattedStringXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistFormattedStringXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistFormattedStringXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistFormattedStringXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistFutureLinter' => 'ArcanistLinter', 'ArcanistFutureLinter' => 'ArcanistLinter',
'ArcanistGeneratedLinter' => 'ArcanistLinter', 'ArcanistGeneratedLinter' => 'ArcanistLinter',
'ArcanistGeneratedLinterTestCase' => 'ArcanistLinterTestCase', 'ArcanistGeneratedLinterTestCase' => 'ArcanistLinterTestCase',

View file

@ -0,0 +1,54 @@
<?php
final class ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRule
extends ArcanistXHPASTLinterRule {
const ID = 105;
public function getLintName() {
return pht('Function Call Should Be Type Cast');
}
public function getLintSeverity() {
return ArcanistLintSeverity::SEVERITY_ADVICE;
}
public function process(XHPASTNode $root) {
static $cast_functions = array(
'boolval' => 'bool',
'doubleval' => 'double',
'floatval' => 'double',
'intval' => 'int',
'strval' => 'string',
);
$casts = $this->getFunctionCalls($root, array_keys($cast_functions));
foreach ($casts as $cast) {
$function_name = $cast
->getChildOfType(0, 'n_SYMBOL_NAME')
->getConcreteString();
$cast_name = $cast_functions[$function_name];
$parameters = $cast->getChildOfType(1, 'n_CALL_PARAMETER_LIST');
$replacement = null;
// Only suggest a replacement if the function call has exactly
// one parameter.
if (count($parameters->getChildren()) == 1) {
$parameter = $parameters->getChildByIndex(0);
$replacement = '('.$cast_name.')'.$parameter->getConcreteString();
}
$this->raiseLintAtNode(
$cast,
pht(
'For consistency, use `%s` (a type cast) instead of `%s` '.
'(a function call). Function calls impose additional overhead.',
'('.$cast_name.')',
$function_name),
$replacement);
}
}
}

View file

@ -0,0 +1,11 @@
<?php
final class ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase
extends ArcanistXHPASTLinterRuleTestCase {
public function testLinter() {
$this->executeTestsInDirectory(
dirname(__FILE__).'/function-call-should-be-type-cast/');
}
}

View file

@ -0,0 +1,19 @@
<?php
boolval($x);
doubleval($x);
floatval($x);
intval($x);
strval($x);
~~~~~~~~~~
advice:2:1
advice:3:1
advice:4:1
advice:5:1
advice:6:1
~~~~~~~~~~
<?php
(bool)$x;
(double)$x;
(double)$x;
(int)$x;
(string)$x;

View file

@ -0,0 +1,11 @@
<?php
// If the function call doesn't have exactly one parameter,
// we don't provide an autofix.
strval($x, $y);
~~~~~~~~~~
advice:4:1
~~~~~~~~~~
<?php
// If the function call doesn't have exactly one parameter,
// we don't provide an autofix.
strval($x, $y);