diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 841b4e84..422c792f 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -15,6 +15,7 @@ phutil_register_library_map(array( 'ArcanistAnoidWorkflow' => 'workflow/ArcanistAnoidWorkflow.php', 'ArcanistArrayIndexSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistArrayIndexSpacingXHPASTLinterRule.php', 'ArcanistArraySeparatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistArraySeparatorXHPASTLinterRule.php', + 'ArcanistArrayValueXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistArrayValueXHPASTLinterRule.php', 'ArcanistBackoutWorkflow' => 'workflow/ArcanistBackoutWorkflow.php', 'ArcanistBaseCommitParser' => 'parser/ArcanistBaseCommitParser.php', 'ArcanistBaseCommitParserTestCase' => 'parser/__tests__/ArcanistBaseCommitParserTestCase.php', @@ -292,6 +293,7 @@ phutil_register_library_map(array( 'ArcanistAnoidWorkflow' => 'ArcanistWorkflow', 'ArcanistArrayIndexSpacingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistArraySeparatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', + 'ArcanistArrayValueXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistBackoutWorkflow' => 'ArcanistWorkflow', 'ArcanistBaseCommitParser' => 'Phobject', 'ArcanistBaseCommitParserTestCase' => 'PhutilTestCase', diff --git a/src/lint/linter/__tests__/xhpast/array-value.lint-test b/src/lint/linter/__tests__/xhpast/array-value.lint-test new file mode 100644 index 00000000..a1339798 --- /dev/null +++ b/src/lint/linter/__tests__/xhpast/array-value.lint-test @@ -0,0 +1,48 @@ + 'bar', 'bar' => 'baz', +); + +array( + 1, /* quack */ 2, /* quack */3, +); + +array( + /* OPEN */ 1, + /* CLOSED */ 2, +); +~~~~~~~~~~ +warning:4:5 +warning:4:8 +warning:8:18 +warning:12:17 +warning:12:32 +~~~~~~~~~~ + 'bar', + 'bar' => 'baz', +); + +array( + 1, /* quack */ + 2, /* quack */ + 3, +); + +array( + /* OPEN */ 1, + /* CLOSED */ 2, +); diff --git a/src/lint/linter/xhpast/rules/ArcanistArrayValueXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistArrayValueXHPASTLinterRule.php new file mode 100644 index 00000000..21f50928 --- /dev/null +++ b/src/lint/linter/xhpast/rules/ArcanistArrayValueXHPASTLinterRule.php @@ -0,0 +1,56 @@ +selectDescendantsOfType('n_ARRAY_LITERAL'); + + foreach ($arrays as $array) { + $array_values = $array + ->getChildOfType(0, 'n_ARRAY_VALUE_LIST') + ->getChildrenOfType('n_ARRAY_VALUE'); + + if (!$array_values) { + // There is no need to check an empty array. + continue; + } + + $multiline = $array->getLineNumber() != $array->getEndLineNumber(); + + if (!$multiline) { + continue; + } + + foreach ($array_values as $value) { + list($before, $after) = $value->getSurroundingNonsemanticTokens(); + + if (strpos(implode('', mpull($before, 'getValue')), "\n") === false) { + if (last($before)->isAnyWhitespace()) { + $token = last($before); + $replacement = "\n".$value->getIndentation(); + } else { + $token = head($value->getTokens()); + $replacement = "\n".$value->getIndentation().$token->getValue(); + } + + $this->raiseLintAtToken( + $token, + pht('Array elements should each occupy a single line.'), + $replacement); + } + } + } + } + +}