diff --git a/src/lint/linter/ArcanistBaseXHPASTLinter.php b/src/lint/linter/ArcanistBaseXHPASTLinter.php index 3549a353..47aa74cc 100644 --- a/src/lint/linter/ArcanistBaseXHPASTLinter.php +++ b/src/lint/linter/ArcanistBaseXHPASTLinter.php @@ -196,6 +196,35 @@ abstract class ArcanistBaseXHPASTLinter extends ArcanistFutureLinter { return idx($this->exceptions, $path); } + +/* -( Utility )------------------------------------------------------------ */ + + /** + * Retrieve all calls to some specified function(s). + * + * Returns all descendant nodes which represent a function call to one of the + * specified functions. + * + * @param XHPASTNode Root node. + * @param list Function names. + * @return AASTNodeList + */ + protected function getFunctionCalls(XHPASTNode $root, array $function_names) { + $calls = $root->selectDescendantsOfType('n_FUNCTION_CALL'); + $nodes = array(); + + foreach ($calls as $call) { + $node = $call->getChildByIndex(0); + $name = strtolower($node->getConcreteString()); + + if (in_array($name, $function_names)) { + $nodes[] = $call; + } + } + + return AASTNodeList::newFromTreeAndNodes($root->getTree(), $nodes); + } + public function getSuperGlobalNames() { return array( '$GLOBALS', diff --git a/src/lint/linter/ArcanistPhutilXHPASTLinter.php b/src/lint/linter/ArcanistPhutilXHPASTLinter.php index 69d1ba86..40fd6296 100644 --- a/src/lint/linter/ArcanistPhutilXHPASTLinter.php +++ b/src/lint/linter/ArcanistPhutilXHPASTLinter.php @@ -21,21 +21,6 @@ final class ArcanistPhutilXHPASTLinter extends ArcanistBaseXHPASTLinter { 'linter is intended for use in Phabricator libraries and extensions.'); } - public function setDeprecatedFunctions(array $map) { - $this->deprecatedFunctions = $map; - return $this; - } - - public function setDynamicStringFunctions(array $map) { - $this->dynamicStringFunctions = $map; - return $this; - } - - public function setDynamicStringClasses(array $map) { - $this->dynamicStringClasses = $map; - return $this; - } - public function getLintNameMap() { return array( self::LINT_ARRAY_COMBINE => pht( @@ -49,16 +34,6 @@ final class ArcanistPhutilXHPASTLinter extends ArcanistBaseXHPASTLinter { ); } - public function getLintSeverityMap() { - $warning = ArcanistLintSeverity::SEVERITY_WARNING; - return array( - self::LINT_ARRAY_COMBINE => $warning, - self::LINT_DEPRECATED_FUNCTION => $warning, - self::LINT_UNSAFE_DYNAMIC_STRING => $warning, - self::LINT_RAGGED_CLASSTREE_EDGE => $warning, - ); - } - public function getLinterName() { return 'PHLXHP'; } @@ -67,9 +42,15 @@ final class ArcanistPhutilXHPASTLinter extends ArcanistBaseXHPASTLinter { return 'phutil-xhpast'; } - public function getVersion() { - // The version number should be incremented whenever a new rule is added. - return '3'; + public function getLintSeverityMap() { + $warning = ArcanistLintSeverity::SEVERITY_WARNING; + + return array( + self::LINT_ARRAY_COMBINE => $warning, + self::LINT_DEPRECATED_FUNCTION => $warning, + self::LINT_UNSAFE_DYNAMIC_STRING => $warning, + self::LINT_RAGGED_CLASSTREE_EDGE => $warning, + ); } public function getLinterConfigurationOptions() { @@ -107,9 +88,15 @@ final class ArcanistPhutilXHPASTLinter extends ArcanistBaseXHPASTLinter { case 'phutil-xhpast.dynamic-string.classes': $this->setDynamicStringClasses($value); return; + default: + parent::setLinterConfigurationValue($key, $value); + return; } + } - return parent::setLinterConfigurationValue($key, $value); + public function getVersion() { + // The version number should be incremented whenever a new rule is added. + return '3'; } protected function resolveFuture($path, Future $future) { @@ -137,6 +124,27 @@ final class ArcanistPhutilXHPASTLinter extends ArcanistBaseXHPASTLinter { } } + +/* -( Setters )------------------------------------------------------------ */ + + public function setDeprecatedFunctions(array $map) { + $this->deprecatedFunctions = $map; + return $this; + } + + public function setDynamicStringClasses(array $map) { + $this->dynamicStringClasses = $map; + return $this; + } + + public function setDynamicStringFunctions(array $map) { + $this->dynamicStringFunctions = $map; + return $this; + } + + +/* -( Linter Rules )------------------------------------------------------- */ + private function lintUnsafeDynamicString(XHPASTNode $root) { $safe = $this->dynamicStringFunctions + array( 'pht' => 0, @@ -206,40 +214,42 @@ final class ArcanistPhutilXHPASTLinter extends ArcanistBaseXHPASTLinter { } private function lintArrayCombine(XHPASTNode $root) { - $function_calls = $root->selectDescendantsOfType('n_FUNCTION_CALL'); + $function_calls = $this->getFunctionCalls($root, array('array_combine')); + foreach ($function_calls as $call) { $name = $call->getChildByIndex(0)->getConcreteString(); - if (strcasecmp($name, 'array_combine') == 0) { - $parameter_list = $call->getChildOfType(1, 'n_CALL_PARAMETER_LIST'); - if (count($parameter_list->getChildren()) !== 2) { - // Wrong number of parameters, but raise that elsewhere if we want. - continue; - } + $parameter_list = $call->getChildOfType(1, 'n_CALL_PARAMETER_LIST'); - $first = $parameter_list->getChildByIndex(0); - $second = $parameter_list->getChildByIndex(1); + if (count($parameter_list->getChildren()) !== 2) { + // Wrong number of parameters, but raise that elsewhere if we want. + continue; + } - if ($first->getConcreteString() == $second->getConcreteString()) { - $this->raiseLintAtNode( - $call, - self::LINT_ARRAY_COMBINE, - pht( - 'Prior to PHP 5.4, `%s` fails when given empty arrays. '. - 'Prefer to write `%s` as `%s`.', - 'array_combine()', - 'array_combine(x, x)', - 'array_fuse(x)')); - } + $first = $parameter_list->getChildByIndex(0); + $second = $parameter_list->getChildByIndex(1); + + if ($first->getConcreteString() == $second->getConcreteString()) { + $this->raiseLintAtNode( + $call, + self::LINT_ARRAY_COMBINE, + pht( + 'Prior to PHP 5.4, `%s` fails when given empty arrays. '. + 'Prefer to write `%s` as `%s`.', + 'array_combine()', + 'array_combine(x, x)', + 'array_fuse(x)')); } } } private function lintDeprecatedFunctions(XHPASTNode $root) { $map = $this->deprecatedFunctions; + $function_calls = $this->getFunctionCalls($root, array_keys($map)); - $function_calls = $root->selectDescendantsOfType('n_FUNCTION_CALL'); foreach ($function_calls as $call) { - $name = $call->getChildByIndex(0)->getConcreteString(); + $name = $call + ->getChildByIndex(0) + ->getConcreteString(); $name = strtolower($name); if (empty($map[$name])) { diff --git a/src/lint/linter/ArcanistXHPASTLinter.php b/src/lint/linter/ArcanistXHPASTLinter.php index 920454de..68161aef 100644 --- a/src/lint/linter/ArcanistXHPASTLinter.php +++ b/src/lint/linter/ArcanistXHPASTLinter.php @@ -4298,31 +4298,4 @@ final class ArcanistXHPASTLinter extends ArcanistBaseXHPASTLinter { } } - - /** - * Retrieve all calls to some specified function(s). - * - * Returns all descendant nodes which represent a function call to one of the - * specified functions. - * - * @param XHPASTNode Root node. - * @param list Function names. - * @return AASTNodeList - */ - protected function getFunctionCalls(XHPASTNode $root, array $function_names) { - $calls = $root->selectDescendantsOfType('n_FUNCTION_CALL'); - $nodes = array(); - - foreach ($calls as $call) { - $node = $call->getChildByIndex(0); - $name = strtolower($node->getConcreteString()); - - if (in_array($name, $function_names)) { - $nodes[] = $call; - } - } - - return AASTNodeList::newFromTreeAndNodes($root->getTree(), $nodes); - } - }