Skip to content

Commit

Permalink
Fixes #5, Comply with PSR2 standard
Browse files Browse the repository at this point in the history
  • Loading branch information
NielsdeBlaauw committed Jan 20, 2019
1 parent 08282b6 commit d2f5fc0
Show file tree
Hide file tree
Showing 9 changed files with 222 additions and 183 deletions.
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,8 @@
"psr-4": {
"NdB\\PhpDocCheck\\": "src"
}
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.4"
}
}
7 changes: 7 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0"?>
<ruleset name="php-doc-check standard" namespace="NdB">
<file>./src</file>
<file>./bin/php-doc-check</file>
<exclude-pattern>*/vendor/*</exclude-pattern>
<rule ref="PSR2"/>
</ruleset>
60 changes: 32 additions & 28 deletions src/AnalysableFile.php
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
<?php
namespace NdB\PhpDocCheck;

class AnalysableFile{
public $has_errors = false;
public $has_warnings = false;
public $findings = array();
class AnalysableFile
{
public $has_errors = false;
public $has_warnings = false;
public $findings = array();

public function __construct(\SplFileInfo $file, \PhpParser\Parser $parser, $arguments){
$this->file = $file;
$this->parser = $parser;
$this->arguments = $arguments;
}
public function __construct(\SplFileInfo $file, \PhpParser\Parser $parser, $arguments)
{
$this->file = $file;
$this->parser = $parser;
$this->arguments = $arguments;
}

public function analyse(){
$statements = $this->parser->parse(file_get_contents($this->file->getRealPath()));
$traverser = new \PhpParser\NodeTraverser();
$traverser->addVisitor(new \NdB\PhpDocCheck\NodeVisitor($this));
$traverser->traverse($statements);
return $this->getProgressIndicator();
}
public function analyse()
{
$statements = $this->parser->parse(file_get_contents($this->file->getRealPath()));
$traverser = new \PhpParser\NodeTraverser();
$traverser->addVisitor(new \NdB\PhpDocCheck\NodeVisitor($this));
$traverser->traverse($statements);
return $this->getProgressIndicator();
}

/**
* Gives a visual progression value, based on analysis result
*/
public function getProgressIndicator() : string{
if(!$this->has_warnings && !$this->has_errors ){
return '.';
}elseif(!$this->has_errors){
return 'W';
}
return 'E';
}
}
/**
* Gives a visual progression value, based on analysis result
*/
public function getProgressIndicator() : string
{
if (!$this->has_warnings && !$this->has_errors) {
return '.';
} elseif (!$this->has_errors) {
return 'W';
}
return 'E';
}
}
12 changes: 7 additions & 5 deletions src/Findings/Error.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<?php
namespace NdB\PhpDocCheck\Findings;

class Error extends Warning{
public function getType():string{
return 'Error';
}
}
class Error extends Warning
{
public function getType():string
{
return 'Error';
}
}
35 changes: 20 additions & 15 deletions src/Findings/Warning.php
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
<?php
namespace NdB\PhpDocCheck\Findings;

class Warning{
public function __construct(string $message, int $line){
$this->message = $message;
$this->line = $line;
}
class Warning
{
public function __construct(string $message, int $line)
{
$this->message = $message;
$this->line = $line;
}

public function getType():string{
return 'Warning';
}
public function getLine():int{
return $this->line;
}
public function getMessage():string{
return $this->message;
}
}
public function getType():string
{
return 'Warning';
}
public function getLine():int
{
return $this->line;
}
public function getMessage():string
{
return $this->message;
}
}
148 changes: 79 additions & 69 deletions src/NodeVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,73 +5,83 @@
use \PhpParser\Node;
use \PhpParser\Node\Stmt;

