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 @@ -240,6 +240,7 @@ 'ArcanistPEP8Linter' => 'lint/linter/ArcanistPEP8Linter.php', 'ArcanistPEP8LinterTestCase' => 'lint/linter/__tests__/ArcanistPEP8LinterTestCase.php', 'ArcanistPHPCloseTagXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPCloseTagXHPASTLinterRule.php', + 'ArcanistPHPCloseTagXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPHPCloseTagXHPASTLinterRuleTestCase.php', 'ArcanistPHPCompatibilityXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPCompatibilityXHPASTLinterRule.php', 'ArcanistPHPCompatibilityXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistPHPCompatibilityXHPASTLinterRuleTestCase.php', 'ArcanistPHPEchoTagXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistPHPEchoTagXHPASTLinterRule.php', @@ -339,6 +340,7 @@ 'ArcanistUnnecessaryFinalModifierXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnnecessaryFinalModifierXHPASTLinterRule.php', 'ArcanistUnnecessaryFinalModifierXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUnnecessaryFinalModifierXHPASTLinterRuleTestCase.php', 'ArcanistUnnecessarySemicolonXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnnecessarySemicolonXHPASTLinterRule.php', + 'ArcanistUnnecessarySemicolonXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUnnecessarySemicolonXHPASTLinterRuleTestCase.php', 'ArcanistUnsafeDynamicStringXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistUnsafeDynamicStringXHPASTLinterRule.php', 'ArcanistUnsafeDynamicStringXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUnsafeDynamicStringXHPASTLinterRuleTestCase.php', 'ArcanistUpgradeWorkflow' => 'workflow/ArcanistUpgradeWorkflow.php', @@ -610,6 +612,7 @@ 'ArcanistPEP8Linter' => 'ArcanistExternalLinter', 'ArcanistPEP8LinterTestCase' => 'ArcanistExternalLinterTestCase', 'ArcanistPHPCloseTagXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', + 'ArcanistPHPCloseTagXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistPHPCompatibilityXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistPHPCompatibilityXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistPHPEchoTagXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', @@ -709,6 +712,7 @@ 'ArcanistUnnecessaryFinalModifierXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistUnnecessaryFinalModifierXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistUnnecessarySemicolonXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', + 'ArcanistUnnecessarySemicolonXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistUnsafeDynamicStringXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistUnsafeDynamicStringXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistUpgradeWorkflow' => 'ArcanistWorkflow', diff --git a/src/lint/linter/xhpast/ArcanistXHPASTLinterRule.php b/src/lint/linter/xhpast/ArcanistXHPASTLinterRule.php --- a/src/lint/linter/xhpast/ArcanistXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/ArcanistXHPASTLinterRule.php @@ -209,7 +209,7 @@ * @param list Function names. * @return AASTNodeList */ - protected function getFunctionCalls(XHPASTNode $root, array $function_names) { + final protected function getFunctionCalls(XHPASTNode $root, array $function_names) { $calls = $root->selectDescendantsOfType('n_FUNCTION_CALL'); $nodes = array(); diff --git a/src/lint/linter/xhpast/rules/ArcanistArrayIndexSpacingXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistArrayIndexSpacingXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistArrayIndexSpacingXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistArrayIndexSpacingXHPASTLinterRule.php @@ -17,15 +17,14 @@ $indexes = $root->selectDescendantsOfType('n_INDEX_ACCESS'); foreach ($indexes as $index) { - $tokens = $index->getChildByIndex(0)->getTokens(); - $last = array_pop($tokens); + $last = last($index->getChildByIndex(0)->getTokens()); $trailing = $last->getNonsemanticTokensAfter(); $trailing_text = implode('', mpull($trailing, 'getValue')); - if (preg_match('/^ +$/', $trailing_text)) { + if (preg_match('/^\s+$/', $trailing_text)) { $this->raiseLintAtOffset( $last->getOffset() + strlen($last->getValue()), - pht('Convention: no spaces before index access.'), + pht('There should be no whitespace before index access.'), $trailing_text, ''); } diff --git a/src/lint/linter/xhpast/rules/ArcanistBlacklistedFunctionXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistBlacklistedFunctionXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistBlacklistedFunctionXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistBlacklistedFunctionXHPASTLinterRule.php @@ -32,17 +32,17 @@ } public function process(XHPASTNode $root) { - $calls = $root->selectDescendantsOfType('n_FUNCTION_CALL'); + $calls = $this->getFunctionCalls( + $root, + array_keys($this->blacklistedFunctions)); foreach ($calls as $call) { $node = $call->getChildByIndex(0); $name = $node->getConcreteString(); - $reason = idx($this->blacklistedFunctions, $name); - - if ($reason) { - $this->raiseLintAtNode($node, $reason); - } + $this->raiseLintAtNode( + $node, + $this->blacklistedFunctions[$name]); } } diff --git a/src/lint/linter/xhpast/rules/ArcanistCallTimePassByReferenceXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistCallTimePassByReferenceXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistCallTimePassByReferenceXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistCallTimePassByReferenceXHPASTLinterRule.php @@ -18,7 +18,10 @@ foreach ($parameters as $parameter) { $this->raiseLintAtNode( $parameter, - pht('Call-time pass-by-reference calls are prohibited.')); + pht( + 'Call-time pass-by-reference calls are prohibited. '. + 'As of PHP 5.4.0, call-time pass-by-reference was removed '. + 'and so using this functionality will raise a fatal error.')); } } } diff --git a/src/lint/linter/xhpast/rules/ArcanistCommentSpacingXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistCommentSpacingXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistCommentSpacingXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistCommentSpacingXHPASTLinterRule.php @@ -14,7 +14,9 @@ } public function process(XHPASTNode $root) { - foreach ($root->selectTokensOfType('T_COMMENT') as $comment) { + $comments = $root->selectTokensOfType('T_COMMENT'); + + foreach ($comments as $comment) { $value = $comment->getValue(); if ($value[0] !== '#') { diff --git a/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php @@ -10,7 +10,9 @@ } public function process(XHPASTNode $root) { - foreach ($root->selectTokensOfType('T_COMMENT') as $comment) { + $comments = $root->selectTokensOfType('T_COMMENT'); + + foreach ($comments as $comment) { $value = $comment->getValue(); if ($value[0] !== '#') { @@ -20,7 +22,7 @@ $this->raiseLintAtOffset( $comment->getOffset(), pht( - 'Use `%s` single-line comments, not `%s`.', + 'Use `%s` for single-line comments, not `%s`.', '//', '#'), '#', diff --git a/src/lint/linter/xhpast/rules/ArcanistDynamicDefineXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistDynamicDefineXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistDynamicDefineXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistDynamicDefineXHPASTLinterRule.php @@ -6,19 +6,20 @@ const ID = 12; public function getLintName() { - return pht('Dynamic `%s`', 'define'); + return pht('Dynamic `%s`', 'define()'); } public function process(XHPASTNode $root) { - $calls = $this->getFunctionCalls($root, array('define')); + $defines = $this->getFunctionCalls($root, array('define')); - foreach ($calls as $call) { - $parameter_list = $call->getChildOfType(1, 'n_CALL_PARAMETER_LIST'); - $defined = $parameter_list->getChildByIndex(0); + foreach ($defines as $define) { + $key = $define + ->getChildOfType(1, 'n_CALL_PARAMETER_LIST') + ->getChildByIndex(0); - if (!$defined->isStaticScalar()) { + if (!$key->isStaticScalar()) { $this->raiseLintAtNode( - $defined, + $key, pht( 'First argument to `%s` must be a string literal.', 'define')); diff --git a/src/lint/linter/xhpast/rules/ArcanistExtractUseXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistExtractUseXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistExtractUseXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistExtractUseXHPASTLinterRule.php @@ -16,7 +16,8 @@ $this->raiseLintAtNode( $call, pht( - 'Avoid `%s`. It is confusing and hinders static analysis.', + 'Avoid the `%s` function. '. + 'It is confusing and hinders static analysis.', 'extract')); } } diff --git a/src/lint/linter/xhpast/rules/ArcanistInnerFunctionXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistInnerFunctionXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistInnerFunctionXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistInnerFunctionXHPASTLinterRule.php @@ -17,8 +17,8 @@ $function_decls = $root->selectDescendantsOfType('n_FUNCTION_DECLARATION'); foreach ($function_decls as $function_declaration) { - $inner_functions = $function_declaration - ->selectDescendantsOfType('n_FUNCTION_DECLARATION'); + $inner_functions = $function_declaration->selectDescendantsOfType( + 'n_FUNCTION_DECLARATION'); foreach ($inner_functions as $inner_function) { if ($inner_function->getChildByIndex(2)->getTypeName() == 'n_EMPTY') { diff --git a/src/lint/linter/xhpast/rules/ArcanistInvalidDefaultParameterXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistInvalidDefaultParameterXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistInvalidDefaultParameterXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistInvalidDefaultParameterXHPASTLinterRule.php @@ -54,8 +54,8 @@ $this->raiseLintAtNode( $default, pht( - 'Default value for parameters with `%s` type hint '. - 'can only be `%s`.', + 'Default value for parameters with `%s` '. + 'type hint can only be `%s`.', 'callable', 'null')); break; diff --git a/src/lint/linter/xhpast/rules/ArcanistLambdaFuncFunctionXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistLambdaFuncFunctionXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistLambdaFuncFunctionXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistLambdaFuncFunctionXHPASTLinterRule.php @@ -10,8 +10,8 @@ } public function process(XHPASTNode $root) { - $function_declarations = $root - ->selectDescendantsOfType('n_FUNCTION_DECLARATION'); + $function_declarations = $root->selectDescendantsOfType( + 'n_FUNCTION_DECLARATION'); foreach ($function_declarations as $function_declaration) { $function_name = $function_declaration->getChildByIndex(2); @@ -21,14 +21,14 @@ continue; } - if ($function_name->getConcreteString() != '__lambda_func') { + if (strtolower($function_name->getConcreteString()) != '__lambda_func') { continue; } $this->raiseLintAtNode( $function_declaration, pht( - 'Declaring a function named `%s` causes any call to %s to fail. '. + 'Declaring a function named `%s` causes any call to `%s` to fail. '. 'This is because `%s` eval-declares the function `%s`, then '. 'modifies the symbol table so that the function is instead '. 'named `%s`, and returns that name.', diff --git a/src/lint/linter/xhpast/rules/ArcanistLogicalOperatorsXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistLogicalOperatorsXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistLogicalOperatorsXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistLogicalOperatorsXHPASTLinterRule.php @@ -20,14 +20,20 @@ foreach ($logical_ands as $logical_and) { $this->raiseLintAtToken( $logical_and, - pht('Use `%s` instead of `%s`.', '&&', 'and'), + pht( + 'Use boolean `%s` instead of logical `%s`.', + '&&', + 'and'), '&&'); } foreach ($logical_ors as $logical_or) { $this->raiseLintAtToken( $logical_or, - pht('Use `%s` instead of `%s`.', '||', 'or'), + pht( + 'Use boolean `%s` instead of logical `%s`.', + '||', + 'or'), '||'); } } diff --git a/src/lint/linter/xhpast/rules/ArcanistNamingConventionsXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistNamingConventionsXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistNamingConventionsXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistNamingConventionsXHPASTLinterRule.php @@ -138,7 +138,7 @@ ? null : pht( 'Follow naming conventions: parameters '. - 'should be named using `%s`', + 'should be named using `%s`.', 'lowercase_with_underscores'), ); } @@ -158,8 +158,8 @@ ArcanistXHPASTLintNamingHook::isUppercaseWithUnderscores($name_string) ? null : pht( - 'Follow naming conventions: class constants '. - 'should be named using `%s`', + 'Follow naming conventions: class constants should be named '. + 'using `%s`.', 'UPPERCASE_WITH_UNDERSCORES'), ); } @@ -186,8 +186,8 @@ ArcanistXHPASTLintNamingHook::stripPHPVariable($name_string)) ? null : pht( - 'Follow naming conventions: class properties '. - 'should be named using `%s`.', + 'Follow naming conventions: class properties should be named '. + 'using `%s`.', 'lowerCamelCase'), ); } diff --git a/src/lint/linter/xhpast/rules/ArcanistObjectOperatorSpacingXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistObjectOperatorSpacingXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistObjectOperatorSpacingXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistObjectOperatorSpacingXHPASTLinterRule.php @@ -29,7 +29,9 @@ $this->raiseLintAtOffset( head($before)->getOffset(), - pht('There should be no whitespace before the object operator.'), + pht( + 'There should be no whitespace before the object operator (`%s`).', + '->'), $value, ''); } @@ -37,7 +39,9 @@ if ($after) { $this->raiseLintAtOffset( head($after)->getOffset(), - pht('There should be no whitespace after the object operator.'), + pht( + 'There should be no whitespace after the object operator (`%s`).', + '->'), implode('', mpull($before, 'getValue')), ''); } diff --git a/src/lint/linter/xhpast/rules/ArcanistPHPCloseTagXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistPHPCloseTagXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistPHPCloseTagXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistPHPCloseTagXHPASTLinterRule.php @@ -6,7 +6,7 @@ const ID = 8; public function getLintName() { - return pht('Use of Close Tag `%s`', '?>'); + return pht('Use of PHP Closing Tag'); } public function process(XHPASTNode $root) { @@ -16,11 +16,13 @@ return; } - foreach ($root->selectTokensOfType('T_CLOSE_TAG') as $token) { + $tokens = $root->selectTokensOfType('T_CLOSE_TAG'); + + foreach ($tokens as $token) { $this->raiseLintAtToken( $token, pht( - 'Do not use the PHP closing tag, `%s`.', + 'Do not use the PHP closing tag (`%s`).', '?>')); } } diff --git a/src/lint/linter/xhpast/rules/ArcanistPHPCompatibilityXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistPHPCompatibilityXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistPHPCompatibilityXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistPHPCompatibilityXHPASTLinterRule.php @@ -363,9 +363,9 @@ $this->raiseLintAtNode( $index->getChildByIndex(1), pht( - 'The `%s` syntax was not introduced until PHP 5.4, but this '. - 'codebase targets an earlier version of PHP. You can rewrite '. - 'this expression using `%s`.', + 'The `%s` syntax was not introduced until PHP 5.4, '. + 'but this codebase targets an earlier version of PHP. '. + 'You can rewrite this expression using `%s`.', 'f()[...]', 'idx()')); break; diff --git a/src/lint/linter/xhpast/rules/ArcanistPHPEchoTagXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistPHPEchoTagXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistPHPEchoTagXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistPHPEchoTagXHPASTLinterRule.php @@ -6,7 +6,7 @@ const ID = 7; public function getLintName() { - return pht('Use of Echo Tag `%s`', 'raiseLintAtToken( $token, pht( - 'Avoid the PHP echo short form, `%s`.', + 'Avoid the PHP echo tag, `%s`.', 'getFunctionCalls($root, array('preg_quote')); foreach ($function_calls as $call) { - $parameter_list = $call->getChildOfType(1, 'n_CALL_PARAMETER_LIST'); - if (count($parameter_list->getChildren()) !== 2) { - $this->raiseLintAtNode( - $call, - pht( - 'If you use pattern delimiters that require escaping '. - '(such as `%s`, but not `%s`) then you should pass two '. - 'arguments to %s, so that %s knows which delimiter to escape.', - '//', - '()', - 'preg_quote', - 'preg_quote')); + $parameters = $call + ->getChildOfType(1, 'n_CALL_PARAMETER_LIST') + ->getChildren(); + + if (count($parameters) == 2) { + continue; } + + $this->raiseLintAtNode( + $call, + pht( + 'If you use pattern delimiters that require escaping '. + '(such as `%s`, but not `%s`) then you should pass two '. + 'arguments to `%s`, so that `%s` knows which delimiter to escape.', + '//', + '()', + 'preg_quote', + 'preg_quote')); } } diff --git a/src/lint/linter/xhpast/rules/ArcanistRaggedClassTreeEdgeXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistRaggedClassTreeEdgeXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistRaggedClassTreeEdgeXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistRaggedClassTreeEdgeXHPASTLinterRule.php @@ -14,25 +14,28 @@ } public function process(XHPASTNode $root) { - $parser = new PhutilDocblockParser(); - $classes = $root->selectDescendantsOfType('n_CLASS_DECLARATION'); + $parser = new PhutilDocblockParser(); + foreach ($classes as $class) { $is_final = false; $is_abstract = false; $is_concrete_extensible = false; $attributes = $class->getChildOfType(0, 'n_CLASS_ATTRIBUTES'); - foreach ($attributes->getChildren() as $child) { - if ($child->getConcreteString() == 'final') { - $is_final = true; - } - if ($child->getConcreteString() == 'abstract') { - $is_abstract = true; + $docblock = $class->getDocblockToken(); + + foreach ($attributes->getChildren() as $attribute) { + switch (strtolower($attribute->getConcreteString())) { + case 'abstract': + $is_abstract = true; + break; + case 'final': + $is_final = true; + break; } } - $docblock = $class->getDocblockToken(); if ($docblock) { list($text, $specials) = $parser->parse($docblock->getValue()); $is_concrete_extensible = idx($specials, 'concrete-extensible'); @@ -40,7 +43,7 @@ if (!$is_final && !$is_abstract && !$is_concrete_extensible) { $this->raiseLintAtNode( - $class->getChildOfType(1, 'n_CLASS_NAME'), + $class, pht( 'This class is neither `%s` nor `%s`, and does not have '. 'a docblock marking it `%s`.', diff --git a/src/lint/linter/xhpast/rules/ArcanistReusedAsIteratorXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistReusedAsIteratorXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistReusedAsIteratorXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistReusedAsIteratorXHPASTLinterRule.php @@ -90,7 +90,7 @@ if ($lval->getTypeName() === 'n_VARIABLE') { $vars[] = $lval; } else if ($lval->getTypeName() === 'n_LIST') { - // Recursivey grab everything out of list(), since the grammar + // Recursively grab everything out of list(), since the grammar // permits list() to be nested. Also note that list() is ONLY valid // as an lval assignments, so we could safely lift this out of the // n_BINARY_EXPRESSION branch. diff --git a/src/lint/linter/xhpast/rules/ArcanistToStringExceptionXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistToStringExceptionXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistToStringExceptionXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistToStringExceptionXHPASTLinterRule.php @@ -13,27 +13,26 @@ $methods = $root->selectDescendantsOfType('n_METHOD_DECLARATION'); foreach ($methods as $method) { - $name = $method + $method_name = $method ->getChildOfType(2, 'n_STRING') ->getConcreteString(); - if ($name != '__toString') { + if (strtolower($method_name) != '__tostring') { continue; } $statements = $method->getChildByIndex(5); - if ($statements->getTypeName() != 'n_STATEMENT_LIST') { continue; } $throws = $statements->selectDescendantsOfType('n_THROW'); - foreach ($throws as $throw) { $this->raiseLintAtNode( $throw, pht( - 'It is not possible to throw an `%s` from within the `%s` method.', + 'It is not possible to throw an `%s` from within the `%s` method. '. + 'Any attempt to do so will result in a fatal error.', 'Exception', '__toString')); } diff --git a/src/lint/linter/xhpast/rules/ArcanistUnnecessaryFinalModifierXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistUnnecessaryFinalModifierXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistUnnecessaryFinalModifierXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistUnnecessaryFinalModifierXHPASTLinterRule.php @@ -6,7 +6,7 @@ const ID = 55; public function getLintName() { - return pht('Unnecessary Final Modifier'); + return pht('Unnecessary `%s` Modifier', 'final'); } public function getLintSeverity() { diff --git a/src/lint/linter/xhpast/rules/ArcanistUnnecessarySemicolonXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistUnnecessarySemicolonXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistUnnecessarySemicolonXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistUnnecessarySemicolonXHPASTLinterRule.php @@ -23,16 +23,16 @@ if (count($statement->getChildren()) > 1) { continue; - } else if ($statement->getChildByIndex(0)->getTypeName() != 'n_EMPTY') { - continue; } - if ($statement->getConcreteString() == ';') { - $this->raiseLintAtNode( - $statement, - pht('Unnecessary semicolons after statement.'), - ''); + if ($statement->getChildByIndex(0)->getTypeName() != 'n_EMPTY') { + continue; } + + $this->raiseLintAtNode( + $statement, + pht('Unnecessary semicolon after statement.'), + ''); } } diff --git a/src/lint/linter/xhpast/rules/ArcanistUselessOverridingMethodXHPASTLinterRule.php b/src/lint/linter/xhpast/rules/ArcanistUselessOverridingMethodXHPASTLinterRule.php --- a/src/lint/linter/xhpast/rules/ArcanistUselessOverridingMethodXHPASTLinterRule.php +++ b/src/lint/linter/xhpast/rules/ArcanistUselessOverridingMethodXHPASTLinterRule.php @@ -34,6 +34,9 @@ } if ($default->getTypeName() != 'n_EMPTY') { + // If the parameter has a default value then it //may// be useless + // (if the parent method declares the same default value), but we + // can't be certain without checking the parent method declaration. continue 2; } @@ -68,12 +71,23 @@ continue; } - $called_class = $function->getChildOfType(0, 'n_CLASS_NAME'); - $called_method = $function->getChildOfType(1, 'n_STRING'); + $called_class = $function->getChildByIndex(0); + $called_method = $function->getChildByIndex(1); - if ($called_class->getConcreteString() != 'parent') { + if ($called_class->getTypeName() != 'n_CLASS_NAME') { continue; - } else if ($called_method->getConcreteString() != $method_name) { + } + + if ($called_method->getTypeName() != 'n_STRING') { + continue; + } + + $called_class = $called_class->getConcreteString(); + $called_method = $called_method->getConcreteString(); + + if (strtolower($called_class) != 'parent') { + continue; + } else if (strtolower($called_method) != strtolower($method_name)) { continue; } diff --git a/src/lint/linter/xhpast/rules/__tests__/ArcanistPHPCloseTagXHPASTLinterRuleTestCase.php b/src/lint/linter/xhpast/rules/__tests__/ArcanistPHPCloseTagXHPASTLinterRuleTestCase.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/xhpast/rules/__tests__/ArcanistPHPCloseTagXHPASTLinterRuleTestCase.php @@ -0,0 +1,10 @@ +executeTestsInDirectory(dirname(__FILE__).'/php-close-tag/'); + } + +} diff --git a/src/lint/linter/xhpast/rules/__tests__/ArcanistUnnecessarySemicolonXHPASTLinterRuleTestCase.php b/src/lint/linter/xhpast/rules/__tests__/ArcanistUnnecessarySemicolonXHPASTLinterRuleTestCase.php new file mode 100644 --- /dev/null +++ b/src/lint/linter/xhpast/rules/__tests__/ArcanistUnnecessarySemicolonXHPASTLinterRuleTestCase.php @@ -0,0 +1,10 @@ +executeTestsInDirectory(dirname(__FILE__).'/unnecessary-semicolon/'); + } + +} diff --git a/src/lint/linter/xhpast/rules/__tests__/__lambda_func-function/lamba-func-function.lint-test b/src/lint/linter/xhpast/rules/__tests__/__lambda_func-function/__lambda_func.lint-test rename from src/lint/linter/xhpast/rules/__tests__/__lambda_func-function/lamba-func-function.lint-test rename to src/lint/linter/xhpast/rules/__tests__/__lambda_func-function/__lambda_func.lint-test --- a/src/lint/linter/xhpast/rules/__tests__/__lambda_func-function/lamba-func-function.lint-test +++ b/src/lint/linter/xhpast/rules/__tests__/__lambda_func-function/__lambda_func.lint-test @@ -1,5 +1,4 @@ someMethod(&$x); +$y->someMethod($x); -$this->myfunc(&$myvar); -$this->myfunc($myvar); +SomeClass::someMethod(&$x); +SomeClass::someMethod($y); -MyClass::myfunc(&$myvar); -MyClass::myfunc($myvar); - -while (testfunc($var1, &$var2, $var3, &$var4) === false) {} - -sprintf('0%o', 0777 & $p); - -$foo(&$myvar); - -array_walk(array(), function () use (&$x) {}); -MyClass::myfunc(array(&$x, &$y)); +$var(&$x); ~~~~~~~~~~ -error:10:8 -error:13:15 -error:16:17 -error:19:24 -error:19:39 -error:23:6 +error:3:11 +error:6:16 +error:9:23 +error:12:6 diff --git a/src/lint/linter/xhpast/rules/__tests__/call-time-pass-by-reference/function-declaration.lint-test b/src/lint/linter/xhpast/rules/__tests__/call-time-pass-by-reference/function-declaration.lint-test new file mode 100644 --- /dev/null +++ b/src/lint/linter/xhpast/rules/__tests__/call-time-pass-by-reference/function-declaration.lint-test @@ -0,0 +1,4 @@ + + + + + + +~~~~~~~~~~ diff --git a/src/lint/linter/xhpast/rules/__tests__/extract-use/extract-use.lint-test b/src/lint/linter/xhpast/rules/__tests__/php-close-tag/php.lint-test rename from src/lint/linter/xhpast/rules/__tests__/extract-use/extract-use.lint-test rename to src/lint/linter/xhpast/rules/__tests__/php-close-tag/php.lint-test --- a/src/lint/linter/xhpast/rules/__tests__/extract-use/extract-use.lint-test +++ b/src/lint/linter/xhpast/rules/__tests__/php-close-tag/php.lint-test @@ -1,5 +1,5 @@ ~~~~~~~~~~ error:3:1 diff --git a/src/lint/linter/xhpast/rules/__tests__/preg_quote-misuse/misuse.lint-test b/src/lint/linter/xhpast/rules/__tests__/preg_quote-misuse/misuse.lint-test new file mode 100644 --- /dev/null +++ b/src/lint/linter/xhpast/rules/__tests__/preg_quote-misuse/misuse.lint-test @@ -0,0 +1,6 @@ +$bar; +~~~~~~~~~~ diff --git a/src/lint/linter/xhpast/rules/__tests__/variable-variable/variable-variables.lint-test b/src/lint/linter/xhpast/rules/__tests__/variable-variable/variable-variables.lint-test deleted file mode 100644 --- a/src/lint/linter/xhpast/rules/__tests__/variable-variable/variable-variables.lint-test +++ /dev/null @@ -1,6 +0,0 @@ -$bar; // okay -~~~~~~~~~~ -error:3:1 diff --git a/src/lint/linter/xhpast/rules/__tests__/variable-variable/variable.lint-test b/src/lint/linter/xhpast/rules/__tests__/variable-variable/variable.lint-test new file mode 100644 --- /dev/null +++ b/src/lint/linter/xhpast/rules/__tests__/variable-variable/variable.lint-test @@ -0,0 +1,7 @@ +