mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-26 00:32:41 +01:00
(stable) Promote 2015 Week 49
This commit is contained in:
commit
05ac4a67e2
33 changed files with 672 additions and 38 deletions
|
@ -32,6 +32,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistBaseXHPASTLinter' => 'lint/linter/ArcanistBaseXHPASTLinter.php',
|
||||
'ArcanistBinaryExpressionSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBinaryExpressionSpacingXHPASTLinterRule.php',
|
||||
'ArcanistBinaryExpressionSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBinaryExpressionSpacingXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistBinaryNumericScalarCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBinaryNumericScalarCasingXHPASTLinterRule.php',
|
||||
'ArcanistBinaryNumericScalarCasingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBinaryNumericScalarCasingXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistBlacklistedFunctionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBlacklistedFunctionXHPASTLinterRule.php',
|
||||
'ArcanistBlacklistedFunctionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBlacklistedFunctionXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistBookmarkWorkflow' => 'workflow/ArcanistBookmarkWorkflow.php',
|
||||
|
@ -145,6 +147,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistFlake8LinterTestCase' => 'lint/linter/__tests__/ArcanistFlake8LinterTestCase.php',
|
||||
'ArcanistFormattedStringXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistFormattedStringXHPASTLinterRule.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',
|
||||
'ArcanistGeneratedLinter' => 'lint/linter/ArcanistGeneratedLinter.php',
|
||||
'ArcanistGeneratedLinterTestCase' => 'lint/linter/__tests__/ArcanistGeneratedLinterTestCase.php',
|
||||
|
@ -161,6 +165,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',
|
||||
|
@ -186,6 +192,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',
|
||||
|
@ -282,6 +290,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistPregQuoteMisuseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPregQuoteMisuseXHPASTLinterRule.php',
|
||||
'ArcanistPregQuoteMisuseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPregQuoteMisuseXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistPublicPropertyXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPublicPropertyXHPASTLinterRule.php',
|
||||
'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPublicPropertyXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistPuppetLintLinter' => 'lint/linter/ArcanistPuppetLintLinter.php',
|
||||
'ArcanistPuppetLintLinterTestCase' => 'lint/linter/__tests__/ArcanistPuppetLintLinterTestCase.php',
|
||||
'ArcanistPyFlakesLinter' => 'lint/linter/ArcanistPyFlakesLinter.php',
|
||||
|
@ -371,6 +381,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistUselessOverridingMethodXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUselessOverridingMethodXHPASTLinterRule.php',
|
||||
'ArcanistUselessOverridingMethodXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUselessOverridingMethodXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistUserAbortException' => 'exception/usage/ArcanistUserAbortException.php',
|
||||
'ArcanistVariableReferenceSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistVariableReferenceSpacingXHPASTLinterRule.php',
|
||||
'ArcanistVariableReferenceSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistVariableReferenceSpacingXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistVariableVariableXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistVariableVariableXHPASTLinterRule.php',
|
||||
'ArcanistVariableVariableXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistVariableVariableXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistVersionWorkflow' => 'workflow/ArcanistVersionWorkflow.php',
|
||||
|
@ -426,6 +438,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistBaseXHPASTLinter' => 'ArcanistFutureLinter',
|
||||
'ArcanistBinaryExpressionSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistBinaryExpressionSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistBinaryNumericScalarCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistBinaryNumericScalarCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistBlacklistedFunctionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistBlacklistedFunctionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistBookmarkWorkflow' => 'ArcanistFeatureWorkflow',
|
||||
|
@ -539,6 +553,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistFlake8LinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||
'ArcanistFormattedStringXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistFormattedStringXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistFutureLinter' => 'ArcanistLinter',
|
||||
'ArcanistGeneratedLinter' => 'ArcanistLinter',
|
||||
'ArcanistGeneratedLinterTestCase' => 'ArcanistLinterTestCase',
|
||||
|
@ -555,6 +571,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistHLintLinter' => 'ArcanistExternalLinter',
|
||||
'ArcanistHLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||
'ArcanistHelpWorkflow' => 'ArcanistWorkflow',
|
||||
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistHgClientChannel' => 'PhutilProtocolChannel',
|
||||
'ArcanistHgProxyClient' => 'Phobject',
|
||||
'ArcanistHgProxyServer' => 'Phobject',
|
||||
|
@ -580,6 +598,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistInvalidDefaultParameterXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistInvalidModifiersXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistInvalidModifiersXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistInvalidOctalNumericScalarXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistJSHintLinter' => 'ArcanistExternalLinter',
|
||||
'ArcanistJSHintLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||
'ArcanistJSONLintLinter' => 'ArcanistExternalLinter',
|
||||
|
@ -676,6 +696,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistPlusOperatorOnStringsXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistPregQuoteMisuseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistPregQuoteMisuseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistPublicPropertyXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistPublicPropertyXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistPuppetLintLinter' => 'ArcanistExternalLinter',
|
||||
'ArcanistPuppetLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||
'ArcanistPyFlakesLinter' => 'ArcanistExternalLinter',
|
||||
|
@ -765,6 +787,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistUselessOverridingMethodXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistUselessOverridingMethodXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistUserAbortException' => 'ArcanistUsageException',
|
||||
'ArcanistVariableReferenceSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistVariableReferenceSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistVariableVariableXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistVariableVariableXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistVersionWorkflow' => 'ArcanistWorkflow',
|
||||
|
|
|
@ -57,6 +57,20 @@ abstract class ArcanistLinter extends Phobject {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return arbitrary additional information.
|
||||
*
|
||||
* Linters can use this method to provide arbitrary additional information to
|
||||
* be included in the output of `arc linters`.
|
||||
*
|
||||
* @return map<string, string> A mapping of header to body content for the
|
||||
* additional information sections.
|
||||
* @task info
|
||||
*/
|
||||
public function getAdditionalInformation() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a human-readable linter name.
|
||||
*
|
||||
|
|
|
@ -46,6 +46,29 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter {
|
|||
return pht('Use XHPAST to enforce coding conventions on PHP source files.');
|
||||
}
|
||||
|
||||
public function getAdditionalInformation() {
|
||||
$table = id(new PhutilConsoleTable())
|
||||
->setBorders(true)
|
||||
->addColumn('id', array('title' => pht('ID')))
|
||||
->addColumn('class', array('title' => pht('Class')))
|
||||
->addColumn('name', array('title' => pht('Name')));
|
||||
|
||||
$rules = $this->rules;
|
||||
ksort($rules);
|
||||
|
||||
foreach ($rules as $id => $rule) {
|
||||
$table->addRow(array(
|
||||
'id' => $id,
|
||||
'class' => get_class($rule),
|
||||
'name' => $rule->getLintName(),
|
||||
));
|
||||
}
|
||||
|
||||
return array(
|
||||
pht('Linter Rules') => $table->drawConsoleString(),
|
||||
);
|
||||
}
|
||||
|
||||
public function getLinterName() {
|
||||
return 'XHP';
|
||||
}
|
||||
|
|
|
@ -237,6 +237,7 @@ abstract class ArcanistXHPASTLinterRule extends Phobject {
|
|||
|
||||
switch ($modifier_list->getTypeName()) {
|
||||
case 'n_CLASS_ATTRIBUTES':
|
||||
case 'n_CLASS_MEMBER_MODIFIER_LIST':
|
||||
case 'n_METHOD_MODIFIER_LIST':
|
||||
break;
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistBinaryNumericScalarCasingXHPASTLinterRule
|
||||
extends ArcanistXHPASTLinterRule {
|
||||
|
||||
const ID = 131;
|
||||
|
||||
public function getLintName() {
|
||||
return pht('Binary Integer Casing');
|
||||
}
|
||||
|
||||
public function getLintSeverity() {
|
||||
return ArcanistLintSeverity::SEVERITY_WARNING;
|
||||
}
|
||||
|
||||
public function process(XHPASTNode $root) {
|
||||
$binaries = $this->getBinaryNumericScalars($root);
|
||||
|
||||
foreach ($binaries as $binary) {
|
||||
$value = substr($binary->getConcreteString(), 2);
|
||||
|
||||
if (!preg_match('/^0b[01]+$/', $binary->getConcreteString())) {
|
||||
$this->raiseLintAtNode(
|
||||
$binary,
|
||||
pht(
|
||||
'For consistency, write binary integers with a leading `%s`.',
|
||||
'0b'),
|
||||
'0b'.$value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getBinaryNumericScalars(XHPASTNode $root) {
|
||||
$numeric_scalars = $root->selectDescendantsOfType('n_NUMERIC_SCALAR');
|
||||
$binary_numeric_scalars = array();
|
||||
|
||||
foreach ($numeric_scalars as $numeric_scalar) {
|
||||
$number = $numeric_scalar->getConcreteString();
|
||||
|
||||
if (preg_match('/^0b[01]+$/i', $number)) {
|
||||
$binary_numeric_scalars[] = $numeric_scalar;
|
||||
}
|
||||
}
|
||||
|
||||
return $binary_numeric_scalars;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<?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;
|
||||
|
||||
if ($cast_functions === null) {
|
||||
$cast_functions = new CaseInsensitiveArray(array(
|
||||
'boolval' => 'bool',
|
||||
'doubleval' => 'double',
|
||||
'floatval' => 'double',
|
||||
'intval' => 'int',
|
||||
'strval' => 'string',
|
||||
));
|
||||
}
|
||||
|
||||
$casts = $this->getFunctionCalls($root, $cast_functions->getKeys());
|
||||
|
||||
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.')';
|
||||
|
||||
if ($parameter->getTypeName() == 'n_BINARY_EXPRESSION') {
|
||||
$replacement .= '('.$parameter->getConcreteString().')';
|
||||
} else {
|
||||
$replacement .= $parameter->getConcreteString();
|
||||
}
|
||||
}
|
||||
|
||||
if (strtolower($function_name) == 'intval') {
|
||||
if (count($parameters->getChildren()) >= 2) {
|
||||
$base = $parameters->getChildByIndex(1);
|
||||
|
||||
if ($base->getTypeName() != 'n_NUMERIC_SCALAR') {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($base->getConcreteString() != '10') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule
|
||||
extends ArcanistXHPASTLinterRule {
|
||||
|
||||
const ID = 127;
|
||||
|
||||
public function getLintName() {
|
||||
return pht('Hexadecimal Integer Casing');
|
||||
}
|
||||
|
||||
public function getLintSeverity() {
|
||||
return ArcanistLintSeverity::SEVERITY_WARNING;
|
||||
}
|
||||
|
||||
public function process(XHPASTNode $root) {
|
||||
$hexadecimals = $this->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 integers '.
|
||||
'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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -414,6 +414,16 @@ final class ArcanistPHPCompatibilityXHPASTLinterRule
|
|||
'$this'));
|
||||
}
|
||||
}
|
||||
|
||||
$numeric_scalars = $root->selectDescendantsOfType('n_NUMERIC_SCALAR');
|
||||
foreach ($numeric_scalars as $numeric_scalar) {
|
||||
if (preg_match('/^0b[01]+$/i', $numeric_scalar->getConcreteString())) {
|
||||
$this->raiseLintAtNode(
|
||||
$numeric_scalar,
|
||||
pht(
|
||||
'Binary integer literals are not available before PHP 5.4.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function lintPHP54Incompatibilities(XHPASTNode $root) {
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistPublicPropertyXHPASTLinterRule
|
||||
extends ArcanistXHPASTLinterRule {
|
||||
|
||||
const ID = 130;
|
||||
|
||||
public function getLintName() {
|
||||
return pht('Use of `%s` Properties', 'public');
|
||||
}
|
||||
|
||||
public function getLintSeverity() {
|
||||
return ArcanistLintSeverity::SEVERITY_ADVICE;
|
||||
}
|
||||
|
||||
public function process(XHPASTNode $root) {
|
||||
$members = $root->selectDescendantsOfType(
|
||||
'n_CLASS_MEMBER_DECLARATION_LIST');
|
||||
|
||||
foreach ($members as $member) {
|
||||
$modifiers = $this->getModifiers($member);
|
||||
|
||||
if (isset($modifiers['public'])) {
|
||||
$this->raiseLintAtNode(
|
||||
$member,
|
||||
pht(
|
||||
'`%s` properties should be avoided. Instead of exposing '.
|
||||
'the property value directly, consider using getter '.
|
||||
'and setter methods.',
|
||||
'public'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistVariableReferenceSpacingXHPASTLinterRule
|
||||
extends ArcanistXHPASTLinterRule {
|
||||
|
||||
const ID = 123;
|
||||
|
||||
public function getLintName() {
|
||||
return pht('Variable Reference Spacing');
|
||||
}
|
||||
|
||||
public function getLintSeverity() {
|
||||
return ArcanistLintSeverity::SEVERITY_WARNING;
|
||||
}
|
||||
|
||||
public function process(XHPASTNode $root) {
|
||||
$references = $root->selectDescendantsOfType('n_VARIABLE_REFERENCE');
|
||||
|
||||
foreach ($references as $reference) {
|
||||
$variable = $reference->getChildByIndex(0);
|
||||
|
||||
list($before, $after) = $variable->getSurroundingNonsemanticTokens();
|
||||
|
||||
if ($before) {
|
||||
$this->raiseLintAtOffset(
|
||||
head($before)->getOffset(),
|
||||
pht('Variable references should not be prefixed with whitespace.'),
|
||||
implode('', mpull($before, 'getValue')),
|
||||
'');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistBinaryNumericScalarCasingXHPASTLinterRuleTestCase
|
||||
extends ArcanistXHPASTLinterRuleTestCase {
|
||||
|
||||
public function testLinter() {
|
||||
$this->executeTestsInDirectory(
|
||||
dirname(__FILE__).'/binary-numeric-scalar-casing/');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistFunctionCallShouldBeTypeCastXHPASTLinterRuleTestCase
|
||||
extends ArcanistXHPASTLinterRuleTestCase {
|
||||
|
||||
public function testLinter() {
|
||||
$this->executeTestsInDirectory(
|
||||
dirname(__FILE__).'/function-call-should-be-type-cast/');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase
|
||||
extends ArcanistXHPASTLinterRuleTestCase {
|
||||
|
||||
public function testLinter() {
|
||||
$this->executeTestsInDirectory(
|
||||
dirname(__FILE__).'/hexadecimal-numeric-scalar-casing/');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistInvalidOctalNumericScalarXHPASTLinterRuleTestCase
|
||||
extends ArcanistXHPASTLinterRuleTestCase {
|
||||
|
||||
public function testLinter() {
|
||||
$this->executeTestsInDirectory(
|
||||
dirname(__FILE__).'/invalid-octal-numeric-scalar/');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistPublicPropertyXHPASTLinterRuleTestCase
|
||||
extends ArcanistXHPASTLinterRuleTestCase {
|
||||
|
||||
public function testLinter() {
|
||||
$this->executeTestsInDirectory(dirname(__FILE__).'/public-property/');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistVariableReferenceSpacingXHPASTLinterRuleTestCase
|
||||
extends ArcanistXHPASTLinterRuleTestCase {
|
||||
|
||||
public function testLinter() {
|
||||
$this->executeTestsInDirectory(
|
||||
dirname(__FILE__).'/variable-reference-spacing/');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
0b1;
|
||||
0B1;
|
||||
~~~~~~~~~~
|
||||
warning:3:1
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
intval($x);
|
||||
intval($x, 8);
|
||||
intval($x, 10);
|
||||
~~~~~~~~~~
|
||||
advice:2:1
|
||||
advice:4:1
|
||||
~~~~~~~~~~
|
||||
<?php
|
||||
(int)$x;
|
||||
intval($x, 8);
|
||||
(int)$x;
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
intval($x / 2) + 1;
|
||||
~~~~~~~~~~
|
||||
advice:2:1
|
||||
~~~~~~~~~~
|
||||
<?php
|
||||
(int)($x / 2) + 1;
|
|
@ -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;
|
|
@ -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);
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
0xFF;
|
||||
0xff;
|
||||
0XFF;
|
||||
~~~~~~~~~~
|
||||
warning:3:1
|
||||
warning:4:1
|
||||
~~~~~~~~~~
|
||||
<?php
|
||||
0xFF;
|
||||
0xFF;
|
||||
0xFF;
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
0b01;
|
||||
~~~~~~~~
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
0;
|
||||
123;
|
||||
0.9;
|
||||
~~~~~~~~~~
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
0xFf;
|
||||
0XFf;
|
||||
~~~~~~~~
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
01234567;
|
||||
08;
|
||||
-08;
|
||||
~~~~~~~~
|
||||
error:3:1
|
||||
error:4:2
|
|
@ -20,11 +20,14 @@ final class SomeClass extends Phobject {
|
|||
}
|
||||
}
|
||||
|
||||
0b1;
|
||||
|
||||
~~~~~~~~~~
|
||||
error:3:5
|
||||
error:4:9
|
||||
error:12:7
|
||||
error:18:7
|
||||
error:23:1
|
||||
~~~~~~~~~~
|
||||
~~~~~~~~~~
|
||||
{
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
class SomeClass {
|
||||
private $x;
|
||||
protected $y;
|
||||
public $z;
|
||||
}
|
||||
~~~~~~~~~~
|
||||
advice:6:3
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
$x = &some_function();
|
||||
$x = & some_function();
|
||||
$x = &
|
||||
some_function();
|
||||
~~~~~~~~~~
|
||||
warning:3:7
|
||||
warning:4:7
|
||||
~~~~~~~~~~
|
||||
<?php
|
||||
$x = &some_function();
|
||||
$x = &some_function();
|
||||
$x = &some_function();
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
$x = &$a;
|
||||
$x = & $b;
|
||||
$x = &
|
||||
$c;
|
||||
~~~~~~~~~~
|
||||
warning:3:7
|
||||
warning:4:7
|
||||
~~~~~~~~~~
|
||||
<?php
|
||||
$x = &$a;
|
||||
$x = &$b;
|
||||
$x = &$c;
|
|
@ -83,54 +83,42 @@ EOTEXT
|
|||
|
||||
$argv = $this->getArgument('argv');
|
||||
if (count($argv) == 0) {
|
||||
if ($aliases) {
|
||||
foreach ($aliases as $alias => $binding) {
|
||||
echo phutil_console_format(
|
||||
"**%s** %s\n",
|
||||
$alias,
|
||||
implode(' ' , $binding));
|
||||
}
|
||||
} else {
|
||||
echo pht("You haven't defined any aliases yet.")."\n";
|
||||
}
|
||||
$this->printAliases($aliases);
|
||||
} else if (count($argv) == 1) {
|
||||
if (empty($aliases[$argv[0]])) {
|
||||
echo pht("No alias '%s' to remove.", $argv[0])."\n";
|
||||
} else {
|
||||
echo pht(
|
||||
"'%s' is currently aliased to '%s'.",
|
||||
phutil_console_format('**arc %s**', $argv[0]),
|
||||
phutil_console_format(
|
||||
'**arc %s**',
|
||||
implode(' ', $aliases[$argv[0]])));
|
||||
$ok = phutil_console_confirm(pht('Delete this alias?'));
|
||||
if ($ok) {
|
||||
$was = implode(' ', $aliases[$argv[0]]);
|
||||
unset($aliases[$argv[0]]);
|
||||
$this->writeAliases($aliases);
|
||||
echo pht("Unaliased '%s' (was '%s').", $argv[0], $was)."\n";
|
||||
} else {
|
||||
throw new ArcanistUserAbortException();
|
||||
}
|
||||
}
|
||||
$this->removeAlias($aliases, $argv[0]);
|
||||
} else {
|
||||
$arc_config = $this->getArcanistConfiguration();
|
||||
$alias = $argv[0];
|
||||
|
||||
if ($arc_config->buildWorkflow($argv[0])) {
|
||||
if ($arc_config->buildWorkflow($alias)) {
|
||||
throw new ArcanistUsageException(
|
||||
pht(
|
||||
"You can not create an alias for '%s' because it is a ".
|
||||
"builtin command. '%s' can only create new commands.",
|
||||
$argv[0],
|
||||
'You can not create an alias for "%s" because it is a '.
|
||||
'builtin command. "%s" can only create new commands.',
|
||||
"arc {$alias}",
|
||||
'arc alias'));
|
||||
}
|
||||
|
||||
$aliases[$argv[0]] = array_slice($argv, 1);
|
||||
echo pht(
|
||||
"Aliased '%s' to '%s'.\n",
|
||||
phutil_console_format('**arc %s**', $argv[0]),
|
||||
phutil_console_format('**arc %s**', implode(' ', $aliases[$argv[0]])));
|
||||
$new_alias = array_slice($argv, 1);
|
||||
|
||||
$command = implode(' ', $new_alias);
|
||||
if (self::isShellCommandAlias($command)) {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Aliased "%s" to shell command "%s".',
|
||||
"arc {$alias}",
|
||||
substr($command, 1)));
|
||||
} else {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Aliased "%s" to "%s".',
|
||||
"arc {$alias}",
|
||||
"arc {$command}"));
|
||||
}
|
||||
|
||||
$aliases[$alias] = $new_alias;
|
||||
$this->writeAliases($aliases);
|
||||
}
|
||||
|
||||
|
@ -173,4 +161,83 @@ EOTEXT
|
|||
return array($new_command, $argv);
|
||||
}
|
||||
|
||||
private function printAliases(array $aliases) {
|
||||
if (!$aliases) {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht('You have not defined any aliases yet.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$table = id(new PhutilConsoleTable())
|
||||
->addColumn('input', array('title' => pht('Alias')))
|
||||
->addColumn('command', array('title' => pht('Command')))
|
||||
->addColumn('type', array('title' => pht('Type')));
|
||||
|
||||
ksort($aliases);
|
||||
|
||||
foreach ($aliases as $alias => $binding) {
|
||||
$command = implode(' ', $binding);
|
||||
if (self::isShellCommandAlias($command)) {
|
||||
$command = substr($command, 1);
|
||||
$type = pht('Shell Command');
|
||||
} else {
|
||||
$command = "arc {$command}";
|
||||
$type = pht('Arcanist Command');
|
||||
}
|
||||
|
||||
$row = array(
|
||||
'input' => "arc {$alias}",
|
||||
'type' => $type,
|
||||
'command' => $command,
|
||||
);
|
||||
|
||||
$table->addRow($row);
|
||||
}
|
||||
|
||||
$table->draw();
|
||||
}
|
||||
|
||||
private function removeAlias(array $aliases, $alias) {
|
||||
if (empty($aliases[$alias])) {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht('No alias "%s" to remove.', $alias));
|
||||
return;
|
||||
}
|
||||
|
||||
$command = implode(' ', $aliases[$alias]);
|
||||
|
||||
if (self::isShellCommandAlias($command)) {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'"%s" is currently aliased to shell command "%s".',
|
||||
"arc {$alias}",
|
||||
substr($command, 1)));
|
||||
} else {
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'"%s" is currently aliased to "%s".',
|
||||
"arc {$alias}",
|
||||
"arc {$command}"));
|
||||
}
|
||||
|
||||
|
||||
$ok = phutil_console_confirm(pht('Delete this alias?'));
|
||||
if (!$ok) {
|
||||
throw new ArcanistUserAbortException();
|
||||
}
|
||||
|
||||
unset($aliases[$alias]);
|
||||
$this->writeAliases($aliases);
|
||||
|
||||
echo tsprintf(
|
||||
"%s\n",
|
||||
pht(
|
||||
'Removed alias "%s".',
|
||||
"arc {$alias}"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ EOTEXT
|
|||
|
||||
if ($exact) {
|
||||
$linter_info = $this->findExactNames($linter_info, $exact);
|
||||
|
||||
if (!$linter_info) {
|
||||
$console->writeOut(
|
||||
"%s\n",
|
||||
|
@ -170,6 +171,18 @@ EOTEXT
|
|||
$print_tail = true;
|
||||
}
|
||||
|
||||
$additional = $linter['additional'];
|
||||
foreach ($additional as $title => $body) {
|
||||
$console->writeOut(
|
||||
"\n%s**%s**\n\n",
|
||||
$pad,
|
||||
$title);
|
||||
|
||||
// TODO: This should maybe use `tsprintf`.
|
||||
// See some discussion in D14563.
|
||||
echo $body;
|
||||
}
|
||||
|
||||
if ($print_tail) {
|
||||
$console->writeOut("\n");
|
||||
}
|
||||
|
@ -250,6 +263,7 @@ EOTEXT
|
|||
'description' => $linter->getInfoDescription(),
|
||||
'exception' => $exception,
|
||||
'options' => $linter->getLinterConfigurationOptions(),
|
||||
'additional' => $linter->getAdditionalInformation(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue