Browse Source
Add tool to check OCP for missing @since tag
Add tool to check OCP for missing @since tag
* gets executed in autotest.sh and fails if some PHPDoc is missing * doesn't check classes/methods that are marked as @deprecated * iterates over all .php files in lib/publicremotes/origin/poc-doctrine-migrations
2 changed files with 118 additions and 0 deletions
@ -0,0 +1,115 @@ |
|||||
|
<?php |
||||
|
/** |
||||
|
* @author Morris Jobke <hey@morrisjobke.de> |
||||
|
* |
||||
|
* @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 <http://www.gnu.org/licenses/> |
||||
|
* |
||||
|
*/ |
||||
|
|
||||
|
|
||||
|
require_once(dirname(__DIR__) . '/3rdparty/autoload.php'); |
||||
|
|
||||
|
/** |
||||
|
* Class SinceTagCheckVisitor |
||||
|
* |
||||
|
* this class checks all methods for the presence of the @since tag |
||||
|
*/ |
||||
|
class SinceTagCheckVisitor extends \PhpParser\NodeVisitorAbstract { |
||||
|
|
||||
|
/** @var string */ |
||||
|
protected $namespace = ''; |
||||
|
/** @var string */ |
||||
|
protected $className = ''; |
||||
|
/** @var bool */ |
||||
|
protected $deprecatedClass = false; |
||||
|
|
||||
|
/** @var array */ |
||||
|
protected $errors = []; |
||||
|
|
||||
|
public function enterNode(\PhpParser\Node $node) { |
||||
|
if($this->deprecatedClass) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if($node instanceof \PhpParser\Node\Stmt\Namespace_) { |
||||
|
$this->namespace = $node->name; |
||||
|
} |
||||
|
|
||||
|
if($node instanceof \PhpParser\Node\Stmt\Interface_ or |
||||
|
$node instanceof \PhpParser\Node\Stmt\Class_) { |
||||
|
$this->className = $node->name; |
||||
|
|
||||
|
/** @var \PhpParser\Comment\Doc[] $comments */ |
||||
|
$comments = $node->getAttribute('comments'); |
||||
|
if(count($comments) !== 0) { |
||||
|
$comment = $comments[count($comments) - 1]; |
||||
|
$text = $comment->getText(); |
||||
|
if(strpos($text, '@deprecated') !== false) { |
||||
|
$this->deprecatedClass = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if($node instanceof \PhpParser\Node\Stmt\ClassMethod) { |
||||
|
/** @var \PhpParser\Node\Stmt\ClassMethod $node */ |
||||
|
/** @var \PhpParser\Comment\Doc[] $comments */ |
||||
|
$comments = $node->getAttribute('comments'); |
||||
|
|
||||
|
if(count($comments) === 0) { |
||||
|
$this->errors[] = 'PHPDoc is needed for ' . $this->namespace . '\\' . $this->className . '::' . $node->name; |
||||
|
return; |
||||
|
} |
||||
|
$comment = $comments[count($comments) - 1]; |
||||
|
$text = $comment->getText(); |
||||
|
if(strpos($text, '@since') === false && strpos($text, '@deprecated') === false) { |
||||
|
$this->errors[] = '@since or @deprecated tag is needed in PHPDoc for ' . $this->namespace . '\\' . $this->className . '::' . $node->name; |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public function getErrors() { |
||||
|
return $this->errors; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
echo 'Parsing all files in lib/public for the presence of @since or @deprecated on each method...' . PHP_EOL . PHP_EOL; |
||||
|
|
||||
|
|
||||
|
$parser = new PhpParser\Parser(new PhpParser\Lexer); |
||||
|
|
||||
|
/* iterate over all .php files in lib/public */ |
||||
|
$Directory = new RecursiveDirectoryIterator(dirname(__DIR__) . '/lib/public'); |
||||
|
$Iterator = new RecursiveIteratorIterator($Directory); |
||||
|
$Regex = new RegexIterator($Iterator, '/^.+\.php$/i', RecursiveRegexIterator::GET_MATCH); |
||||
|
|
||||
|
$errors = []; |
||||
|
|
||||
|
foreach($Regex as $file) { |
||||
|
$stmts = $parser->parse(file_get_contents($file[0])); |
||||
|
|
||||
|
$visitor = new SinceTagCheckVisitor($this->blackListedClassNames); |
||||
|
$traverser = new \PhpParser\NodeTraverser(); |
||||
|
$traverser->addVisitor($visitor); |
||||
|
$traverser->traverse($stmts); |
||||
|
|
||||
|
$errors = array_merge($errors, $visitor->getErrors()); |
||||
|
} |
||||
|
|
||||
|
if(count($errors)) { |
||||
|
echo join(PHP_EOL, $errors) . PHP_EOL . PHP_EOL; |
||||
|
exit(1); |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue