1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-22 06:42:41 +01:00

Lint rule for duplicate keys in array literals

Summary:
Raise an error if an array is initialized with the same key present more than
once.

Test Plan:
bin/arc unit
Also added some duplicates to ArcanistXHPASTLinter.php and verified the output
of bin/arc lint.

Reviewed By: epriestley
Reviewers: jungejason, epriestley, aran
CC: aran, epriestley
Revert Plan:
Tags:

Differential Revision: 346
This commit is contained in:
Lovro Puzar 2011-05-25 12:24:25 -07:00
parent d762311a9d
commit 4b041b8f84
2 changed files with 106 additions and 0 deletions

View file

@ -46,6 +46,7 @@ class ArcanistXHPASTLinter extends ArcanistLinter {
const LINT_CLASS_FILENAME_MISMATCH = 19;
const LINT_TAUTOLOGICAL_EXPRESSION = 20;
const LINT_PLUS_OPERATOR_ON_STRINGS = 21;
const LINT_DUPLICATE_KEYS_IN_ARRAY = 22;
public function getLintNameMap() {
@ -71,6 +72,7 @@ class ArcanistXHPASTLinter extends ArcanistLinter {
self::LINT_CLASS_FILENAME_MISMATCH => 'Class-Filename Mismatch',
self::LINT_TAUTOLOGICAL_EXPRESSION => 'Tautological Expression',
self::LINT_PLUS_OPERATOR_ON_STRINGS => 'Not String Concatenation',
self::LINT_DUPLICATE_KEYS_IN_ARRAY => 'Duplicate Keys in Array',
);
}
@ -149,6 +151,7 @@ class ArcanistXHPASTLinter extends ArcanistLinter {
$this->lintPrimaryDeclarationFilenameMatch($root);
$this->lintTautologicalExpressions($root);
$this->lintPlusOperatorOnStrings($root);
$this->lintDuplicateKeysInArray($root);
}
private function lintTautologicalExpressions($root) {
@ -1008,6 +1011,60 @@ class ArcanistXHPASTLinter extends ArcanistLinter {
}
}
/**
* Finds duplicate keys in array initializers, as in
* array(1 => 'anything', 1 => 'foo'). Since the first entry is ignored,
* this is almost certainly an error.
*/
private function lintDuplicateKeysInArray($root) {
$array_literals = $root->selectDescendantsOfType('n_ARRAY_LITERAL');
foreach ($array_literals as $array_literal) {
$nodes_by_key = array();
$keys_warn = array();
$list_node = $array_literal->getChildByIndex(0);
foreach ($list_node->getChildren() as $array_entry) {
$key_node = $array_entry->getChildByIndex(0);
switch ($key_node->getTypeName()) {
case 'n_STRING_SCALAR':
case 'n_NUMERIC_SCALAR':
// Scalars: array(1 => 'v1', '1' => 'v2');
$key = 'scalar:'.(string)$key_node->evalStatic();
break;
case 'n_SYMBOL_NAME':
case 'n_VARIABLE':
case 'n_CLASS_STATIC_ACCESS':
// Constants: array(CONST => 'v1', CONST => 'v2');
// Variables: array($a => 'v1', $a => 'v2');
// Class constants and vars: array(C::A => 'v1', C::A => 'v2');
$key = $key_node->getTypeName().':'.$key_node->getConcreteString();
break;
default:
$key = null;
}
if ($key !== null) {
if (isset($nodes_by_key[$key])) {
$keys_warn[$key] = true;
}
$nodes_by_key[$key][] = $key_node;
}
}
foreach ($keys_warn as $key => $_) {
foreach ($nodes_by_key[$key] as $node) {
$this->raiseLintAtNode(
$node,
self::LINT_DUPLICATE_KEYS_IN_ARRAY,
"Duplicate key in array initializer. PHP will ignore all ".
"but the last entry.");
}
}
}
}
protected function raiseLintAtToken(
XHPASTToken $token,
$code,

View file

@ -0,0 +1,49 @@
<?php
$a = array(
'a' => 'val1',
$a => 'val2',
'a' => val3(),
1 => val4(),
'1' => val5(),
1 => $val6,
'b' => 'val7',
b() => 'val8',
);
static $b = array(
1 => 'one',
2 => 'two',
2 => 'TWO',
);
$c = array();
$d = array(
A => 'ay',
A => 'aye',
'A' => 'AYE',
);
$e = array(
self::B => 'bee',
self::B => 'bea',
self::B() => 'ehh',
self::$B => 'weh',
B => 'b',
C::B => 'cb',
);
$f = array(
$a => 'var',
'a' => 'lit',
$a => 'var2',
);
~~~~~~~~~~
error:3:3
error:5:3
error:6:3
error:7:3
error:8:3
error:14:3
error:15:3
error:19:3
error:20:3
error:24:3
error:25:3
error:32:3
error:34:3