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 @@ -49,6 +49,7 @@ const LINT_EMPTY_STATEMENT = 47; const LINT_ARRAY_SEPARATOR = 48; const LINT_CONSTRUCTOR_PARENTHESES = 49; + const LINT_EVAL_USE = 50; private $naminghook; private $switchhook; @@ -109,6 +110,7 @@ self::LINT_EMPTY_STATEMENT => 'Empty Block Statement', self::LINT_ARRAY_SEPARATOR => 'Array Separator', self::LINT_CONSTRUCTOR_PARENTHESES => 'Constructor Parentheses', + self::LINT_EVAL_USE => 'Use of eval()', ); } @@ -199,7 +201,7 @@ public function getVersion() { // The version number should be incremented whenever a new rule is added. - return '10'; + return '11'; } protected function resolveFuture($path, Future $future) { @@ -271,6 +273,7 @@ 'lintEmptyBlockStatements' => self::LINT_EMPTY_STATEMENT, 'lintArraySeparator' => self::LINT_ARRAY_SEPARATOR, 'lintConstructorParentheses' => self::LINT_CONSTRUCTOR_PARENTHESES, + 'lintEvalUsage' => self::LINT_EVAL_USE, ); foreach ($method_codes as $method => $codes) { @@ -2819,6 +2822,25 @@ } } + private function lintEvalUsage(XHPASTNode $root) { + $calls = $root->selectDescendantsOfType('n_FUNCTION_CALL'); + + foreach ($calls as $call) { + $node = $call->getChildByIndex(0); + $name = $node->getConcreteString(); + + if ($name == 'eval') { + $this->raiseLintAtNode( + $node, + self::LINT_EVAL_USE, + pht( + 'The %s function should be avoided. It is potentially '. + 'unsafe and makes debugging more difficult.', + 'eval()')); + } + } + } + public function getSuperGlobalNames() { return array( '$GLOBALS', diff --git a/src/lint/linter/__tests__/xhpast/eval.lint-test b/src/lint/linter/__tests__/xhpast/eval.lint-test new file mode 100644 --- /dev/null +++ b/src/lint/linter/__tests__/xhpast/eval.lint-test @@ -0,0 +1,4 @@ +