mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-15 03:12:40 +01:00
(stable) Promote 2015 Week 34
This commit is contained in:
commit
0d2b7fde78
13 changed files with 127 additions and 18 deletions
|
@ -54,6 +54,7 @@ phutil_register_library_map(array(
|
||||||
'ArcanistCommentStyleXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php',
|
'ArcanistCommentStyleXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php',
|
||||||
'ArcanistCommitWorkflow' => 'workflow/ArcanistCommitWorkflow.php',
|
'ArcanistCommitWorkflow' => 'workflow/ArcanistCommitWorkflow.php',
|
||||||
'ArcanistCompilerLintRenderer' => 'lint/renderer/ArcanistCompilerLintRenderer.php',
|
'ArcanistCompilerLintRenderer' => 'lint/renderer/ArcanistCompilerLintRenderer.php',
|
||||||
|
'ArcanistComposerLinter' => 'lint/linter/ArcanistComposerLinter.php',
|
||||||
'ArcanistComprehensiveLintEngine' => 'lint/engine/ArcanistComprehensiveLintEngine.php',
|
'ArcanistComprehensiveLintEngine' => 'lint/engine/ArcanistComprehensiveLintEngine.php',
|
||||||
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistConcatenationOperatorXHPASTLinterRule.php',
|
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistConcatenationOperatorXHPASTLinterRule.php',
|
||||||
'ArcanistConfiguration' => 'configuration/ArcanistConfiguration.php',
|
'ArcanistConfiguration' => 'configuration/ArcanistConfiguration.php',
|
||||||
|
@ -337,6 +338,7 @@ phutil_register_library_map(array(
|
||||||
'ArcanistCommentStyleXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistCommentStyleXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistCommitWorkflow' => 'ArcanistWorkflow',
|
'ArcanistCommitWorkflow' => 'ArcanistWorkflow',
|
||||||
'ArcanistCompilerLintRenderer' => 'ArcanistLintRenderer',
|
'ArcanistCompilerLintRenderer' => 'ArcanistLintRenderer',
|
||||||
|
'ArcanistComposerLinter' => 'ArcanistLinter',
|
||||||
'ArcanistComprehensiveLintEngine' => 'ArcanistLintEngine',
|
'ArcanistComprehensiveLintEngine' => 'ArcanistLintEngine',
|
||||||
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
'ArcanistConcatenationOperatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||||
'ArcanistConfiguration' => 'Phobject',
|
'ArcanistConfiguration' => 'Phobject',
|
||||||
|
|
|
@ -471,6 +471,8 @@ abstract class ArcanistLintEngine extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function executeLinters(array $runnable) {
|
private function executeLinters(array $runnable) {
|
||||||
|
assert_instances_of($runnable, 'ArcanistLinter');
|
||||||
|
|
||||||
$all_paths = $this->getPaths();
|
$all_paths = $this->getPaths();
|
||||||
$path_chunks = array_chunk($all_paths, 32, $preserve_keys = true);
|
$path_chunks = array_chunk($all_paths, 32, $preserve_keys = true);
|
||||||
|
|
||||||
|
|
55
src/lint/linter/ArcanistComposerLinter.php
Normal file
55
src/lint/linter/ArcanistComposerLinter.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class ArcanistComposerLinter extends ArcanistLinter {
|
||||||
|
|
||||||
|
const LINT_OUT_OF_DATE = 1;
|
||||||
|
|
||||||
|
public function getInfoName() {
|
||||||
|
return pht('Composer');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInfoDescription() {
|
||||||
|
return pht('A linter for Composer related files.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLinterName() {
|
||||||
|
return 'COMPOSER';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLinterConfigurationName() {
|
||||||
|
return 'composer';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLintNameMap() {
|
||||||
|
return array(
|
||||||
|
self::LINT_OUT_OF_DATE => pht('Lock file out-of-date'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lintPath($path) {
|
||||||
|
switch (basename($path)) {
|
||||||
|
case 'composer.json':
|
||||||
|
$this->lintComposerJson($path);
|
||||||
|
break;
|
||||||
|
case 'composer.lock':
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function lintComposerJson($path) {
|
||||||
|
$composer_hash = md5(Filesystem::readFile(dirname($path).'/composer.json'));
|
||||||
|
$composer_lock = phutil_json_decode(
|
||||||
|
Filesystem::readFile(dirname($path).'/composer.lock'));
|
||||||
|
|
||||||
|
if ($composer_hash !== $composer_lock['hash']) {
|
||||||
|
$this->raiseLintAtPath(
|
||||||
|
self::LINT_OUT_OF_DATE,
|
||||||
|
pht(
|
||||||
|
"The '%s' file seems to be out-of-date. ".
|
||||||
|
"You probably need to run `%s`.",
|
||||||
|
'composer.lock',
|
||||||
|
'composer update'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -22,9 +22,14 @@ final class ArcanistInlineHTMLXHPASTLinterRule
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preg_match('/^\s*$/', $html->getValue())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$this->raiseLintAtToken(
|
$this->raiseLintAtToken(
|
||||||
$html,
|
$html,
|
||||||
pht('PHP files must only contain PHP code.'));
|
pht('PHP files must only contain PHP code.'));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ final class ArcanistPyLintLinter extends ArcanistExternalLinter {
|
||||||
$options = array();
|
$options = array();
|
||||||
|
|
||||||
$options[] = '--reports=no';
|
$options[] = '--reports=no';
|
||||||
$options[] = '--msg-template="{line}|{column}|{msg_id}|{symbol}|{msg}"';
|
$options[] = '--msg-template={line}|{column}|{msg_id}|{symbol}|{msg}';
|
||||||
|
|
||||||
// Specify an `--rcfile`, either absolute or relative to the project root.
|
// Specify an `--rcfile`, either absolute or relative to the project root.
|
||||||
// Stupidly, the command line args above are overridden by rcfile, so be
|
// Stupidly, the command line args above are overridden by rcfile, so be
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
array ( 1, 2, 3 );
|
array ( 1, 2, 3 );
|
||||||
list ( $x, $y ) = array();
|
list ( $x, $y ) = array();
|
||||||
|
[ 1, 2 , 3 ];
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
warning:3:6
|
warning:3:6
|
||||||
warning:3:8
|
warning:3:8
|
||||||
|
@ -9,8 +10,11 @@ warning:3:16
|
||||||
warning:4:5
|
warning:4:5
|
||||||
warning:4:7
|
warning:4:7
|
||||||
warning:4:14
|
warning:4:14
|
||||||
|
warning:5:2
|
||||||
|
warning:5:11
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
array(1, 2, 3);
|
array(1, 2, 3);
|
||||||
list($x, $y) = array();
|
list($x, $y) = array();
|
||||||
|
[1, 2 , 3];
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
|
|
||||||
This shouldn't fatal the parser.
|
This shouldn't fatal the parser.
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
disabled:2:1
|
||||||
|
|
|
@ -3,6 +3,7 @@ garbage garbage
|
||||||
|
|
||||||
?>
|
?>
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
disabled:1:1
|
||||||
error:1:1
|
error:1:1
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
garbage garbage
|
garbage garbage
|
||||||
|
|
|
@ -179,6 +179,12 @@ function some_func($x, $y) {
|
||||||
echo $z;
|
echo $z;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function some_func($x, $y) {
|
||||||
|
$func = function ($z) use ($x) {
|
||||||
|
echo "$x/$y/$z";
|
||||||
|
};
|
||||||
|
}
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
warning:9:3
|
warning:9:3
|
||||||
error:28:3
|
error:28:3
|
||||||
|
@ -201,3 +207,4 @@ error:150:9
|
||||||
error:164:9
|
error:164:9
|
||||||
error:171:5
|
error:171:5
|
||||||
error:178:10
|
error:178:10
|
||||||
|
error:185:14
|
||||||
|
|
|
@ -24,6 +24,11 @@ final class ArcanistCallParenthesesXHPASTLinterRule
|
||||||
foreach ($nodes as $node) {
|
foreach ($nodes as $node) {
|
||||||
switch ($node->getTypeName()) {
|
switch ($node->getTypeName()) {
|
||||||
case 'n_ARRAY_LITERAL':
|
case 'n_ARRAY_LITERAL':
|
||||||
|
if (head($node->getTokens())->getTypeName() == '[') {
|
||||||
|
// Short array syntax.
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
|
||||||
$params = $node->getChildOfType(0, 'n_ARRAY_VALUE_LIST');
|
$params = $node->getChildOfType(0, 'n_ARRAY_VALUE_LIST');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -44,6 +49,7 @@ final class ArcanistCallParenthesesXHPASTLinterRule
|
||||||
$tokens = $params->getTokens();
|
$tokens = $params->getTokens();
|
||||||
$first = head($tokens);
|
$first = head($tokens);
|
||||||
|
|
||||||
|
|
||||||
$leading = $first->getNonsemanticTokensBefore();
|
$leading = $first->getNonsemanticTokensBefore();
|
||||||
$leading_text = implode('', mpull($leading, 'getValue'));
|
$leading_text = implode('', mpull($leading, 'getValue'));
|
||||||
if (preg_match('/^\s+$/', $leading_text)) {
|
if (preg_match('/^\s+$/', $leading_text)) {
|
||||||
|
|
|
@ -29,12 +29,6 @@ final class ArcanistParenthesesSpacingXHPASTLinterRule
|
||||||
|
|
||||||
$token_o = array_shift($tokens);
|
$token_o = array_shift($tokens);
|
||||||
$token_c = array_pop($tokens);
|
$token_c = array_pop($tokens);
|
||||||
if ($token_o->getTypeName() !== '(') {
|
|
||||||
throw new Exception(pht('Expected open parentheses.'));
|
|
||||||
}
|
|
||||||
if ($token_c->getTypeName() !== ')') {
|
|
||||||
throw new Exception(pht('Expected close parentheses.'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$nonsem_o = $token_o->getNonsemanticTokensAfter();
|
$nonsem_o = $token_o->getNonsemanticTokensAfter();
|
||||||
$nonsem_c = $token_c->getNonsemanticTokensBefore();
|
$nonsem_c = $token_c->getNonsemanticTokensBefore();
|
||||||
|
|
|
@ -68,6 +68,7 @@ final class ArcanistUndeclaredVariableXHPASTLinterRule
|
||||||
) + array_fill_keys($this->getSuperGlobalNames(), 0);
|
) + array_fill_keys($this->getSuperGlobalNames(), 0);
|
||||||
$declaration_tokens = array();
|
$declaration_tokens = array();
|
||||||
$exclude_tokens = array();
|
$exclude_tokens = array();
|
||||||
|
$exclude_strings = array();
|
||||||
$vars = array();
|
$vars = array();
|
||||||
|
|
||||||
// First up, find all the different kinds of declarations, as explained
|
// First up, find all the different kinds of declarations, as explained
|
||||||
|
@ -175,6 +176,16 @@ final class ArcanistUndeclaredVariableXHPASTLinterRule
|
||||||
foreach ($func_decl->selectDescendantsOfType('n_VARIABLE') as $var) {
|
foreach ($func_decl->selectDescendantsOfType('n_VARIABLE') as $var) {
|
||||||
$exclude_tokens[$var->getID()] = true;
|
$exclude_tokens[$var->getID()] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (array('n_STRING_SCALAR', 'n_HEREDOC') as $type) {
|
||||||
|
foreach ($func_decl->selectDescendantsOfType($type) as $string) {
|
||||||
|
$exclude_strings[$string->getID()] = array();
|
||||||
|
|
||||||
|
foreach ($string->getStringVariables() as $offset => $var) {
|
||||||
|
$exclude_strings[$string->getID()][$var] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we have every declaration except foreach(), handled below. Build
|
// Now we have every declaration except foreach(), handled below. Build
|
||||||
|
@ -316,6 +327,10 @@ final class ArcanistUndeclaredVariableXHPASTLinterRule
|
||||||
foreach (array('n_STRING_SCALAR', 'n_HEREDOC') as $type) {
|
foreach (array('n_STRING_SCALAR', 'n_HEREDOC') as $type) {
|
||||||
foreach ($body->selectDescendantsOfType($type) as $string) {
|
foreach ($body->selectDescendantsOfType($type) as $string) {
|
||||||
foreach ($string->getStringVariables() as $offset => $var) {
|
foreach ($string->getStringVariables() as $offset => $var) {
|
||||||
|
if (isset($exclude_strings[$string->getID()][$var])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$all[$string->getOffset() + $offset - 1] = '$'.$var;
|
$all[$string->getOffset() + $offset - 1] = '$'.$var;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -492,17 +492,34 @@ EOTEXT
|
||||||
'arc amend',
|
'arc amend',
|
||||||
'--revision <id>'));
|
'--revision <id>'));
|
||||||
} else if (count($revisions) > 1) {
|
} else if (count($revisions) > 1) {
|
||||||
$message = pht(
|
switch ($this->branchType) {
|
||||||
"There are multiple revisions on feature %s '%s' which are not ".
|
case self::REFTYPE_BOOKMARK:
|
||||||
"present on '%s':\n\n".
|
$message = pht(
|
||||||
"%s\n".
|
"There are multiple revisions on feature bookmark '%s' which are ".
|
||||||
"Separate these revisions onto different %s, or use --revision <id>' ".
|
"not present on '%s':\n\n".
|
||||||
"to use the commit message from <id> and land them all.",
|
"%s\n".
|
||||||
$this->branchType,
|
'Separate these revisions onto different bookmarks, or use '.
|
||||||
$this->branch,
|
'--revision <id> to use the commit message from <id> '.
|
||||||
$this->onto,
|
'and land them all.',
|
||||||
$this->renderRevisionList($revisions),
|
$this->branch,
|
||||||
$this->branchType.'s');
|
$this->onto,
|
||||||
|
$this->renderRevisionList($revisions));
|
||||||
|
break;
|
||||||
|
case self::REFTYPE_BRANCH:
|
||||||
|
default:
|
||||||
|
$message = pht(
|
||||||
|
"There are multiple revisions on feature branch '%s' which are ".
|
||||||
|
"not present on '%s':\n\n".
|
||||||
|
"%s\n".
|
||||||
|
'Separate these revisions onto different branches, or use '.
|
||||||
|
'--revision <id> to use the commit message from <id> '.
|
||||||
|
'and land them all.',
|
||||||
|
$this->branch,
|
||||||
|
$this->onto,
|
||||||
|
$this->renderRevisionList($revisions));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
throw new ArcanistUsageException($message);
|
throw new ArcanistUsageException($message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue