Skip to content

Commit 0235680

Browse files
committed
modified ScopeProcessor and fixed container creation bug
1 parent 9bc5f02 commit 0235680

6 files changed

Lines changed: 165 additions & 127 deletions

File tree

src/Command/AbstractCommand.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@
55
use DI\ContainerBuilder;
66

77
abstract class AbstractCommand implements CommandInterface{
8-
protected $container;
8+
protected static $container;
99
public function __construct(){
1010
$this->createContainer();
1111
}
1212
public function get($serviceName){
13-
return $this->container->get($serviceName);
13+
return self::$container->get($serviceName);
1414
}
1515
public function getContainer(){
16-
return $this->container;
16+
return self::$container;
1717
}
1818
protected function createContainer(){
19+
if(!empty(self::$container)){
20+
return;
21+
}
1922
$builder = new ContainerBuilder;
2023
$builder->setDefinitionCache(new \Doctrine\Common\Cache\ArrayCache);
2124
$builder->addDefinitions(__DIR__ . '/config.php');
22-
$this->container = $builder->build();
25+
self::$container = $builder->build();
2326
}
2427
protected function isVerbose($arguments){
2528
$verbose = false;

src/Complete/ContentManager.php

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,23 @@
1414
use Parser\Processor\IndexProcessor;
1515
use Parser\Processor\ScopeProcessor;
1616

17+
1718
class ContentManager {
1819
public function __construct(
1920
Parser $parser,
2021
IndexGenerator $generator,
2122
ContextResolver $contextResolver,
22-
ScopeResolver $scopeResolver,
2323
Completer $completer,
2424
IndexProcessor $indexProcessor,
2525
ScopeProcessor $scopeProcessor
2626
){
2727
$this->parser = $parser;
2828
$this->generator = $generator;
2929
$this->contextResolver = $contextResolver;
30-
$this->scopeResolver = $scopeResolver;
3130
$this->completer = $completer;
3231
$this->indexProcessor = $indexProcessor;
3332
$this->scopeProcessor = $scopeProcessor;
33+
$this->cachePool = [];
3434
}
3535
public function createCompletion(
3636
Project $project,
@@ -39,6 +39,7 @@ public function createCompletion(
3939
$column,
4040
$file
4141
){
42+
$start = microtime(1);
4243
$entries = [];
4344
if($line){
4445
list($lines, $badLine, $completionLine) = $this->prepareContent(
@@ -47,19 +48,24 @@ public function createCompletion(
4748
$column
4849
);
4950
try {
50-
$this->updateFileIndex($project, $lines, $file);
51-
$scope = $this->findScope(
52-
$project, implode("\n", $lines), $line, $file
53-
);
51+
$scope = $this->processFileContent($project, $lines, $line, $file);
52+
echo microtime(1) - $start;
53+
echo " for indexing preparing\n";
54+
echo microtime(1) - $start;
55+
echo " for scope preparing\n";
5456
}
5557
catch(\Exception $e){
5658
$scope = new Scope;
5759
}
5860
$entries = $this->findEntries($project, $scope, $completionLine, $column, $lines);
61+
echo microtime(1) - $start;
62+
echo " for entries preparing\n";
5963
}
6064
elseif(!empty($content)) {
6165
$this->updateFileIndex($project, $content, $file);
6266
}
67+
echo microtime(1) - $start;
68+
echo " seconds for creaeting completion\n";
6369

6470
return [
6571
"entries" => $entries,
@@ -70,9 +76,6 @@ protected function findEntries(Project $project, Scope $scope, $badLine, $column
7076
$context = $this->contextResolver->getContext($badLine, $column);
7177
return $this->completer->getEntries($project, $context, $scope);
7278
}
73-
protected function findScope(Project $project, $content, $line, $file){
74-
return $this->scopeResolver->findScope($project, $content, $line, $file);
75-
}
7679
/**
7780
* @TODO
7881
* Should check for bad lines
@@ -89,8 +92,12 @@ protected function prepareContent($content, $line, $column){
8992
$lines[$line-1] = "";
9093
return [$lines, trim($badLine), trim($completionLine)];
9194
}
92-
protected function updateFileIndex(Project $project, $lines, $file){
93-
//gc_disable();
95+
96+
/**
97+
*
98+
* @return Scope
99+
*/
100+
protected function processFileContent(Project $project, $lines, $line, $file){
94101
if(is_array($lines)){
95102
$content = implode("\n", $lines);
96103
}
@@ -104,23 +111,44 @@ protected function updateFileIndex(Project $project, $lines, $file){
104111
if(!$fqcn){
105112
return;
106113
}
107-
$this->indexProcessor->clearResultNodes();
108-
$parser = $this->parser;
109-
$parser->addProcessor($this->indexProcessor);
110-
$nodes = $parser->parseContent($fqcn, $file, $content);
111-
$this->generator->processFileNodes(
112-
$project->getIndex(),
113-
$fqcn,
114-
$nodes
115-
);
116-
//gc_enable();
114+
if(!array_key_exists($file, $this->cachePool)){
115+
$this->cachePool[$file] = [0, null, null];
116+
}
117+
if($this->isValidCache($file, $content)){
118+
list($hash, $indexNodes, $scopeNodes) = $this->cachePool[$file];
119+
}
120+
else {
121+
$this->indexProcessor->clearResultNodes();
122+
$this->scopeProcessor->clearResultNodes();
123+
$this->scopeProcessor->setIndex($project->getIndex());
124+
$this->scopeProcessor->setLine($line);
125+
$parser = $this->parser;
126+
$parser->addProcessor($this->indexProcessor);
127+
$parser->addProcessor($this->scopeProcessor);
128+
$nodes = $parser->parseContent($fqcn, $file, $content);
129+
$this->generator->processFileNodes(
130+
$project->getIndex(),
131+
$fqcn,
132+
$nodes
133+
);
134+
$scopeNodes = $this->scopeProcessor->getResultNodes();
135+
$contentHash = hash('sha1', $content);
136+
$this->cachePool[$file] = [$contentHash, $nodes, $scopeNodes];
137+
}
138+
return $scopeNodes[0];
139+
}
140+
141+
private function isValidCache($file, $content){
142+
$contentHash = hash('sha1', $content);
143+
list($hash) = $this->cachePool[$file];
144+
return $hash === $contentHash;
117145
}
118146

119147
private $parser;
120148
private $generator;
121149
private $contextResolver;
122-
private $scopeResolver;
123150
private $completer;
124151
private $indexProcessor;
125152
private $scopeProcessor;
153+
private $cachePool;
126154
}

src/Complete/Resolver/ScopeResolver.php

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/Parser/Parser.php

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,33 @@ public function __construct(
2020
$this->parser = $parser;
2121
$this->traverser = $traverser;
2222
$this->useParser = $useParser;
23+
$this->processors = [];
24+
$this->astPool = [];
2325
}
2426
public function parseFile(FQCN $fqcn, $file){
2527
$file = $this->path->getAbsolutePath($file);
2628
$content = $this->path->read($file);
2729
return $this->parseContent($fqcn, $file, $content);
2830
}
2931
public function parseContent(FQCN $fqcn, $file, $content){
30-
try{
31-
$uses = new Uses($this->parseFQCN($fqcn->getNamespace()));
32-
$this->useParser->setUses($uses);
33-
$ast = $this->parser->parse($content);
34-
35-
$this->setFileInfo($fqcn, $file);
36-
$this->traverser->traverse($ast);
32+
$hash = hash('md5', $content);
33+
if(!array_key_exists($file, $this->astPool)){
34+
$this->astPool[$file] = [0,0];
3735
}
38-
catch(\Exception $e){
39-
printf("Parsing failed in file %s\n", $file);
36+
$uses = new Uses($this->parseFQCN($fqcn->getNamespace()));
37+
$this->useParser->setUses($uses);
38+
list($oldHash, $ast) = $this->astPool[$file];
39+
if($oldHash !== $hash){
40+
try{
41+
$ast = $this->parser->parse($content);
42+
}
43+
catch(\Exception $e){
44+
printf("Parsing failed in file %s\n", $file);
45+
}
46+
$this->astPool[$file] = [$hash, $ast];
4047
}
48+
$this->setFileInfo($fqcn, $file);
49+
$this->traverser->traverse($ast);
4150
return $this->getResultNode();
4251
}
4352
public function parseFQCN($fqcn){
@@ -76,4 +85,5 @@ protected function setFileInfo(FQCN $fqcn, $file){
7685
private $traverser;
7786
/** @var Processor\ProcessorInterface[] */
7887
private $processors;
88+
private $astPool;
7989
}

src/Parser/Processor/ScopeProcessor.php

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,109 @@
22

33
namespace Parser\Processor;
44

5-
use PhpParser\NodeVisitorAbstract;
5+
use Parser\UseParser;
66
use Entity\FQCN;
7+
use Entity\Index;
8+
use Entity\Node\Variable;
9+
use Entity\Completion\Scope;
10+
use PhpParser\Node;
11+
use PhpParser\Node\Stmt\Use_;
12+
use PhpParser\Node\Stmt\ClassMethod;
13+
use PhpParser\Node\Expr\Assign;
14+
use PhpParser\NodeVisitorAbstract;
715

816
class ScopeProcessor extends NodeVisitorAbstract implements ProcessorInterface {
17+
public function __construct(
18+
UseParser $useParser
19+
){
20+
$this->resultNodes = [];
21+
$this->useParser = $useParser;
22+
}
23+
public function setLine($line){
24+
$this->line = $line;
25+
}
26+
public function leaveNode(Node $node){
27+
list($startLine, $endLine) = $this->getNodeLines($node);
28+
if(!$this->isIn($node, $this->line)){
29+
return;
30+
}
31+
if($node instanceof ClassMethod){
32+
$this->createScopeFromMethod($node);
33+
}
34+
elseif($node instanceof Assign){
35+
$this->addVarToScope($node);
36+
}
37+
}
938
public function setFileInfo(FQCN $fqcn, $file){
10-
39+
$this->scope = new Scope;
40+
$this->scope->setFQCN($fqcn);
1141
}
1242
public function clearResultNodes(){
1343
$this->resultNodes = [];
1444
}
1545
public function getResultNodes(){
46+
$this->resultNodes = [ $this->scope ];
1647
return $this->resultNodes;
1748
}
18-
protected function addResultNode($resultNode){
19-
if(!$resultNode){
49+
public function isIn($node, $line){
50+
list($startLine, $endLine) = $this->getNodeLines($node);
51+
if($node instanceof ClassMethod){
52+
return $line >= $startLine && $line <= $endLine;
53+
}
54+
return $line >= $startLine;
55+
}
56+
public function getNodeLines($node){
57+
$startLine = $endLine = -1;
58+
if($node->hasAttribute('startLine')){
59+
$startLine = $node->getAttribute('startLine');
60+
}
61+
if($node->hasAttribute('endLine')){
62+
$endLine = $node->getAttribute('endLine');
63+
}
64+
return [$startLine, $endLine];
65+
}
66+
public function createScopeFromMethod(ClassMethod $node){
67+
$this->scope = new Scope($this->scope);
68+
$index = $this->getIndex();
69+
if(empty($index)){
70+
echo "empty index\n";
71+
return;
72+
}
73+
$fqcn = $this->scope->getFQCN();
74+
$classData = $index->findClassByFQCN($fqcn);
75+
if(empty($classData)){
76+
printf("Empty class in %s\n", $fqcn->toString());
77+
return;
78+
}
79+
$method = $classData->methods->get($node->name);
80+
if(empty($method)){
81+
printf("Empty method in %s::%s\n", $fqcn->toString(), $node->name);
2082
return;
2183
}
22-
$this->resultNodes[] = $resultNode;
84+
foreach($method->arguments AS $param){
85+
$var = new Variable($param->name);
86+
$var->setFQCN($param->type);
87+
$this->scope->addVar($var);
88+
}
89+
}
90+
public function addVarToScope(Assign $node){
91+
}
92+
public function parseUse(Use_ $node, $fqcn, $file){
93+
$this->useParser->parse($node, $fqcn, $file);
94+
}
95+
public function parseFQCN($fqcn){
96+
return $this->useParser->parseFQCN($fqcn);
97+
}
98+
public function getIndex(){
99+
return $this->index;
100+
}
101+
public function setIndex(Index $index){
102+
$this->index = $index;
23103
}
24104
/** @var ClassData[]|InterfaceData[] */
25105
private $resultNodes;
106+
private $line;
107+
/** @var UseParser */
108+
private $useParser;
109+
private $index;
26110
}

0 commit comments

Comments
 (0)