Skip to content

Commit e4ffd09

Browse files
committed
added static completer and static typeresolver
1 parent c25cbb9 commit e4ffd09

10 files changed

Lines changed: 213 additions & 16 deletions

File tree

bin/server.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
use React\Http\Response;
55
use React\Http\Request;
66

7-
require "app/config/bin.php";
8-
require "vendor/autoload.php";
7+
define("ROOT", dirname(__DIR__));
8+
9+
require ROOT . "/app/config/bin.php";
10+
require ROOT . "/vendor/autoload.php";
911

1012
$noFsIO = false;
1113
$port = 15155;

src/Complete/CompleteEngine.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,10 @@ protected function processFileContent(Project $project, $lines, $line, $file){
116116
return;
117117
}
118118
$fqcn = $project->getIndex()->findFQCNByFile($file);
119-
if(!$fqcn instanceof FQN){
119+
if (!$fqcn instanceof FQN) {
120120
$fqcn = new FQN();
121121
}
122-
if(!array_key_exists($file, $this->cachePool)){
122+
if (!array_key_exists($file, $this->cachePool)) {
123123
$this->cachePool[$file] = [0, [], []];
124124
}
125125
if($this->isValidCache($file, $content)){

src/Complete/Completer/CompleterFactory.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ public function __construct(
1212
InterfaceNameCompleter $interfaceNameCompleter,
1313
NamespaceCompleter $namespaceCompleter,
1414
ObjectCompleter $objectCompleter,
15+
StaticCompleter $staticCompleter,
1516
UseCompleter $useCompleter
1617
){
1718
$this->classNameCompleter = $classNameCompleter;
1819
$this->interfaceNameCompleter = $interfaceNameCompleter;
1920
$this->namespaceCompleter = $namespaceCompleter;
2021
$this->objectCompleter = $objectCompleter;
22+
$this->staticCompleter = $staticCompleter;
2123
$this->useCompleter = $useCompleter;
2224
}
2325
public function getCompleter(Context $context){
@@ -36,12 +38,16 @@ public function getCompleter(Context $context){
3638
elseif($context->isThis() || $context->isObject()){
3739
return $this->objectCompleter;
3840
}
41+
elseif($context->isClassStatic()){
42+
return $this->staticCompleter;
43+
}
3944
return null;
4045
}
4146

4247
private $classNameCompleter;
4348
private $interfaceNameCompleter;
4449
private $namespaceCompleter;
4550
private $objectCompleter;
51+
private $staticCompleter;
4652
private $useCompleter;
4753
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
namespace Complete\Completer;
4+
5+
use Entity\Project;
6+
use Entity\FQCN;
7+
use Entity\Node\MethodData;
8+
use Entity\Node\ClassProperty;
9+
use Entity\Node\InterfaceData;
10+
use Entity\Completion\Context;
11+
use Entity\Completion\Entry;
12+
use Entity\Completion\Scope;
13+
use Entity\Collection\Specification;
14+
use Psr\Log\LoggerInterface;
15+
16+
class StaticCompleter {
17+
public function __construct(LoggerInterface $logger){
18+
$this->logger = $logger;
19+
}
20+
public function getEntries(Project $project, Context $context){
21+
/** @var FQCN $fqcn */
22+
list($fqcn, $isThis) = $context->getData();
23+
$this->logger->addDebug('creating static entries');
24+
if(!$fqcn instanceof FQCN){
25+
return [];
26+
}
27+
$index = $project->getIndex();
28+
$this->logger->addDebug('Creating completion for ' . $fqcn->toString());
29+
$class = $index->findClassByFQCN($fqcn);
30+
if(empty($class)){
31+
$class = $index->findInterfaceByFQCN($fqcn);
32+
}
33+
if(empty($class)){
34+
return [];
35+
}
36+
$entries = [];
37+
$spec = new Specification($isThis ? 'private' : 'public', true);
38+
if($class->methods !== null){
39+
foreach($class->methods->all($spec) AS $method){
40+
$entry = $this->createEntryForMethod($method);
41+
$entries[$method->name] = $entry;
42+
}
43+
}
44+
if($class instanceof InterfaceData){
45+
return $entries;
46+
}
47+
if($class->properties !== null){
48+
foreach($class->properties->all($spec) AS $property){
49+
$entries[$property->name] = $this->createEntryForProperty($property);
50+
}
51+
}
52+
if($class->constants !== null)
53+
{
54+
foreach($class->constants->all() as $const){
55+
$entries[$const] = $this->createEntryForConst($const);
56+
}
57+
}
58+
ksort($entries);
59+
return $entries;
60+
}
61+
62+
/**
63+
* Creates menu entry for MethodData
64+
*
65+
* @param MethodData $method a method
66+
* @return Entry
67+
*/
68+
protected function createEntryForMethod(MethodData $method){
69+
return new Entry(
70+
$method->name,
71+
$method->getSignature(),
72+
sprintf("%s\n%s\n", $method->getSignature(), $method->doc)
73+
);
74+
}
75+
76+
protected function createEntryForProperty(ClassProperty $prop){
77+
$type = $prop->type instanceof FQCN ? $prop->type->toString() : 'mixed';
78+
return new Entry(
79+
$prop->name,
80+
$type
81+
);
82+
}
83+
84+
protected function createEntryForConst($const){
85+
return new Entry($const);
86+
}
87+
88+
/** @property LoggerInterface */
89+
private $logger;
90+
}

src/Complete/Resolver/ContextResolver.php

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,24 @@
66
use Entity\Completion\Context;
77
use Entity\Completion\Scope;
88
use Entity\Index;
9+
use Entity\FQCN;
910
use Parser\ErrorFreePhpParser;
11+
use Parser\UseParser;
1012
use Psr\Log\LoggerInterface;
1113
use PhpParser\Node\Expr\Variable;
14+
use PhpParser\Node\Name;
1215

1316
class ContextResolver{
1417
public function __construct(
1518
ErrorFreePhpParser $parser,
1619
NodeTypeResolver $typeResolver,
17-
LoggerInterface $logger
20+
LoggerInterface $logger,
21+
UseParser $useParser
1822
){
1923
$this->parser = $parser;
2024
$this->typeResolver = $typeResolver;
2125
$this->logger = $logger;
26+
$this->useParser = $useParser;
2227
}
2328
public function getContext($badLine, Index $index, Scope $scope = null){
2429
if(empty($badLine)){
@@ -62,9 +67,27 @@ protected function createContext(Scope $scope, Token $token, $badLine, Index $in
6267
else {
6368
$workingNode = $nodes;
6469
}
70+
$isThis = false;
71+
if($workingNode instanceof Variable && $workingNode->name === 'this')
72+
{
73+
$isThis = true;
74+
}
75+
if(
76+
$workingNode instanceof Name
77+
)
78+
{
79+
$nodeFQCN = $this->useParser->getFQCN($workingNode);
80+
if(
81+
$scope->getFQCN() instanceof FQCN
82+
&& $nodeFQCN->toString() === $scope->getFQCN()->toString()
83+
)
84+
{
85+
$isThis = true;
86+
}
87+
}
6588
$context->setData([
6689
$this->typeResolver->getChainType($workingNode, $index, $scope),
67-
$workingNode instanceof Variable && $workingNode->name === 'this'
90+
$isThis
6891
]);
6992
}
7093
if($token->isUseOperator()
@@ -107,4 +130,5 @@ protected function prepareLine($badLine){
107130
private $logger;
108131
private $parser;
109132
private $typeResolver;
133+
private $useParser;
110134
}

src/Complete/Resolver/NodeTypeResolver.php

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
use Entity\FQN;
88
use Entity\Completion\Scope;
99
use Parser\UseParser;
10+
use PhpParser\Node\Name;
1011
use PhpParser\Node\Expr\Variable;
1112
use PhpParser\Node\Expr\PropertyFetch;
13+
use PhpParser\Node\Expr\StaticPropertyFetch;
14+
use PhpParser\Node\Expr\StaticCall;
1215
use PhpParser\Node\Expr\MethodCall;
1316
use PhpParser\Node\Expr\New_;
1417
use Psr\Log\LoggerInterface;
@@ -34,7 +37,9 @@ public function __construct(
3437
public function getType($node, Index $index, Scope $scope){
3538
if($node instanceof Variable
3639
|| $node instanceof PropertyFetch
40+
|| $node instanceof StaticPropertyFetch
3741
|| $node instanceof MethodCall
42+
|| $node instanceof StaticCall
3843
){
3944
return $this->getChainType($node, $index, $scope);
4045
}
@@ -43,9 +48,6 @@ public function getType($node, Index $index, Scope $scope){
4348
}
4449
return null;
4550
}
46-
public function getNewType($node, Index $index, Scope $scope){
47-
48-
}
4951

5052
/**
5153
* Calculates type of the passed chained node
@@ -75,19 +77,28 @@ public function getChainType($node, Index $index, Scope $scope){
7577
}
7678
$type = $this->getPropertyType($block['name'], $type, $index);
7779
}
80+
elseif($block['type'] === 'class'){
81+
$type = $block['name'];
82+
}
7883
}
7984
return $type;
8085
}
8186
protected function createChain($node){
8287
$chain = [];
8388
while(!($node instanceof Variable)){
84-
if($node instanceof PropertyFetch){
89+
if(
90+
$node instanceof PropertyFetch
91+
|| $node instanceof StaticPropertyFetch
92+
){
8593
$chain[] = [
8694
'type' => 'property',
8795
'name' => $node->name
8896
];
8997
}
90-
elseif($node instanceof MethodCall){
98+
elseif(
99+
$node instanceof MethodCall
100+
|| $node instanceof StaticCall
101+
){
91102
$chain[] = [
92103
'type' => 'method',
93104
'name' => $node->name
@@ -98,12 +109,21 @@ protected function createChain($node){
98109
}
99110
$node = $node->var;
100111
}
112+
if(property_exists($node, 'class')){
113+
$node = $node->class;
114+
}
101115
if($node instanceof Variable){
102116
$chain[] = [
103117
'type' => 'var',
104118
'name' => $node->name
105119
];
106120
}
121+
elseif($node instanceof Name){
122+
$chain[] = [
123+
'type' => 'class',
124+
'name' => $this->useParser->getFQCN($node)
125+
];
126+
}
107127
return array_reverse($chain);
108128
}
109129
protected function getVarType($name, Scope $scope){
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace Entity\Collection;
4+
5+
class ConstCollection {
6+
7+
public function __construct($class){
8+
$this->class = $class;
9+
$this->map['class'] = 'class';
10+
}
11+
public function add($constant){
12+
$this->map[$constant] = $constant;
13+
}
14+
public function all(Specification $spec = null){
15+
$consts = $this->map;
16+
$parent = $this->class->getParent();
17+
if($parent instanceof ClassData){
18+
$props = array_merge(
19+
$parent->properties->all(),
20+
$consts
21+
);
22+
}
23+
sort($consts);
24+
return $consts;
25+
}
26+
public function get($propName, $spec = null){
27+
if(array_key_exists($propName, $this->map)){
28+
$const = $this->map[$propName];
29+
return $const;
30+
}
31+
$parent = $this->class->getParent();
32+
if($parent instanceof ClassData){
33+
return $parent->properties->get($name);
34+
}
35+
}
36+
37+
private $map = [];
38+
private $class;
39+
}

src/Entity/Collection/MethodsCollection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public function remove(MethodData $method){
2424
}
2525
public function get($name, Specification $spec = null){
2626
if($spec === null){
27-
$spec = new Specification('private', false, true);
27+
$spec = new Specification('private', true, true);
2828
}
2929
if(array_key_exists($name, $this->methods)){
3030
$method = $this->methods[$name];

src/Entity/Completion/Token.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public function add($code, $symbol){
1919
$this->addType(self::T_CONTINUE_PROCESS);
2020
break;
2121
case T_VARIABLE:
22+
case T_DOUBLE_COLON:
2223
case T_OBJECT_OPERATOR:
2324
if($this->isWhitespace()){
2425
$this->addType(self::T_UNKNOWN);
@@ -112,6 +113,13 @@ protected function removeType($type){
112113
}
113114
}
114115

116+
/**
117+
* @return Token
118+
*/
119+
protected static function test(){
120+
121+
}
122+
115123
const T_UNKNOWN = -1;
116124
const T_CONTINUE_PROCESS = 1;
117125
const T_TERMINATE = 2;
@@ -128,7 +136,7 @@ protected function removeType($type){
128136
protected static $MAP = [
129137
T_VARIABLE => Token::T_VAR,
130138
T_OBJECT_OPERATOR => Token::T_OBJECT_OPERATOR,
131-
T_STATIC => Token::T_STATIC_OPERATOR,
139+
T_DOUBLE_COLON => Token::T_STATIC_OPERATOR,
132140
T_USE => Token::T_USE_OPERATOR,
133141
T_NAMESPACE => Token::T_NAMESPACE_OPERATOR,
134142
T_NEW => Token::T_NEW_OPERATOR,

0 commit comments

Comments
 (0)