From 4e95031ec4e74bb99dc2dc819ddb77893564e01c Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 15 Jun 2015 12:51:22 +0200 Subject: Allow app:check-code to check for deprecated methods --- lib/private/app/codechecker.php | 63 ++++++++++++++++-------------- lib/private/app/codecheckvisitor.php | 45 ++++++++++++++------- lib/private/app/deprecationcodechecker.php | 44 +++++++++++++++++++++ 3 files changed, 109 insertions(+), 43 deletions(-) create mode 100644 lib/private/app/deprecationcodechecker.php (limited to 'lib') diff --git a/lib/private/app/codechecker.php b/lib/private/app/codechecker.php index 3f6cd19d6b4..38d98255cf1 100644 --- a/lib/private/app/codechecker.php +++ b/lib/private/app/codechecker.php @@ -28,7 +28,6 @@ use PhpParser\Lexer; use PhpParser\Node; use PhpParser\Node\Name; use PhpParser\NodeTraverser; -use PhpParser\NodeVisitorAbstract; use PhpParser\Parser; use RecursiveCallbackFilterIterator; use RecursiveDirectoryIterator; @@ -48,37 +47,43 @@ class CodeChecker extends BasicEmitter { /** @var Parser */ private $parser; + /** @var string */ + protected $blackListDescription = 'private'; + /** @var string[] */ - private $blackListedClassNames; + protected $blackListedClassNames = [ + // classes replaced by the public api + 'OC_API', + 'OC_App', + 'OC_AppConfig', + 'OC_Avatar', + 'OC_BackgroundJob', + 'OC_Config', + 'OC_DB', + 'OC_Files', + 'OC_Helper', + 'OC_Hook', + 'OC_Image', + 'OC_JSON', + 'OC_L10N', + 'OC_Log', + 'OC_Mail', + 'OC_Preferences', + 'OC_Search_Provider', + 'OC_Search_Result', + 'OC_Request', + 'OC_Response', + 'OC_Template', + 'OC_User', + 'OC_Util', + ]; + + /** @var bool */ + protected $checkEqualOperators = false; + public function __construct() { $this->parser = new Parser(new Lexer); - $this->blackListedClassNames = [ - // classes replaced by the public api - 'OC_API', - 'OC_App', - 'OC_AppConfig', - 'OC_Avatar', - 'OC_BackgroundJob', - 'OC_Config', - 'OC_DB', - 'OC_Files', - 'OC_Helper', - 'OC_Hook', - 'OC_Image', - 'OC_JSON', - 'OC_L10N', - 'OC_Log', - 'OC_Mail', - 'OC_Preferences', - 'OC_Search_Provider', - 'OC_Search_Result', - 'OC_Request', - 'OC_Response', - 'OC_Template', - 'OC_User', - 'OC_Util', - ]; } /** @@ -138,7 +143,7 @@ class CodeChecker extends BasicEmitter { $code = file_get_contents($file); $statements = $this->parser->parse($code); - $visitor = new CodeCheckVisitor($this->blackListedClassNames); + $visitor = new CodeCheckVisitor($this->blackListDescription, $this->blackListedClassNames, $this->checkEqualOperators); $traverser = new NodeTraverser; $traverser->addVisitor($visitor); diff --git a/lib/private/app/codecheckvisitor.php b/lib/private/app/codecheckvisitor.php index e983bd8630b..d4b5bedbb1f 100644 --- a/lib/private/app/codecheckvisitor.php +++ b/lib/private/app/codecheckvisitor.php @@ -27,15 +27,41 @@ use PhpParser\Node\Name; use PhpParser\NodeVisitorAbstract; class CodeCheckVisitor extends NodeVisitorAbstract { + /** @var string */ + protected $blackListDescription; + /** @var string[] */ + protected $blackListedClassNames; + /** @var bool */ + protected $checkEqualOperatorUsage; + /** @var string[] */ + protected $errorMessages; - public function __construct($blackListedClassNames) { + /** + * @param string $blackListDescription + * @param string[] $blackListedClassNames + * @param bool $checkEqualOperatorUsage + */ + public function __construct($blackListDescription, $blackListedClassNames, $checkEqualOperatorUsage) { + $this->blackListDescription = $blackListDescription; $this->blackListedClassNames = array_map('strtolower', $blackListedClassNames); + $this->checkEqualOperatorUsage = $checkEqualOperatorUsage; + + $this->errorMessages = [ + CodeChecker::CLASS_EXTENDS_NOT_ALLOWED => "{$this->blackListDescription} class must not be extended", + CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED => "{$this->blackListDescription} interface must not be implemented", + CodeChecker::STATIC_CALL_NOT_ALLOWED => "Static method of {$this->blackListDescription} class must not be called", + CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED => "Constant of {$this->blackListDescription} class must not not be fetched", + CodeChecker::CLASS_NEW_FETCH_NOT_ALLOWED => "{$this->blackListDescription} class must not be instanciated", + + CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED => "is discouraged", + ]; } + /** @var array */ public $errors = []; public function enterNode(Node $node) { - if ($node instanceof Node\Expr\BinaryOp\Equal) { + if ($this->checkEqualOperatorUsage && $node instanceof Node\Expr\BinaryOp\Equal) { $this->errors[]= [ 'disallowedToken' => '==', 'errorCode' => CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED, @@ -43,7 +69,7 @@ class CodeCheckVisitor extends NodeVisitorAbstract { 'reason' => $this->buildReason('==', CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED) ]; } - if ($node instanceof Node\Expr\BinaryOp\NotEqual) { + if ($this->checkEqualOperatorUsage && $node instanceof Node\Expr\BinaryOp\NotEqual) { $this->errors[]= [ 'disallowedToken' => '!=', 'errorCode' => CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED, @@ -115,17 +141,8 @@ class CodeCheckVisitor extends NodeVisitorAbstract { } 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", - CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED => "is discouraged" - ]; - - if (isset($errorMessages[$errorCode])) { - return $errorMessages[$errorCode]; + if (isset($this->errorMessages[$errorCode])) { + return $this->errorMessages[$errorCode]; } return "$name usage not allowed - error: $errorCode"; diff --git a/lib/private/app/deprecationcodechecker.php b/lib/private/app/deprecationcodechecker.php new file mode 100644 index 00000000000..c89428927c1 --- /dev/null +++ b/lib/private/app/deprecationcodechecker.php @@ -0,0 +1,44 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\App; + +use PhpParser\Lexer; +use PhpParser\Node; +use PhpParser\Node\Name; + +class DeprecationCodeChecker extends CodeChecker { + protected $checkEqualOperators = true; + + /** @var string */ + protected $blackListDescription = 'deprecated'; + + protected $blackListedClassNames = [ + // Deprecated classes + 'OCP\IConfig', + 'OCP\Contacts', + 'OCP\DB', + 'OCP\IHelper', + 'OCP\JSON', + 'OCP\Response', + 'OCP\AppFramework\IApi', + ]; +} -- cgit v1.2.3 From d2fc1b230235e1aa9fa5d956e9a7edbbeef72dfb Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 15 Jun 2015 15:24:45 +0200 Subject: Correctly handle use statements --- lib/private/app/codechecker.php | 1 + lib/private/app/codecheckvisitor.php | 44 ++++++++++++++++++++-- .../app/code-checker/test-deprecated-use-alias.php | 9 +++++ .../code-checker/test-deprecated-use-sub-alias.php | 9 +++++ .../app/code-checker/test-deprecated-use-sub.php | 9 +++++ .../data/app/code-checker/test-deprecated-use.php | 9 +++++ tests/data/app/code-checker/test-use.php | 12 ++++++ tests/lib/app/codechecker.php | 9 +++-- tests/lib/app/deprecationcodechecker.php | 13 +++++-- 9 files changed, 104 insertions(+), 11 deletions(-) create mode 100644 tests/data/app/code-checker/test-deprecated-use-alias.php create mode 100644 tests/data/app/code-checker/test-deprecated-use-sub-alias.php create mode 100644 tests/data/app/code-checker/test-deprecated-use-sub.php create mode 100644 tests/data/app/code-checker/test-deprecated-use.php create mode 100644 tests/data/app/code-checker/test-use.php (limited to 'lib') diff --git a/lib/private/app/codechecker.php b/lib/private/app/codechecker.php index 38d98255cf1..0216e61e7ae 100644 --- a/lib/private/app/codechecker.php +++ b/lib/private/app/codechecker.php @@ -43,6 +43,7 @@ class CodeChecker extends BasicEmitter { const CLASS_CONST_FETCH_NOT_ALLOWED = 1003; const CLASS_NEW_FETCH_NOT_ALLOWED = 1004; const OP_OPERATOR_USAGE_DISCOURAGED = 1005; + const CLASS_USE_NOT_ALLOWED = 1006; /** @var Parser */ private $parser; diff --git a/lib/private/app/codecheckvisitor.php b/lib/private/app/codecheckvisitor.php index d4b5bedbb1f..0dec5b3715d 100644 --- a/lib/private/app/codecheckvisitor.php +++ b/lib/private/app/codecheckvisitor.php @@ -43,7 +43,12 @@ class CodeCheckVisitor extends NodeVisitorAbstract { */ public function __construct($blackListDescription, $blackListedClassNames, $checkEqualOperatorUsage) { $this->blackListDescription = $blackListDescription; - $this->blackListedClassNames = array_map('strtolower', $blackListedClassNames); + + $this->blackListedClassNames = []; + foreach ($blackListedClassNames as $class) { + $class = strtolower($class); + $this->blackListedClassNames[$class] = $class; + } $this->checkEqualOperatorUsage = $checkEqualOperatorUsage; $this->errorMessages = [ @@ -52,6 +57,7 @@ class CodeCheckVisitor extends NodeVisitorAbstract { CodeChecker::STATIC_CALL_NOT_ALLOWED => "Static method of {$this->blackListDescription} class must not be called", CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED => "Constant of {$this->blackListDescription} class must not not be fetched", CodeChecker::CLASS_NEW_FETCH_NOT_ALLOWED => "{$this->blackListDescription} class must not be instanciated", + CodeChecker::CLASS_USE_NOT_ALLOWED => "{$this->blackListDescription} class must not be imported with a use statement", CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED => "is discouraged", ]; @@ -127,15 +133,47 @@ class CodeCheckVisitor extends NodeVisitorAbstract { } } } + if ($node instanceof Node\Stmt\UseUse) { + $this->checkBlackList($node->name->toString(), CodeChecker::CLASS_USE_NOT_ALLOWED, $node); + if ($node->alias) { + $this->addUseNameToBlackList($node->name->toString(), $node->alias); + } else { + $this->addUseNameToBlackList($node->name->toString(), $node->name->getLast()); + } + } + } + + /** + * Check whether an alias was introduced for a namespace of a blacklisted class + * + * Example: + * - Blacklist entry: OCP\AppFramework\IApi + * - Name: OCP\AppFramework + * - Alias: OAF + * => new blacklist entry: OAF\IApi + * + * @param string $name + * @param string $alias + */ + private function addUseNameToBlackList($name, $alias) { + $name = strtolower($name); + $alias = strtolower($alias); + + foreach ($this->blackListedClassNames as $blackListedAlias => $blackListedClassName) { + if (strpos($blackListedClassName, $name . '\\') === 0) { + $aliasedClassName = str_replace($name, $alias, $blackListedClassName); + $this->blackListedClassNames[$aliasedClassName] = $blackListedClassName; + } + } } private function checkBlackList($name, $errorCode, Node $node) { - if (in_array(strtolower($name), $this->blackListedClassNames)) { + if (isset($this->blackListedClassNames[strtolower($name)])) { $this->errors[]= [ 'disallowedToken' => $name, 'errorCode' => $errorCode, 'line' => $node->getLine(), - 'reason' => $this->buildReason($name, $errorCode) + 'reason' => $this->buildReason($this->blackListedClassNames[strtolower($name)], $errorCode) ]; } } diff --git a/tests/data/app/code-checker/test-deprecated-use-alias.php b/tests/data/app/code-checker/test-deprecated-use-alias.php new file mode 100644 index 00000000000..a92187fa880 --- /dev/null +++ b/tests/data/app/code-checker/test-deprecated-use-alias.php @@ -0,0 +1,9 @@ + Date: Mon, 15 Jun 2015 16:08:54 +0200 Subject: Add deprecation version to the list --- lib/private/app/codecheckvisitor.php | 9 +++++++-- lib/private/app/deprecationcodechecker.php | 14 +++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/private/app/codecheckvisitor.php b/lib/private/app/codecheckvisitor.php index 0dec5b3715d..2d0569e8324 100644 --- a/lib/private/app/codecheckvisitor.php +++ b/lib/private/app/codecheckvisitor.php @@ -38,14 +38,19 @@ class CodeCheckVisitor extends NodeVisitorAbstract { /** * @param string $blackListDescription - * @param string[] $blackListedClassNames + * @param array $blackListedClassNames * @param bool $checkEqualOperatorUsage */ public function __construct($blackListDescription, $blackListedClassNames, $checkEqualOperatorUsage) { $this->blackListDescription = $blackListDescription; $this->blackListedClassNames = []; - foreach ($blackListedClassNames as $class) { + foreach ($blackListedClassNames as $class => $blackListInfo) { + if (is_numeric($class) && is_string($blackListInfo)) { + $class = $blackListInfo; + $blackListInfo = null; + } + $class = strtolower($class); $this->blackListedClassNames[$class] = $class; } diff --git a/lib/private/app/deprecationcodechecker.php b/lib/private/app/deprecationcodechecker.php index c89428927c1..32ae4e7d7ba 100644 --- a/lib/private/app/deprecationcodechecker.php +++ b/lib/private/app/deprecationcodechecker.php @@ -33,12 +33,12 @@ class DeprecationCodeChecker extends CodeChecker { protected $blackListedClassNames = [ // Deprecated classes - 'OCP\IConfig', - 'OCP\Contacts', - 'OCP\DB', - 'OCP\IHelper', - 'OCP\JSON', - 'OCP\Response', - 'OCP\AppFramework\IApi', + 'OCP\Config' => '8.0.0', + 'OCP\Contacts' => '8.1.0', + 'OCP\DB' => '8.1.0', + 'OCP\IHelper' => '8.1.0', + 'OCP\JSON' => '8.1.0', + 'OCP\Response' => '8.1.0', + 'OCP\AppFramework\IApi' => '8.0.0', ]; } -- cgit v1.2.3 From f228a3dc28b579b3d11126544928edacd2e2d9c4 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 15 Jun 2015 17:20:38 +0200 Subject: Add support for deprecated constants --- lib/private/app/codechecker.php | 4 +- lib/private/app/codecheckvisitor.php | 43 +++++++++++++-- lib/private/app/deprecationcodechecker.php | 15 ++++-- .../test-deprecated-constant-alias.php | 12 +++++ .../test-deprecated-constant-sub-alias.php | 12 +++++ .../code-checker/test-deprecated-constant-sub.php | 12 +++++ .../app/code-checker/test-deprecated-constant.php | 10 ++++ tests/lib/app/codecheckvisitor.php | 63 ++++++++++++++++++++++ tests/lib/app/mock/codechecker.php | 39 ++++++++++++++ 9 files changed, 202 insertions(+), 8 deletions(-) create mode 100644 tests/data/app/code-checker/test-deprecated-constant-alias.php create mode 100644 tests/data/app/code-checker/test-deprecated-constant-sub-alias.php create mode 100644 tests/data/app/code-checker/test-deprecated-constant-sub.php create mode 100644 tests/data/app/code-checker/test-deprecated-constant.php create mode 100644 tests/lib/app/codecheckvisitor.php create mode 100644 tests/lib/app/mock/codechecker.php (limited to 'lib') diff --git a/lib/private/app/codechecker.php b/lib/private/app/codechecker.php index 0216e61e7ae..57e1a4c5b5d 100644 --- a/lib/private/app/codechecker.php +++ b/lib/private/app/codechecker.php @@ -79,6 +79,8 @@ class CodeChecker extends BasicEmitter { 'OC_Util', ]; + protected $blackListedConstants = []; + /** @var bool */ protected $checkEqualOperators = false; @@ -144,7 +146,7 @@ class CodeChecker extends BasicEmitter { $code = file_get_contents($file); $statements = $this->parser->parse($code); - $visitor = new CodeCheckVisitor($this->blackListDescription, $this->blackListedClassNames, $this->checkEqualOperators); + $visitor = new CodeCheckVisitor($this->blackListDescription, $this->blackListedClassNames, $this->blackListedConstants, $this->checkEqualOperators); $traverser = new NodeTraverser; $traverser->addVisitor($visitor); diff --git a/lib/private/app/codecheckvisitor.php b/lib/private/app/codecheckvisitor.php index 2d0569e8324..60c685747be 100644 --- a/lib/private/app/codecheckvisitor.php +++ b/lib/private/app/codecheckvisitor.php @@ -31,6 +31,8 @@ class CodeCheckVisitor extends NodeVisitorAbstract { protected $blackListDescription; /** @var string[] */ protected $blackListedClassNames; + /** @var string[] */ + protected $blackListedConstants; /** @var bool */ protected $checkEqualOperatorUsage; /** @var string[] */ @@ -39,9 +41,10 @@ class CodeCheckVisitor extends NodeVisitorAbstract { /** * @param string $blackListDescription * @param array $blackListedClassNames + * @param array $blackListedConstants * @param bool $checkEqualOperatorUsage */ - public function __construct($blackListDescription, $blackListedClassNames, $checkEqualOperatorUsage) { + public function __construct($blackListDescription, $blackListedClassNames, $blackListedConstants, $checkEqualOperatorUsage) { $this->blackListDescription = $blackListDescription; $this->blackListedClassNames = []; @@ -54,6 +57,13 @@ class CodeCheckVisitor extends NodeVisitorAbstract { $class = strtolower($class); $this->blackListedClassNames[$class] = $class; } + + $this->blackListedConstants = []; + foreach ($blackListedConstants as $constant => $blackListInfo) { + $constant = strtolower($constant); + $this->blackListedConstants[$constant] = $constant; + } + $this->checkEqualOperatorUsage = $checkEqualOperatorUsage; $this->errorMessages = [ @@ -122,6 +132,8 @@ class CodeCheckVisitor extends NodeVisitorAbstract { * $n = $i::ADMIN_AUTH; */ } + + $this->checkBlackListConstant($node->class->toString(), $node->name, $node); } } if ($node instanceof Node\Expr\New_) { @@ -170,15 +182,40 @@ class CodeCheckVisitor extends NodeVisitorAbstract { $this->blackListedClassNames[$aliasedClassName] = $blackListedClassName; } } + + foreach ($this->blackListedConstants as $blackListedAlias => $blackListedConstant) { + if (strpos($blackListedConstant, $name . '\\') === 0 || strpos($blackListedConstant, $name . '::') === 0) { + $aliasedClassName = str_replace($name, $alias, $blackListedConstant); + $this->blackListedConstants[$aliasedClassName] = $blackListedConstant; + } + } + + $name = strtolower($name); } private function checkBlackList($name, $errorCode, Node $node) { - if (isset($this->blackListedClassNames[strtolower($name)])) { + $lowerName = strtolower($name); + + if (isset($this->blackListedClassNames[$lowerName])) { $this->errors[]= [ 'disallowedToken' => $name, 'errorCode' => $errorCode, 'line' => $node->getLine(), - 'reason' => $this->buildReason($this->blackListedClassNames[strtolower($name)], $errorCode) + 'reason' => $this->buildReason($this->blackListedClassNames[$lowerName], $errorCode) + ]; + } + } + + private function checkBlackListConstant($class, $constants, Node $node) { + $name = $class . '::' . $constants; + $lowerName = strtolower($name); + + if (isset($this->blackListedConstants[$lowerName])) { + $this->errors[]= [ + 'disallowedToken' => $name, + 'errorCode' => CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED, + 'line' => $node->getLine(), + 'reason' => $this->buildReason($this->blackListedConstants[$lowerName], CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED) ]; } } diff --git a/lib/private/app/deprecationcodechecker.php b/lib/private/app/deprecationcodechecker.php index 32ae4e7d7ba..9a23bb2c530 100644 --- a/lib/private/app/deprecationcodechecker.php +++ b/lib/private/app/deprecationcodechecker.php @@ -21,10 +21,6 @@ namespace OC\App; -use PhpParser\Lexer; -use PhpParser\Node; -use PhpParser\Node\Name; - class DeprecationCodeChecker extends CodeChecker { protected $checkEqualOperators = true; @@ -41,4 +37,15 @@ class DeprecationCodeChecker extends CodeChecker { 'OCP\Response' => '8.1.0', 'OCP\AppFramework\IApi' => '8.0.0', ]; + + protected $blackListedConstants = [ + // Deprecated constants + 'OCP::PERMISSION_CREATE' => '8.0.0', + 'OCP::PERMISSION_READ' => '8.0.0', + 'OCP::PERMISSION_UPDATE' => '8.0.0', + 'OCP::PERMISSION_DELETE' => '8.0.0', + 'OCP::PERMISSION_SHARE' => '8.0.0', + 'OCP::PERMISSION_ALL' => '8.0.0', + 'OCP::FILENAME_INVALID_CHARS' => '8.0.0', + ]; } diff --git a/tests/data/app/code-checker/test-deprecated-constant-alias.php b/tests/data/app/code-checker/test-deprecated-constant-alias.php new file mode 100644 index 00000000000..4f3d3e81316 --- /dev/null +++ b/tests/data/app/code-checker/test-deprecated-constant-alias.php @@ -0,0 +1,12 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\App; + +use OC; +use Test\TestCase; + +class CodeCheckVisitor extends TestCase { + + public function providesFilesToCheck() { + return [ + ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use.php'], + ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use-alias.php'], + ['AppFramework\IApi', 1001, 'test-deprecated-use-sub.php'], + ['OAF\IApi', 1001, 'test-deprecated-use-sub-alias.php'], + ]; + } + + /** + * @dataProvider providesFilesToCheck + * @param string $expectedErrorToken + * @param int $expectedErrorCode + * @param string $fileToVerify + */ + public function testFindInvalidUsage($expectedErrorToken, $expectedErrorCode, $fileToVerify) { + $checker = new \Test\App\Mock\CodeChecker(); + $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertEquals(1, count($errors)); + $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); + $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); + } + + public function providesConstantsToCheck() { + return [ + ['OCP\NamespaceName\ClassName::CONSTANT_NAME', 1003, 'test-deprecated-constant.php'], + ['Constant::CONSTANT_NAME', 1003, 'test-deprecated-constant-alias.php'], + ['NamespaceName\ClassName::CONSTANT_NAME', 1003, 'test-deprecated-constant-sub.php'], + ['Constant\ClassName::CONSTANT_NAME', 1003, 'test-deprecated-constant-sub-alias.php'], + ]; + } + + /** + * @dataProvider providesConstantsToCheck + * @param string $expectedErrorToken + * @param int $expectedErrorCode + * @param string $fileToVerify + */ + public function testConstantsToCheck($expectedErrorToken, $expectedErrorCode, $fileToVerify) { + $checker = new \Test\App\Mock\CodeChecker(); + $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertEquals(1, count($errors)); + $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); + $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); + } +} diff --git a/tests/lib/app/mock/codechecker.php b/tests/lib/app/mock/codechecker.php new file mode 100644 index 00000000000..228fd881e44 --- /dev/null +++ b/tests/lib/app/mock/codechecker.php @@ -0,0 +1,39 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace Test\App\Mock; + +class CodeChecker extends \OC\App\CodeChecker { + protected $checkEqualOperators = true; + + /** @var string */ + protected $blackListDescription = 'deprecated'; + + protected $blackListedClassNames = [ + // Deprecated classes + 'OCP\AppFramework\IApi' => '8.0.0', + ]; + + protected $blackListedConstants = [ + // Deprecated constants + 'OCP\NamespaceName\ClassName::CONSTANT_NAME' => '8.0.0', + ]; +} -- cgit v1.2.3 From 2783a780708e4e5c04b6935840416d219bc4d852 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 15 Jun 2015 17:50:37 +0200 Subject: Allow checking for functions --- lib/private/app/codechecker.php | 4 +- lib/private/app/codecheckvisitor.php | 48 ++++++++++++++++++---- lib/private/app/deprecationcodechecker.php | 12 ++++++ .../test-deprecated-constant-alias.php | 8 +--- .../test-deprecated-constant-sub-alias.php | 8 +--- .../code-checker/test-deprecated-constant-sub.php | 6 +-- .../app/code-checker/test-deprecated-constant.php | 6 +-- .../test-deprecated-function-alias.php | 5 +++ .../test-deprecated-function-sub-alias.php | 5 +++ .../code-checker/test-deprecated-function-sub.php | 5 +++ .../app/code-checker/test-deprecated-function.php | 3 ++ tests/lib/app/codecheckvisitor.php | 28 ++++++++++++- tests/lib/app/mock/codechecker.php | 5 +++ 13 files changed, 109 insertions(+), 34 deletions(-) create mode 100644 tests/data/app/code-checker/test-deprecated-function-alias.php create mode 100644 tests/data/app/code-checker/test-deprecated-function-sub-alias.php create mode 100644 tests/data/app/code-checker/test-deprecated-function-sub.php create mode 100644 tests/data/app/code-checker/test-deprecated-function.php (limited to 'lib') diff --git a/lib/private/app/codechecker.php b/lib/private/app/codechecker.php index 57e1a4c5b5d..b3d8a3b1e81 100644 --- a/lib/private/app/codechecker.php +++ b/lib/private/app/codechecker.php @@ -81,6 +81,8 @@ class CodeChecker extends BasicEmitter { protected $blackListedConstants = []; + protected $blackListedFunctions = []; + /** @var bool */ protected $checkEqualOperators = false; @@ -146,7 +148,7 @@ class CodeChecker extends BasicEmitter { $code = file_get_contents($file); $statements = $this->parser->parse($code); - $visitor = new CodeCheckVisitor($this->blackListDescription, $this->blackListedClassNames, $this->blackListedConstants, $this->checkEqualOperators); + $visitor = new CodeCheckVisitor($this->blackListDescription, $this->blackListedClassNames, $this->blackListedConstants, $this->blackListedFunctions, $this->checkEqualOperators); $traverser = new NodeTraverser; $traverser->addVisitor($visitor); diff --git a/lib/private/app/codecheckvisitor.php b/lib/private/app/codecheckvisitor.php index 60c685747be..4741a997c7d 100644 --- a/lib/private/app/codecheckvisitor.php +++ b/lib/private/app/codecheckvisitor.php @@ -33,6 +33,8 @@ class CodeCheckVisitor extends NodeVisitorAbstract { protected $blackListedClassNames; /** @var string[] */ protected $blackListedConstants; + /** @var string[] */ + protected $blackListedFunctions; /** @var bool */ protected $checkEqualOperatorUsage; /** @var string[] */ @@ -42,9 +44,10 @@ class CodeCheckVisitor extends NodeVisitorAbstract { * @param string $blackListDescription * @param array $blackListedClassNames * @param array $blackListedConstants + * @param array $blackListedFunctions * @param bool $checkEqualOperatorUsage */ - public function __construct($blackListDescription, $blackListedClassNames, $blackListedConstants, $checkEqualOperatorUsage) { + public function __construct($blackListDescription, $blackListedClassNames, $blackListedConstants, $blackListedFunctions, $checkEqualOperatorUsage) { $this->blackListDescription = $blackListDescription; $this->blackListedClassNames = []; @@ -59,9 +62,15 @@ class CodeCheckVisitor extends NodeVisitorAbstract { } $this->blackListedConstants = []; - foreach ($blackListedConstants as $constant => $blackListInfo) { - $constant = strtolower($constant); - $this->blackListedConstants[$constant] = $constant; + foreach ($blackListedConstants as $constantName => $blackListInfo) { + $constantName = strtolower($constantName); + $this->blackListedConstants[$constantName] = $constantName; + } + + $this->blackListedFunctions = []; + foreach ($blackListedFunctions as $functionName => $blackListInfo) { + $functionName = strtolower($functionName); + $this->blackListedFunctions[$functionName] = $functionName; } $this->checkEqualOperatorUsage = $checkEqualOperatorUsage; @@ -118,6 +127,8 @@ class CodeCheckVisitor extends NodeVisitorAbstract { * $n = $i::call(); */ } + + $this->checkBlackListFunction($node->class->toString(), $node->name, $node); } } if ($node instanceof Node\Expr\ClassConstFetch) { @@ -185,12 +196,17 @@ class CodeCheckVisitor extends NodeVisitorAbstract { foreach ($this->blackListedConstants as $blackListedAlias => $blackListedConstant) { if (strpos($blackListedConstant, $name . '\\') === 0 || strpos($blackListedConstant, $name . '::') === 0) { - $aliasedClassName = str_replace($name, $alias, $blackListedConstant); - $this->blackListedConstants[$aliasedClassName] = $blackListedConstant; + $aliasedConstantName = str_replace($name, $alias, $blackListedConstant); + $this->blackListedConstants[$aliasedConstantName] = $blackListedConstant; } } - $name = strtolower($name); + foreach ($this->blackListedFunctions as $blackListedAlias => $blackListedFunction) { + if (strpos($blackListedFunction, $name . '\\') === 0 || strpos($blackListedFunction, $name . '::') === 0) { + $aliasedFunctionName = str_replace($name, $alias, $blackListedFunction); + $this->blackListedFunctions[$aliasedFunctionName] = $blackListedFunction; + } + } } private function checkBlackList($name, $errorCode, Node $node) { @@ -206,8 +222,8 @@ class CodeCheckVisitor extends NodeVisitorAbstract { } } - private function checkBlackListConstant($class, $constants, Node $node) { - $name = $class . '::' . $constants; + private function checkBlackListConstant($class, $constantName, Node $node) { + $name = $class . '::' . $constantName; $lowerName = strtolower($name); if (isset($this->blackListedConstants[$lowerName])) { @@ -220,6 +236,20 @@ class CodeCheckVisitor extends NodeVisitorAbstract { } } + private function checkBlackListFunction($class, $functionName, Node $node) { + $name = $class . '::' . $functionName; + $lowerName = strtolower($name); + + if (isset($this->blackListedFunctions[$lowerName])) { + $this->errors[]= [ + 'disallowedToken' => $name, + 'errorCode' => CodeChecker::STATIC_CALL_NOT_ALLOWED, + 'line' => $node->getLine(), + 'reason' => $this->buildReason($this->blackListedFunctions[$lowerName], CodeChecker::STATIC_CALL_NOT_ALLOWED) + ]; + } + } + private function buildReason($name, $errorCode) { if (isset($this->errorMessages[$errorCode])) { return $this->errorMessages[$errorCode]; diff --git a/lib/private/app/deprecationcodechecker.php b/lib/private/app/deprecationcodechecker.php index 9a23bb2c530..48146c74fa8 100644 --- a/lib/private/app/deprecationcodechecker.php +++ b/lib/private/app/deprecationcodechecker.php @@ -48,4 +48,16 @@ class DeprecationCodeChecker extends CodeChecker { 'OCP::PERMISSION_ALL' => '8.0.0', 'OCP::FILENAME_INVALID_CHARS' => '8.0.0', ]; + + protected $blackListedFunctions = [ + // Deprecated functions + 'OCP::image_path' => '8.0.0', + 'OCP::mimetype_icon' => '8.0.0', + 'OCP::preview_icon' => '8.0.0', + 'OCP::publicPreview_icon' => '8.0.0', + 'OCP::human_file_size' => '8.0.0', + 'OCP::relative_modified_date' => '8.0.0', + 'OCP::simple_file_size' => '8.0.0', + 'OCP::html_select_options' => '8.0.0', + ]; } diff --git a/tests/data/app/code-checker/test-deprecated-constant-alias.php b/tests/data/app/code-checker/test-deprecated-constant-alias.php index 4f3d3e81316..b5a5bfdb762 100644 --- a/tests/data/app/code-checker/test-deprecated-constant-alias.php +++ b/tests/data/app/code-checker/test-deprecated-constant-alias.php @@ -1,12 +1,8 @@ assertEquals($expectedErrorCode, $errors[0]['errorCode']); $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); } + + public function providesFunctionsToCheck() { + return [ + ['OCP\NamespaceName\ClassName::functionName', 1002, 'test-deprecated-function.php'], + ['Alias::functionName', 1002, 'test-deprecated-function-alias.php'], + ['NamespaceName\ClassName::functionName', 1002, 'test-deprecated-function-sub.php'], + ['SubAlias\ClassName::functionName', 1002, 'test-deprecated-function-sub-alias.php'], + ]; + } + + /** + * @dataProvider providesFunctionsToCheck + * @param string $expectedErrorToken + * @param int $expectedErrorCode + * @param string $fileToVerify + */ + public function testFunctionsToCheck($expectedErrorToken, $expectedErrorCode, $fileToVerify) { + $checker = new \Test\App\Mock\CodeChecker(); + $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertEquals(1, count($errors)); + $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); + $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); + } } diff --git a/tests/lib/app/mock/codechecker.php b/tests/lib/app/mock/codechecker.php index 228fd881e44..e67d060b1f4 100644 --- a/tests/lib/app/mock/codechecker.php +++ b/tests/lib/app/mock/codechecker.php @@ -36,4 +36,9 @@ class CodeChecker extends \OC\App\CodeChecker { // Deprecated constants 'OCP\NamespaceName\ClassName::CONSTANT_NAME' => '8.0.0', ]; + + protected $blackListedFunctions = [ + // Deprecated constants + 'OCP\NamespaceName\ClassName::functionName' => '8.0.0', + ]; } -- cgit v1.2.3 From eb1c4379415c60dbb873b549683978af79d1027d Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Mon, 15 Jun 2015 18:36:04 +0200 Subject: Check for methods as good as possible --- lib/private/app/codechecker.php | 5 +- lib/private/app/codecheckvisitor.php | 55 ++++++++++++- lib/private/app/deprecationcodechecker.php | 64 +++++++++++++++ .../test-deprecated-function-alias.php | 1 + .../test-deprecated-function-sub-alias.php | 1 + .../code-checker/test-deprecated-function-sub.php | 1 + .../app/code-checker/test-deprecated-function.php | 1 + .../app/code-checker/test-deprecated-method.php | 5 ++ tests/lib/app/codecheckvisitor.php | 92 +++++++++------------- tests/lib/app/mock/codechecker.php | 7 +- 10 files changed, 171 insertions(+), 61 deletions(-) create mode 100644 tests/data/app/code-checker/test-deprecated-method.php (limited to 'lib') diff --git a/lib/private/app/codechecker.php b/lib/private/app/codechecker.php index b3d8a3b1e81..93f82def81e 100644 --- a/lib/private/app/codechecker.php +++ b/lib/private/app/codechecker.php @@ -44,6 +44,7 @@ class CodeChecker extends BasicEmitter { const CLASS_NEW_FETCH_NOT_ALLOWED = 1004; const OP_OPERATOR_USAGE_DISCOURAGED = 1005; const CLASS_USE_NOT_ALLOWED = 1006; + const CLASS_METHOD_CALL_NOT_ALLOWED = 1007; /** @var Parser */ private $parser; @@ -83,6 +84,8 @@ class CodeChecker extends BasicEmitter { protected $blackListedFunctions = []; + protected $blackListedMethods = []; + /** @var bool */ protected $checkEqualOperators = false; @@ -148,7 +151,7 @@ class CodeChecker extends BasicEmitter { $code = file_get_contents($file); $statements = $this->parser->parse($code); - $visitor = new CodeCheckVisitor($this->blackListDescription, $this->blackListedClassNames, $this->blackListedConstants, $this->blackListedFunctions, $this->checkEqualOperators); + $visitor = new CodeCheckVisitor($this->blackListDescription, $this->blackListedClassNames, $this->blackListedConstants, $this->blackListedFunctions, $this->blackListedMethods, $this->checkEqualOperators); $traverser = new NodeTraverser; $traverser->addVisitor($visitor); diff --git a/lib/private/app/codecheckvisitor.php b/lib/private/app/codecheckvisitor.php index 4741a997c7d..dd12d2faa4d 100644 --- a/lib/private/app/codecheckvisitor.php +++ b/lib/private/app/codecheckvisitor.php @@ -35,6 +35,8 @@ class CodeCheckVisitor extends NodeVisitorAbstract { protected $blackListedConstants; /** @var string[] */ protected $blackListedFunctions; + /** @var string[] */ + protected $blackListedMethods; /** @var bool */ protected $checkEqualOperatorUsage; /** @var string[] */ @@ -45,9 +47,10 @@ class CodeCheckVisitor extends NodeVisitorAbstract { * @param array $blackListedClassNames * @param array $blackListedConstants * @param array $blackListedFunctions + * @param array $blackListedMethods * @param bool $checkEqualOperatorUsage */ - public function __construct($blackListDescription, $blackListedClassNames, $blackListedConstants, $blackListedFunctions, $checkEqualOperatorUsage) { + public function __construct($blackListDescription, $blackListedClassNames, $blackListedConstants, $blackListedFunctions, $blackListedMethods, $checkEqualOperatorUsage) { $this->blackListDescription = $blackListDescription; $this->blackListedClassNames = []; @@ -73,6 +76,12 @@ class CodeCheckVisitor extends NodeVisitorAbstract { $this->blackListedFunctions[$functionName] = $functionName; } + $this->blackListedMethods = []; + foreach ($blackListedMethods as $functionName => $blackListInfo) { + $functionName = strtolower($functionName); + $this->blackListedMethods[$functionName] = $functionName; + } + $this->checkEqualOperatorUsage = $checkEqualOperatorUsage; $this->errorMessages = [ @@ -82,6 +91,7 @@ class CodeCheckVisitor extends NodeVisitorAbstract { CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED => "Constant of {$this->blackListDescription} class must not not be fetched", CodeChecker::CLASS_NEW_FETCH_NOT_ALLOWED => "{$this->blackListDescription} class must not be instanciated", CodeChecker::CLASS_USE_NOT_ALLOWED => "{$this->blackListDescription} class must not be imported with a use statement", + CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED => "Method of {$this->blackListDescription} class must not be called", CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED => "is discouraged", ]; @@ -119,16 +129,32 @@ class CodeCheckVisitor extends NodeVisitorAbstract { if (!is_null($node->class)) { if ($node->class instanceof Name) { $this->checkBlackList($node->class->toString(), CodeChecker::STATIC_CALL_NOT_ALLOWED, $node); + + $this->checkBlackListFunction($node->class->toString(), $node->name, $node); + $this->checkBlackListMethod($node->class->toString(), $node->name, $node); } + if ($node->class instanceof Node\Expr\Variable) { /** * TODO: find a way to detect something like this: * $c = "OC_API"; - * $n = $i::call(); + * $n = $c::call(); */ + // $this->checkBlackListMethod($node->class->..., $node->name, $node); + } + } + } + if ($node instanceof Node\Expr\MethodCall) { + if (!is_null($node->var)) { + if ($node->var instanceof Node\Expr\Variable) { + /** + * TODO: find a way to detect something like this: + * $c = new OC_API(); + * $n = $c::call(); + * $n = $c->call(); + */ + // $this->checkBlackListMethod($node->var->..., $node->name, $node); } - - $this->checkBlackListFunction($node->class->toString(), $node->name, $node); } } if ($node instanceof Node\Expr\ClassConstFetch) { @@ -207,6 +233,13 @@ class CodeCheckVisitor extends NodeVisitorAbstract { $this->blackListedFunctions[$aliasedFunctionName] = $blackListedFunction; } } + + foreach ($this->blackListedMethods as $blackListedAlias => $blackListedMethod) { + if (strpos($blackListedMethod, $name . '\\') === 0 || strpos($blackListedMethod, $name . '::') === 0) { + $aliasedMethodName = str_replace($name, $alias, $blackListedMethod); + $this->blackListedMethods[$aliasedMethodName] = $blackListedMethod; + } + } } private function checkBlackList($name, $errorCode, Node $node) { @@ -250,6 +283,20 @@ class CodeCheckVisitor extends NodeVisitorAbstract { } } + private function checkBlackListMethod($class, $functionName, Node $node) { + $name = $class . '::' . $functionName; + $lowerName = strtolower($name); + + if (isset($this->blackListedMethods[$lowerName])) { + $this->errors[]= [ + 'disallowedToken' => $name, + 'errorCode' => CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED, + 'line' => $node->getLine(), + 'reason' => $this->buildReason($this->blackListedMethods[$lowerName], CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED) + ]; + } + } + private function buildReason($name, $errorCode) { if (isset($this->errorMessages[$errorCode])) { return $this->errorMessages[$errorCode]; diff --git a/lib/private/app/deprecationcodechecker.php b/lib/private/app/deprecationcodechecker.php index 48146c74fa8..5bec83f971a 100644 --- a/lib/private/app/deprecationcodechecker.php +++ b/lib/private/app/deprecationcodechecker.php @@ -60,4 +60,68 @@ class DeprecationCodeChecker extends CodeChecker { 'OCP::simple_file_size' => '8.0.0', 'OCP::html_select_options' => '8.0.0', ]; + + protected $blackListedMethods = [ + // Deprecated methods + 'OCP\App::register' => '8.1.0', + 'OCP\App::addNavigationEntry' => '8.1.0', + 'OCP\App::setActiveNavigationEntry' => '8.1.0', + + 'OCP\AppFramework\Controller::params' => '7.0.0', + 'OCP\AppFramework\Controller::getParams' => '7.0.0', + 'OCP\AppFramework\Controller::method' => '7.0.0', + 'OCP\AppFramework\Controller::getUploadedFile' => '7.0.0', + 'OCP\AppFramework\Controller::env' => '7.0.0', + 'OCP\AppFramework\Controller::cookie' => '7.0.0', + 'OCP\AppFramework\Controller::render' => '7.0.0', + + 'OCP\AppFramework\IAppContainer::getCoreApi' => '8.0.0', + 'OCP\AppFramework\IAppContainer::isLoggedIn' => '8.0.0', + 'OCP\AppFramework\IAppContainer::isAdminUser' => '8.0.0', + 'OCP\AppFramework\IAppContainer::log' => '8.0.0', + + 'OCP\BackgroundJob::addQueuedTask' => '6.0.0', + 'OCP\BackgroundJob::addRegularTask' => '6.0.0', + 'OCP\BackgroundJob::allQueuedTasks' => '6.0.0', + 'OCP\BackgroundJob::allRegularTasks' => '6.0.0', + 'OCP\BackgroundJob::deleteQueuedTask' => '6.0.0', + 'OCP\BackgroundJob::findQueuedTask' => '6.0.0', + 'OCP\BackgroundJob::queuedTaskWhereAppIs' => '6.0.0', + 'OCP\BackgroundJob::registerJob' => '8.1.0', + + 'OCP\Files::tmpFile' => '8.1.0', + 'OCP\Files::tmpFolder' => '8.1.0', + + 'OCP\IAppConfig::getValue' => '8.0.0', + 'OCP\IAppConfig::deleteKey' => '8.0.0', + 'OCP\IAppConfig::getKeys' => '8.0.0', + 'OCP\IAppConfig::setValue' => '8.0.0', + 'OCP\IAppConfig::deleteApp' => '8.0.0', + + 'OCP\ISearch::search' => '8.0.0', + + 'OCP\IServerContainer::getDb' => '8.1.0', + 'OCP\IServerContainer::getHTTPHelper' => '8.1.0', + + 'OCP\User::getUser' => '8.0.0', + 'OCP\User::getUsers' => '8.1.0', + 'OCP\User::getDisplayName' => '8.1.0', + 'OCP\User::getDisplayNames' => '8.1.0', + 'OCP\User::userExists' => '8.1.0', + 'OCP\User::logout' => '8.1.0', + 'OCP\User::checkPassword' => '8.1.0', + + 'OCP\Util::sendMail' => '8.1.0', + 'OCP\Util::formatDate' => '8.0.0', + 'OCP\Util::encryptedFiles' => '8.1.0', + 'OCP\Util::linkToRoute' => '8.1.0', + 'OCP\Util::linkTo' => '8.1.0', + 'OCP\Util::getServerHost' => '8.1.0', + 'OCP\Util::getServerProtocol' => '8.1.0', + 'OCP\Util::getRequestUri' => '8.1.0', + 'OCP\Util::getScriptName' => '8.1.0', + 'OCP\Util::imagePath' => '8.1.0', + 'OCP\Util::isValidFileName' => '8.1.0', + 'OCP\Util::generateRandomBytes' => '8.1.0', + ]; } diff --git a/tests/data/app/code-checker/test-deprecated-function-alias.php b/tests/data/app/code-checker/test-deprecated-function-alias.php index 0c958cc635c..28ed5051191 100644 --- a/tests/data/app/code-checker/test-deprecated-function-alias.php +++ b/tests/data/app/code-checker/test-deprecated-function-alias.php @@ -3,3 +3,4 @@ use OCP\NamespaceName\ClassName as Alias; Alias::functionName(); +Alias::methodName(); diff --git a/tests/data/app/code-checker/test-deprecated-function-sub-alias.php b/tests/data/app/code-checker/test-deprecated-function-sub-alias.php index f728eaf9fd0..73dd5814531 100644 --- a/tests/data/app/code-checker/test-deprecated-function-sub-alias.php +++ b/tests/data/app/code-checker/test-deprecated-function-sub-alias.php @@ -3,3 +3,4 @@ use OCP\NamespaceName as SubAlias; SubAlias\ClassName::functionName(); +SubAlias\ClassName::methodName(); diff --git a/tests/data/app/code-checker/test-deprecated-function-sub.php b/tests/data/app/code-checker/test-deprecated-function-sub.php index f7e15903d5d..c08d3bad8c0 100644 --- a/tests/data/app/code-checker/test-deprecated-function-sub.php +++ b/tests/data/app/code-checker/test-deprecated-function-sub.php @@ -3,3 +3,4 @@ use OCP\NamespaceName; NamespaceName\ClassName::functionName(); +NamespaceName\ClassName::methodName(); diff --git a/tests/data/app/code-checker/test-deprecated-function.php b/tests/data/app/code-checker/test-deprecated-function.php index 0016076e377..12a144a7118 100644 --- a/tests/data/app/code-checker/test-deprecated-function.php +++ b/tests/data/app/code-checker/test-deprecated-function.php @@ -1,3 +1,4 @@ methodName(); +$class::methodName(); diff --git a/tests/lib/app/codecheckvisitor.php b/tests/lib/app/codecheckvisitor.php index 3eac3beedc8..d836f1b3c84 100644 --- a/tests/lib/app/codecheckvisitor.php +++ b/tests/lib/app/codecheckvisitor.php @@ -15,73 +15,55 @@ class CodeCheckVisitor extends TestCase { public function providesFilesToCheck() { return [ - ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use.php'], - ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use-alias.php'], - ['AppFramework\IApi', 1001, 'test-deprecated-use-sub.php'], - ['OAF\IApi', 1001, 'test-deprecated-use-sub-alias.php'], - ]; - } + [[['OCP\AppFramework\IApi', 1006]], 'test-deprecated-use.php'], + [[['OCP\AppFramework\IApi', 1006]], 'test-deprecated-use-alias.php'], + [[['AppFramework\IApi', 1001]], 'test-deprecated-use-sub.php'], + [[['OAF\IApi', 1001]], 'test-deprecated-use-sub-alias.php'], - /** - * @dataProvider providesFilesToCheck - * @param string $expectedErrorToken - * @param int $expectedErrorCode - * @param string $fileToVerify - */ - public function testFindInvalidUsage($expectedErrorToken, $expectedErrorCode, $fileToVerify) { - $checker = new \Test\App\Mock\CodeChecker(); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + [[['OCP\NamespaceName\ClassName::CONSTANT_NAME', 1003]], 'test-deprecated-constant.php'], + [[['Alias::CONSTANT_NAME', 1003]], 'test-deprecated-constant-alias.php'], + [[['NamespaceName\ClassName::CONSTANT_NAME', 1003]], 'test-deprecated-constant-sub.php'], + [[['SubAlias\ClassName::CONSTANT_NAME', 1003]], 'test-deprecated-constant-sub-alias.php'], - $this->assertEquals(1, count($errors)); - $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); - $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); - } + [[ + ['OCP\NamespaceName\ClassName::functionName', 1002], + ['OCP\NamespaceName\ClassName::methodName', 1007], + ], 'test-deprecated-function.php'], + [[ + ['Alias::functionName', 1002], + ['Alias::methodName', 1007], + ], 'test-deprecated-function-alias.php'], + [[ + ['NamespaceName\ClassName::functionName', 1002], + ['NamespaceName\ClassName::methodName', 1007], + ], 'test-deprecated-function-sub.php'], + [[ + ['SubAlias\ClassName::functionName', 1002], + ['SubAlias\ClassName::methodName', 1007], + ], 'test-deprecated-function-sub-alias.php'], - public function providesConstantsToCheck() { - return [ - ['OCP\NamespaceName\ClassName::CONSTANT_NAME', 1003, 'test-deprecated-constant.php'], - ['Alias::CONSTANT_NAME', 1003, 'test-deprecated-constant-alias.php'], - ['NamespaceName\ClassName::CONSTANT_NAME', 1003, 'test-deprecated-constant-sub.php'], - ['SubAlias\ClassName::CONSTANT_NAME', 1003, 'test-deprecated-constant-sub-alias.php'], + // TODO Failing to resolve variables to classes +// [[['OCP\NamespaceName\ClassName::methodName', 1007]], 'test-deprecated-method.php'], +// [[['Alias::methodName', 1002]], 'test-deprecated-method-alias.php'], +// [[['NamespaceName\ClassName::methodName', 1002]], 'test-deprecated-method-sub.php'], +// [[['SubAlias\ClassName::methodName', 1002]], 'test-deprecated-method-sub-alias.php'], ]; } /** - * @dataProvider providesConstantsToCheck - * @param string $expectedErrorToken - * @param int $expectedErrorCode + * @dataProvider providesFilesToCheck + * @param array $expectedErrors * @param string $fileToVerify */ - public function testConstantsToCheck($expectedErrorToken, $expectedErrorCode, $fileToVerify) { + public function testMethodsToCheck($expectedErrors, $fileToVerify) { $checker = new \Test\App\Mock\CodeChecker(); $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); - $this->assertEquals(1, count($errors)); - $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); - $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); - } - - public function providesFunctionsToCheck() { - return [ - ['OCP\NamespaceName\ClassName::functionName', 1002, 'test-deprecated-function.php'], - ['Alias::functionName', 1002, 'test-deprecated-function-alias.php'], - ['NamespaceName\ClassName::functionName', 1002, 'test-deprecated-function-sub.php'], - ['SubAlias\ClassName::functionName', 1002, 'test-deprecated-function-sub-alias.php'], - ]; - } - - /** - * @dataProvider providesFunctionsToCheck - * @param string $expectedErrorToken - * @param int $expectedErrorCode - * @param string $fileToVerify - */ - public function testFunctionsToCheck($expectedErrorToken, $expectedErrorCode, $fileToVerify) { - $checker = new \Test\App\Mock\CodeChecker(); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + $this->assertCount(sizeof($expectedErrors), $errors); - $this->assertEquals(1, count($errors)); - $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); - $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); + foreach ($expectedErrors as $int => $expectedError) { + $this->assertEquals($expectedError[0], $errors[$int]['disallowedToken']); + $this->assertEquals($expectedError[1], $errors[$int]['errorCode']); + } } } diff --git a/tests/lib/app/mock/codechecker.php b/tests/lib/app/mock/codechecker.php index e67d060b1f4..b5a775cc43d 100644 --- a/tests/lib/app/mock/codechecker.php +++ b/tests/lib/app/mock/codechecker.php @@ -38,7 +38,12 @@ class CodeChecker extends \OC\App\CodeChecker { ]; protected $blackListedFunctions = [ - // Deprecated constants + // Deprecated functions 'OCP\NamespaceName\ClassName::functionName' => '8.0.0', ]; + + protected $blackListedMethods = [ + // Deprecated methods + 'OCP\NamespaceName\ClassName::methodName' => '8.0.0', + ]; } -- cgit v1.2.3 From bba87a2a3b46d20a552efa4a1d00d3253aedf27b Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 7 Jul 2015 12:08:12 +0200 Subject: Restructor the code into different classes instead of extending --- core/command/app/checkcode.php | 11 +- lib/private/app/codechecker.php | 162 ------------ lib/private/app/codechecker/codechecker.php | 125 +++++++++ lib/private/app/codechecker/deprecationlist.php | 152 +++++++++++ lib/private/app/codechecker/ichecklist.php | 53 ++++ lib/private/app/codechecker/nodevisitor.php | 302 +++++++++++++++++++++ lib/private/app/codechecker/privatelist.php | 105 ++++++++ lib/private/app/codecheckvisitor.php | 307 ---------------------- lib/private/app/deprecationcodechecker.php | 127 --------- tests/lib/app/codechecker.php | 58 ---- tests/lib/app/codechecker/codecheckertest.php | 62 +++++ tests/lib/app/codechecker/deprecationlisttest.php | 68 +++++ tests/lib/app/codechecker/mock/testlist.php | 81 ++++++ tests/lib/app/codechecker/nodevisitortest.php | 71 +++++ tests/lib/app/codecheckvisitor.php | 69 ----- tests/lib/app/deprecationcodechecker.php | 64 ----- tests/lib/app/mock/codechecker.php | 49 ---- 17 files changed, 1026 insertions(+), 840 deletions(-) delete mode 100644 lib/private/app/codechecker.php create mode 100644 lib/private/app/codechecker/codechecker.php create mode 100644 lib/private/app/codechecker/deprecationlist.php create mode 100644 lib/private/app/codechecker/ichecklist.php create mode 100644 lib/private/app/codechecker/nodevisitor.php create mode 100644 lib/private/app/codechecker/privatelist.php delete mode 100644 lib/private/app/codecheckvisitor.php delete mode 100644 lib/private/app/deprecationcodechecker.php delete mode 100644 tests/lib/app/codechecker.php create mode 100644 tests/lib/app/codechecker/codecheckertest.php create mode 100644 tests/lib/app/codechecker/deprecationlisttest.php create mode 100644 tests/lib/app/codechecker/mock/testlist.php create mode 100644 tests/lib/app/codechecker/nodevisitortest.php delete mode 100644 tests/lib/app/codecheckvisitor.php delete mode 100644 tests/lib/app/deprecationcodechecker.php delete mode 100644 tests/lib/app/mock/codechecker.php (limited to 'lib') diff --git a/core/command/app/checkcode.php b/core/command/app/checkcode.php index 5beb13e2c7c..a533ce767f3 100644 --- a/core/command/app/checkcode.php +++ b/core/command/app/checkcode.php @@ -23,8 +23,9 @@ namespace OC\Core\Command\App; -use OC\App\CodeChecker; -use OC\App\DeprecationCodeChecker; +use OC\App\CodeChecker\CodeChecker; +use OC\App\CodeChecker\DeprecationList; +use OC\App\CodeChecker\PrivateList; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -52,10 +53,12 @@ class CheckCode extends Command { protected function execute(InputInterface $input, OutputInterface $output) { $appId = $input->getArgument('app-id'); if ($input->getOption('deprecated')) { - $codeChecker = new DeprecationCodeChecker(); + $list = new DeprecationList(); } else { - $codeChecker = new CodeChecker(); + $list = new PrivateList(); } + $codeChecker = new CodeChecker($list); + $codeChecker->listen('CodeChecker', 'analyseFileBegin', function($params) use ($output) { if(OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $output->writeln("Analysing {$params}"); diff --git a/lib/private/app/codechecker.php b/lib/private/app/codechecker.php deleted file mode 100644 index 93f82def81e..00000000000 --- a/lib/private/app/codechecker.php +++ /dev/null @@ -1,162 +0,0 @@ - - * @author Morris Jobke - * @author Thomas Müller - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OC\App; - -use OC\Hooks\BasicEmitter; -use PhpParser\Lexer; -use PhpParser\Node; -use PhpParser\Node\Name; -use PhpParser\NodeTraverser; -use PhpParser\Parser; -use RecursiveCallbackFilterIterator; -use RecursiveDirectoryIterator; -use RecursiveIteratorIterator; -use RegexIterator; -use SplFileInfo; - -class CodeChecker extends BasicEmitter { - - const CLASS_EXTENDS_NOT_ALLOWED = 1000; - const CLASS_IMPLEMENTS_NOT_ALLOWED = 1001; - const STATIC_CALL_NOT_ALLOWED = 1002; - const CLASS_CONST_FETCH_NOT_ALLOWED = 1003; - const CLASS_NEW_FETCH_NOT_ALLOWED = 1004; - const OP_OPERATOR_USAGE_DISCOURAGED = 1005; - const CLASS_USE_NOT_ALLOWED = 1006; - const CLASS_METHOD_CALL_NOT_ALLOWED = 1007; - - /** @var Parser */ - private $parser; - - /** @var string */ - protected $blackListDescription = 'private'; - - /** @var string[] */ - protected $blackListedClassNames = [ - // classes replaced by the public api - 'OC_API', - 'OC_App', - 'OC_AppConfig', - 'OC_Avatar', - 'OC_BackgroundJob', - 'OC_Config', - 'OC_DB', - 'OC_Files', - 'OC_Helper', - 'OC_Hook', - 'OC_Image', - 'OC_JSON', - 'OC_L10N', - 'OC_Log', - 'OC_Mail', - 'OC_Preferences', - 'OC_Search_Provider', - 'OC_Search_Result', - 'OC_Request', - 'OC_Response', - 'OC_Template', - 'OC_User', - 'OC_Util', - ]; - - protected $blackListedConstants = []; - - protected $blackListedFunctions = []; - - protected $blackListedMethods = []; - - /** @var bool */ - protected $checkEqualOperators = false; - - - public function __construct() { - $this->parser = new Parser(new Lexer); - } - - /** - * @param string $appId - * @return array - */ - public function analyse($appId) { - $appPath = \OC_App::getAppPath($appId); - if ($appPath === false) { - 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 ($folder) { - return $folder . '/' . $item; - }, ['vendor', '3rdparty', '.git', 'l10n', 'tests', 'test']); - - $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) { - return false; - } - } - return true; - }); - $iterator = new RecursiveIteratorIterator($iterator); - $iterator = new RegexIterator($iterator, '/^.+\.php$/i'); - - foreach ($iterator as $file) { - /** @var SplFileInfo $file */ - $this->emit('CodeChecker', 'analyseFileBegin', [$file->getPathname()]); - $fileErrors = $this->analyseFile($file); - $this->emit('CodeChecker', 'analyseFileFinished', [$file->getPathname(), $fileErrors]); - $errors = array_merge($fileErrors, $errors); - } - - return $errors; - } - - - /** - * @param string $file - * @return array - */ - public function analyseFile($file) { - $code = file_get_contents($file); - $statements = $this->parser->parse($code); - - $visitor = new CodeCheckVisitor($this->blackListDescription, $this->blackListedClassNames, $this->blackListedConstants, $this->blackListedFunctions, $this->blackListedMethods, $this->checkEqualOperators); - $traverser = new NodeTraverser; - $traverser->addVisitor($visitor); - - $traverser->traverse($statements); - - return $visitor->errors; - } -} diff --git a/lib/private/app/codechecker/codechecker.php b/lib/private/app/codechecker/codechecker.php new file mode 100644 index 00000000000..b2ee9d6d71d --- /dev/null +++ b/lib/private/app/codechecker/codechecker.php @@ -0,0 +1,125 @@ + + * @author Morris Jobke + * @author Thomas Müller + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\App\CodeChecker; + +use OC\Hooks\BasicEmitter; +use PhpParser\Lexer; +use PhpParser\Node; +use PhpParser\Node\Name; +use PhpParser\NodeTraverser; +use PhpParser\Parser; +use RecursiveCallbackFilterIterator; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use RegexIterator; +use SplFileInfo; + +class CodeChecker extends BasicEmitter { + + const CLASS_EXTENDS_NOT_ALLOWED = 1000; + const CLASS_IMPLEMENTS_NOT_ALLOWED = 1001; + const STATIC_CALL_NOT_ALLOWED = 1002; + const CLASS_CONST_FETCH_NOT_ALLOWED = 1003; + const CLASS_NEW_FETCH_NOT_ALLOWED = 1004; + const OP_OPERATOR_USAGE_DISCOURAGED = 1005; + const CLASS_USE_NOT_ALLOWED = 1006; + const CLASS_METHOD_CALL_NOT_ALLOWED = 1007; + + /** @var Parser */ + private $parser; + + /** @var ICheckList */ + protected $list; + + public function __construct(ICheckList $list) { + $this->list = $list; + $this->parser = new Parser(new Lexer); + } + + /** + * @param string $appId + * @return array + */ + public function analyse($appId) { + $appPath = \OC_App::getAppPath($appId); + if ($appPath === false) { + 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 ($folder) { + return $folder . '/' . $item; + }, ['vendor', '3rdparty', '.git', 'l10n', 'tests', 'test']); + + $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) { + return false; + } + } + return true; + }); + $iterator = new RecursiveIteratorIterator($iterator); + $iterator = new RegexIterator($iterator, '/^.+\.php$/i'); + + foreach ($iterator as $file) { + /** @var SplFileInfo $file */ + $this->emit('CodeChecker', 'analyseFileBegin', [$file->getPathname()]); + $fileErrors = $this->analyseFile($file); + $this->emit('CodeChecker', 'analyseFileFinished', [$file->getPathname(), $fileErrors]); + $errors = array_merge($fileErrors, $errors); + } + + return $errors; + } + + + /** + * @param string $file + * @return array + */ + public function analyseFile($file) { + $code = file_get_contents($file); + $statements = $this->parser->parse($code); + + $visitor = new NodeVisitor($this->list); + $traverser = new NodeTraverser; + $traverser->addVisitor($visitor); + + $traverser->traverse($statements); + + return $visitor->errors; + } +} diff --git a/lib/private/app/codechecker/deprecationlist.php b/lib/private/app/codechecker/deprecationlist.php new file mode 100644 index 00000000000..d0abc75a30f --- /dev/null +++ b/lib/private/app/codechecker/deprecationlist.php @@ -0,0 +1,152 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\App\CodeChecker; + +class DeprecationList implements ICheckList { + /** + * @return string + */ + public function getDescription() { + return 'deprecated'; + } + + /** + * @return array E.g.: `'ClassName' => 'oc version',` + */ + public function getClasses() { + return [ + 'OCP\Config' => '8.0.0', + 'OCP\Contacts' => '8.1.0', + 'OCP\DB' => '8.1.0', + 'OCP\IHelper' => '8.1.0', + 'OCP\JSON' => '8.1.0', + 'OCP\Response' => '8.1.0', + 'OCP\AppFramework\IApi' => '8.0.0', + ]; + } + + /** + * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` + */ + public function getConstants() { + return [ + 'OCP::PERMISSION_CREATE' => '8.0.0', + 'OCP::PERMISSION_READ' => '8.0.0', + 'OCP::PERMISSION_UPDATE' => '8.0.0', + 'OCP::PERMISSION_DELETE' => '8.0.0', + 'OCP::PERMISSION_SHARE' => '8.0.0', + 'OCP::PERMISSION_ALL' => '8.0.0', + 'OCP::FILENAME_INVALID_CHARS' => '8.0.0', + ]; + } + + /** + * @return array E.g.: `'functionName' => 'oc version',` + */ + public function getFunctions() { + return [ + 'OCP::image_path' => '8.0.0', + 'OCP::mimetype_icon' => '8.0.0', + 'OCP::preview_icon' => '8.0.0', + 'OCP::publicPreview_icon' => '8.0.0', + 'OCP::human_file_size' => '8.0.0', + 'OCP::relative_modified_date' => '8.0.0', + 'OCP::simple_file_size' => '8.0.0', + 'OCP::html_select_options' => '8.0.0', + ]; + } + + /** + * @return array E.g.: `'ClassName::methodName' => 'oc version',` + */ + public function getMethods() { + return [ + 'OCP\App::register' => '8.1.0', + 'OCP\App::addNavigationEntry' => '8.1.0', + 'OCP\App::setActiveNavigationEntry' => '8.1.0', + + 'OCP\AppFramework\Controller::params' => '7.0.0', + 'OCP\AppFramework\Controller::getParams' => '7.0.0', + 'OCP\AppFramework\Controller::method' => '7.0.0', + 'OCP\AppFramework\Controller::getUploadedFile' => '7.0.0', + 'OCP\AppFramework\Controller::env' => '7.0.0', + 'OCP\AppFramework\Controller::cookie' => '7.0.0', + 'OCP\AppFramework\Controller::render' => '7.0.0', + + 'OCP\AppFramework\IAppContainer::getCoreApi' => '8.0.0', + 'OCP\AppFramework\IAppContainer::isLoggedIn' => '8.0.0', + 'OCP\AppFramework\IAppContainer::isAdminUser' => '8.0.0', + 'OCP\AppFramework\IAppContainer::log' => '8.0.0', + + 'OCP\BackgroundJob::addQueuedTask' => '6.0.0', + 'OCP\BackgroundJob::addRegularTask' => '6.0.0', + 'OCP\BackgroundJob::allQueuedTasks' => '6.0.0', + 'OCP\BackgroundJob::allRegularTasks' => '6.0.0', + 'OCP\BackgroundJob::deleteQueuedTask' => '6.0.0', + 'OCP\BackgroundJob::findQueuedTask' => '6.0.0', + 'OCP\BackgroundJob::queuedTaskWhereAppIs' => '6.0.0', + 'OCP\BackgroundJob::registerJob' => '8.1.0', + + 'OCP\Files::tmpFile' => '8.1.0', + 'OCP\Files::tmpFolder' => '8.1.0', + + 'OCP\IAppConfig::getValue' => '8.0.0', + 'OCP\IAppConfig::deleteKey' => '8.0.0', + 'OCP\IAppConfig::getKeys' => '8.0.0', + 'OCP\IAppConfig::setValue' => '8.0.0', + 'OCP\IAppConfig::deleteApp' => '8.0.0', + + 'OCP\ISearch::search' => '8.0.0', + + 'OCP\IServerContainer::getDb' => '8.1.0', + 'OCP\IServerContainer::getHTTPHelper' => '8.1.0', + + 'OCP\User::getUser' => '8.0.0', + 'OCP\User::getUsers' => '8.1.0', + 'OCP\User::getDisplayName' => '8.1.0', + 'OCP\User::getDisplayNames' => '8.1.0', + 'OCP\User::userExists' => '8.1.0', + 'OCP\User::logout' => '8.1.0', + 'OCP\User::checkPassword' => '8.1.0', + + 'OCP\Util::sendMail' => '8.1.0', + 'OCP\Util::formatDate' => '8.0.0', + 'OCP\Util::encryptedFiles' => '8.1.0', + 'OCP\Util::linkToRoute' => '8.1.0', + 'OCP\Util::linkTo' => '8.1.0', + 'OCP\Util::getServerHost' => '8.1.0', + 'OCP\Util::getServerProtocol' => '8.1.0', + 'OCP\Util::getRequestUri' => '8.1.0', + 'OCP\Util::getScriptName' => '8.1.0', + 'OCP\Util::imagePath' => '8.1.0', + 'OCP\Util::isValidFileName' => '8.1.0', + 'OCP\Util::generateRandomBytes' => '8.1.0', + ]; + } + + /** + * @return bool + */ + public function checkStrongComparisons() { + return true; + } +} diff --git a/lib/private/app/codechecker/ichecklist.php b/lib/private/app/codechecker/ichecklist.php new file mode 100644 index 00000000000..c5cc82e6bb5 --- /dev/null +++ b/lib/private/app/codechecker/ichecklist.php @@ -0,0 +1,53 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ +namespace OC\App\CodeChecker; + +interface ICheckList { + /** + * @return string + */ + public function getDescription(); + + /** + * @return array E.g.: `'ClassName' => 'oc version',` + */ + public function getClasses(); + + /** + * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` + */ + public function getConstants(); + + /** + * @return array E.g.: `'functionName' => 'oc version',` + */ + public function getFunctions(); + + /** + * @return array E.g.: `'ClassName::methodName' => 'oc version',` + */ + public function getMethods(); + + /** + * @return bool + */ + public function checkStrongComparisons(); +} diff --git a/lib/private/app/codechecker/nodevisitor.php b/lib/private/app/codechecker/nodevisitor.php new file mode 100644 index 00000000000..8ec4a0320f4 --- /dev/null +++ b/lib/private/app/codechecker/nodevisitor.php @@ -0,0 +1,302 @@ + + * @author Thomas Müller + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\App\CodeChecker; + +use PhpParser\Node; +use PhpParser\Node\Name; +use PhpParser\NodeVisitorAbstract; + +class NodeVisitor extends NodeVisitorAbstract { + /** @var string */ + protected $blackListDescription; + /** @var string[] */ + protected $blackListedClassNames; + /** @var string[] */ + protected $blackListedConstants; + /** @var string[] */ + protected $blackListedFunctions; + /** @var string[] */ + protected $blackListedMethods; + /** @var bool */ + protected $checkEqualOperatorUsage; + /** @var string[] */ + protected $errorMessages; + + /** + * @param ICheckList $list + */ + public function __construct(ICheckList $list) { + $this->blackListDescription = $list->getDescription(); + + $this->blackListedClassNames = []; + foreach ($list->getClasses() as $class => $blackListInfo) { + if (is_numeric($class) && is_string($blackListInfo)) { + $class = $blackListInfo; + $blackListInfo = null; + } + + $class = strtolower($class); + $this->blackListedClassNames[$class] = $class; + } + + $this->blackListedConstants = []; + foreach ($list->getConstants() as $constantName => $blackListInfo) { + $constantName = strtolower($constantName); + $this->blackListedConstants[$constantName] = $constantName; + } + + $this->blackListedFunctions = []; + foreach ($list->getFunctions() as $functionName => $blackListInfo) { + $functionName = strtolower($functionName); + $this->blackListedFunctions[$functionName] = $functionName; + } + + $this->blackListedMethods = []; + foreach ($list->getMethods() as $functionName => $blackListInfo) { + $functionName = strtolower($functionName); + $this->blackListedMethods[$functionName] = $functionName; + } + + $this->checkEqualOperatorUsage = $list->checkStrongComparisons(); + + $this->errorMessages = [ + CodeChecker::CLASS_EXTENDS_NOT_ALLOWED => "{$this->blackListDescription} class must not be extended", + CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED => "{$this->blackListDescription} interface must not be implemented", + CodeChecker::STATIC_CALL_NOT_ALLOWED => "Static method of {$this->blackListDescription} class must not be called", + CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED => "Constant of {$this->blackListDescription} class must not not be fetched", + CodeChecker::CLASS_NEW_FETCH_NOT_ALLOWED => "{$this->blackListDescription} class must not be instanciated", + CodeChecker::CLASS_USE_NOT_ALLOWED => "{$this->blackListDescription} class must not be imported with a use statement", + CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED => "Method of {$this->blackListDescription} class must not be called", + + CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED => "is discouraged", + ]; + } + + /** @var array */ + public $errors = []; + + public function enterNode(Node $node) { + if ($this->checkEqualOperatorUsage && $node instanceof Node\Expr\BinaryOp\Equal) { + $this->errors[]= [ + 'disallowedToken' => '==', + 'errorCode' => CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED, + 'line' => $node->getLine(), + 'reason' => $this->buildReason('==', CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED) + ]; + } + if ($this->checkEqualOperatorUsage && $node instanceof Node\Expr\BinaryOp\NotEqual) { + $this->errors[]= [ + 'disallowedToken' => '!=', + 'errorCode' => CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED, + 'line' => $node->getLine(), + 'reason' => $this->buildReason('!=', CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED) + ]; + } + 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); + + $this->checkBlackListFunction($node->class->toString(), $node->name, $node); + $this->checkBlackListMethod($node->class->toString(), $node->name, $node); + } + + if ($node->class instanceof Node\Expr\Variable) { + /** + * TODO: find a way to detect something like this: + * $c = "OC_API"; + * $n = $c::call(); + */ + // $this->checkBlackListMethod($node->class->..., $node->name, $node); + } + } + } + if ($node instanceof Node\Expr\MethodCall) { + if (!is_null($node->var)) { + if ($node->var instanceof Node\Expr\Variable) { + /** + * TODO: find a way to detect something like this: + * $c = new OC_API(); + * $n = $c::call(); + * $n = $c->call(); + */ + // $this->checkBlackListMethod($node->var->..., $node->name, $node); + } + } + } + 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; + */ + } + + $this->checkBlackListConstant($node->class->toString(), $node->name, $node); + } + } + 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; + */ + } + } + } + if ($node instanceof Node\Stmt\UseUse) { + $this->checkBlackList($node->name->toString(), CodeChecker::CLASS_USE_NOT_ALLOWED, $node); + if ($node->alias) { + $this->addUseNameToBlackList($node->name->toString(), $node->alias); + } else { + $this->addUseNameToBlackList($node->name->toString(), $node->name->getLast()); + } + } + } + + /** + * Check whether an alias was introduced for a namespace of a blacklisted class + * + * Example: + * - Blacklist entry: OCP\AppFramework\IApi + * - Name: OCP\AppFramework + * - Alias: OAF + * => new blacklist entry: OAF\IApi + * + * @param string $name + * @param string $alias + */ + private function addUseNameToBlackList($name, $alias) { + $name = strtolower($name); + $alias = strtolower($alias); + + foreach ($this->blackListedClassNames as $blackListedAlias => $blackListedClassName) { + if (strpos($blackListedClassName, $name . '\\') === 0) { + $aliasedClassName = str_replace($name, $alias, $blackListedClassName); + $this->blackListedClassNames[$aliasedClassName] = $blackListedClassName; + } + } + + foreach ($this->blackListedConstants as $blackListedAlias => $blackListedConstant) { + if (strpos($blackListedConstant, $name . '\\') === 0 || strpos($blackListedConstant, $name . '::') === 0) { + $aliasedConstantName = str_replace($name, $alias, $blackListedConstant); + $this->blackListedConstants[$aliasedConstantName] = $blackListedConstant; + } + } + + foreach ($this->blackListedFunctions as $blackListedAlias => $blackListedFunction) { + if (strpos($blackListedFunction, $name . '\\') === 0 || strpos($blackListedFunction, $name . '::') === 0) { + $aliasedFunctionName = str_replace($name, $alias, $blackListedFunction); + $this->blackListedFunctions[$aliasedFunctionName] = $blackListedFunction; + } + } + + foreach ($this->blackListedMethods as $blackListedAlias => $blackListedMethod) { + if (strpos($blackListedMethod, $name . '\\') === 0 || strpos($blackListedMethod, $name . '::') === 0) { + $aliasedMethodName = str_replace($name, $alias, $blackListedMethod); + $this->blackListedMethods[$aliasedMethodName] = $blackListedMethod; + } + } + } + + private function checkBlackList($name, $errorCode, Node $node) { + $lowerName = strtolower($name); + + if (isset($this->blackListedClassNames[$lowerName])) { + $this->errors[]= [ + 'disallowedToken' => $name, + 'errorCode' => $errorCode, + 'line' => $node->getLine(), + 'reason' => $this->buildReason($this->blackListedClassNames[$lowerName], $errorCode) + ]; + } + } + + private function checkBlackListConstant($class, $constantName, Node $node) { + $name = $class . '::' . $constantName; + $lowerName = strtolower($name); + + if (isset($this->blackListedConstants[$lowerName])) { + $this->errors[]= [ + 'disallowedToken' => $name, + 'errorCode' => CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED, + 'line' => $node->getLine(), + 'reason' => $this->buildReason($this->blackListedConstants[$lowerName], CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED) + ]; + } + } + + private function checkBlackListFunction($class, $functionName, Node $node) { + $name = $class . '::' . $functionName; + $lowerName = strtolower($name); + + if (isset($this->blackListedFunctions[$lowerName])) { + $this->errors[]= [ + 'disallowedToken' => $name, + 'errorCode' => CodeChecker::STATIC_CALL_NOT_ALLOWED, + 'line' => $node->getLine(), + 'reason' => $this->buildReason($this->blackListedFunctions[$lowerName], CodeChecker::STATIC_CALL_NOT_ALLOWED) + ]; + } + } + + private function checkBlackListMethod($class, $functionName, Node $node) { + $name = $class . '::' . $functionName; + $lowerName = strtolower($name); + + if (isset($this->blackListedMethods[$lowerName])) { + $this->errors[]= [ + 'disallowedToken' => $name, + 'errorCode' => CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED, + 'line' => $node->getLine(), + 'reason' => $this->buildReason($this->blackListedMethods[$lowerName], CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED) + ]; + } + } + + private function buildReason($name, $errorCode) { + if (isset($this->errorMessages[$errorCode])) { + return $this->errorMessages[$errorCode]; + } + + return "$name usage not allowed - error: $errorCode"; + } +} diff --git a/lib/private/app/codechecker/privatelist.php b/lib/private/app/codechecker/privatelist.php new file mode 100644 index 00000000000..e44926ada77 --- /dev/null +++ b/lib/private/app/codechecker/privatelist.php @@ -0,0 +1,105 @@ + + * @author Morris Jobke + * @author Thomas Müller + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\App\CodeChecker; + +use OC\Hooks\BasicEmitter; +use PhpParser\Lexer; +use PhpParser\Node; +use PhpParser\Node\Name; +use PhpParser\NodeTraverser; +use PhpParser\Parser; +use RecursiveCallbackFilterIterator; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use RegexIterator; +use SplFileInfo; + +class PrivateList implements ICheckList { + /** + * @return string + */ + public function getDescription() { + return 'private'; + } + + /** + * @return array + */ + public function getClasses() { + return [ + // classes replaced by the public api + 'OC_API', + 'OC_App', + 'OC_AppConfig', + 'OC_Avatar', + 'OC_BackgroundJob', + 'OC_Config', + 'OC_DB', + 'OC_Files', + 'OC_Helper', + 'OC_Hook', + 'OC_Image', + 'OC_JSON', + 'OC_L10N', + 'OC_Log', + 'OC_Mail', + 'OC_Preferences', + 'OC_Search_Provider', + 'OC_Search_Result', + 'OC_Request', + 'OC_Response', + 'OC_Template', + 'OC_User', + 'OC_Util', + ]; + } + + /** + * @return array + */ + public function getConstants() { + return []; + } + + /** + * @return array + */ + public function getFunctions() { + return []; + } + + /** + * @return array + */ + public function getMethods() { + return []; + } + + /** + * @return bool + */ + public function checkStrongComparisons() { + return false; + } +} diff --git a/lib/private/app/codecheckvisitor.php b/lib/private/app/codecheckvisitor.php deleted file mode 100644 index dd12d2faa4d..00000000000 --- a/lib/private/app/codecheckvisitor.php +++ /dev/null @@ -1,307 +0,0 @@ - - * @author Thomas Müller - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OC\App; - -use PhpParser\Node; -use PhpParser\Node\Name; -use PhpParser\NodeVisitorAbstract; - -class CodeCheckVisitor extends NodeVisitorAbstract { - /** @var string */ - protected $blackListDescription; - /** @var string[] */ - protected $blackListedClassNames; - /** @var string[] */ - protected $blackListedConstants; - /** @var string[] */ - protected $blackListedFunctions; - /** @var string[] */ - protected $blackListedMethods; - /** @var bool */ - protected $checkEqualOperatorUsage; - /** @var string[] */ - protected $errorMessages; - - /** - * @param string $blackListDescription - * @param array $blackListedClassNames - * @param array $blackListedConstants - * @param array $blackListedFunctions - * @param array $blackListedMethods - * @param bool $checkEqualOperatorUsage - */ - public function __construct($blackListDescription, $blackListedClassNames, $blackListedConstants, $blackListedFunctions, $blackListedMethods, $checkEqualOperatorUsage) { - $this->blackListDescription = $blackListDescription; - - $this->blackListedClassNames = []; - foreach ($blackListedClassNames as $class => $blackListInfo) { - if (is_numeric($class) && is_string($blackListInfo)) { - $class = $blackListInfo; - $blackListInfo = null; - } - - $class = strtolower($class); - $this->blackListedClassNames[$class] = $class; - } - - $this->blackListedConstants = []; - foreach ($blackListedConstants as $constantName => $blackListInfo) { - $constantName = strtolower($constantName); - $this->blackListedConstants[$constantName] = $constantName; - } - - $this->blackListedFunctions = []; - foreach ($blackListedFunctions as $functionName => $blackListInfo) { - $functionName = strtolower($functionName); - $this->blackListedFunctions[$functionName] = $functionName; - } - - $this->blackListedMethods = []; - foreach ($blackListedMethods as $functionName => $blackListInfo) { - $functionName = strtolower($functionName); - $this->blackListedMethods[$functionName] = $functionName; - } - - $this->checkEqualOperatorUsage = $checkEqualOperatorUsage; - - $this->errorMessages = [ - CodeChecker::CLASS_EXTENDS_NOT_ALLOWED => "{$this->blackListDescription} class must not be extended", - CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED => "{$this->blackListDescription} interface must not be implemented", - CodeChecker::STATIC_CALL_NOT_ALLOWED => "Static method of {$this->blackListDescription} class must not be called", - CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED => "Constant of {$this->blackListDescription} class must not not be fetched", - CodeChecker::CLASS_NEW_FETCH_NOT_ALLOWED => "{$this->blackListDescription} class must not be instanciated", - CodeChecker::CLASS_USE_NOT_ALLOWED => "{$this->blackListDescription} class must not be imported with a use statement", - CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED => "Method of {$this->blackListDescription} class must not be called", - - CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED => "is discouraged", - ]; - } - - /** @var array */ - public $errors = []; - - public function enterNode(Node $node) { - if ($this->checkEqualOperatorUsage && $node instanceof Node\Expr\BinaryOp\Equal) { - $this->errors[]= [ - 'disallowedToken' => '==', - 'errorCode' => CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED, - 'line' => $node->getLine(), - 'reason' => $this->buildReason('==', CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED) - ]; - } - if ($this->checkEqualOperatorUsage && $node instanceof Node\Expr\BinaryOp\NotEqual) { - $this->errors[]= [ - 'disallowedToken' => '!=', - 'errorCode' => CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED, - 'line' => $node->getLine(), - 'reason' => $this->buildReason('!=', CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED) - ]; - } - 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); - - $this->checkBlackListFunction($node->class->toString(), $node->name, $node); - $this->checkBlackListMethod($node->class->toString(), $node->name, $node); - } - - if ($node->class instanceof Node\Expr\Variable) { - /** - * TODO: find a way to detect something like this: - * $c = "OC_API"; - * $n = $c::call(); - */ - // $this->checkBlackListMethod($node->class->..., $node->name, $node); - } - } - } - if ($node instanceof Node\Expr\MethodCall) { - if (!is_null($node->var)) { - if ($node->var instanceof Node\Expr\Variable) { - /** - * TODO: find a way to detect something like this: - * $c = new OC_API(); - * $n = $c::call(); - * $n = $c->call(); - */ - // $this->checkBlackListMethod($node->var->..., $node->name, $node); - } - } - } - 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; - */ - } - - $this->checkBlackListConstant($node->class->toString(), $node->name, $node); - } - } - 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; - */ - } - } - } - if ($node instanceof Node\Stmt\UseUse) { - $this->checkBlackList($node->name->toString(), CodeChecker::CLASS_USE_NOT_ALLOWED, $node); - if ($node->alias) { - $this->addUseNameToBlackList($node->name->toString(), $node->alias); - } else { - $this->addUseNameToBlackList($node->name->toString(), $node->name->getLast()); - } - } - } - - /** - * Check whether an alias was introduced for a namespace of a blacklisted class - * - * Example: - * - Blacklist entry: OCP\AppFramework\IApi - * - Name: OCP\AppFramework - * - Alias: OAF - * => new blacklist entry: OAF\IApi - * - * @param string $name - * @param string $alias - */ - private function addUseNameToBlackList($name, $alias) { - $name = strtolower($name); - $alias = strtolower($alias); - - foreach ($this->blackListedClassNames as $blackListedAlias => $blackListedClassName) { - if (strpos($blackListedClassName, $name . '\\') === 0) { - $aliasedClassName = str_replace($name, $alias, $blackListedClassName); - $this->blackListedClassNames[$aliasedClassName] = $blackListedClassName; - } - } - - foreach ($this->blackListedConstants as $blackListedAlias => $blackListedConstant) { - if (strpos($blackListedConstant, $name . '\\') === 0 || strpos($blackListedConstant, $name . '::') === 0) { - $aliasedConstantName = str_replace($name, $alias, $blackListedConstant); - $this->blackListedConstants[$aliasedConstantName] = $blackListedConstant; - } - } - - foreach ($this->blackListedFunctions as $blackListedAlias => $blackListedFunction) { - if (strpos($blackListedFunction, $name . '\\') === 0 || strpos($blackListedFunction, $name . '::') === 0) { - $aliasedFunctionName = str_replace($name, $alias, $blackListedFunction); - $this->blackListedFunctions[$aliasedFunctionName] = $blackListedFunction; - } - } - - foreach ($this->blackListedMethods as $blackListedAlias => $blackListedMethod) { - if (strpos($blackListedMethod, $name . '\\') === 0 || strpos($blackListedMethod, $name . '::') === 0) { - $aliasedMethodName = str_replace($name, $alias, $blackListedMethod); - $this->blackListedMethods[$aliasedMethodName] = $blackListedMethod; - } - } - } - - private function checkBlackList($name, $errorCode, Node $node) { - $lowerName = strtolower($name); - - if (isset($this->blackListedClassNames[$lowerName])) { - $this->errors[]= [ - 'disallowedToken' => $name, - 'errorCode' => $errorCode, - 'line' => $node->getLine(), - 'reason' => $this->buildReason($this->blackListedClassNames[$lowerName], $errorCode) - ]; - } - } - - private function checkBlackListConstant($class, $constantName, Node $node) { - $name = $class . '::' . $constantName; - $lowerName = strtolower($name); - - if (isset($this->blackListedConstants[$lowerName])) { - $this->errors[]= [ - 'disallowedToken' => $name, - 'errorCode' => CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED, - 'line' => $node->getLine(), - 'reason' => $this->buildReason($this->blackListedConstants[$lowerName], CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED) - ]; - } - } - - private function checkBlackListFunction($class, $functionName, Node $node) { - $name = $class . '::' . $functionName; - $lowerName = strtolower($name); - - if (isset($this->blackListedFunctions[$lowerName])) { - $this->errors[]= [ - 'disallowedToken' => $name, - 'errorCode' => CodeChecker::STATIC_CALL_NOT_ALLOWED, - 'line' => $node->getLine(), - 'reason' => $this->buildReason($this->blackListedFunctions[$lowerName], CodeChecker::STATIC_CALL_NOT_ALLOWED) - ]; - } - } - - private function checkBlackListMethod($class, $functionName, Node $node) { - $name = $class . '::' . $functionName; - $lowerName = strtolower($name); - - if (isset($this->blackListedMethods[$lowerName])) { - $this->errors[]= [ - 'disallowedToken' => $name, - 'errorCode' => CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED, - 'line' => $node->getLine(), - 'reason' => $this->buildReason($this->blackListedMethods[$lowerName], CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED) - ]; - } - } - - private function buildReason($name, $errorCode) { - if (isset($this->errorMessages[$errorCode])) { - return $this->errorMessages[$errorCode]; - } - - return "$name usage not allowed - error: $errorCode"; - } -} diff --git a/lib/private/app/deprecationcodechecker.php b/lib/private/app/deprecationcodechecker.php deleted file mode 100644 index 5bec83f971a..00000000000 --- a/lib/private/app/deprecationcodechecker.php +++ /dev/null @@ -1,127 +0,0 @@ - - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OC\App; - -class DeprecationCodeChecker extends CodeChecker { - protected $checkEqualOperators = true; - - /** @var string */ - protected $blackListDescription = 'deprecated'; - - protected $blackListedClassNames = [ - // Deprecated classes - 'OCP\Config' => '8.0.0', - 'OCP\Contacts' => '8.1.0', - 'OCP\DB' => '8.1.0', - 'OCP\IHelper' => '8.1.0', - 'OCP\JSON' => '8.1.0', - 'OCP\Response' => '8.1.0', - 'OCP\AppFramework\IApi' => '8.0.0', - ]; - - protected $blackListedConstants = [ - // Deprecated constants - 'OCP::PERMISSION_CREATE' => '8.0.0', - 'OCP::PERMISSION_READ' => '8.0.0', - 'OCP::PERMISSION_UPDATE' => '8.0.0', - 'OCP::PERMISSION_DELETE' => '8.0.0', - 'OCP::PERMISSION_SHARE' => '8.0.0', - 'OCP::PERMISSION_ALL' => '8.0.0', - 'OCP::FILENAME_INVALID_CHARS' => '8.0.0', - ]; - - protected $blackListedFunctions = [ - // Deprecated functions - 'OCP::image_path' => '8.0.0', - 'OCP::mimetype_icon' => '8.0.0', - 'OCP::preview_icon' => '8.0.0', - 'OCP::publicPreview_icon' => '8.0.0', - 'OCP::human_file_size' => '8.0.0', - 'OCP::relative_modified_date' => '8.0.0', - 'OCP::simple_file_size' => '8.0.0', - 'OCP::html_select_options' => '8.0.0', - ]; - - protected $blackListedMethods = [ - // Deprecated methods - 'OCP\App::register' => '8.1.0', - 'OCP\App::addNavigationEntry' => '8.1.0', - 'OCP\App::setActiveNavigationEntry' => '8.1.0', - - 'OCP\AppFramework\Controller::params' => '7.0.0', - 'OCP\AppFramework\Controller::getParams' => '7.0.0', - 'OCP\AppFramework\Controller::method' => '7.0.0', - 'OCP\AppFramework\Controller::getUploadedFile' => '7.0.0', - 'OCP\AppFramework\Controller::env' => '7.0.0', - 'OCP\AppFramework\Controller::cookie' => '7.0.0', - 'OCP\AppFramework\Controller::render' => '7.0.0', - - 'OCP\AppFramework\IAppContainer::getCoreApi' => '8.0.0', - 'OCP\AppFramework\IAppContainer::isLoggedIn' => '8.0.0', - 'OCP\AppFramework\IAppContainer::isAdminUser' => '8.0.0', - 'OCP\AppFramework\IAppContainer::log' => '8.0.0', - - 'OCP\BackgroundJob::addQueuedTask' => '6.0.0', - 'OCP\BackgroundJob::addRegularTask' => '6.0.0', - 'OCP\BackgroundJob::allQueuedTasks' => '6.0.0', - 'OCP\BackgroundJob::allRegularTasks' => '6.0.0', - 'OCP\BackgroundJob::deleteQueuedTask' => '6.0.0', - 'OCP\BackgroundJob::findQueuedTask' => '6.0.0', - 'OCP\BackgroundJob::queuedTaskWhereAppIs' => '6.0.0', - 'OCP\BackgroundJob::registerJob' => '8.1.0', - - 'OCP\Files::tmpFile' => '8.1.0', - 'OCP\Files::tmpFolder' => '8.1.0', - - 'OCP\IAppConfig::getValue' => '8.0.0', - 'OCP\IAppConfig::deleteKey' => '8.0.0', - 'OCP\IAppConfig::getKeys' => '8.0.0', - 'OCP\IAppConfig::setValue' => '8.0.0', - 'OCP\IAppConfig::deleteApp' => '8.0.0', - - 'OCP\ISearch::search' => '8.0.0', - - 'OCP\IServerContainer::getDb' => '8.1.0', - 'OCP\IServerContainer::getHTTPHelper' => '8.1.0', - - 'OCP\User::getUser' => '8.0.0', - 'OCP\User::getUsers' => '8.1.0', - 'OCP\User::getDisplayName' => '8.1.0', - 'OCP\User::getDisplayNames' => '8.1.0', - 'OCP\User::userExists' => '8.1.0', - 'OCP\User::logout' => '8.1.0', - 'OCP\User::checkPassword' => '8.1.0', - - 'OCP\Util::sendMail' => '8.1.0', - 'OCP\Util::formatDate' => '8.0.0', - 'OCP\Util::encryptedFiles' => '8.1.0', - 'OCP\Util::linkToRoute' => '8.1.0', - 'OCP\Util::linkTo' => '8.1.0', - 'OCP\Util::getServerHost' => '8.1.0', - 'OCP\Util::getServerProtocol' => '8.1.0', - 'OCP\Util::getRequestUri' => '8.1.0', - 'OCP\Util::getScriptName' => '8.1.0', - 'OCP\Util::imagePath' => '8.1.0', - 'OCP\Util::isValidFileName' => '8.1.0', - 'OCP\Util::generateRandomBytes' => '8.1.0', - ]; -} diff --git a/tests/lib/app/codechecker.php b/tests/lib/app/codechecker.php deleted file mode 100644 index 435aedfe3ad..00000000000 --- a/tests/lib/app/codechecker.php +++ /dev/null @@ -1,58 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace Test\App; - -use OC; -use Test\TestCase; - -class CodeChecker extends TestCase { - - /** - * @dataProvider providesFilesToCheck - * @param string $expectedErrorToken - * @param int $expectedErrorCode - * @param string $fileToVerify - */ - public function testFindInvalidUsage($expectedErrorToken, $expectedErrorCode, $fileToVerify) { - $checker = new OC\App\CodeChecker(); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); - - $this->assertEquals(1, count($errors)); - $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); - $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); - } - - public function providesFilesToCheck() { - return [ - ['OC_Hook', 1000, 'test-extends.php'], - ['oC_Avatar', 1001, 'test-implements.php'], - ['OC_App', 1002, 'test-static-call.php'], - ['OC_API', 1003, 'test-const.php'], - ['OC_AppConfig', 1004, 'test-new.php'], - ['OC_AppConfig', 1006, 'test-use.php'], - ]; - } - - /** - * @dataProvider validFilesData - * @param string $fileToVerify - */ - public function testPassValidUsage($fileToVerify) { - $checker = new OC\App\CodeChecker(); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); - - $this->assertEquals(0, count($errors)); - } - - public function validFilesData() { - return [ - ['test-identical-operator.php'], - ]; - } -} diff --git a/tests/lib/app/codechecker/codecheckertest.php b/tests/lib/app/codechecker/codecheckertest.php new file mode 100644 index 00000000000..93bf0b32c58 --- /dev/null +++ b/tests/lib/app/codechecker/codecheckertest.php @@ -0,0 +1,62 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\App\CodeChecker; + +use OC; +use Test\TestCase; + +class CodeCheckerTest extends TestCase { + + /** + * @dataProvider providesFilesToCheck + * @param string $expectedErrorToken + * @param int $expectedErrorCode + * @param string $fileToVerify + */ + public function testFindInvalidUsage($expectedErrorToken, $expectedErrorCode, $fileToVerify) { + $checker = new OC\App\CodeChecker\CodeChecker( + new OC\App\CodeChecker\PrivateList() + ); + $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertEquals(1, count($errors)); + $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); + $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); + } + + public function providesFilesToCheck() { + return [ + ['OC_Hook', 1000, 'test-extends.php'], + ['oC_Avatar', 1001, 'test-implements.php'], + ['OC_App', 1002, 'test-static-call.php'], + ['OC_API', 1003, 'test-const.php'], + ['OC_AppConfig', 1004, 'test-new.php'], + ['OC_AppConfig', 1006, 'test-use.php'], + ]; + } + + /** + * @dataProvider validFilesData + * @param string $fileToVerify + */ + public function testPassValidUsage($fileToVerify) { + $checker = new OC\App\CodeChecker\CodeChecker( + new OC\App\CodeChecker\PrivateList() + ); + $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertEquals(0, count($errors)); + } + + public function validFilesData() { + return [ + ['test-identical-operator.php'], + ]; + } +} diff --git a/tests/lib/app/codechecker/deprecationlisttest.php b/tests/lib/app/codechecker/deprecationlisttest.php new file mode 100644 index 00000000000..2293d31a1f6 --- /dev/null +++ b/tests/lib/app/codechecker/deprecationlisttest.php @@ -0,0 +1,68 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\App; + +use OC; +use Test\TestCase; + +class DeprecationListTest extends TestCase { + + /** + * @dataProvider providesFilesToCheck + * @param string $expectedErrorToken + * @param int $expectedErrorCode + * @param string $fileToVerify + */ + public function testFindInvalidUsage($expectedErrorToken, $expectedErrorCode, $fileToVerify) { + $checker = new OC\App\CodeChecker\CodeChecker( + new OC\App\CodeChecker\DeprecationList() + ); + $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertEquals(1, count($errors)); + $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); + $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); + } + + public function providesFilesToCheck() { + return [ + ['==', 1005, 'test-equal.php'], + ['!=', 1005, 'test-not-equal.php'], + ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use.php'], + ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use-alias.php'], + ['AppFramework\IApi', 1001, 'test-deprecated-use-sub.php'], + ['OAF\IApi', 1001, 'test-deprecated-use-sub-alias.php'], + ]; + } + + /** + * @dataProvider validFilesData + * @param string $fileToVerify + */ + public function testPassValidUsage($fileToVerify) { + $checker = new OC\App\CodeChecker\CodeChecker( + new OC\App\CodeChecker\DeprecationList() + ); + $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertEquals(0, count($errors)); + } + + public function validFilesData() { + return [ + ['test-extends.php'], + ['test-implements.php'], + ['test-static-call.php'], + ['test-const.php'], + ['test-new.php'], + ['test-use.php'], + ['test-identical-operator.php'], + ]; + } +} diff --git a/tests/lib/app/codechecker/mock/testlist.php b/tests/lib/app/codechecker/mock/testlist.php new file mode 100644 index 00000000000..c4985e8e625 --- /dev/null +++ b/tests/lib/app/codechecker/mock/testlist.php @@ -0,0 +1,81 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace Test\App\CodeChecker\Mock; + +use OC\App\CodeChecker\ICheckList; + +class TestList implements ICheckList { + + /** + * @return string + */ + public function getDescription() { + return 'deprecated'; + } + + /** + * @return array E.g.: `'ClassName' => 'oc version',` + */ + public function getClasses() { + return [ + // Deprecated classes + 'OCP\AppFramework\IApi' => '8.0.0', + ]; + } + + /** + * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` + */ + public function getConstants() { + return [ + // Deprecated constants + 'OCP\NamespaceName\ClassName::CONSTANT_NAME' => '8.0.0', + ]; + } + + /** + * @return array E.g.: `'functionName' => 'oc version',` + */ + public function getFunctions() { + return [ + // Deprecated functions + 'OCP\NamespaceName\ClassName::functionName' => '8.0.0', + ]; + } + + /** + * @return array E.g.: `'ClassName::methodName' => 'oc version',` + */ + public function getMethods() { + return [ + // Deprecated methods + 'OCP\NamespaceName\ClassName::methodName' => '8.0.0', + ]; + } + + /** + * @return bool + */ + public function checkStrongComparisons() { + return true; + } +} diff --git a/tests/lib/app/codechecker/nodevisitortest.php b/tests/lib/app/codechecker/nodevisitortest.php new file mode 100644 index 00000000000..1207ca6a043 --- /dev/null +++ b/tests/lib/app/codechecker/nodevisitortest.php @@ -0,0 +1,71 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\AppCodeChecker; + +use OC; +use Test\TestCase; + +class NodeVisitorTest extends TestCase { + + public function providesFilesToCheck() { + return [ + [[['OCP\AppFramework\IApi', 1006]], 'test-deprecated-use.php'], + [[['OCP\AppFramework\IApi', 1006]], 'test-deprecated-use-alias.php'], + [[['AppFramework\IApi', 1001]], 'test-deprecated-use-sub.php'], + [[['OAF\IApi', 1001]], 'test-deprecated-use-sub-alias.php'], + + [[['OCP\NamespaceName\ClassName::CONSTANT_NAME', 1003]], 'test-deprecated-constant.php'], + [[['Alias::CONSTANT_NAME', 1003]], 'test-deprecated-constant-alias.php'], + [[['NamespaceName\ClassName::CONSTANT_NAME', 1003]], 'test-deprecated-constant-sub.php'], + [[['SubAlias\ClassName::CONSTANT_NAME', 1003]], 'test-deprecated-constant-sub-alias.php'], + + [[ + ['OCP\NamespaceName\ClassName::functionName', 1002], + ['OCP\NamespaceName\ClassName::methodName', 1007], + ], 'test-deprecated-function.php'], + [[ + ['Alias::functionName', 1002], + ['Alias::methodName', 1007], + ], 'test-deprecated-function-alias.php'], + [[ + ['NamespaceName\ClassName::functionName', 1002], + ['NamespaceName\ClassName::methodName', 1007], + ], 'test-deprecated-function-sub.php'], + [[ + ['SubAlias\ClassName::functionName', 1002], + ['SubAlias\ClassName::methodName', 1007], + ], 'test-deprecated-function-sub-alias.php'], + + // TODO Failing to resolve variables to classes +// [[['OCP\NamespaceName\ClassName::methodName', 1007]], 'test-deprecated-method.php'], +// [[['Alias::methodName', 1002]], 'test-deprecated-method-alias.php'], +// [[['NamespaceName\ClassName::methodName', 1002]], 'test-deprecated-method-sub.php'], +// [[['SubAlias\ClassName::methodName', 1002]], 'test-deprecated-method-sub-alias.php'], + ]; + } + + /** + * @dataProvider providesFilesToCheck + * @param array $expectedErrors + * @param string $fileToVerify + */ + public function testMethodsToCheck($expectedErrors, $fileToVerify) { + $checker = new OC\App\CodeChecker\CodeChecker( + new \Test\App\CodeChecker\Mock\TestList() + ); + $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertCount(sizeof($expectedErrors), $errors); + + foreach ($expectedErrors as $int => $expectedError) { + $this->assertEquals($expectedError[0], $errors[$int]['disallowedToken']); + $this->assertEquals($expectedError[1], $errors[$int]['errorCode']); + } + } +} diff --git a/tests/lib/app/codecheckvisitor.php b/tests/lib/app/codecheckvisitor.php deleted file mode 100644 index d836f1b3c84..00000000000 --- a/tests/lib/app/codecheckvisitor.php +++ /dev/null @@ -1,69 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace Test\App; - -use OC; -use Test\TestCase; - -class CodeCheckVisitor extends TestCase { - - public function providesFilesToCheck() { - return [ - [[['OCP\AppFramework\IApi', 1006]], 'test-deprecated-use.php'], - [[['OCP\AppFramework\IApi', 1006]], 'test-deprecated-use-alias.php'], - [[['AppFramework\IApi', 1001]], 'test-deprecated-use-sub.php'], - [[['OAF\IApi', 1001]], 'test-deprecated-use-sub-alias.php'], - - [[['OCP\NamespaceName\ClassName::CONSTANT_NAME', 1003]], 'test-deprecated-constant.php'], - [[['Alias::CONSTANT_NAME', 1003]], 'test-deprecated-constant-alias.php'], - [[['NamespaceName\ClassName::CONSTANT_NAME', 1003]], 'test-deprecated-constant-sub.php'], - [[['SubAlias\ClassName::CONSTANT_NAME', 1003]], 'test-deprecated-constant-sub-alias.php'], - - [[ - ['OCP\NamespaceName\ClassName::functionName', 1002], - ['OCP\NamespaceName\ClassName::methodName', 1007], - ], 'test-deprecated-function.php'], - [[ - ['Alias::functionName', 1002], - ['Alias::methodName', 1007], - ], 'test-deprecated-function-alias.php'], - [[ - ['NamespaceName\ClassName::functionName', 1002], - ['NamespaceName\ClassName::methodName', 1007], - ], 'test-deprecated-function-sub.php'], - [[ - ['SubAlias\ClassName::functionName', 1002], - ['SubAlias\ClassName::methodName', 1007], - ], 'test-deprecated-function-sub-alias.php'], - - // TODO Failing to resolve variables to classes -// [[['OCP\NamespaceName\ClassName::methodName', 1007]], 'test-deprecated-method.php'], -// [[['Alias::methodName', 1002]], 'test-deprecated-method-alias.php'], -// [[['NamespaceName\ClassName::methodName', 1002]], 'test-deprecated-method-sub.php'], -// [[['SubAlias\ClassName::methodName', 1002]], 'test-deprecated-method-sub-alias.php'], - ]; - } - - /** - * @dataProvider providesFilesToCheck - * @param array $expectedErrors - * @param string $fileToVerify - */ - public function testMethodsToCheck($expectedErrors, $fileToVerify) { - $checker = new \Test\App\Mock\CodeChecker(); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); - - $this->assertCount(sizeof($expectedErrors), $errors); - - foreach ($expectedErrors as $int => $expectedError) { - $this->assertEquals($expectedError[0], $errors[$int]['disallowedToken']); - $this->assertEquals($expectedError[1], $errors[$int]['errorCode']); - } - } -} diff --git a/tests/lib/app/deprecationcodechecker.php b/tests/lib/app/deprecationcodechecker.php deleted file mode 100644 index 57d9ca85a7a..00000000000 --- a/tests/lib/app/deprecationcodechecker.php +++ /dev/null @@ -1,64 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace Test\App; - -use OC; -use Test\TestCase; - -class DeprecationCodeChecker extends TestCase { - - /** - * @dataProvider providesFilesToCheck - * @param string $expectedErrorToken - * @param int $expectedErrorCode - * @param string $fileToVerify - */ - public function testFindInvalidUsage($expectedErrorToken, $expectedErrorCode, $fileToVerify) { - $checker = new \OC\App\DeprecationCodeChecker(); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); - - $this->assertEquals(1, count($errors)); - $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); - $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); - } - - public function providesFilesToCheck() { - return [ - ['==', 1005, 'test-equal.php'], - ['!=', 1005, 'test-not-equal.php'], - ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use.php'], - ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use-alias.php'], - ['AppFramework\IApi', 1001, 'test-deprecated-use-sub.php'], - ['OAF\IApi', 1001, 'test-deprecated-use-sub-alias.php'], - ]; - } - - /** - * @dataProvider validFilesData - * @param string $fileToVerify - */ - public function testPassValidUsage($fileToVerify) { - $checker = new \OC\App\DeprecationCodeChecker(); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); - - $this->assertEquals(0, count($errors)); - } - - public function validFilesData() { - return [ - ['test-extends.php'], - ['test-implements.php'], - ['test-static-call.php'], - ['test-const.php'], - ['test-new.php'], - ['test-use.php'], - ['test-identical-operator.php'], - ]; - } -} diff --git a/tests/lib/app/mock/codechecker.php b/tests/lib/app/mock/codechecker.php deleted file mode 100644 index b5a775cc43d..00000000000 --- a/tests/lib/app/mock/codechecker.php +++ /dev/null @@ -1,49 +0,0 @@ - - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace Test\App\Mock; - -class CodeChecker extends \OC\App\CodeChecker { - protected $checkEqualOperators = true; - - /** @var string */ - protected $blackListDescription = 'deprecated'; - - protected $blackListedClassNames = [ - // Deprecated classes - 'OCP\AppFramework\IApi' => '8.0.0', - ]; - - protected $blackListedConstants = [ - // Deprecated constants - 'OCP\NamespaceName\ClassName::CONSTANT_NAME' => '8.0.0', - ]; - - protected $blackListedFunctions = [ - // Deprecated functions - 'OCP\NamespaceName\ClassName::functionName' => '8.0.0', - ]; - - protected $blackListedMethods = [ - // Deprecated methods - 'OCP\NamespaceName\ClassName::methodName' => '8.0.0', - ]; -} -- cgit v1.2.3 From a0c6f2e5e071a287717e58f32c5b3cf6e219f321 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 7 Jul 2015 15:37:56 +0200 Subject: Use the decorator pattern --- core/command/app/checkcode.php | 14 +- lib/private/app/codechecker/codechecker.php | 10 +- lib/private/app/codechecker/deprecationcheck.php | 163 +++++++++++++++++++++ lib/private/app/codechecker/deprecationlist.php | 152 ------------------- lib/private/app/codechecker/emptycheck.php | 65 ++++++++ lib/private/app/codechecker/icheck.php | 53 +++++++ lib/private/app/codechecker/ichecklist.php | 53 ------- lib/private/app/codechecker/nodevisitor.php | 4 +- lib/private/app/codechecker/privatecheck.php | 104 +++++++++++++ lib/private/app/codechecker/privatelist.php | 105 ------------- .../app/codechecker/strongcomparisoncheck.php | 78 ++++++++++ tests/lib/app/codechecker/codecheckertest.php | 16 +- tests/lib/app/codechecker/deprecationchecktest.php | 70 +++++++++ tests/lib/app/codechecker/deprecationlisttest.php | 68 --------- tests/lib/app/codechecker/mock/testlist.php | 15 +- tests/lib/app/codechecker/nodevisitortest.php | 10 +- .../app/codechecker/strongcomparisonchecktest.php | 70 +++++++++ 17 files changed, 646 insertions(+), 404 deletions(-) create mode 100644 lib/private/app/codechecker/deprecationcheck.php delete mode 100644 lib/private/app/codechecker/deprecationlist.php create mode 100644 lib/private/app/codechecker/emptycheck.php create mode 100644 lib/private/app/codechecker/icheck.php delete mode 100644 lib/private/app/codechecker/ichecklist.php create mode 100644 lib/private/app/codechecker/privatecheck.php delete mode 100644 lib/private/app/codechecker/privatelist.php create mode 100644 lib/private/app/codechecker/strongcomparisoncheck.php create mode 100644 tests/lib/app/codechecker/deprecationchecktest.php delete mode 100644 tests/lib/app/codechecker/deprecationlisttest.php create mode 100644 tests/lib/app/codechecker/strongcomparisonchecktest.php (limited to 'lib') diff --git a/core/command/app/checkcode.php b/core/command/app/checkcode.php index a533ce767f3..3f4fb95868c 100644 --- a/core/command/app/checkcode.php +++ b/core/command/app/checkcode.php @@ -24,8 +24,10 @@ namespace OC\Core\Command\App; use OC\App\CodeChecker\CodeChecker; -use OC\App\CodeChecker\DeprecationList; -use OC\App\CodeChecker\PrivateList; +use OC\App\CodeChecker\DeprecationCheck; +use OC\App\CodeChecker\EmptyCheck; +use OC\App\CodeChecker\PrivateCheck; +use OC\App\CodeChecker\StrongComparisonCheck; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -52,12 +54,14 @@ class CheckCode extends Command { protected function execute(InputInterface $input, OutputInterface $output) { $appId = $input->getArgument('app-id'); + $checkList = new EmptyCheck(); if ($input->getOption('deprecated')) { - $list = new DeprecationList(); + $checkList = new DeprecationCheck($checkList); + $checkList = new StrongComparisonCheck($checkList); } else { - $list = new PrivateList(); + $checkList = new PrivateCheck($checkList); } - $codeChecker = new CodeChecker($list); + $codeChecker = new CodeChecker($checkList); $codeChecker->listen('CodeChecker', 'analyseFileBegin', function($params) use ($output) { if(OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { diff --git a/lib/private/app/codechecker/codechecker.php b/lib/private/app/codechecker/codechecker.php index b2ee9d6d71d..ae16b156178 100644 --- a/lib/private/app/codechecker/codechecker.php +++ b/lib/private/app/codechecker/codechecker.php @@ -49,11 +49,11 @@ class CodeChecker extends BasicEmitter { /** @var Parser */ private $parser; - /** @var ICheckList */ - protected $list; + /** @var ICheck */ + protected $checkList; - public function __construct(ICheckList $list) { - $this->list = $list; + public function __construct(ICheck $checkList) { + $this->checkList = $checkList; $this->parser = new Parser(new Lexer); } @@ -114,7 +114,7 @@ class CodeChecker extends BasicEmitter { $code = file_get_contents($file); $statements = $this->parser->parse($code); - $visitor = new NodeVisitor($this->list); + $visitor = new NodeVisitor($this->checkList); $traverser = new NodeTraverser; $traverser->addVisitor($visitor); diff --git a/lib/private/app/codechecker/deprecationcheck.php b/lib/private/app/codechecker/deprecationcheck.php new file mode 100644 index 00000000000..bac59e4dd7c --- /dev/null +++ b/lib/private/app/codechecker/deprecationcheck.php @@ -0,0 +1,163 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\App\CodeChecker; + +class DeprecationCheck implements ICheck { + /** @var ICheck */ + protected $check; + + /** + * @param ICheck $check + */ + public function __construct(ICheck $check) { + $this->check = $check; + } + + /** + * @return string + */ + public function getDescription() { + $innerDescription = $this->check->getDescription(); + return 'deprecated' . (($innerDescription === '') ? '' : ' ' . $innerDescription); + } + + /** + * @return array E.g.: `'ClassName' => 'oc version',` + */ + public function getClasses() { + return array_merge([ + 'OCP\Config' => '8.0.0', + 'OCP\Contacts' => '8.1.0', + 'OCP\DB' => '8.1.0', + 'OCP\IHelper' => '8.1.0', + 'OCP\JSON' => '8.1.0', + 'OCP\Response' => '8.1.0', + 'OCP\AppFramework\IApi' => '8.0.0', + ], $this->check->getClasses()); + } + + /** + * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` + */ + public function getConstants() { + return array_merge([ + 'OCP::PERMISSION_CREATE' => '8.0.0', + 'OCP::PERMISSION_READ' => '8.0.0', + 'OCP::PERMISSION_UPDATE' => '8.0.0', + 'OCP::PERMISSION_DELETE' => '8.0.0', + 'OCP::PERMISSION_SHARE' => '8.0.0', + 'OCP::PERMISSION_ALL' => '8.0.0', + 'OCP::FILENAME_INVALID_CHARS' => '8.0.0', + ], $this->check->getConstants()); + } + + /** + * @return array E.g.: `'functionName' => 'oc version',` + */ + public function getFunctions() { + return array_merge([ + 'OCP::image_path' => '8.0.0', + 'OCP::mimetype_icon' => '8.0.0', + 'OCP::preview_icon' => '8.0.0', + 'OCP::publicPreview_icon' => '8.0.0', + 'OCP::human_file_size' => '8.0.0', + 'OCP::relative_modified_date' => '8.0.0', + 'OCP::simple_file_size' => '8.0.0', + 'OCP::html_select_options' => '8.0.0', + ], $this->check->getFunctions()); + } + + /** + * @return array E.g.: `'ClassName::methodName' => 'oc version',` + */ + public function getMethods() { + return array_merge([ + 'OCP\App::register' => '8.1.0', + 'OCP\App::addNavigationEntry' => '8.1.0', + 'OCP\App::setActiveNavigationEntry' => '8.1.0', + + 'OCP\AppFramework\Controller::params' => '7.0.0', + 'OCP\AppFramework\Controller::getParams' => '7.0.0', + 'OCP\AppFramework\Controller::method' => '7.0.0', + 'OCP\AppFramework\Controller::getUploadedFile' => '7.0.0', + 'OCP\AppFramework\Controller::env' => '7.0.0', + 'OCP\AppFramework\Controller::cookie' => '7.0.0', + 'OCP\AppFramework\Controller::render' => '7.0.0', + + 'OCP\AppFramework\IAppContainer::getCoreApi' => '8.0.0', + 'OCP\AppFramework\IAppContainer::isLoggedIn' => '8.0.0', + 'OCP\AppFramework\IAppContainer::isAdminUser' => '8.0.0', + 'OCP\AppFramework\IAppContainer::log' => '8.0.0', + + 'OCP\BackgroundJob::addQueuedTask' => '6.0.0', + 'OCP\BackgroundJob::addRegularTask' => '6.0.0', + 'OCP\BackgroundJob::allQueuedTasks' => '6.0.0', + 'OCP\BackgroundJob::allRegularTasks' => '6.0.0', + 'OCP\BackgroundJob::deleteQueuedTask' => '6.0.0', + 'OCP\BackgroundJob::findQueuedTask' => '6.0.0', + 'OCP\BackgroundJob::queuedTaskWhereAppIs' => '6.0.0', + 'OCP\BackgroundJob::registerJob' => '8.1.0', + + 'OCP\Files::tmpFile' => '8.1.0', + 'OCP\Files::tmpFolder' => '8.1.0', + + 'OCP\IAppConfig::getValue' => '8.0.0', + 'OCP\IAppConfig::deleteKey' => '8.0.0', + 'OCP\IAppConfig::getKeys' => '8.0.0', + 'OCP\IAppConfig::setValue' => '8.0.0', + 'OCP\IAppConfig::deleteApp' => '8.0.0', + + 'OCP\ISearch::search' => '8.0.0', + + 'OCP\IServerContainer::getDb' => '8.1.0', + 'OCP\IServerContainer::getHTTPHelper' => '8.1.0', + + 'OCP\User::getUser' => '8.0.0', + 'OCP\User::getUsers' => '8.1.0', + 'OCP\User::getDisplayName' => '8.1.0', + 'OCP\User::getDisplayNames' => '8.1.0', + 'OCP\User::userExists' => '8.1.0', + 'OCP\User::logout' => '8.1.0', + 'OCP\User::checkPassword' => '8.1.0', + + 'OCP\Util::sendMail' => '8.1.0', + 'OCP\Util::formatDate' => '8.0.0', + 'OCP\Util::encryptedFiles' => '8.1.0', + 'OCP\Util::linkToRoute' => '8.1.0', + 'OCP\Util::linkTo' => '8.1.0', + 'OCP\Util::getServerHost' => '8.1.0', + 'OCP\Util::getServerProtocol' => '8.1.0', + 'OCP\Util::getRequestUri' => '8.1.0', + 'OCP\Util::getScriptName' => '8.1.0', + 'OCP\Util::imagePath' => '8.1.0', + 'OCP\Util::isValidFileName' => '8.1.0', + 'OCP\Util::generateRandomBytes' => '8.1.0', + ], $this->check->getMethods()); + } + + /** + * @return bool + */ + public function checkStrongComparisons() { + return $this->check->checkStrongComparisons(); + } +} diff --git a/lib/private/app/codechecker/deprecationlist.php b/lib/private/app/codechecker/deprecationlist.php deleted file mode 100644 index d0abc75a30f..00000000000 --- a/lib/private/app/codechecker/deprecationlist.php +++ /dev/null @@ -1,152 +0,0 @@ - - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OC\App\CodeChecker; - -class DeprecationList implements ICheckList { - /** - * @return string - */ - public function getDescription() { - return 'deprecated'; - } - - /** - * @return array E.g.: `'ClassName' => 'oc version',` - */ - public function getClasses() { - return [ - 'OCP\Config' => '8.0.0', - 'OCP\Contacts' => '8.1.0', - 'OCP\DB' => '8.1.0', - 'OCP\IHelper' => '8.1.0', - 'OCP\JSON' => '8.1.0', - 'OCP\Response' => '8.1.0', - 'OCP\AppFramework\IApi' => '8.0.0', - ]; - } - - /** - * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` - */ - public function getConstants() { - return [ - 'OCP::PERMISSION_CREATE' => '8.0.0', - 'OCP::PERMISSION_READ' => '8.0.0', - 'OCP::PERMISSION_UPDATE' => '8.0.0', - 'OCP::PERMISSION_DELETE' => '8.0.0', - 'OCP::PERMISSION_SHARE' => '8.0.0', - 'OCP::PERMISSION_ALL' => '8.0.0', - 'OCP::FILENAME_INVALID_CHARS' => '8.0.0', - ]; - } - - /** - * @return array E.g.: `'functionName' => 'oc version',` - */ - public function getFunctions() { - return [ - 'OCP::image_path' => '8.0.0', - 'OCP::mimetype_icon' => '8.0.0', - 'OCP::preview_icon' => '8.0.0', - 'OCP::publicPreview_icon' => '8.0.0', - 'OCP::human_file_size' => '8.0.0', - 'OCP::relative_modified_date' => '8.0.0', - 'OCP::simple_file_size' => '8.0.0', - 'OCP::html_select_options' => '8.0.0', - ]; - } - - /** - * @return array E.g.: `'ClassName::methodName' => 'oc version',` - */ - public function getMethods() { - return [ - 'OCP\App::register' => '8.1.0', - 'OCP\App::addNavigationEntry' => '8.1.0', - 'OCP\App::setActiveNavigationEntry' => '8.1.0', - - 'OCP\AppFramework\Controller::params' => '7.0.0', - 'OCP\AppFramework\Controller::getParams' => '7.0.0', - 'OCP\AppFramework\Controller::method' => '7.0.0', - 'OCP\AppFramework\Controller::getUploadedFile' => '7.0.0', - 'OCP\AppFramework\Controller::env' => '7.0.0', - 'OCP\AppFramework\Controller::cookie' => '7.0.0', - 'OCP\AppFramework\Controller::render' => '7.0.0', - - 'OCP\AppFramework\IAppContainer::getCoreApi' => '8.0.0', - 'OCP\AppFramework\IAppContainer::isLoggedIn' => '8.0.0', - 'OCP\AppFramework\IAppContainer::isAdminUser' => '8.0.0', - 'OCP\AppFramework\IAppContainer::log' => '8.0.0', - - 'OCP\BackgroundJob::addQueuedTask' => '6.0.0', - 'OCP\BackgroundJob::addRegularTask' => '6.0.0', - 'OCP\BackgroundJob::allQueuedTasks' => '6.0.0', - 'OCP\BackgroundJob::allRegularTasks' => '6.0.0', - 'OCP\BackgroundJob::deleteQueuedTask' => '6.0.0', - 'OCP\BackgroundJob::findQueuedTask' => '6.0.0', - 'OCP\BackgroundJob::queuedTaskWhereAppIs' => '6.0.0', - 'OCP\BackgroundJob::registerJob' => '8.1.0', - - 'OCP\Files::tmpFile' => '8.1.0', - 'OCP\Files::tmpFolder' => '8.1.0', - - 'OCP\IAppConfig::getValue' => '8.0.0', - 'OCP\IAppConfig::deleteKey' => '8.0.0', - 'OCP\IAppConfig::getKeys' => '8.0.0', - 'OCP\IAppConfig::setValue' => '8.0.0', - 'OCP\IAppConfig::deleteApp' => '8.0.0', - - 'OCP\ISearch::search' => '8.0.0', - - 'OCP\IServerContainer::getDb' => '8.1.0', - 'OCP\IServerContainer::getHTTPHelper' => '8.1.0', - - 'OCP\User::getUser' => '8.0.0', - 'OCP\User::getUsers' => '8.1.0', - 'OCP\User::getDisplayName' => '8.1.0', - 'OCP\User::getDisplayNames' => '8.1.0', - 'OCP\User::userExists' => '8.1.0', - 'OCP\User::logout' => '8.1.0', - 'OCP\User::checkPassword' => '8.1.0', - - 'OCP\Util::sendMail' => '8.1.0', - 'OCP\Util::formatDate' => '8.0.0', - 'OCP\Util::encryptedFiles' => '8.1.0', - 'OCP\Util::linkToRoute' => '8.1.0', - 'OCP\Util::linkTo' => '8.1.0', - 'OCP\Util::getServerHost' => '8.1.0', - 'OCP\Util::getServerProtocol' => '8.1.0', - 'OCP\Util::getRequestUri' => '8.1.0', - 'OCP\Util::getScriptName' => '8.1.0', - 'OCP\Util::imagePath' => '8.1.0', - 'OCP\Util::isValidFileName' => '8.1.0', - 'OCP\Util::generateRandomBytes' => '8.1.0', - ]; - } - - /** - * @return bool - */ - public function checkStrongComparisons() { - return true; - } -} diff --git a/lib/private/app/codechecker/emptycheck.php b/lib/private/app/codechecker/emptycheck.php new file mode 100644 index 00000000000..78a0d303790 --- /dev/null +++ b/lib/private/app/codechecker/emptycheck.php @@ -0,0 +1,65 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ +namespace OC\App\CodeChecker; + +class EmptyCheck implements ICheck { + /** + * @return string + */ + public function getDescription() { + return ''; + } + + /** + * @return array E.g.: `'ClassName' => 'oc version',` + */ + public function getClasses() { + return []; + } + + /** + * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` + */ + public function getConstants() { + return []; + } + + /** + * @return array E.g.: `'functionName' => 'oc version',` + */ + public function getFunctions() { + return []; + } + + /** + * @return array E.g.: `'ClassName::methodName' => 'oc version',` + */ + public function getMethods() { + return []; + } + + /** + * @return bool + */ + public function checkStrongComparisons() { + return false; + } +} diff --git a/lib/private/app/codechecker/icheck.php b/lib/private/app/codechecker/icheck.php new file mode 100644 index 00000000000..7625a105b0a --- /dev/null +++ b/lib/private/app/codechecker/icheck.php @@ -0,0 +1,53 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ +namespace OC\App\CodeChecker; + +interface ICheck { + /** + * @return string + */ + public function getDescription(); + + /** + * @return array E.g.: `'ClassName' => 'oc version',` + */ + public function getClasses(); + + /** + * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` + */ + public function getConstants(); + + /** + * @return array E.g.: `'functionName' => 'oc version',` + */ + public function getFunctions(); + + /** + * @return array E.g.: `'ClassName::methodName' => 'oc version',` + */ + public function getMethods(); + + /** + * @return bool + */ + public function checkStrongComparisons(); +} diff --git a/lib/private/app/codechecker/ichecklist.php b/lib/private/app/codechecker/ichecklist.php deleted file mode 100644 index c5cc82e6bb5..00000000000 --- a/lib/private/app/codechecker/ichecklist.php +++ /dev/null @@ -1,53 +0,0 @@ - - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ -namespace OC\App\CodeChecker; - -interface ICheckList { - /** - * @return string - */ - public function getDescription(); - - /** - * @return array E.g.: `'ClassName' => 'oc version',` - */ - public function getClasses(); - - /** - * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` - */ - public function getConstants(); - - /** - * @return array E.g.: `'functionName' => 'oc version',` - */ - public function getFunctions(); - - /** - * @return array E.g.: `'ClassName::methodName' => 'oc version',` - */ - public function getMethods(); - - /** - * @return bool - */ - public function checkStrongComparisons(); -} diff --git a/lib/private/app/codechecker/nodevisitor.php b/lib/private/app/codechecker/nodevisitor.php index 8ec4a0320f4..80acb9f2414 100644 --- a/lib/private/app/codechecker/nodevisitor.php +++ b/lib/private/app/codechecker/nodevisitor.php @@ -43,9 +43,9 @@ class NodeVisitor extends NodeVisitorAbstract { protected $errorMessages; /** - * @param ICheckList $list + * @param ICheck $list */ - public function __construct(ICheckList $list) { + public function __construct(ICheck $list) { $this->blackListDescription = $list->getDescription(); $this->blackListedClassNames = []; diff --git a/lib/private/app/codechecker/privatecheck.php b/lib/private/app/codechecker/privatecheck.php new file mode 100644 index 00000000000..e7497f3dbfc --- /dev/null +++ b/lib/private/app/codechecker/privatecheck.php @@ -0,0 +1,104 @@ + + * @author Morris Jobke + * @author Thomas Müller + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\App\CodeChecker; + +class PrivateCheck implements ICheck { + /** @var ICheck */ + protected $check; + + /** + * @param ICheck $check + */ + public function __construct(ICheck $check) { + $this->check = $check; + } + + /** + * @return string + */ + public function getDescription() { + $innerDescription = $this->check->getDescription(); + return 'private' . (($innerDescription === '') ? '' : ' ' . $innerDescription); + } + + /** + * @return array + */ + public function getClasses() { + return array_merge([ + // classes replaced by the public api + 'OC_API' => '6.0.0', + 'OC_App' => '6.0.0', + 'OC_AppConfig' => '6.0.0', + 'OC_Avatar' => '6.0.0', + 'OC_BackgroundJob' => '6.0.0', + 'OC_Config' => '6.0.0', + 'OC_DB' => '6.0.0', + 'OC_Files' => '6.0.0', + 'OC_Helper' => '6.0.0', + 'OC_Hook' => '6.0.0', + 'OC_Image' => '6.0.0', + 'OC_JSON' => '6.0.0', + 'OC_L10N' => '6.0.0', + 'OC_Log' => '6.0.0', + 'OC_Mail' => '6.0.0', + 'OC_Preferences' => '6.0.0', + 'OC_Search_Provider' => '6.0.0', + 'OC_Search_Result' => '6.0.0', + 'OC_Request' => '6.0.0', + 'OC_Response' => '6.0.0', + 'OC_Template' => '6.0.0', + 'OC_User' => '6.0.0', + 'OC_Util' => '6.0.0', + ], $this->check->getClasses()); + } + + /** + * @return array + */ + public function getConstants() { + return $this->check->getConstants(); + } + + /** + * @return array + */ + public function getFunctions() { + return $this->check->getFunctions(); + } + + /** + * @return array + */ + public function getMethods() { + return $this->check->getMethods(); + } + + /** + * @return bool + */ + public function checkStrongComparisons() { + return $this->check->checkStrongComparisons(); + } +} diff --git a/lib/private/app/codechecker/privatelist.php b/lib/private/app/codechecker/privatelist.php deleted file mode 100644 index e44926ada77..00000000000 --- a/lib/private/app/codechecker/privatelist.php +++ /dev/null @@ -1,105 +0,0 @@ - - * @author Morris Jobke - * @author Thomas Müller - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License, version 3, - * along with this program. If not, see - * - */ - -namespace OC\App\CodeChecker; - -use OC\Hooks\BasicEmitter; -use PhpParser\Lexer; -use PhpParser\Node; -use PhpParser\Node\Name; -use PhpParser\NodeTraverser; -use PhpParser\Parser; -use RecursiveCallbackFilterIterator; -use RecursiveDirectoryIterator; -use RecursiveIteratorIterator; -use RegexIterator; -use SplFileInfo; - -class PrivateList implements ICheckList { - /** - * @return string - */ - public function getDescription() { - return 'private'; - } - - /** - * @return array - */ - public function getClasses() { - return [ - // classes replaced by the public api - 'OC_API', - 'OC_App', - 'OC_AppConfig', - 'OC_Avatar', - 'OC_BackgroundJob', - 'OC_Config', - 'OC_DB', - 'OC_Files', - 'OC_Helper', - 'OC_Hook', - 'OC_Image', - 'OC_JSON', - 'OC_L10N', - 'OC_Log', - 'OC_Mail', - 'OC_Preferences', - 'OC_Search_Provider', - 'OC_Search_Result', - 'OC_Request', - 'OC_Response', - 'OC_Template', - 'OC_User', - 'OC_Util', - ]; - } - - /** - * @return array - */ - public function getConstants() { - return []; - } - - /** - * @return array - */ - public function getFunctions() { - return []; - } - - /** - * @return array - */ - public function getMethods() { - return []; - } - - /** - * @return bool - */ - public function checkStrongComparisons() { - return false; - } -} diff --git a/lib/private/app/codechecker/strongcomparisoncheck.php b/lib/private/app/codechecker/strongcomparisoncheck.php new file mode 100644 index 00000000000..bfbde1acbef --- /dev/null +++ b/lib/private/app/codechecker/strongcomparisoncheck.php @@ -0,0 +1,78 @@ + + * @author Morris Jobke + * @author Thomas Müller + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\App\CodeChecker; + +class StrongComparisonCheck implements ICheck { + /** @var ICheck */ + protected $check; + + /** + * @param ICheck $check + */ + public function __construct(ICheck $check) { + $this->check = $check; + } + + /** + * @return string + */ + public function getDescription() { + return $this->check->getDescription(); + } + + /** + * @return array + */ + public function getClasses() { + return $this->check->getClasses(); + } + + /** + * @return array + */ + public function getConstants() { + return $this->check->getConstants(); + } + + /** + * @return array + */ + public function getFunctions() { + return $this->check->getFunctions(); + } + + /** + * @return array + */ + public function getMethods() { + return $this->check->getMethods(); + } + + /** + * @return bool + */ + public function checkStrongComparisons() { + return true; + } +} diff --git a/tests/lib/app/codechecker/codecheckertest.php b/tests/lib/app/codechecker/codecheckertest.php index 93bf0b32c58..cdbb7c17da5 100644 --- a/tests/lib/app/codechecker/codecheckertest.php +++ b/tests/lib/app/codechecker/codecheckertest.php @@ -8,7 +8,9 @@ namespace Test\App\CodeChecker; -use OC; +use OC\App\CodeChecker\CodeChecker; +use OC\App\CodeChecker\EmptyCheck; +use OC\App\CodeChecker\PrivateCheck; use Test\TestCase; class CodeCheckerTest extends TestCase { @@ -20,10 +22,10 @@ class CodeCheckerTest extends TestCase { * @param string $fileToVerify */ public function testFindInvalidUsage($expectedErrorToken, $expectedErrorCode, $fileToVerify) { - $checker = new OC\App\CodeChecker\CodeChecker( - new OC\App\CodeChecker\PrivateList() + $checker = new CodeChecker( + new PrivateCheck(new EmptyCheck()) ); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + $errors = $checker->analyseFile(\OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); $this->assertEquals(1, count($errors)); $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); @@ -46,10 +48,10 @@ class CodeCheckerTest extends TestCase { * @param string $fileToVerify */ public function testPassValidUsage($fileToVerify) { - $checker = new OC\App\CodeChecker\CodeChecker( - new OC\App\CodeChecker\PrivateList() + $checker = new CodeChecker( + new PrivateCheck(new EmptyCheck()) ); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + $errors = $checker->analyseFile(\OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); $this->assertEquals(0, count($errors)); } diff --git a/tests/lib/app/codechecker/deprecationchecktest.php b/tests/lib/app/codechecker/deprecationchecktest.php new file mode 100644 index 00000000000..2cf64a9d186 --- /dev/null +++ b/tests/lib/app/codechecker/deprecationchecktest.php @@ -0,0 +1,70 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\App\CodeChecker; + +use OC\App\CodeChecker\CodeChecker; +use OC\App\CodeChecker\DeprecationCheck; +use OC\App\CodeChecker\EmptyCheck; +use Test\TestCase; + +class DeprecationCheckTest extends TestCase { + + /** + * @dataProvider providesFilesToCheck + * @param string $expectedErrorToken + * @param int $expectedErrorCode + * @param string $fileToVerify + */ + public function testFindInvalidUsage($expectedErrorToken, $expectedErrorCode, $fileToVerify) { + $checker = new CodeChecker( + new DeprecationCheck(new EmptyCheck()) + ); + $errors = $checker->analyseFile(\OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertEquals(1, count($errors)); + $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); + $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); + } + + public function providesFilesToCheck() { + return [ + ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use.php'], + ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use-alias.php'], + ['AppFramework\IApi', 1001, 'test-deprecated-use-sub.php'], + ['OAF\IApi', 1001, 'test-deprecated-use-sub-alias.php'], + ]; + } + + /** + * @dataProvider validFilesData + * @param string $fileToVerify + */ + public function testPassValidUsage($fileToVerify) { + $checker = new CodeChecker( + new DeprecationCheck(new EmptyCheck()) + ); + $errors = $checker->analyseFile(\OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertEquals(0, count($errors)); + } + + public function validFilesData() { + return [ + ['test-equal.php'], + ['test-not-equal.php'], + ['test-extends.php'], + ['test-implements.php'], + ['test-static-call.php'], + ['test-const.php'], + ['test-new.php'], + ['test-use.php'], + ['test-identical-operator.php'], + ]; + } +} diff --git a/tests/lib/app/codechecker/deprecationlisttest.php b/tests/lib/app/codechecker/deprecationlisttest.php deleted file mode 100644 index 2293d31a1f6..00000000000 --- a/tests/lib/app/codechecker/deprecationlisttest.php +++ /dev/null @@ -1,68 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -namespace Test\App; - -use OC; -use Test\TestCase; - -class DeprecationListTest extends TestCase { - - /** - * @dataProvider providesFilesToCheck - * @param string $expectedErrorToken - * @param int $expectedErrorCode - * @param string $fileToVerify - */ - public function testFindInvalidUsage($expectedErrorToken, $expectedErrorCode, $fileToVerify) { - $checker = new OC\App\CodeChecker\CodeChecker( - new OC\App\CodeChecker\DeprecationList() - ); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); - - $this->assertEquals(1, count($errors)); - $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); - $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); - } - - public function providesFilesToCheck() { - return [ - ['==', 1005, 'test-equal.php'], - ['!=', 1005, 'test-not-equal.php'], - ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use.php'], - ['OCP\AppFramework\IApi', 1006, 'test-deprecated-use-alias.php'], - ['AppFramework\IApi', 1001, 'test-deprecated-use-sub.php'], - ['OAF\IApi', 1001, 'test-deprecated-use-sub-alias.php'], - ]; - } - - /** - * @dataProvider validFilesData - * @param string $fileToVerify - */ - public function testPassValidUsage($fileToVerify) { - $checker = new OC\App\CodeChecker\CodeChecker( - new OC\App\CodeChecker\DeprecationList() - ); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); - - $this->assertEquals(0, count($errors)); - } - - public function validFilesData() { - return [ - ['test-extends.php'], - ['test-implements.php'], - ['test-static-call.php'], - ['test-const.php'], - ['test-new.php'], - ['test-use.php'], - ['test-identical-operator.php'], - ]; - } -} diff --git a/tests/lib/app/codechecker/mock/testlist.php b/tests/lib/app/codechecker/mock/testlist.php index c4985e8e625..5f5a9fcc38e 100644 --- a/tests/lib/app/codechecker/mock/testlist.php +++ b/tests/lib/app/codechecker/mock/testlist.php @@ -21,15 +21,24 @@ namespace Test\App\CodeChecker\Mock; -use OC\App\CodeChecker\ICheckList; +use OC\App\CodeChecker\ICheck; -class TestList implements ICheckList { +class TestList implements ICheck { + /** @var ICheck */ + protected $check; + + /** + * @param ICheck $check + */ + public function __construct(ICheck $check) { + $this->check = $check; + } /** * @return string */ public function getDescription() { - return 'deprecated'; + return 'testing'; } /** diff --git a/tests/lib/app/codechecker/nodevisitortest.php b/tests/lib/app/codechecker/nodevisitortest.php index 1207ca6a043..0b5aea28324 100644 --- a/tests/lib/app/codechecker/nodevisitortest.php +++ b/tests/lib/app/codechecker/nodevisitortest.php @@ -8,7 +8,9 @@ namespace Test\AppCodeChecker; -use OC; +use OC\App\CodeChecker\CodeChecker; +use OC\App\CodeChecker\EmptyCheck; +use Test\App\CodeChecker\Mock\TestList; use Test\TestCase; class NodeVisitorTest extends TestCase { @@ -56,10 +58,10 @@ class NodeVisitorTest extends TestCase { * @param string $fileToVerify */ public function testMethodsToCheck($expectedErrors, $fileToVerify) { - $checker = new OC\App\CodeChecker\CodeChecker( - new \Test\App\CodeChecker\Mock\TestList() + $checker = new CodeChecker( + new TestList(new EmptyCheck()) ); - $errors = $checker->analyseFile(OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + $errors = $checker->analyseFile(\OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); $this->assertCount(sizeof($expectedErrors), $errors); diff --git a/tests/lib/app/codechecker/strongcomparisonchecktest.php b/tests/lib/app/codechecker/strongcomparisonchecktest.php new file mode 100644 index 00000000000..c73eae286ab --- /dev/null +++ b/tests/lib/app/codechecker/strongcomparisonchecktest.php @@ -0,0 +1,70 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\App\CodeChecker; + +use OC\App\CodeChecker\CodeChecker; +use OC\App\CodeChecker\EmptyCheck; +use OC\App\CodeChecker\StrongComparisonCheck; +use Test\TestCase; + +class StrongComparisonCheckTest extends TestCase { + + /** + * @dataProvider providesFilesToCheck + * @param string $expectedErrorToken + * @param int $expectedErrorCode + * @param string $fileToVerify + */ + public function testFindInvalidUsage($expectedErrorToken, $expectedErrorCode, $fileToVerify) { + $checker = new CodeChecker( + new StrongComparisonCheck(new EmptyCheck()) + ); + $errors = $checker->analyseFile(\OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertEquals(1, count($errors)); + $this->assertEquals($expectedErrorCode, $errors[0]['errorCode']); + $this->assertEquals($expectedErrorToken, $errors[0]['disallowedToken']); + } + + public function providesFilesToCheck() { + return [ + ['==', 1005, 'test-equal.php'], + ['!=', 1005, 'test-not-equal.php'], + ]; + } + + /** + * @dataProvider validFilesData + * @param string $fileToVerify + */ + public function testPassValidUsage($fileToVerify) { + $checker = new CodeChecker( + new StrongComparisonCheck(new EmptyCheck()) + ); + $errors = $checker->analyseFile(\OC::$SERVERROOT . "/tests/data/app/code-checker/$fileToVerify"); + + $this->assertEquals(0, count($errors)); + } + + public function validFilesData() { + return [ + ['test-deprecated-use.php'], + ['test-deprecated-use-alias.php'], + ['test-deprecated-use-sub.php'], + ['test-deprecated-use-sub-alias.php'], + ['test-extends.php'], + ['test-implements.php'], + ['test-static-call.php'], + ['test-const.php'], + ['test-new.php'], + ['test-use.php'], + ['test-identical-operator.php'], + ]; + } +} -- cgit v1.2.3 From 8a64abf4e45a5050ae27140ada4dd66eea4ae502 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 16 Jul 2015 11:40:32 +0200 Subject: Only decorate the type when it was matched --- lib/private/app/codechecker/abstractcheck.php | 139 +++++++++++++++++++++ lib/private/app/codechecker/codechecker.php | 2 +- lib/private/app/codechecker/deprecationcheck.php | 48 +++---- lib/private/app/codechecker/emptycheck.php | 4 +- lib/private/app/codechecker/icheck.php | 4 +- lib/private/app/codechecker/nodevisitor.php | 24 ++-- lib/private/app/codechecker/privatecheck.php | 42 ++----- .../app/codechecker/strongcomparisoncheck.php | 6 +- tests/lib/app/codechecker/mock/testlist.php | 4 +- 9 files changed, 194 insertions(+), 79 deletions(-) create mode 100644 lib/private/app/codechecker/abstractcheck.php (limited to 'lib') diff --git a/lib/private/app/codechecker/abstractcheck.php b/lib/private/app/codechecker/abstractcheck.php new file mode 100644 index 00000000000..c1c6524e42f --- /dev/null +++ b/lib/private/app/codechecker/abstractcheck.php @@ -0,0 +1,139 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OC\App\CodeChecker; + +abstract class AbstractCheck implements ICheck { + /** @var ICheck */ + protected $check; + + /** + * @param ICheck $check + */ + public function __construct(ICheck $check) { + $this->check = $check; + } + + /** + * @param int $errorCode + * @param string $errorObject + * @return string + */ + public function getDescription($errorCode, $errorObject) { + switch ($errorCode) { + case CodeChecker::STATIC_CALL_NOT_ALLOWED: + $functions = $this->getLocalFunctions(); + $functions = array_change_key_case($functions, CASE_LOWER); + if (isset($functions[$errorObject])) { + return $this->getLocalDescription(); + } + // no break; + case CodeChecker::CLASS_EXTENDS_NOT_ALLOWED: + case CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED: + case CodeChecker::CLASS_NEW_NOT_ALLOWED: + case CodeChecker::CLASS_USE_NOT_ALLOWED: + $classes = $this->getLocalClasses(); + $classes = array_change_key_case($classes, CASE_LOWER); + if (isset($classes[$errorObject])) { + return $this->getLocalDescription(); + } + break; + + case CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED: + $constants = $this->getLocalConstants(); + $constants = array_change_key_case($constants, CASE_LOWER); + if (isset($constants[$errorObject])) { + return $this->getLocalDescription(); + } + break; + + case CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED: + $methods = $this->getLocalMethods(); + $methods = array_change_key_case($methods, CASE_LOWER); + if (isset($methods[$errorObject])) { + return $this->getLocalDescription(); + } + break; + } + + return $this->check->getDescription($errorCode, $errorObject); + } + + /** + * @return string + */ + abstract protected function getLocalDescription(); + + /** + * @return array + */ + abstract protected function getLocalClasses(); + + /** + * @return array + */ + abstract protected function getLocalConstants(); + + /** + * @return array + */ + abstract protected function getLocalFunctions(); + + /** + * @return array + */ + abstract protected function getLocalMethods(); + + /** + * @return array E.g.: `'ClassName' => 'oc version',` + */ + public function getClasses() { + return array_merge($this->getLocalClasses(), $this->check->getClasses()); + } + + /** + * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` + */ + public function getConstants() { + return array_merge($this->getLocalConstants(), $this->check->getConstants()); + } + + /** + * @return array E.g.: `'functionName' => 'oc version',` + */ + public function getFunctions() { + return array_merge($this->getLocalFunctions(), $this->check->getFunctions()); + } + + /** + * @return array E.g.: `'ClassName::methodName' => 'oc version',` + */ + public function getMethods() { + return array_merge($this->getLocalMethods(), $this->check->getMethods()); + } + + /** + * @return bool + */ + public function checkStrongComparisons() { + return $this->check->checkStrongComparisons(); + } +} diff --git a/lib/private/app/codechecker/codechecker.php b/lib/private/app/codechecker/codechecker.php index ae16b156178..ef7dc7f3e4d 100644 --- a/lib/private/app/codechecker/codechecker.php +++ b/lib/private/app/codechecker/codechecker.php @@ -41,7 +41,7 @@ class CodeChecker extends BasicEmitter { const CLASS_IMPLEMENTS_NOT_ALLOWED = 1001; const STATIC_CALL_NOT_ALLOWED = 1002; const CLASS_CONST_FETCH_NOT_ALLOWED = 1003; - const CLASS_NEW_FETCH_NOT_ALLOWED = 1004; + const CLASS_NEW_NOT_ALLOWED = 1004; const OP_OPERATOR_USAGE_DISCOURAGED = 1005; const CLASS_USE_NOT_ALLOWED = 1006; const CLASS_METHOD_CALL_NOT_ALLOWED = 1007; diff --git a/lib/private/app/codechecker/deprecationcheck.php b/lib/private/app/codechecker/deprecationcheck.php index bac59e4dd7c..bd34bac1a61 100644 --- a/lib/private/app/codechecker/deprecationcheck.php +++ b/lib/private/app/codechecker/deprecationcheck.php @@ -21,30 +21,19 @@ namespace OC\App\CodeChecker; -class DeprecationCheck implements ICheck { - /** @var ICheck */ - protected $check; - - /** - * @param ICheck $check - */ - public function __construct(ICheck $check) { - $this->check = $check; - } - +class DeprecationCheck extends AbstractCheck implements ICheck { /** * @return string */ - public function getDescription() { - $innerDescription = $this->check->getDescription(); - return 'deprecated' . (($innerDescription === '') ? '' : ' ' . $innerDescription); + protected function getLocalDescription() { + return 'deprecated'; } /** * @return array E.g.: `'ClassName' => 'oc version',` */ - public function getClasses() { - return array_merge([ + protected function getLocalClasses() { + return [ 'OCP\Config' => '8.0.0', 'OCP\Contacts' => '8.1.0', 'OCP\DB' => '8.1.0', @@ -52,14 +41,14 @@ class DeprecationCheck implements ICheck { 'OCP\JSON' => '8.1.0', 'OCP\Response' => '8.1.0', 'OCP\AppFramework\IApi' => '8.0.0', - ], $this->check->getClasses()); + ]; } /** * @return array E.g.: `'ClassName::CONSTANT_NAME' => 'oc version',` */ - public function getConstants() { - return array_merge([ + protected function getLocalConstants() { + return [ 'OCP::PERMISSION_CREATE' => '8.0.0', 'OCP::PERMISSION_READ' => '8.0.0', 'OCP::PERMISSION_UPDATE' => '8.0.0', @@ -67,14 +56,14 @@ class DeprecationCheck implements ICheck { 'OCP::PERMISSION_SHARE' => '8.0.0', 'OCP::PERMISSION_ALL' => '8.0.0', 'OCP::FILENAME_INVALID_CHARS' => '8.0.0', - ], $this->check->getConstants()); + ]; } /** * @return array E.g.: `'functionName' => 'oc version',` */ - public function getFunctions() { - return array_merge([ + protected function getLocalFunctions() { + return [ 'OCP::image_path' => '8.0.0', 'OCP::mimetype_icon' => '8.0.0', 'OCP::preview_icon' => '8.0.0', @@ -83,14 +72,14 @@ class DeprecationCheck implements ICheck { 'OCP::relative_modified_date' => '8.0.0', 'OCP::simple_file_size' => '8.0.0', 'OCP::html_select_options' => '8.0.0', - ], $this->check->getFunctions()); + ]; } /** * @return array E.g.: `'ClassName::methodName' => 'oc version',` */ - public function getMethods() { - return array_merge([ + protected function getLocalMethods() { + return [ 'OCP\App::register' => '8.1.0', 'OCP\App::addNavigationEntry' => '8.1.0', 'OCP\App::setActiveNavigationEntry' => '8.1.0', @@ -151,13 +140,6 @@ class DeprecationCheck implements ICheck { 'OCP\Util::imagePath' => '8.1.0', 'OCP\Util::isValidFileName' => '8.1.0', 'OCP\Util::generateRandomBytes' => '8.1.0', - ], $this->check->getMethods()); - } - - /** - * @return bool - */ - public function checkStrongComparisons() { - return $this->check->checkStrongComparisons(); + ]; } } diff --git a/lib/private/app/codechecker/emptycheck.php b/lib/private/app/codechecker/emptycheck.php index 78a0d303790..0e5df55d090 100644 --- a/lib/private/app/codechecker/emptycheck.php +++ b/lib/private/app/codechecker/emptycheck.php @@ -22,9 +22,11 @@ namespace OC\App\CodeChecker; class EmptyCheck implements ICheck { /** + * @param int $errorCode + * @param string $errorObject * @return string */ - public function getDescription() { + public function getDescription($errorCode, $errorObject) { return ''; } diff --git a/lib/private/app/codechecker/icheck.php b/lib/private/app/codechecker/icheck.php index 7625a105b0a..a00e0d8fa13 100644 --- a/lib/private/app/codechecker/icheck.php +++ b/lib/private/app/codechecker/icheck.php @@ -22,9 +22,11 @@ namespace OC\App\CodeChecker; interface ICheck { /** + * @param int $errorCode + * @param string $errorObject * @return string */ - public function getDescription(); + public function getDescription($errorCode, $errorObject); /** * @return array E.g.: `'ClassName' => 'oc version',` diff --git a/lib/private/app/codechecker/nodevisitor.php b/lib/private/app/codechecker/nodevisitor.php index 80acb9f2414..a22f852f36a 100644 --- a/lib/private/app/codechecker/nodevisitor.php +++ b/lib/private/app/codechecker/nodevisitor.php @@ -27,6 +27,9 @@ use PhpParser\Node\Name; use PhpParser\NodeVisitorAbstract; class NodeVisitor extends NodeVisitorAbstract { + /** @var ICheck */ + protected $list; + /** @var string */ protected $blackListDescription; /** @var string[] */ @@ -46,7 +49,7 @@ class NodeVisitor extends NodeVisitorAbstract { * @param ICheck $list */ public function __construct(ICheck $list) { - $this->blackListDescription = $list->getDescription(); + $this->list = $list; $this->blackListedClassNames = []; foreach ($list->getClasses() as $class => $blackListInfo) { @@ -80,13 +83,13 @@ class NodeVisitor extends NodeVisitorAbstract { $this->checkEqualOperatorUsage = $list->checkStrongComparisons(); $this->errorMessages = [ - CodeChecker::CLASS_EXTENDS_NOT_ALLOWED => "{$this->blackListDescription} class must not be extended", - CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED => "{$this->blackListDescription} interface must not be implemented", - CodeChecker::STATIC_CALL_NOT_ALLOWED => "Static method of {$this->blackListDescription} class must not be called", - CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED => "Constant of {$this->blackListDescription} class must not not be fetched", - CodeChecker::CLASS_NEW_FETCH_NOT_ALLOWED => "{$this->blackListDescription} class must not be instanciated", - CodeChecker::CLASS_USE_NOT_ALLOWED => "{$this->blackListDescription} class must not be imported with a use statement", - CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED => "Method of {$this->blackListDescription} class must not be called", + CodeChecker::CLASS_EXTENDS_NOT_ALLOWED => "%s class must not be extended", + CodeChecker::CLASS_IMPLEMENTS_NOT_ALLOWED => "%s interface must not be implemented", + CodeChecker::STATIC_CALL_NOT_ALLOWED => "Static method of %s class must not be called", + CodeChecker::CLASS_CONST_FETCH_NOT_ALLOWED => "Constant of %s class must not not be fetched", + CodeChecker::CLASS_NEW_NOT_ALLOWED => "%s class must not be instantiated", + CodeChecker::CLASS_USE_NOT_ALLOWED => "%s class must not be imported with a use statement", + CodeChecker::CLASS_METHOD_CALL_NOT_ALLOWED => "Method of %s class must not be called", CodeChecker::OP_OPERATOR_USAGE_DISCOURAGED => "is discouraged", ]; @@ -171,7 +174,7 @@ class NodeVisitor extends NodeVisitorAbstract { 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); + $this->checkBlackList($node->class->toString(), CodeChecker::CLASS_NEW_NOT_ALLOWED, $node); } if ($node->class instanceof Node\Expr\Variable) { /** @@ -294,7 +297,8 @@ class NodeVisitor extends NodeVisitorAbstract { private function buildReason($name, $errorCode) { if (isset($this->errorMessages[$errorCode])) { - return $this->errorMessages[$errorCode]; + $desc = $this->list->getDescription($errorCode, $name); + return sprintf($this->errorMessages[$errorCode], $desc); } return "$name usage not allowed - error: $errorCode"; diff --git a/lib/private/app/codechecker/privatecheck.php b/lib/private/app/codechecker/privatecheck.php index e7497f3dbfc..d6f4eb06981 100644 --- a/lib/private/app/codechecker/privatecheck.php +++ b/lib/private/app/codechecker/privatecheck.php @@ -23,30 +23,19 @@ namespace OC\App\CodeChecker; -class PrivateCheck implements ICheck { - /** @var ICheck */ - protected $check; - - /** - * @param ICheck $check - */ - public function __construct(ICheck $check) { - $this->check = $check; - } - +class PrivateCheck extends AbstractCheck implements ICheck { /** * @return string */ - public function getDescription() { - $innerDescription = $this->check->getDescription(); - return 'private' . (($innerDescription === '') ? '' : ' ' . $innerDescription); + protected function getLocalDescription() { + return 'private'; } /** * @return array */ - public function getClasses() { - return array_merge([ + public function getLocalClasses() { + return [ // classes replaced by the public api 'OC_API' => '6.0.0', 'OC_App' => '6.0.0', @@ -71,34 +60,27 @@ class PrivateCheck implements ICheck { 'OC_Template' => '6.0.0', 'OC_User' => '6.0.0', 'OC_Util' => '6.0.0', - ], $this->check->getClasses()); + ]; } /** * @return array */ - public function getConstants() { - return $this->check->getConstants(); + public function getLocalConstants() { + return []; } /** * @return array */ - public function getFunctions() { - return $this->check->getFunctions(); + public function getLocalFunctions() { + return []; } /** * @return array */ - public function getMethods() { - return $this->check->getMethods(); - } - - /** - * @return bool - */ - public function checkStrongComparisons() { - return $this->check->checkStrongComparisons(); + public function getLocalMethods() { + return []; } } diff --git a/lib/private/app/codechecker/strongcomparisoncheck.php b/lib/private/app/codechecker/strongcomparisoncheck.php index bfbde1acbef..7de0fe3e5c3 100644 --- a/lib/private/app/codechecker/strongcomparisoncheck.php +++ b/lib/private/app/codechecker/strongcomparisoncheck.php @@ -35,10 +35,12 @@ class StrongComparisonCheck implements ICheck { } /** + * @param int $errorCode + * @param string $errorObject * @return string */ - public function getDescription() { - return $this->check->getDescription(); + public function getDescription($errorCode, $errorObject) { + return $this->check->getDescription($errorCode, $errorObject); } /** diff --git a/tests/lib/app/codechecker/mock/testlist.php b/tests/lib/app/codechecker/mock/testlist.php index 5f5a9fcc38e..1fe83293acf 100644 --- a/tests/lib/app/codechecker/mock/testlist.php +++ b/tests/lib/app/codechecker/mock/testlist.php @@ -35,9 +35,11 @@ class TestList implements ICheck { } /** + * @param int $errorCode + * @param string $errorObject * @return string */ - public function getDescription() { + public function getDescription($errorCode, $errorObject) { return 'testing'; } -- cgit v1.2.3 From 3566dcf246d122bbc4010aeb42c5b2d9259f8ea5 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 16 Jul 2015 11:47:20 +0200 Subject: PR #17046 deprecated OCP\Util::mb_(sub)str_replace() --- core/command/app/checkcode.php | 2 +- lib/private/app/codechecker/deprecationcheck.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/core/command/app/checkcode.php b/core/command/app/checkcode.php index 79c34d6fb48..a4e7322460f 100644 --- a/core/command/app/checkcode.php +++ b/core/command/app/checkcode.php @@ -52,7 +52,7 @@ class CheckCode extends Command { 'checker', 'c', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, - 'enable the specified checker', + 'enable the specified checker(s)', [ 'private', 'deprecation', 'strong-comparison' ] ); } diff --git a/lib/private/app/codechecker/deprecationcheck.php b/lib/private/app/codechecker/deprecationcheck.php index bd34bac1a61..3b6dc968bb5 100644 --- a/lib/private/app/codechecker/deprecationcheck.php +++ b/lib/private/app/codechecker/deprecationcheck.php @@ -140,6 +140,8 @@ class DeprecationCheck extends AbstractCheck implements ICheck { 'OCP\Util::imagePath' => '8.1.0', 'OCP\Util::isValidFileName' => '8.1.0', 'OCP\Util::generateRandomBytes' => '8.1.0', + 'OCP\Util::mb_str_replace' => '8.2.0', + 'OCP\Util::mb_substr_replace' => '8.2.0', ]; } } -- cgit v1.2.3