diff --git a/src/lint/linter/ArcanistXHPASTLinter.php b/src/lint/linter/ArcanistXHPASTLinter.php --- a/src/lint/linter/ArcanistXHPASTLinter.php +++ b/src/lint/linter/ArcanistXHPASTLinter.php @@ -57,6 +57,7 @@ const LINT_UNNECESSARY_FINAL_MODIFIER = 55; const LINT_UNNECESSARY_SEMICOLON = 56; const LINT_CAST_SPACING = 57; + const LINT_PHP_SAPI = 58; private $blacklistedFunctions = array(); private $naminghook; @@ -127,6 +128,7 @@ self::LINT_UNNECESSARY_FINAL_MODIFIER => 'Unnecessary Final Modifier', self::LINT_UNNECESSARY_SEMICOLON => 'Unnecessary Semicolon', self::LINT_CAST_SPACING => 'Cast Spacing', + self::LINT_PHP_SAPI => 'PHP SAPI Function', ); } @@ -172,6 +174,7 @@ self::LINT_UNNECESSARY_FINAL_MODIFIER => $advice, self::LINT_UNNECESSARY_SEMICOLON => $advice, self::LINT_CAST_SPACING => $advice, + self::LINT_PHP_SAPI => $warning, ); } @@ -239,7 +242,7 @@ public function getVersion() { // The version number should be incremented whenever a new rule is added. - return '19'; + return '20'; } protected function resolveFuture($path, Future $future) { @@ -320,6 +323,7 @@ 'lintUnnecessaryFinalModifier' => self::LINT_UNNECESSARY_FINAL_MODIFIER, 'lintUnnecessarySemicolons' => self::LINT_UNNECESSARY_SEMICOLON, 'lintCastSpacing' => self::LINT_CAST_SPACING, + 'lintPHPSAPI' => self::LINT_PHP_SAPI, ); foreach ($method_codes as $method => $codes) { @@ -3292,6 +3296,46 @@ } } + private function lintPHPSAPI(XHPASTNode $root) { + $function_calls = $this->getFunctionCalls($root, array('php_sapi_name')); + + foreach ($function_calls as $function_call) { + $this->raiseLintAtNode( + $function_call, + self::LINT_PHP_SAPI, + pht( + 'Use the %s constant instead of calling php_sapi_name()', + 'PHP_SAPI'), + 'PHP_SAPI_NAME'); + } + } + + /** + * 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/__tests__/xhpast/php-sapi.lint-test b/src/lint/linter/__tests__/xhpast/php-sapi.lint-test new file mode 100644 --- /dev/null +++ b/src/lint/linter/__tests__/xhpast/php-sapi.lint-test @@ -0,0 +1,9 @@ +