class NodeVisitor extends \PhpParser\NodeVisitorAbstract{
public function __construct(AnalysableFile &$file){
$this->file =& $file;
}
class NodeVisitor extends \PhpParser\NodeVisitorAbstract
{
public function __construct(AnalysableFile &$file)
{
$this->file =& $file;
}

/**
* Determines if this node and it's children are of a complexity that could
* use some clarification based on Cyclomatic Complexity.
*/
public function leaveNode(\PhpParser\Node $node) {
if(is_a($node, "\PhpParser\Node\FunctionLike")){
$methodCcn = $this->calculate_complexity($node) + 1; // each method by default is CCN 1 even if it's empty

$name = 'Anonynous function';
if(\property_exists($node, 'name')){
$name = $node->name;
}
if(empty($node->getDocComment())){
if($methodCcn >= $this->file->arguments['complexity-error-treshold']){
$this->file->has_errors = true;
$this->file->findings[] = new \NdB\PhpDocCheck\Findings\Error(sprintf("%s has no documentation and a complexity of %d", $name, $methodCcn), $node->getStartLine());
}elseif($methodCcn >= $this->file->arguments['complexity-warning-treshold']){
$this->file->has_warnings = true;
$this->file->findings[] = new \NdB\PhpDocCheck\Findings\Warning(sprintf("%s has no documentation and a complexity of %d", $name, $methodCcn), $node->getStartLine());
}
}
}
}

/**
* Recursively calculates Cyclomatic Complexity
*/
protected function calculate_complexity($node){
$ccn = 0;
foreach (get_object_vars($node) as $name => $member) {
foreach (is_array($member) ? $member : [$member] as $memberItem) {
if ($memberItem instanceof Node) {
$ccn += $this->calculate_complexity($memberItem);
}
}
}
switch (true) {
case $node instanceof Stmt\If_:
case $node instanceof Stmt\ElseIf_:
case $node instanceof Stmt\For_:
case $node instanceof Stmt\Foreach_:
case $node instanceof Stmt\While_:
case $node instanceof Stmt\Do_:
case $node instanceof Node\Expr\BinaryOp\LogicalAnd:
case $node instanceof Node\Expr\BinaryOp\LogicalOr:
case $node instanceof Node\Expr\BinaryOp\LogicalXor:
case $node instanceof Node\Expr\BinaryOp\BooleanAnd:
case $node instanceof Node\Expr\BinaryOp\BooleanOr:
case $node instanceof Stmt\Catch_:
case $node instanceof Node\Expr\Ternary:
case $node instanceof Node\Expr\BinaryOp\Coalesce:
$ccn++;
break;
case $node instanceof Stmt\Case_: // include default
if ($node->cond !== null) { // exclude default
$ccn++;
}
break;
case $node instanceof Node\Expr\BinaryOp\Spaceship:
$ccn += 2;
break;
}
return $ccn;
}
}
/**
* Determines if this node and it's children are of a complexity that could
* use some clarification based on Cyclomatic Complexity.
*/
public function leaveNode(\PhpParser\Node $node)
{
if (is_a($node, "\PhpParser\Node\FunctionLike")) {
$methodCcn = $this->calculateComplexity($node) + 1; // each method by default is CCN 1 even if it's empty

$name = 'Anonynous function';
if (\property_exists($node, 'name')) {
$name = $node->name;
}
if (empty($node->getDocComment())) {
if ($methodCcn >= $this->file->arguments['complexity-error-treshold']) {
$this->file->has_errors = true;
$this->file->findings[] = new \NdB\PhpDocCheck\Findings\Error(
sprintf("%s has no documentation and a complexity of %d", $name, $methodCcn),
$node->getStartLine()
);
} elseif ($methodCcn >= $this->file->arguments['complexity-warning-treshold']) {
$this->file->has_warnings = true;
$this->file->findings[] = new \NdB\PhpDocCheck\Findings\Warning(
sprintf("%s has no documentation and a complexity of %d", $name, $methodCcn),
$node->getStartLine()
);
}
}
}
}

/**
* Recursively calculates Cyclomatic Complexity
*/
protected function calculateComplexity($node)
{
$ccn = 0;
foreach (get_object_vars($node) as $name => $member) {
foreach (is_array($member) ? $member : [$member] as $memberItem) {
if ($memberItem instanceof Node) {
$ccn += $this->calculateComplexity($memberItem);
}
}
}
switch (true) {
case $node instanceof Stmt\If_:
case $node instanceof Stmt\ElseIf_:
case $node instanceof Stmt\For_:
case $node instanceof Stmt\Foreach_:
case $node instanceof Stmt\While_:
case $node instanceof Stmt\Do_:
case $node instanceof Node\Expr\BinaryOp\LogicalAnd:
case $node instanceof Node\Expr\BinaryOp\LogicalOr:
case $node instanceof Node\Expr\BinaryOp\LogicalXor:
case $node instanceof Node\Expr\BinaryOp\BooleanAnd:
case $node instanceof Node\Expr\BinaryOp\BooleanOr:
case $node instanceof Stmt\Catch_:
case $node instanceof Node\Expr\Ternary:
case $node instanceof Node\Expr\BinaryOp\Coalesce:
$ccn++;
break;
case $node instanceof Stmt\Case_: // include default
if ($node->cond !== null) { // exclude default
$ccn++;
}
break;
case $node instanceof Node\Expr\BinaryOp\Spaceship:
$ccn += 2;
break;
}
return $ccn;
}
}
44 changes: 24 additions & 20 deletions src/Output/AbstractOutput.php
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
<?php
namespace NdB\PhpDocCheck\Output;

abstract class AbstractOutput{
public function __construct(array $files){
$this->files = $files;
}
abstract class AbstractOutput
{
public function __construct(array $files)
{
$this->files = $files;
}

public function display(){
echo $this->get();
}
public function display()
{
echo $this->get();
}

/**
* Determines if this scan has 'failed' and should be fixed. Or if it was
* flawless. CI will fail when a non zero exit code is returned.
*/
public function getExitCode(){
foreach($this->files as $file){
if($file->has_errors || $file->has_warnings){
return 1;
}
}
return 0;
}
}
/**
* Determines if this scan has 'failed' and should be fixed. Or if it was
* flawless. CI will fail when a non zero exit code is returned.
*/
public function getExitCode()
{
foreach ($this->files as $file) {
if ($file->has_errors || $file->has_warnings) {
return 1;
}
}
return 0;
}
}
30 changes: 16 additions & 14 deletions src/Output/Json.php
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
<?php
namespace NdB\PhpDocCheck\Output;

class Json{
public function get(){
$output = array();
foreach($this->files as $file){
if(!empty($file->findings)){
$output[] = array(
'file'=>$file->file->getRealPath(),
'findings'=>$file->findings,
);
}
}
return json_encode($output);
}
}
class Json
{
public function get()
{
$output = array();
foreach ($this->files as $file) {
if (!empty($file->findings)) {
$output[] = array(
'file'=>$file->file->getRealPath(),
'findings'=>$file->findings,
);
}
}
return json_encode($output);
}
}
Loading

0 comments on commit d2f5fc0

Please sign in to comment.