From 9ecb36e81f703c5e7aae36c046f441e03f27cbdb Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Fri, 30 Jan 2015 17:31:51 +0100 Subject: integrate code checker in the installer --- lib/private/app/codechecker.php | 23 +++++-- lib/private/app/codecheckervisitor.php | 111 --------------------------------- lib/private/app/codecheckvisitor.php | 111 +++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 115 deletions(-) delete mode 100644 lib/private/app/codecheckervisitor.php create mode 100644 lib/private/app/codecheckvisitor.php (limited to 'lib/private/app') diff --git a/lib/private/app/codechecker.php b/lib/private/app/codechecker.php index 28816a8fdc5..dbec53579a8 100644 --- a/lib/private/app/codechecker.php +++ b/lib/private/app/codechecker.php @@ -29,6 +29,12 @@ class CodeChecker extends BasicEmitter { const CLASS_CONST_FETCH_NOT_ALLOWED = 1003; const CLASS_NEW_FETCH_NOT_ALLOWED = 1004; + /** @var Parser */ + private $parser; + + /** @var string[] */ + private $blackListedClassNames; + public function __construct() { $this->parser = new Parser(new Lexer); $this->blackListedClassNames = [ @@ -67,14 +73,22 @@ class CodeChecker extends BasicEmitter { throw new \RuntimeException("No app with given id <$appId> known."); } + return $this->analyseFolder($appPath); + } + + /** + * @param string $folder + * @return array + */ + public function analyseFolder($folder) { $errors = []; - $excludes = array_map(function($item) use ($appPath) { - return $appPath . '/' . $item; + $excludes = array_map(function($item) use ($folder) { + return $folder . '/' . $item; }, ['vendor', '3rdparty', '.git', 'l10n']); - $iterator = new RecursiveDirectoryIterator($appPath, RecursiveDirectoryIterator::SKIP_DOTS); - $iterator = new RecursiveCallbackFilterIterator($iterator, function($item) use ($appPath, $excludes){ + $iterator = new RecursiveDirectoryIterator($folder, RecursiveDirectoryIterator::SKIP_DOTS); + $iterator = new RecursiveCallbackFilterIterator($iterator, function($item) use ($folder, $excludes){ /** @var SplFileInfo $item */ foreach($excludes as $exclude) { if (substr($item->getPath(), 0, strlen($exclude)) === $exclude) { @@ -96,6 +110,7 @@ class CodeChecker extends BasicEmitter { return $errors; } + /** * @param string $file * @return array diff --git a/lib/private/app/codecheckervisitor.php b/lib/private/app/codecheckervisitor.php deleted file mode 100644 index 939c905bcf6..00000000000 --- a/lib/private/app/codecheckervisitor.php +++ /dev/null @@ -1,111 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace OC\App; - -use OC\Hooks\BasicEmitter; -use PhpParser\Lexer; -use PhpParser\Node; -use PhpParser\Node\Name; -use PhpParser\NodeTraverser; -use PhpParser\NodeVisitorAbstract; -use PhpParser\Parser; -use RecursiveCallbackFilterIterator; -use RecursiveDirectoryIterator; -use RecursiveIteratorIterator; -use RegexIterator; -use SplFileInfo; - -class CodeCheckVisitor extends NodeVisitorAbstract { - - public function __construct($blackListedClassNames) { - $this->blackListedClassNames = array_map('strtolower', $blackListedClassNames); - } - - public $errors = []; - - public function enterNode(Node $node) { - if ($node instanceof Node\Stmt\Class_) { - if (!is_null($node->extends)) { - $this->checkBlackList($node->extends->toString(), CodeChecker::CLASS_EXTENDS_NOT_ALLOWED, $node); - } - foreach ($node->implements as $implements) { - $this->checkBlackList($implements->toString(), CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED, $node); - } - } - if ($node instanceof Node\Expr\StaticCall) { - if (!is_null($node->class)) { - if ($node->class instanceof Name) { - $this->checkBlackList($node->class->toString(), CodeChecker::STATIC_CALL_NOT_ALLOWED, $node); - } - if ($node->class instanceof Node\Expr\Variable) { - /** - * TODO: find a way to detect something like this: - * $c = "OC_API"; - * $n = $i::call(); - */ - } - } - } - if ($node instanceof Node\Expr\ClassConstFetch) { - if (!is_null($node->class)) { - if ($node->class instanceof Name) { - $this->checkBlackList($node->class->toString(), CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED, $node); - } - if ($node->class instanceof Node\Expr\Variable) { - /** - * TODO: find a way to detect something like this: - * $c = "OC_API"; - * $n = $i::ADMIN_AUTH; - */ - } - } - } - if ($node instanceof Node\Expr\New_) { - if (!is_null($node->class)) { - if ($node->class instanceof Name) { - $this->checkBlackList($node->class->toString(), CodeChecker::CLASS_NEW_FETCH_NOT_ALLOWED, $node); - } - if ($node->class instanceof Node\Expr\Variable) { - /** - * TODO: find a way to detect something like this: - * $c = "OC_API"; - * $n = new $i; - */ - } - } - } - } - - private function checkBlackList($name, $errorCode, Node $node) { - if (in_array(strtolower($name), $this->blackListedClassNames)) { - $this->errors[]= [ - 'disallowedToken' => $name, - 'errorCode' => $errorCode, - 'line' => $node->getLine(), - 'reason' => $this->buildReason($name, $errorCode) - ]; - } - } - - private function buildReason($name, $errorCode) { - static $errorMessages= [ - CodeChecker::CLASS_EXTENDS_NOT_ALLOWED => "used as base class", - CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED => "used as interface", - CodeChecker::STATIC_CALL_NOT_ALLOWED => "static method call on private class", - CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED => "used to fetch a const from", - CodeChecker::CLASS_NEW_FETCH_NOT_ALLOWED => "is instanciated", - ]; - - if (isset($errorMessages[$errorCode])) { - return $errorMessages[$errorCode]; - } - - return "$name usage not allowed - error: $errorCode"; - } -} diff --git a/lib/private/app/codecheckvisitor.php b/lib/private/app/codecheckvisitor.php new file mode 100644 index 00000000000..939c905bcf6 --- /dev/null +++ b/lib/private/app/codecheckvisitor.php @@ -0,0 +1,111 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC\App; + +use OC\Hooks\BasicEmitter; +use PhpParser\Lexer; +use PhpParser\Node; +use PhpParser\Node\Name; +use PhpParser\NodeTraverser; +use PhpParser\NodeVisitorAbstract; +use PhpParser\Parser; +use RecursiveCallbackFilterIterator; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use RegexIterator; +use SplFileInfo; + +class CodeCheckVisitor extends NodeVisitorAbstract { + + public function __construct($blackListedClassNames) { + $this->blackListedClassNames = array_map('strtolower', $blackListedClassNames); + } + + public $errors = []; + + public function enterNode(Node $node) { + if ($node instanceof Node\Stmt\Class_) { + if (!is_null($node->extends)) { + $this->checkBlackList($node->extends->toString(), CodeChecker::CLASS_EXTENDS_NOT_ALLOWED, $node); + } + foreach ($node->implements as $implements) { + $this->checkBlackList($implements->toString(), CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED, $node); + } + } + if ($node instanceof Node\Expr\StaticCall) { + if (!is_null($node->class)) { + if ($node->class instanceof Name) { + $this->checkBlackList($node->class->toString(), CodeChecker::STATIC_CALL_NOT_ALLOWED, $node); + } + if ($node->class instanceof Node\Expr\Variable) { + /** + * TODO: find a way to detect something like this: + * $c = "OC_API"; + * $n = $i::call(); + */ + } + } + } + if ($node instanceof Node\Expr\ClassConstFetch) { + if (!is_null($node->class)) { + if ($node->class instanceof Name) { + $this->checkBlackList($node->class->toString(), CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED, $node); + } + if ($node->class instanceof Node\Expr\Variable) { + /** + * TODO: find a way to detect something like this: + * $c = "OC_API"; + * $n = $i::ADMIN_AUTH; + */ + } + } + } + if ($node instanceof Node\Expr\New_) { + if (!is_null($node->class)) { + if ($node->class instanceof Name) { + $this->checkBlackList($node->class->toString(), CodeChecker::CLASS_NEW_FETCH_NOT_ALLOWED, $node); + } + if ($node->class instanceof Node\Expr\Variable) { + /** + * TODO: find a way to detect something like this: + * $c = "OC_API"; + * $n = new $i; + */ + } + } + } + } + + private function checkBlackList($name, $errorCode, Node $node) { + if (in_array(strtolower($name), $this->blackListedClassNames)) { + $this->errors[]= [ + 'disallowedToken' => $name, + 'errorCode' => $errorCode, + 'line' => $node->getLine(), + 'reason' => $this->buildReason($name, $errorCode) + ]; + } + } + + private function buildReason($name, $errorCode) { + static $errorMessages= [ + CodeChecker::CLASS_EXTENDS_NOT_ALLOWED => "used as base class", + CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED => "used as interface", + CodeChecker::STATIC_CALL_NOT_ALLOWED => "static method call on private class", + CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED => "used to fetch a const from", + CodeChecker::CLASS_NEW_FETCH_NOT_ALLOWED => "is instanciated", + ]; + + if (isset($errorMessages[$errorCode])) { + return $errorMessages[$errorCode]; + } + + return "$name usage not allowed - error: $errorCode"; + } +} -- cgit v1.2.3