Completed
Push — try/code-signature-diff ( 1167f1...529505 )
by
unknown
143:54 queued 135:49
created

Class_Method_Declaration::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 5
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Automattic\Jetpack\Analyzer;
4
5
use PhpParser\Error;
6
use PhpParser\NodeDumper;
7
use PhpParser\ParserFactory;
8
use PhpParser\Node;
9
use PhpParser\Node\Stmt\Function_;
10
use PhpParser\Node\Stmt\ClassMethod_;
11
use PhpParser\NodeTraverser;
12
use PhpParser\NodeVisitorAbstract;
13
14
// const STATE_NONE = 0;
15
// const STATE_CLASS_DECLARATION = 1;
16
17
const VIS_PUBLIC  = 0;
18
const VIS_PRIVATE = 1;
19
20
class Analyzer extends NodeVisitorAbstract {
21
	private $declarations;
22
	private $base_path;
23
	private $current_path;
24
	private $current_relative_path;
25
	private $current_class;
26
	private $parser;
27
28
	function __construct( $base_path ) {
29
		$this->parser       = ( new ParserFactory() )->create( ParserFactory::PREFER_PHP7 );
30
		$this->declarations = array();
31
		$this->base_path    = $this->slashit( $base_path );
32
	}
33
34
	private function slashit( $path ) {
35
		$path .= ( substr( $path, -1 ) == '/' ? '' : '/' );
36
		return $path;
37
	}
38
39
	protected function add_declaration( $declaration ) {
40
		$this->declarations[] = $declaration;
41
	}
42
43
	public function print_declarations() {
44
		// print_r( $this->declarations );
45
		foreach ( $this->declarations as $dec ) {
46
			echo $dec->to_string() . "\n";
47
		}
48
	}
49
50
	public function scan() {
51
		$exclude = array( '.git', 'vendor', 'tests', 'docker', 'bin', 'scss', 'images', 'docs', 'languages', 'node_modules' );
52
		$filter  = function ( $file, $key, $iterator ) use ( $exclude ) {
53
			if ( $iterator->hasChildren() && ! in_array( $file->getFilename(), $exclude ) ) {
54
				return true;
55
			}
56
			return $file->isFile();
57
		};
58
59
		$inner_iterator = new \RecursiveDirectoryIterator( $this->base_path, \RecursiveDirectoryIterator::SKIP_DOTS );
60
61
		$iterator = new \RecursiveIteratorIterator(
62
			new \RecursiveCallbackFilterIterator( $inner_iterator, $filter )
63
		);
64
65
		$display = array( 'php' );
66
		foreach ( $iterator as $file ) {
67
			if ( in_array( strtolower( array_pop( explode( '.', $file ) ) ), $display ) ) {
0 ignored issues
show
Bug introduced by
explode('.', $file) cannot be passed to array_pop() as the parameter $array expects a reference.
Loading history...
68
				echo "$file\n";
69
				$this->file( $file );
70
			}
71
		}
72
	}
73
74
	public function file( $file_path ) {
75
		$this->current_path = $file_path;
76
		$this->current_relative_path = str_replace( $this->base_path, '', $file_path );
77
78
		$source             = file_get_contents( $file_path );
79
		try {
80
			$ast = $this->parser->parse( $source );
81
		} catch ( Error $error ) {
0 ignored issues
show
Bug introduced by
The class PhpParser\Error does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
82
			echo "Parse error: {$error->getMessage()}\n";
83
			return;
84
		}
85
86
		// $dumper = new NodeDumper;
87
		// echo $dumper->dump($ast) . "\n";
88
89
		$traverser = new NodeTraverser();
90
		$traverser->addVisitor( $this );
91
		$ast = $traverser->traverse( $ast );
0 ignored issues
show
Unused Code introduced by
$ast is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
92
	}
93
94
	public function enterNode( Node $node ) {
95
		// print_r($node);
96
		if ( $node instanceof Node\Stmt\Class_ ) {
0 ignored issues
show
Bug introduced by
The class PhpParser\Node\Stmt\Class_ does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
97
			$this->current_class = $node->name->name;
98
			$this->add_declaration( new Class_Declaration( $this->current_relative_path, $node->getLine(), $node->name->name ) );
99
		}
100
		if ( $node instanceof Node\Stmt\Property && $node->isPublic() ) {
0 ignored issues
show
Bug introduced by
The class PhpParser\Node\Stmt\Property does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
101
			$this->add_declaration( new Class_Property_Declaration( $this->current_relative_path, $node->getLine(), $node->props[0]->name->name, $this->current_class ) );
102
		}
103
		if ( $node instanceof Node\Stmt\ClassMethod && $node->isPublic() ) {
0 ignored issues
show
Bug introduced by
The class PhpParser\Node\Stmt\ClassMethod does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
104
			$method = new Class_Method_Declaration( $this->current_relative_path, $node->getLine(), $node->name->name, $node->isStatic(), $this->current_class );
105
			foreach ( $node->getParams() as $param ) {
106
				$method->add_param( $node->var->name, $node->default, $node->type, $node->byRef, $node->variadic );
107
			}
108
			$this->add_declaration( $method );
109
		}
110
	}
111
112
	public function leaveNode( Node $node ) {
113
		if ( $node instanceof Node\Stmt\Class_ ) {
0 ignored issues
show
Bug introduced by
The class PhpParser\Node\Stmt\Class_ does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
114
			$this->current_class = null;
115
		}
116
	}
117
}
118
119
class Declaration {
120
	public $path;
121
	public $line;
122
	public $name;
123
124
	function __construct( $path, $line, $name ) {
125
		$this->path = $path;
126
		$this->line = $line;
127
		$this->name = $name;
128
	}
129
130
	function to_string() {
131
		return $this->path . ':' . $this->line . ' ' . $this->name;
132
	}
133
}
134
135
class Class_Declaration extends Declaration {
136
}
137
138
/**
139
 * We only log public class methods, whether they are static, and their parameters
140
 */
141
class Class_Method_Declaration extends Declaration {
142
	public $static;
143
	public $class_name;
144
145
	function __construct( $path, $line, $name, $static, $class_name ) {
146
		$this->static = $static;
147
		$this->class_name = $class_name;
148
		$this->params = array();
0 ignored issues
show
Bug introduced by
The property params does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
149
		parent::__construct( $path, $line, $name );
150
	}
151
152
	function add_param( $name, $default, $type, $byRef, $variadic ) {
153
		$this->params[] = (object) compact( 'name', 'default', 'type', 'byRef', 'variadic' );
154
	}
155
156
	function to_string() {
157
		$sep = $this->static ? '::' : '->';
158
		return $this->path . ':' . $this->line . ' ' . $this->class_name . $sep . $this->name;
159
	}
160
}
161
162
/**
163
 * We only log public class variables
164
 */
165
class Class_Property_Declaration extends Declaration {
166
	public $class_name;
167
168
	function __construct( $path, $line, $name, $class_name ) {
169
		$this->class_name = $class_name;
170
		parent::__construct( $path, $line, $name );
171
	}
172
173
	function to_string() {
174
		$sep = $this->static ? '::$' : '->';
0 ignored issues
show
Bug introduced by
The property static does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
175
		return $this->path . ':' . $this->line . ' ' . $this->class_name . $sep . $this->name;
176
	}
177
}
178