diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 218a1fa9..3c859155 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -163,6 +163,8 @@ phutil_register_library_map(array( 'ArcanistHLintLinter' => 'lint/linter/ArcanistHLintLinter.php', 'ArcanistHLintLinterTestCase' => 'lint/linter/__tests__/ArcanistHLintLinterTestCase.php', 'ArcanistHelpWorkflow' => 'workflow/ArcanistHelpWorkflow.php', + 'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule.php', + 'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase.php', 'ArcanistHgClientChannel' => 'hgdaemon/ArcanistHgClientChannel.php', 'ArcanistHgProxyClient' => 'hgdaemon/ArcanistHgProxyClient.php', 'ArcanistHgProxyServer' => 'hgdaemon/ArcanistHgProxyServer.php', @@ -561,6 +563,8 @@ phutil_register_library_map(array( 'ArcanistHLintLinter' => 'ArcanistExternalLinter', 'ArcanistHLintLinterTestCase' => 'ArcanistExternalLinterTestCase', 'ArcanistHelpWorkflow' => 'ArcanistWorkflow', + 'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', + 'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistHgClientChannel' => 'PhutilProtocolChannel', 'ArcanistHgProxyClient' => 'Phobject', 'ArcanistHgProxyServer' => 'Phobject', diff --git a/src/lint/linter/xhpast/rules/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule.php new file mode 100644 index 00000000..790526a4 --- /dev/null +++ b/src/lint/linter/xhpast/rules/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule.php @@ -0,0 +1,50 @@ +getHexadecimalNumericScalars($root); + + foreach ($hexadecimals as $hexadecimal) { + $value = substr($hexadecimal->getConcreteString(), 2); + + if (!preg_match('/^0x[0-9A-F]+$/', $hexadecimal->getConcreteString())) { + $this->raiseLintAtNode( + $hexadecimal, + pht( + 'For consistency, write hexadecimals in uppercase '. + 'with a leading `%s`.', + '0x'), + '0x'.strtoupper($value)); + } + } + } + + private function getHexadecimalNumericScalars(XHPASTNode $root) { + $numeric_scalars = $root->selectDescendantsOfType('n_NUMERIC_SCALAR'); + $hexadecimal_numeric_scalars = array(); + + foreach ($numeric_scalars as $numeric_scalar) { + $number = $numeric_scalar->getConcreteString(); + + if (preg_match('/^0x[0-9A-F]+$/i', $number)) { + $hexadecimal_numeric_scalars[] = $numeric_scalar; + } + } + + return $hexadecimal_numeric_scalars; + + } + +} diff --git a/src/lint/linter/xhpast/rules/__tests__/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase.php b/src/lint/linter/xhpast/rules/__tests__/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase.php new file mode 100644 index 00000000..f73d2b02 --- /dev/null +++ b/src/lint/linter/xhpast/rules/__tests__/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase.php @@ -0,0 +1,11 @@ +executeTestsInDirectory( + dirname(__FILE__).'/hexadecimal-numeric-scalar-casing/'); + } + +} diff --git a/src/lint/linter/xhpast/rules/__tests__/hexadecimal-numeric-scalar-casing/hexadecimal.lint-test b/src/lint/linter/xhpast/rules/__tests__/hexadecimal-numeric-scalar-casing/hexadecimal.lint-test new file mode 100644 index 00000000..aae5eec7 --- /dev/null +++ b/src/lint/linter/xhpast/rules/__tests__/hexadecimal-numeric-scalar-casing/hexadecimal.lint-test @@ -0,0 +1,12 @@ +