Skip to content

Commit d939919

Browse files
authored
Merge pull request #10 from permafrost-dev/reduce-complexity-2
Reduce class complexity
2 parents c60e1ac + 193d773 commit d939919

5 files changed

Lines changed: 170 additions & 227 deletions

File tree

src/Searcher.php

Lines changed: 53 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Permafrost\PhpCodeSearch\Results\FileSearchResults;
77
use Permafrost\PhpCodeSearch\Results\SearchError;
88
use Permafrost\PhpCodeSearch\Support\Arr;
9+
use Permafrost\PhpCodeSearch\Support\NameResolver;
910
use Permafrost\PhpCodeSearch\Support\VirtualFile;
1011
use Permafrost\PhpCodeSearch\Visitors\AssignmentVisitor;
1112
use Permafrost\PhpCodeSearch\Visitors\FunctionCallVisitor;
@@ -17,7 +18,6 @@
1718
use Permafrost\PhpCodeSearch\Visitors\VariableReferenceVisitor;
1819
use PhpParser\Error;
1920
use PhpParser\Node;
20-
use PhpParser\Node\Expr\FuncCall;
2121
use PhpParser\Node\Stmt;
2222
use PhpParser\NodeFinder;
2323
use PhpParser\NodeTraverser;
@@ -32,19 +32,19 @@ class Searcher
3232
protected $ast = [];
3333

3434
/** @var array */
35-
protected $functions = [];
35+
protected $assignments = [];
3636

3737
/** @var array */
38-
protected $methods = [];
38+
protected $classes = [];
3939

4040
/** @var array */
41-
protected $classes = [];
41+
protected $functions = [];
4242

4343
/** @var array */
44-
protected $static = [];
44+
protected $methods = [];
4545

4646
/** @var array */
47-
protected $assignments = [];
47+
protected $static = [];
4848

4949
/** @var array */
5050
protected $variables = [];
@@ -57,48 +57,44 @@ public function __construct($parser = null)
5757
$this->parser = $parser ?? (new ParserFactory())->create(ParserFactory::PREFER_PHP7);
5858
}
5959

60-
public function functions(array $names): self
60+
public function assignments(array $varNames): self
6161
{
62-
$this->functions = array_merge($this->functions, $names);
62+
$this->assignments = array_merge($this->assignments, $varNames);
6363

6464
return $this;
6565
}
6666

67-
public function methods(array $names): self
67+
public function classes(array $names): self
6868
{
69-
$this->methods = array_merge($this->methods, $names);
69+
$this->classes = array_merge($this->classes, $names);
7070

7171
return $this;
7272
}
7373

74-
public function variables(array $names): self
74+
public function functions(array $names): self
7575
{
76-
$this->variables = array_merge($this->variables, $names);
76+
$this->functions = array_merge($this->functions, $names);
7777

7878
return $this;
7979
}
8080

81-
public function static(array $names): self
81+
public function methods(array $names): self
8282
{
83-
$this->static = array_merge($this->static, $names);
83+
$this->methods = array_merge($this->methods, $names);
8484

8585
return $this;
8686
}
8787

88-
public function assignments(array $varNames): self
88+
public function static(array $names): self
8989
{
90-
$varNames = array_map(function ($item) {
91-
return ltrim($item, '$');
92-
}, $varNames);
93-
94-
$this->assignments = array_merge($this->assignments, $varNames);
90+
$this->static = array_merge($this->static, $names);
9591

9692
return $this;
9793
}
9894

99-
public function classes(array $names): self
95+
public function variables(array $names): self
10096
{
101-
$this->classes = $names;
97+
$this->variables = array_merge($this->variables, $names);
10298

10399
return $this;
104100
}
@@ -111,33 +107,30 @@ public function withoutSnippets(): self
111107
}
112108

113109
/**
114-
* @param File|string $file
110+
* @param File|VirtualFile|string $file
115111
* @return FileSearchResults
116112
*/
117113
public function search($file): FileSearchResults
118114
{
119-
if (is_string($file)) {
120-
$file = new File($file);
121-
}
115+
$file = is_string($file) ? new File($file) : $file;
122116

123117
$results = new FileSearchResults($file, $this->withSnippets);
124118

125119
if (! $this->parseFile($file, $results)) {
126120
return $results;
127121
}
128122

129-
$calls = $this->findAllReferences($this->ast);
130-
131-
$this->traverseNodes($results, $calls);
123+
$this->traverseNodes(
124+
$results,
125+
$this->findAllReferences($this->ast)
126+
);
132127

133128
return $results;
134129
}
135130

