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 @@ -64,6 +64,7 @@ const LINT_CLASS_NAME_LITERAL = 62; const LINT_USELESS_OVERRIDING_METHOD = 63; const LINT_NO_PARENT_SCOPE = 64; + const LINT_LAMBDA_FUNC_FUNCTION = 65; private $blacklistedFunctions = array(); private $naminghook; @@ -200,6 +201,8 @@ => pht('Useless Overriding Method'), self::LINT_NO_PARENT_SCOPE => pht('No Parent Scope'), + self::LINT_LAMBDA_FUNC_FUNCTION + => pht('%s Function', '__lambda_func'), ); } @@ -318,7 +321,7 @@ public function getVersion() { // The version number should be incremented whenever a new rule is added. - return '26'; + return '27'; } protected function resolveFuture($path, Future $future) { @@ -409,6 +412,7 @@ 'lintClassNameLiteral' => self::LINT_CLASS_NAME_LITERAL, 'lintUselessOverridingMethods' => self::LINT_USELESS_OVERRIDING_METHOD, 'lintNoParentScope' => self::LINT_NO_PARENT_SCOPE, + 'lintLambdaFuncFunction' => self::LINT_LAMBDA_FUNC_FUNCTION, ); foreach ($method_codes as $method => $codes) { @@ -3887,6 +3891,38 @@ } } + private function lintLambdaFuncFunction(XHPASTNode $root) { + $function_declarations = $root + ->selectDescendantsOfType('n_FUNCTION_DECLARATION'); + + foreach ($function_declarations as $function_declaration) { + $function_name = $function_declaration->getChildByIndex(2); + + if ($function_name->getTypeName() == 'n_EMPTY') { + // Anonymous closure. + continue; + } + + if ($function_name->getConcreteString() != '__lambda_func') { + continue; + } + + $this->raiseLintAtNode( + $function_declaration, + self::LINT_LAMBDA_FUNC_FUNCTION, + pht( + '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.', + '__lambda_func', + 'create_function', + 'create_function', + '__lambda_func', + '"\0lambda_".(++$i)')); + } + } + /** * Retrieve all calls to some specified function(s). diff --git a/src/lint/linter/__tests__/xhpast/lamba-func-function.lint-test b/src/lint/linter/__tests__/xhpast/lamba-func-function.lint-test new file mode 100644 --- /dev/null +++ b/src/lint/linter/__tests__/xhpast/lamba-func-function.lint-test @@ -0,0 +1,4 @@ +<?php +function __lambda_func() {} +~~~~~~~~~~ +error:2:1