1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Automattic\Jetpack\Analyzer; |
4
|
|
|
|
5
|
|
|
use PhpParser\ParserFactory; |
6
|
|
|
use PhpParser\NodeTraverser; |
7
|
|
|
use PhpParser\NodeVisitor\NameResolver; |
8
|
|
|
|
9
|
|
|
class Declarations extends PersistentList { |
10
|
|
|
|
11
|
|
|
private $parser; |
12
|
|
|
|
13
|
|
|
function __construct() { |
14
|
|
|
$this->parser = ( new ParserFactory() )->create( ParserFactory::PREFER_PHP7 ); |
15
|
|
|
parent::__construct(); |
16
|
|
|
} |
17
|
|
|
|
18
|
|
|
private function slashit( $path ) { |
19
|
|
|
$path .= ( substr( $path, -1 ) == '/' ? '' : '/' ); |
20
|
|
|
return $path; |
21
|
|
|
} |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Scan every PHP in the root |
25
|
|
|
*/ |
26
|
|
View Code Duplication |
public function scan( $root, $exclude = array() ) { |
27
|
|
|
if ( is_dir( $root ) ) { |
28
|
|
|
return $this->scan_dir( $this->slashit( $root ), $exclude ); |
29
|
|
|
} elseif ( is_file( $root ) ) { |
30
|
|
|
return $this->scan_file( $this->slashit( dirname( $root ) ), $root ); |
31
|
|
|
} else { |
32
|
|
|
throw new \Exception( "Expected $root to be a file or directory" ); |
33
|
|
|
} |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
public function scan_dir( $root, $exclude = array() ) { |
37
|
|
|
|
38
|
|
|
if ( is_null( $exclude ) || ! is_array( $exclude ) ) { |
39
|
|
|
throw new Exception( 'Exclude must be an array' ); |
40
|
|
|
} |
41
|
|
|
|
42
|
|
View Code Duplication |
$filter = function ( $file, $key, $iterator ) use ( $exclude ) { |
43
|
|
|
if ( $iterator->hasChildren() && ! in_array( $file->getFilename(), $exclude ) ) { |
44
|
|
|
return true; |
45
|
|
|
} |
46
|
|
|
return $file->isFile(); |
47
|
|
|
}; |
48
|
|
|
|
49
|
|
|
$inner_iterator = new \RecursiveDirectoryIterator( $root, \RecursiveDirectoryIterator::SKIP_DOTS ); |
50
|
|
|
|
51
|
|
|
$iterator = new \RecursiveIteratorIterator( |
52
|
|
|
new \RecursiveCallbackFilterIterator( $inner_iterator, $filter ) |
53
|
|
|
); |
54
|
|
|
|
55
|
|
|
$valid_extensions = array( 'php' ); |
56
|
|
View Code Duplication |
foreach ( $iterator as $file ) { |
57
|
|
|
$parts = explode( '.', $file ); |
58
|
|
|
$current_extension = strtolower( array_pop( $parts ) ); |
59
|
|
|
|
60
|
|
|
if ( in_array( $current_extension, $valid_extensions, true ) ) { |
61
|
|
|
$this->scan_file( $root, $file ); |
62
|
|
|
} |
63
|
|
|
} |
64
|
|
|
} |
65
|
|
|
|
66
|
|
View Code Duplication |
public function scan_file( $root, $file_path ) { |
67
|
|
|
$file_path_relative = str_replace( $root, '', $file_path ); |
68
|
|
|
|
69
|
|
|
$source = file_get_contents( $file_path ); |
70
|
|
|
try { |
71
|
|
|
$ast = $this->parser->parse( $source ); |
72
|
|
|
} catch ( \Error $error ) { |
|
|
|
|
73
|
|
|
echo "Parse error: {$error->getMessage()}\n"; |
74
|
|
|
return; |
75
|
|
|
} catch ( \RuntimeException $error ) { |
76
|
|
|
echo "Parse error: {$error->getMessage()}\n"; |
77
|
|
|
return; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
// $dumper = new NodeDumper; |
81
|
|
|
// echo $dumper->dump($ast) . "\n"; |
82
|
|
|
|
83
|
|
|
$traverser = new NodeTraverser(); |
84
|
|
|
$nameResolver = new NameResolver(); |
85
|
|
|
$traverser->addVisitor( $nameResolver ); |
86
|
|
|
|
87
|
|
|
// Resolve names |
88
|
|
|
$ast = $traverser->traverse( $ast ); |
89
|
|
|
|
90
|
|
|
// now scan for public methods etc |
91
|
|
|
$traverser = new NodeTraverser(); |
92
|
|
|
$declaration_visitor = new Declarations\Visitor( $file_path_relative, $this ); |
93
|
|
|
$traverser->addVisitor( $declaration_visitor ); |
94
|
|
|
$ast = $traverser->traverse( $ast ); |
|
|
|
|
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
public function load( $file_path ) { |
98
|
|
|
$row = 1; |
99
|
|
|
if ( ( $handle = fopen( $file_path, 'r' ) ) !== false ) { |
100
|
|
|
while ( ( $data = fgetcsv( $handle, 1000, ',' ) ) !== false ) { |
101
|
|
|
$num = count( $data ); |
|
|
|
|
102
|
|
|
@list( $type, $file, $line, $class_name, $name, $static, $params_json ) = $data; |
|
|
|
|
103
|
|
|
switch ( $type ) { |
104
|
|
|
case 'class': |
105
|
|
|
$this->add( new Declarations\Class_( $file, $line, $class_name ) ); |
106
|
|
|
break; |
107
|
|
|
|
108
|
|
|
case 'property': |
109
|
|
|
$this->add( new Declarations\Class_Property( $file, $line, $class_name, $name, $static ) ); |
110
|
|
|
break; |
111
|
|
|
|
112
|
|
|
case 'class_const': |
113
|
|
|
$this->add( new Declarations\Class_Const( $file, $line, $class_name, $name ) ); |
114
|
|
|
break; |
115
|
|
|
|
116
|
|
View Code Duplication |
case 'method': |
117
|
|
|
$params = json_decode( $params_json ); |
118
|
|
|
$declaration = new Declarations\Class_Method( $file, $line, $class_name, $name, $static ); |
119
|
|
|
if ( is_array( $params ) ) { |
120
|
|
|
foreach ( $params as $param ) { |
121
|
|
|
$declaration->add_param( $param->name, $param->default, $param->type, $param->byRef, $param->variadic ); |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
$this->add( $declaration ); |
126
|
|
|
|
127
|
|
|
break; |
128
|
|
|
|
129
|
|
View Code Duplication |
case 'function': |
130
|
|
|
$params = json_decode( $params_json ); |
131
|
|
|
$declaration = new Declarations\Function_( $file, $line, $name ); |
132
|
|
|
if ( is_array( $params ) ) { |
133
|
|
|
foreach ( $params as $param ) { |
134
|
|
|
$declaration->add_param( $param->name, $param->default, $param->type, $param->byRef, $param->variadic ); |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
$this->add( $declaration ); |
139
|
|
|
|
140
|
|
|
break; |
141
|
|
|
} |
142
|
|
|
$row++; |
143
|
|
|
} |
144
|
|
|
fclose( $handle ); |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
|
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.