136131
public function searchCode(string $code): FileSearchResults
137132
{
138-
$file = new VirtualFile($code);
139-
140-
return $this->search($file);
133+
return $this->search(new VirtualFile($code));
141134
}
142135

143136
/**
@@ -161,147 +154,49 @@ protected function parseFile($file, FileSearchResults $results): bool
161154

162155
protected function findAllReferences(array $ast): array
163156
{
164-
$staticMethodCalls = $this->findReferences($ast, Node\Expr\StaticCall::class, 'class', $this->static);
165-
$staticProperties = $this->findReferences($ast, Node\Expr\StaticPropertyFetch::class, 'class', $this->static);
166-
$functionCalls = $this->findReferences($ast, FuncCall::class, 'name', $this->functions);
167-
$assignments = $this->findReferences($ast, Node\Expr\Assign::class, 'var', $this->assignments);
168-
$classes = $this->findReferences($ast, Node\Expr\New_::class, 'class', $this->classes);
169-
$methods = $this->findReferences($ast, Node\Expr\MethodCall::class, 'name', $this->methods);
170-
$variables = $this->findReferences($ast, Node\Expr\Variable::class, 'name', $this->variables);
171-
$functionDefs = $this->findReferences($ast, Node\Stmt\Function_::class, 'name', $this->functions);
172-
173-
return $this->sortNodesByLineNumber(
174-
$assignments,
175-
$classes,
176-
$functionCalls,
177-
$functionDefs,
178-
$methods,
179-
$staticMethodCalls,
180-
$staticProperties,
181-
$variables
182-
);
183-
}
184-
185-
protected function findReferences(array $ast, string $class, ?string $nodeNameProp, array $names): array
186-
{
187-
$nodeFinder = new NodeFinder();
188-
189-
$nodes = $nodeFinder->findInstanceOf($ast, $class);
190-
191-
if (! $nodeNameProp) {
192-
return $nodes;
157+
$nodeMap = [
158+
Node\Expr\Assign::class => $this->assignments,
159+
Node\Expr\FuncCall::class => $this->functions,
160+
Node\Expr\MethodCall::class => $this->methods,
161+
Node\Expr\New_::class => $this->classes,
162+
Node\Expr\StaticCall::class => $this->static,
163+
Node\Expr\StaticPropertyFetch::class => $this->static,
164+
Node\Expr\Variable::class => $this->variables,
165+
Node\Stmt\Function_::class => $this->functions,
166+
];
167+
168+
$result = [];
169+
170+
foreach($nodeMap as $parserNodeClass => $names) {
171+
$result[] = $this->findReferences($ast, $parserNodeClass, $names);
193172
}
194173

195-
return array_filter($nodes, function (Node $node) use ($names, $nodeNameProp) {
196-
$name = '';
197-
198-
if ($node instanceof FuncCall) {
199-
if (! method_exists($node->name, 'toString')) {
200-
return false;
201-
}
202-
203-
$name = $node->name->toString();
204-
205-
return Arr::matches($name, $names, true);
206-
}
207-
208-
if ($node instanceof Node\Expr\MethodCall) {
209-
if (! method_exists($node->name, 'toString')) {
210-
return false;
211-
}
212-
213-
$name = $node->name->toString();
214-
215-
return Arr::matches($name, $names, true);
216-
}
217-
218-
if ($node instanceof Node\Expr\StaticPropertyFetch) {
219-
$name = $node->class->toString();
220-
$methodName = $node->name->name;
221-
222-
return Arr::matches($methodName, $names, true) || Arr::matches("{$name}::\${$methodName}", $names, true);
223-
}
224-
225-
if ($node instanceof Node\Expr\StaticCall) {
226-
if (! method_exists($node->class, 'toString')) {
227-
return false;
228-
}
229-
if (! method_exists($node->name, 'toString')) {
230-
return false;
231-
}
232-
233-
$name = $node->class->toString();
234-
$methodName = $node->name->toString();
235-
236-
return Arr::matches($name, $names, true) || Arr::matches("{$name}::{$methodName}", $names, true);
237-
}
238-
239-
if ($node instanceof Node\Expr\Variable) {
240-
$name = $node->name;
241-
242-
return Arr::matches($name, $names, true);
243-
}
244-
245-
if ($node instanceof Node\Stmt\Function_) {
246-
$name = $node->name->name;
247-
248-
return Arr::matches($name, $names, true);
249-
}
250-
251-
if ($node instanceof Node\Expr\Array_) {
252-
return false;
253-
}
254-
255-
if ($node instanceof Node\Expr\ArrayItem) {
256-
return false;
257-
}
258-
259-
if ($node instanceof Node\Expr\ArrayDimFetch) {
260-
$name = $node->var->name;
261-
262-
return Arr::matches($name, $names, true);
263-
}
264-
265-
// if ($node instanceof Node\Expr\New_) {
266-
// $name = $node->class->name->name;
267-
// }
268-
269-
if ($node instanceof Node\Expr\Assign) {
270-
if (! $node->var instanceof Node\Expr\Variable) {
271-
return false;
272-
}
273-
274-
$name = $node->var->name;
275-
}
276-
277-
if (! empty($name)) {
278-
return in_array($name, $names, true);
279-
}
174+
return $this->sortNodesByLineNumber(...$result);
175+
}
280176

281-
if (isset($node->{$nodeNameProp}->name)) {
282-
return in_array($node->{$nodeNameProp}->name, $names, true);
283-
}
177+
protected function findReferences(array $ast, string $class, array $names): array
178+
{
179+
$nodes = (new NodeFinder())->findInstanceOf($ast, $class);
284180

285-
if (! isset($node->{$nodeNameProp}->parts)) {
286-
return false;
287-
}
181+
return collect($nodes)->filter(function(Node $node) use ($names) {
182+
$name = NameResolver::resolve($node) ?? false;
288183

289-
return in_array($node->{$nodeNameProp}->parts[0], $names, true);
290-
});
184+
return $name && Arr::matchesAny($name, $names, true);
185+
})->all();
291186
}
292187

293188
protected function traverseNodes(FileSearchResults $results, array $nodes): void
294189
{
295190
$traverser = new NodeTraverser();
296191

192+
$traverser->addVisitor(new AssignmentVisitor($results, $this->assignments));
297193
$traverser->addVisitor(new FunctionCallVisitor($results, $this->functions));
298-
$traverser->addVisitor(new StaticCallVisitor($results, $this->static));
194+
$traverser->addVisitor(new FunctionDefinitionVisitor($results, $this->functions));
299195
$traverser->addVisitor(new MethodCallVisitor($results, $this->methods));
300-
$traverser->addVisitor(new VariableReferenceVisitor($results, $this->variables));
301196
$traverser->addVisitor(new NewClassVisitor($results, $this->classes));
302-
$traverser->addVisitor(new AssignmentVisitor($results, $this->assignments));
197+
$traverser->addVisitor(new StaticCallVisitor($results, $this->static));
303198
$traverser->addVisitor(new StaticPropertyVisitor($results, $this->static));
304-
$traverser->addVisitor(new FunctionDefinitionVisitor($results, $this->functions));
199+
$traverser->addVisitor(new VariableReferenceVisitor($results, $this->variables));
305200

306201
$traverser->traverse($nodes);
307202
}

src/Support/Arr.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,19 @@ public static function matches(string $str, array $values, bool $allowRegex = tr
4040
return false;
4141
}
4242

43+
public static function matchesAny($strings, array $values, bool $allowRegex = true): bool
44+
{
45+
if (! is_array($strings)) {
46+
$strings = [$strings];
47+
}
48+
49+
return collect($strings)->map(function(string $str) use ($values, $allowRegex) {
50+
return self::matches($str, $values, $allowRegex);
51+
})->filter(function($value) {
52+
return $value;
53+
})->count() > 0;
54+
}
55+
4356
/**
4457
* Determine whether the given value is array accessible.
4558
*

0 commit comments

Comments
 (0)