diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -181,6 +181,7 @@ 'ArcanistModifierOrderingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistModifierOrderingXHPASTLinterRule.php', 'ArcanistNamingConventionsXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNamingConventionsXHPASTLinterRule.php', 'ArcanistNewlineAfterOpenTagXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNewlineAfterOpenTagXHPASTLinterRule.php', + 'ArcanistNewlineAfterUseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistNewlineAfterUseXHPASTLinterRule.php', 'ArcanistNoEffectException' => 'exception/usage/ArcanistNoEffectException.php', 'ArcanistNoEngineException' => 'exception/usage/ArcanistNoEngineException.php', 'ArcanistNoLintLinter' => 'lint/linter/ArcanistNoLintLinter.php', @@ -476,6 +477,7 @@ 'ArcanistModifierOrderingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistNamingConventionsXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistNewlineAfterOpenTagXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', + 'ArcanistNewlineAfterUseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistNoEffectException' => 'ArcanistUsageException', 'ArcanistNoEngineException' => 'ArcanistUsageException', 'ArcanistNoLintLinter' => 'ArcanistLinter', diff --git a/src/lint/linter/__tests__/xhpast/newline-after-use.lint-test b/src/lint/linter/__tests__/xhpast/newline-after-use.lint-test new file mode 100644 --- /dev/null +++ b/src/lint/linter/__tests__/xhpast/newline-after-use.lint-test @@ -0,0 +1,30 @@ +selectDescendantsOfType('n_USE_LIST'); + + if (count($uses) > 0) { + $uses->rewind(); + for ($use = $uses->current(); $uses->valid(); $use = $uses->current()) { + // Get 'n_STATEMENT' above current 'use' and its surrounding whitespace. + $statement = $use->getParentNode(); + list($before, $after) = $statement->getSurroundingNonSemanticTokens(); + // Progress '$uses' List to next element before next loop. + $uses->next(); + + // Check if current 'use' has a blank newline after it. + if (preg_match('/^\n\s*\n/', head($after)->getValue())) { + // Continue if there are more 'use's, otherwise break. + if ($uses->valid()) { + continue; + } else { + break; + } + } + + // If there are more 'use' statements, + // see if next 'use' is on the next line. + if ($uses->valid()) { + $next = $uses->current(); + if (($use->getLineNumber() + 1) == $next->getLineNumber()) { + continue; + } + } else { + // If no more 'use's left raise lint on last one. + $this->raiseListAtStatement($statement); + break; + } + + $this->raiseListAtStatement($statement); + } + } + } + + public function raiseListAtStatement($statement) { + $this->raiseLintAtNode( + $statement, + pht( + 'Use lists should be separated from code by an empty line.'), + $statement->getConcreteString()."\n"); + } + +}