1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-29 10:12:41 +01:00

(stable) Promote 2015 Week 49

This commit is contained in:
epriestley 2015-12-04 16:15:32 -08:00
commit 05ac4a67e2
33 changed files with 672 additions and 38 deletions

View file

@ -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',

View file

@ -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.
*

View file

@ -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';
}

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}

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

@ -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) {

View file

@ -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'));
}
}
}
}

View file

@ -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')),
'');
}
}
}
}

View file

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

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,11 @@
<?php
final class ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase
extends ArcanistXHPASTLinterRuleTestCase {
public function testLinter() {
$this->executeTestsInDirectory(
dirname(__FILE__).'/hexadecimal-numeric-scalar-casing/');
}
}

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,10 @@
<?php
final class ArcanistPublicPropertyXHPASTLinterRuleTestCase
extends ArcanistXHPASTLinterRuleTestCase {
public function testLinter() {
$this->executeTestsInDirectory(dirname(__FILE__).'/public-property/');
}
}

View file

@ -0,0 +1,11 @@
<?php
final class ArcanistVariableReferenceSpacingXHPASTLinterRuleTestCase
extends ArcanistXHPASTLinterRuleTestCase {
public function testLinter() {
$this->executeTestsInDirectory(
dirname(__FILE__).'/variable-reference-spacing/');
}
}

View file

@ -0,0 +1,5 @@
<?php
0b1;
0B1;
~~~~~~~~~~
warning:3:1

View file

@ -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;

View file

@ -0,0 +1,7 @@
<?php
intval($x / 2) + 1;
~~~~~~~~~~
advice:2:1
~~~~~~~~~~
<?php
(int)($x / 2) + 1;

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);

View file

@ -0,0 +1,12 @@
<?php
0xFF;
0xff;
0XFF;
~~~~~~~~~~
warning:3:1
warning:4:1
~~~~~~~~~~
<?php
0xFF;
0xFF;
0xFF;

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

View file

@ -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
~~~~~~~~~~
~~~~~~~~~~
{

View file

@ -0,0 +1,9 @@
<?php
class SomeClass {
private $x;
protected $y;
public $z;
}
~~~~~~~~~~
advice:6:3

View file

@ -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();

View file

@ -0,0 +1,13 @@
<?php
$x = &$a;
$x = & $b;
$x = &
$c;
~~~~~~~~~~
warning:3:7
warning:4:7
~~~~~~~~~~
<?php
$x = &$a;
$x = &$b;
$x = &$c;

View file

@ -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}"));
}
}

View file

@ -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(),
);
}