diff --git a/src/lint/linter/ArcanistBaseXHPASTLinter.php b/src/lint/linter/ArcanistBaseXHPASTLinter.php --- a/src/lint/linter/ArcanistBaseXHPASTLinter.php +++ b/src/lint/linter/ArcanistBaseXHPASTLinter.php @@ -36,6 +36,29 @@ $replace); } + final public function raiseLintAtTokens( + XHPASTToken $start_token, + XHPASTToken $end_token, + $code, + $desc, + $replace = null) { + + $token = $start_token->getPrevToken(); + $value = ''; + + while ($token != $end_token) { + $token = $token->getNextToken(); + $value .= $token->getValue(); + } + + return $this->raiseLintAtOffset( + $start_token->getOffset(), + $code, + $desc, + $value, + $replace); + } + final public function raiseLintAtNode( XHPASTNode $node, $code, diff --git a/src/lint/linter/__tests__/xhpast/elseif.lint-test b/src/lint/linter/__tests__/xhpast/else-if.lint-test copy from src/lint/linter/__tests__/xhpast/elseif.lint-test copy to src/lint/linter/__tests__/xhpast/else-if.lint-test --- a/src/lint/linter/__tests__/xhpast/elseif.lint-test +++ b/src/lint/linter/__tests__/xhpast/else-if.lint-test @@ -7,7 +7,7 @@ echo 'baz'; } ~~~~~~~~~~ -advice:4:3 +warning:4:3 ~~~~~~~~~~ linter->raiseLintAtTokens( + $start_token, + $end_token, + $this->getLintID(), + $desc, + $replace); + } + /* -( Utility )------------------------------------------------------------ */ /** diff --git a/src/lint/linter/xhpast/rules/ArcanistElseIfUsageXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistElseIfUsageXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistElseIfUsageXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistElseIfUsageXHPASTLinterRule.php @@ -5,15 +5,68 @@ const ID = 42; + private $allowElseif = false; + public function getLintName() { return pht('ElseIf Usage'); } public function getLintSeverity() { - return ArcanistLintSeverity::SEVERITY_ADVICE; + return ArcanistLintSeverity::SEVERITY_WARNING; + } + + public function getLinterConfigurationOptions() { + return array( + 'xhpast.allow-elseif' => array( + 'type' => 'optional bool', + 'help' => pht( + 'Whether to allow the use of `%s` instead of `%s`.', + 'elseif', + 'else if'), + ), + ); + } + + public function setLinterConfigurationValue($key, $value) { + switch ($key) { + case 'xhpast.allow-elseif': + $this->allowElseif = $value; + return; + + default: + parent::setLinterConfigurationValue($key, $value); + return; + } } public function process(XHPASTNode $root) { + if ($this->allowElseif) { + $this->lintSingleTokenElseif($root); + } else { + $this->lintDoubleTokenElseif($root); + } + } + + private function lintSingleTokenElseif(XHPASTNode $root) { + $nodes = $root->selectDescendantsOfType('n_ELSEIF'); + + foreach ($nodes as $node) { + $tokens = $node->getTokens(); + $head_token = head($tokens); + + if ($head_token->getTypeName() == 'T_ELSEIF') { + continue; + } + + $this->raiseLintAtTokens( + $head_token, + $head_token->getNextToken()->getNextToken(), + pht('Usage of `%s` is preferred over `%s`.', 'elseif', 'else if'), + 'elseif'); + } + } + + private function lintDoubleTokenElseif(XHPASTNode $root) { $tokens = $root->selectTokensOfType('T_ELSEIF'); foreach ($tokens as $token) {