1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2025-01-19 19:21:09 +01:00

(stable) Promote 2015 Week 32

This commit is contained in:
epriestley 2015-08-08 08:02:40 -07:00
commit 1e5059f16a
21 changed files with 324 additions and 29 deletions

View file

@ -32,6 +32,7 @@ phutil_register_library_map(array(
'ArcanistCSSLintLinterTestCase' => 'lint/linter/__tests__/ArcanistCSSLintLinterTestCase.php',
'ArcanistCSharpLinter' => 'lint/linter/ArcanistCSharpLinter.php',
'ArcanistCallConduitWorkflow' => 'workflow/ArcanistCallConduitWorkflow.php',
'ArcanistCallParenthesesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCallParenthesesXHPASTLinterRule.php',
'ArcanistCallTimePassByReferenceXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCallTimePassByReferenceXHPASTLinterRule.php',
'ArcanistCapabilityNotSupportedException' => 'workflow/exception/ArcanistCapabilityNotSupportedException.php',
'ArcanistCastSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCastSpacingXHPASTLinterRule.php',
@ -42,7 +43,6 @@ phutil_register_library_map(array(
'ArcanistClassNameLiteralXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistClassNameLiteralXHPASTLinterRule.php',
'ArcanistCloseRevisionWorkflow' => 'workflow/ArcanistCloseRevisionWorkflow.php',
'ArcanistCloseWorkflow' => 'workflow/ArcanistCloseWorkflow.php',
'ArcanistClosingCallParenthesesXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistClosingCallParenthesesXHPASTLinterRule.php',
'ArcanistClosureLinter' => 'lint/linter/ArcanistClosureLinter.php',
'ArcanistClosureLinterTestCase' => 'lint/linter/__tests__/ArcanistClosureLinterTestCase.php',
'ArcanistCoffeeLintLinter' => 'lint/linter/ArcanistCoffeeLintLinter.php',
@ -171,6 +171,7 @@ phutil_register_library_map(array(
'ArcanistNoLintLinterTestCase' => 'lint/linter/__tests__/ArcanistNoLintLinterTestCase.php',
'ArcanistNoParentScopeXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNoParentScopeXHPASTLinterRule.php',
'ArcanistNoneLintRenderer' => 'lint/renderer/ArcanistNoneLintRenderer.php',
'ArcanistObjectOperatorSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistObjectOperatorSpacingXHPASTLinterRule.php',
'ArcanistPEP8Linter' => 'lint/linter/ArcanistPEP8Linter.php',
'ArcanistPEP8LinterTestCase' => 'lint/linter/__tests__/ArcanistPEP8LinterTestCase.php',
'ArcanistPHPCloseTagXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPCloseTagXHPASTLinterRule.php',
@ -237,6 +238,8 @@ phutil_register_library_map(array(
'ArcanistTodoWorkflow' => 'workflow/ArcanistTodoWorkflow.php',
'ArcanistUSEnglishTranslation' => 'internationalization/ArcanistUSEnglishTranslation.php',
'ArcanistUnableToParseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnableToParseXHPASTLinterRule.php',
'ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRule.php',
'ArcanistUnaryPrefixExpressionSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnaryPrefixExpressionSpacingXHPASTLinterRule.php',
'ArcanistUndeclaredVariableXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUndeclaredVariableXHPASTLinterRule.php',
'ArcanistUnitConsoleRenderer' => 'unit/renderer/ArcanistUnitConsoleRenderer.php',
'ArcanistUnitRenderer' => 'unit/renderer/ArcanistUnitRenderer.php',
@ -305,6 +308,7 @@ phutil_register_library_map(array(
'ArcanistCSSLintLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCSharpLinter' => 'ArcanistLinter',
'ArcanistCallConduitWorkflow' => 'ArcanistWorkflow',
'ArcanistCallParenthesesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCallTimePassByReferenceXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCapabilityNotSupportedException' => 'Exception',
'ArcanistCastSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
@ -315,7 +319,6 @@ phutil_register_library_map(array(
'ArcanistClassNameLiteralXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCloseRevisionWorkflow' => 'ArcanistWorkflow',
'ArcanistCloseWorkflow' => 'ArcanistWorkflow',
'ArcanistClosingCallParenthesesXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistClosureLinter' => 'ArcanistExternalLinter',
'ArcanistClosureLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistCoffeeLintLinter' => 'ArcanistExternalLinter',
@ -444,6 +447,7 @@ phutil_register_library_map(array(
'ArcanistNoLintLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistNoParentScopeXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistNoneLintRenderer' => 'ArcanistLintRenderer',
'ArcanistObjectOperatorSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistPEP8Linter' => 'ArcanistExternalLinter',
'ArcanistPEP8LinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistPHPCloseTagXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
@ -510,6 +514,8 @@ phutil_register_library_map(array(
'ArcanistTodoWorkflow' => 'ArcanistWorkflow',
'ArcanistUSEnglishTranslation' => 'PhutilTranslation',
'ArcanistUnableToParseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUnaryPrefixExpressionSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUndeclaredVariableXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistUnitConsoleRenderer' => 'ArcanistUnitRenderer',
'ArcanistUnitRenderer' => 'Phobject',

View file

@ -72,24 +72,7 @@ final class ArcanistLintMessage extends Phobject {
}
public function setLine($line) {
if ($line === null) {
// This just means that we don't have any line information.
} else {
// For compatibility, accept digit strings since a lot of linters pass
// line numbers that they have parsed from command output or XML, which
// won't be properly typed.
if (is_string($line) && preg_match('/^\d+\z/', $line)) {
$line = (int)$line;
}
if (!is_int($line)) {
throw new Exception(
pht(
'Parameter passed to setLine() must be an integer.'));
}
}
$this->line = $line;
$this->line = $this->validateInteger($line, 'setLine');
return $this;
}
@ -98,7 +81,7 @@ final class ArcanistLintMessage extends Phobject {
}
public function setChar($char) {
$this->char = $char;
$this->char = $this->validateInteger($char, 'setChar');
return $this;
}
@ -242,4 +225,35 @@ final class ArcanistLintMessage extends Phobject {
return $this->bypassChangedLineFiltering;
}
/**
* Validate an integer-like value, returning a strict integer.
*
* Further on, the pipeline is strict about types. We want to be a little
* less strict in linters themselves, since they often parse command line
* output or XML and will end up with string representations of numbers.
*
* @param mixed Integer or digit string.
* @return int Integer.
*/
private function validateInteger($value, $caller) {
if ($value === null) {
// This just means that we don't have any information.
return null;
}
// Strings like "234" are fine, coerce them to integers.
if (is_string($value) && preg_match('/^\d+\z/', $value)) {
$value = (int)$value;
}
if (!is_int($value)) {
throw new Exception(
pht(
'Parameter passed to "%s" must be an integer.',
$caller.'()'));
}
return $value;
}
}

View file

@ -16,9 +16,11 @@ The duck says, "Quack!"
The robot says, "Beep beep boop boop!"
EODOC
);
f (1);
~~~~~~~~~~
warning:4:4
warning:9:4
warning:19:2
~~~~~~~~~~
<?php
@ -37,3 +39,4 @@ The duck says, "Quack!"
The robot says, "Beep beep boop boop!"
EODOC
);
f(1);

View file

@ -28,7 +28,7 @@ warning:4:14
warning:5:11
warning:8:15
error:10:13
warning:11:23
warning:13:23
warning:16:31
warning:19:33
warning:24:14

View file

@ -2,4 +2,3 @@
This shouldn't fatal the parser.
~~~~~~~~~~
error:1:10

View file

@ -2,7 +2,14 @@
exit(-1);
exit -1;
strtoupper(33 * exit - 6);
echo '';
print '';
$x = new stdClass();
$y = clone $x;
~~~~~~~~~~
error:3:1
warning:3:5
warning:3:6
error:4:17
warning:4:21

View file

@ -21,7 +21,7 @@ final class Quack {
function () use ($this_is_a_closure) {};
function() use ($this_is_a_closure) {};
function f(&$YY) {}

View file

@ -0,0 +1,12 @@
<?php
$x -> doSomething();
id(new Something())
->doSomething();
~~~~~~~~~~
warning:2:3
warning:2:6
~~~~~~~~~~
<?php
$x->doSomething();
id(new Something())
->doSomething();

View file

@ -4,7 +4,6 @@ garbage garbage
?>
~~~~~~~~~~
error:1:1
error:4:1
~~~~~~~~~~
garbage garbage
<?php

View file

@ -0,0 +1,9 @@
<?php
$x ++;
$y--;
~~~~~~~~~~
warning:2:3
~~~~~~~~~~
<?php
$x++;
$y--;

View file

@ -0,0 +1,12 @@
<?php
$f = @ fopen($path, 'rb');
@fclose($f);
exit ();
~~~~~~~~~~
warning:2:7
warning:4:5
~~~~~~~~~~
<?php
$f = @fopen($path, 'rb');
@fclose($f);
exit();

View file

@ -1,6 +1,6 @@
<?php
function () use ($c) {
function() use ($c) {
$c++;
};
@ -172,6 +172,13 @@ function catchy() {
}
}
function some_func($x, $y) {
$func = function($z) use ($x) {
echo $x;
echo $y;
echo $z;
};
}
~~~~~~~~~~
error:28:3
error:30:3
@ -191,3 +198,4 @@ error:144:8
error:150:9
error:164:9
error:171:5
error:178:10

View file

@ -1,6 +1,6 @@
<?php
final class ArcanistClosingCallParenthesesXHPASTLinterRule
final class ArcanistCallParenthesesXHPASTLinterRule
extends ArcanistXHPASTLinterRule {
const ID = 37;
@ -19,6 +19,22 @@ final class ArcanistClosingCallParenthesesXHPASTLinterRule
'n_METHOD_CALL',
));
foreach ($calls as $call) {
$params = $call->getChildOfType(1, 'n_CALL_PARAMETER_LIST');
$tokens = $params->getTokens();
$first = head($tokens);
$leading = $first->getNonsemanticTokensBefore();
$leading_text = implode('', mpull($leading, 'getValue'));
if (preg_match('/^\s+$/', $leading_text)) {
$this->raiseLintAtOffset(
$first->getOffset() - strlen($leading_text),
pht('Convention: no spaces before opening parenthesis in calls.'),
$leading_text,
'');
}
}
foreach ($calls as $call) {
// If the last parameter of a call is a HEREDOC, don't apply this rule.
$params = $call

View file

@ -0,0 +1,47 @@
<?php
final class ArcanistObjectOperatorSpacingXHPASTLinterRule
extends ArcanistXHPASTLinterRule {
const ID = 74;
public function getLintName() {
return pht('Object Operator Spacing');
}
public function getLintSeverity() {
return ArcanistLintSeverity::SEVERITY_WARNING;
}
public function process(XHPASTNode $root) {
$operators = $root->selectTokensOfType('T_OBJECT_OPERATOR');
foreach ($operators as $operator) {
$before = $operator->getNonsemanticTokensBefore();
$after = $operator->getNonsemanticTokensAfter();
if ($before) {
$value = implode('', mpull($before, 'getValue'));
if (strpos($value, "\n") !== false) {
continue;
}
$this->raiseLintAtOffset(
head($before)->getOffset(),
pht('There should be no whitespace before the object operator.'),
$value,
'');
}
if ($after) {
$this->raiseLintAtOffset(
head($after)->getOffset(),
pht('There should be no whitespace after the object operator.'),
implode('', mpull($before, 'getValue')),
'');
}
}
}
}

View file

@ -10,6 +10,12 @@ final class ArcanistPHPCloseTagXHPASTLinterRule
}
public function process(XHPASTNode $root) {
$inline_html = $root->selectDescendantsOfType('n_INLINE_HTML');
if ($inline_html) {
return;
}
foreach ($root->selectTokensOfType('T_CLOSE_TAG') as $token) {
$this->raiseLintAtToken(
$token,

View file

@ -0,0 +1,36 @@
<?php
final class ArcanistUnaryPostfixExpressionSpacingXHPASTLinterRule
extends ArcanistXHPASTLinterRule {
const ID = 75;
public function getLintName() {
return pht('Space Before Unary Postfix Operator');
}
public function getLintSeverity() {
return ArcanistLintSeverity::SEVERITY_WARNING;
}
public function process(XHPASTNode $root) {
$expressions = $root->selectDescendantsOfType('n_UNARY_POSTFIX_EXPRESSION');
foreach ($expressions as $expression) {
$operator = $expression->getChildOfType(1, 'n_OPERATOR');
$operator_value = $operator->getConcreteString();
list($before, $after) = $operator->getSurroundingNonsemanticTokens();
if (!empty($before)) {
$leading_text = implode('', mpull($before, 'getValue'));
$this->raiseLintAtOffset(
$operator->getOffset() - strlen($leading_text),
pht('Unary postfix operators should not be prefixed by whitespace.'),
$leading_text,
'');
}
}
}
}

View file

@ -0,0 +1,44 @@
<?php
final class ArcanistUnaryPrefixExpressionSpacingXHPASTLinterRule
extends ArcanistXHPASTLinterRule {
const ID = 73;
public function getLintName() {
return pht('Space After Unary Prefix Operator');
}
public function getLintSeverity() {
return ArcanistLintSeverity::SEVERITY_WARNING;
}
public function process(XHPASTNode $root) {
$expressions = $root->selectDescendantsOfType('n_UNARY_PREFIX_EXPRESSION');
foreach ($expressions as $expression) {
$operator = $expression->getChildOfType(0, 'n_OPERATOR');
$operator_value = $operator->getConcreteString();
list($before, $after) = $operator->getSurroundingNonsemanticTokens();
switch (strtolower($operator_value)) {
case 'clone':
case 'echo':
case 'print':
break;
default:
if (!empty($after)) {
$this->raiseLintAtOffset(
$operator->getOffset() + strlen($operator->getConcreteString()),
pht(
'Unary prefix operators should not be followed by whitespace.'),
implode('', mpull($after, 'getValue')),
'');
}
break;
}
}
}
}

View file

@ -164,6 +164,17 @@ final class ArcanistUndeclaredVariableXHPASTLinterRule
$scope_destroyed_at = min($scope_destroyed_at, $call->getOffset());
}
$func_decls = $body->selectDescendantsOfType('n_FUNCTION_DECLARATION');
foreach ($func_decls as $func_decl) {
if ($func_decl->getChildByIndex(2)->getTypeName() != 'n_EMPTY') {
continue;
}
foreach ($func_decl->selectDescendantsOfType('n_VARIABLE') as $var) {
$exclude_tokens[$var->getID()] = true;
}
}
// Now we have every declaration except foreach(), handled below. Build
// two maps, one which just keeps track of which tokens are part of
// declarations ($declaration_tokens) and one which has the first offset

View file

@ -152,4 +152,68 @@ final class ArcanistUnitTestResult extends Phobject {
);
}
public static function getAllResultCodes() {
return array(
self::RESULT_PASS,
self::RESULT_FAIL,
self::RESULT_SKIP,
self::RESULT_BROKEN,
self::RESULT_UNSOUND,
);
}
public static function getResultCodeName($result_code) {
$spec = self::getResultCodeSpec($result_code);
if (!$spec) {
return null;
}
return idx($spec, 'name');
}
public static function getResultCodeDescription($result_code) {
$spec = self::getResultCodeSpec($result_code);
if (!$spec) {
return null;
}
return idx($spec, 'description');
}
private static function getResultCodeSpec($result_code) {
$specs = self::getResultCodeSpecs();
return idx($specs, $result_code);
}
private static function getResultCodeSpecs() {
return array(
self::RESULT_PASS => array(
'name' => pht('Pass'),
'description' => pht(
'The test passed.'),
),
self::RESULT_FAIL => array(
'name' => pht('Fail'),
'description' => pht(
'The test failed.'),
),
self::RESULT_SKIP => array(
'name' => pht('Skip'),
'description' => pht(
'The test was not executed.'),
),
self::RESULT_BROKEN => array(
'name' => pht('Broken'),
'description' => pht(
'The test failed in an abnormal or severe way. For example, the '.
'harness crashed instead of reporting a failure.'),
),
self::RESULT_UNSOUND => array(
'name' => pht('Unsound'),
'description' => pht(
'The test failed, but this change is probably not what broke it. '.
'For example, it might have already been failing.'),
),
);
}
}

View file

@ -7,6 +7,8 @@
*/
final class NoseTestEngine extends ArcanistUnitTestEngine {
private $parser;
public function run() {
$paths = $this->getPaths();

View file

@ -161,8 +161,8 @@ EOTEXT
$commit_hash = $commit['identifier'];
// Convert commit hash from SVN to Git/HG (for FB case)
if ($is_git_svn || $is_hg_svn) {
$commit_hash = $repository_api->
getHashFromFromSVNRevisionNumber($commit_hash);
$commit_hash = $repository_api
->getHashFromFromSVNRevisionNumber($commit_hash);
}
} else {
// Assume input is a commit hash