1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2025-01-10 23:01:04 +01:00

Add a linter rule for invalid octals

Summary: PHP doesn't handle octals very well. Basically, it seems that any numeric scalar matching `/^0\d+$/` will be treated as an octal, whereas this should be `/^0[0-7]+$/`. As a result, `08` and `09` are both treated as `0` (because they are invalid octals. This diff adds a linter rule to detect this abnormality.

Test Plan: Added unit tests.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: epriestley

Differential Revision: https://secure.phabricator.com/D14604
This commit is contained in:
Joshua Spence 2015-12-03 08:11:22 +11:00
parent 8ed3c45c82
commit 560e4ae491
7 changed files with 78 additions and 0 deletions

View file

@ -190,6 +190,8 @@ phutil_register_library_map(array(
'ArcanistInvalidDefaultParameterXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInvalidDefaultParameterXHPASTLinterRuleTestCase.php',
'ArcanistInvalidModifiersXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInvalidModifiersXHPASTLinterRule.php',
'ArcanistInvalidModifiersXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInvalidModifiersXHPASTLinterRuleTestCase.php',
'ArcanistInvalidOctalNumericScalarXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInvalidOctalNumericScalarXHPASTLinterRule.php',
'ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase.php',
'ArcanistJSHintLinter' => 'lint/linter/ArcanistJSHintLinter.php',
'ArcanistJSHintLinterTestCase' => 'lint/linter/__tests__/ArcanistJSHintLinterTestCase.php',
'ArcanistJSONLintLinter' => 'lint/linter/ArcanistJSONLintLinter.php',
@ -590,6 +592,8 @@ phutil_register_library_map(array(
'ArcanistInvalidDefaultParameterXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInvalidModifiersXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInvalidModifiersXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInvalidOctalNumericScalarXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistJSHintLinter' => 'ArcanistExternalLinter',
'ArcanistJSHintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistJSONLintLinter' => 'ArcanistExternalLinter',

View file

@ -0,0 +1,44 @@
<?php
final class ArcanistInvalidOctalNumericScalarXHPASTLinterRule
extends ArcanistXHPASTLinterRule {
const ID = 125;
public function getLintName() {
return pht('Invalid Octal Numeric Scalar');
}
public function process(XHPASTNode $root) {
$octals = $this->getOctalNumericScalars($root);
foreach ($octals as $octal) {
if (!preg_match('/^0[0-7]*$/', $octal->getConcreteString())) {
$this->raiseLintAtNode(
$octal,
pht(
'Invalid octal numeric scalar. `%s` is not a '.
'valid octal and will be interpreted as `%d`.',
$octal->getConcreteString(),
intval($octal->getConcreteString(), 8)));
}
}
}
private function getOctalNumericScalars(XHPASTNode $root) {
$numeric_scalars = $root->selectDescendantsOfType('n_NUMERIC_SCALAR');
$octal_numeric_scalars = array();
foreach ($numeric_scalars as $numeric_scalar) {
$number = $numeric_scalar->getConcreteString();
if (preg_match('/^0\d+$/', $number)) {
$octal_numeric_scalars[] = $numeric_scalar;
}
}
return $octal_numeric_scalars;
}
}

View file

@ -0,0 +1,11 @@
<?php
final class ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase
extends ArcanistXHPASTLinterRuleTestCase {
public function testLinter() {
$this->executeTestsInDirectory(
dirname(__FILE__).'/invalid-octal-numeric-scalar/');
}
}

View file

@ -0,0 +1,3 @@
<?php
0b01;
~~~~~~~~

View file

@ -0,0 +1,5 @@
<?php
0;
123;
0.9;
~~~~~~~~~~

View file

@ -0,0 +1,4 @@
<?php
0xFf;
0XFf;
~~~~~~~~

View file

@ -0,0 +1,7 @@
<?php
01234567;
08;
-08;
~~~~~~~~
error:3:1
error:4:2