Skip to content

Commit 617d811

Browse files
parsing interfaces and return type (#335)
1 parent 1f8418e commit 617d811

20 files changed

+194
-4
lines changed

src/Analyzer/ClassDescription.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ class ClassDescription
2626
/** @var bool */
2727
private $abstract;
2828

29+
/** @var bool */
30+
private $interface;
31+
2932
/** @var list<string> */
3033
private $docBlock;
3134

@@ -45,6 +48,7 @@ public function __construct(
4548
?FullyQualifiedClassName $extends,
4649
bool $final,
4750
bool $abstract,
51+
bool $interface,
4852
array $docBlock = [],
4953
array $attributes = []
5054
) {
@@ -57,6 +61,7 @@ public function __construct(
5761
$this->fullPath = '';
5862
$this->docBlock = $docBlock;
5963
$this->attributes = $attributes;
64+
$this->interface = $interface;
6065
}
6166

6267
public function setFullPath(string $fullPath): void
@@ -166,6 +171,11 @@ public function isAbstract(): bool
166171
return $this->abstract;
167172
}
168173

174+
public function isInterface(): bool
175+
{
176+
return $this->interface;
177+
}
178+
169179
public function getDocBlock(): array
170180
{
171181
return $this->docBlock;

src/Analyzer/ClassDescriptionBuilder.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class ClassDescriptionBuilder
3434
/** @var list<FullyQualifiedClassName> */
3535
private $attributes;
3636

37+
/** @var bool */
38+
private $interface;
39+
3740
/**
3841
* @param list<ClassDependency> $classDependencies
3942
* @param list<FullyQualifiedClassName> $interfaces
@@ -47,6 +50,7 @@ private function __construct(
4750
array $interfaces,
4851
bool $final,
4952
bool $abstract,
53+
bool $interface,
5054
array $docBlock = [],
5155
array $attributes = []
5256
) {
@@ -58,6 +62,7 @@ private function __construct(
5862
$this->abstract = $abstract;
5963
$this->docBlock = $docBlock;
6064
$this->attributes = $attributes;
65+
$this->interface = $interface;
6166
}
6267

6368
public static function create(): self
@@ -69,6 +74,7 @@ public static function create(): self
6974
[],
7075
false,
7176
false,
77+
false,
7278
[],
7379
[]
7480
);
@@ -89,6 +95,7 @@ public function clear(): void
8995
$this->abstract = false;
9096
$this->docBlock = [];
9197
$this->attributes = [];
98+
$this->interface = false;
9299
}
93100

94101
public function setFilePath(string $filePath): self
@@ -132,6 +139,7 @@ public function get(): ClassDescription
132139
$this->extend,
133140
$this->final,
134141
$this->abstract,
142+
$this->interface,
135143
$this->docBlock,
136144
$this->attributes
137145
);
@@ -154,6 +162,13 @@ public function setAbstract(bool $abstract): self
154162
return $this;
155163
}
156164

165+
public function setInterface(bool $interface): self
166+
{
167+
$this->interface = $interface;
168+
169+
return $this;
170+
}
171+
157172
public function addDocBlock(string $docBlock): self
158173
{
159174
$this->docBlock[] = $docBlock;

src/Analyzer/FileVisitor.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,30 @@ public function enterNode(Node $node): void
166166
if ($node instanceof Node\Param) {
167167
$this->addParamDependency($node);
168168
}
169+
170+
if ($node instanceof Node\Stmt\Interface_) {
171+
if (null === $node->namespacedName) {
172+
return;
173+
}
174+
175+
$this->classDescriptionBuilder->setClassName($node->namespacedName->toCodeString());
176+
$this->classDescriptionBuilder->setInterface(true);
177+
178+
foreach ($node->attrGroups as $attributeGroup) {
179+
foreach ($attributeGroup->attrs as $attribute) {
180+
$this->classDescriptionBuilder
181+
->addAttribute($attribute->name->toString(), $attribute->getLine());
182+
}
183+
}
184+
}
185+
186+
if ($node instanceof Node\Stmt\ClassMethod) {
187+
$returnType = $node->returnType;
188+
if ($returnType instanceof Node\Name\FullyQualified) {
189+
$this->classDescriptionBuilder
190+
->addDependency(new ClassDependency($returnType->toCodeString(), $returnType->getLine()));
191+
}
192+
}
169193
}
170194

171195
public function getClassDescriptions(): array
@@ -189,6 +213,11 @@ public function leaveNode(Node $node): void
189213
$this->classDescriptions[] = $this->classDescriptionBuilder->get();
190214
$this->classDescriptionBuilder->clear();
191215
}
216+
217+
if ($node instanceof Node\Stmt\Interface_) {
218+
$this->classDescriptions[] = $this->classDescriptionBuilder->get();
219+
$this->classDescriptionBuilder->clear();
220+
}
192221
}
193222

194223
private function isSelfOrStaticOrParent(string $dependencyClass): bool

src/Expression/ForClasses/Implement.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ public function describe(ClassDescription $theClass, string $because): Descripti
2929

3030
public function evaluate(ClassDescription $theClass, Violations $violations, string $because): void
3131
{
32+
if ($theClass->isInterface()) {
33+
return;
34+
}
35+
3236
$interface = $this->interface;
3337
$interfaces = $theClass->getInterfaces();
3438
$implements = function (FullyQualifiedClassName $FQCN) use ($interface): bool {

src/Expression/ForClasses/NotImplement.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ public function describe(ClassDescription $theClass, string $because): Descripti
2929

3030
public function evaluate(ClassDescription $theClass, Violations $violations, string $because): void
3131
{
32+
if ($theClass->isInterface()) {
33+
return;
34+
}
35+
3236
$interface = $this->interface;
3337
$interfaces = $theClass->getInterfaces();
3438
$implements = function (FullyQualifiedClassName $FQCN) use ($interface): bool {

tests/E2E/Cli/DebugExpressionCommandTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public function test_parse_error_dont_stop_execution(): void
7070
$appTester = $this->createAppTester();
7171
$appTester->run(['debug:expression', 'expression' => 'NotExtend', 'arguments' => ['NotFound'], '--from-dir' => __DIR__.'/../_fixtures/parse_error']);
7272
$errorMessage = <<<END
73+
ContainerAwareInterface
7374
WARNING: Some files could not be parsed for these errors:
7475
- Syntax error, unexpected T_STRING, expecting '{' on line 8: Services/CartService.php
7576

tests/Unit/Analyzer/ClassDescriptionBuilderTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,32 @@ public function test_it_should_set_file_path(): void
133133
$classDescription = $classDescriptionBuilder->get();
134134
$this->assertEquals($filePath, $classDescription->fullPath());
135135
}
136+
137+
public function test_it_should_create_interface(): void
138+
{
139+
$FQCN = 'HappyIsland';
140+
$classDescriptionBuilder = ClassDescriptionBuilder::create();
141+
$classDescriptionBuilder->setClassName($FQCN);
142+
$classDescriptionBuilder->setInterface(true);
143+
144+
$classDescription = $classDescriptionBuilder->get();
145+
146+
$this->assertInstanceOf(ClassDescription::class, $classDescription);
147+
148+
$this->assertTrue($classDescription->isInterface());
149+
}
150+
151+
public function test_it_should_create_not_interface(): void
152+
{
153+
$FQCN = 'HappyIsland';
154+
$classDescriptionBuilder = ClassDescriptionBuilder::create();
155+
$classDescriptionBuilder->setClassName($FQCN);
156+
$classDescriptionBuilder->setInterface(false);
157+
158+
$classDescription = $classDescriptionBuilder->get();
159+
160+
$this->assertInstanceOf(ClassDescription::class, $classDescription);
161+
162+
$this->assertFalse($classDescription->isInterface());
163+
}
136164
}

tests/Unit/Analyzer/FileVisitorTest.php

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -669,8 +669,8 @@ class test implements Order
669669

670670
$violations = new Violations();
671671

672-
$notHaveDependencyOutsideNamespace = new Implement('Foo\Order');
673-
$notHaveDependencyOutsideNamespace->evaluate($cd[0], $violations, 'we want to add this rule for our software');
672+
$implement = new Implement('Foo\Order');
673+
$implement->evaluate($cd[0], $violations, 'we want to add this rule for our software');
674674

675675
$this->assertCount(0, $violations, $violations->toString());
676676
}
@@ -704,4 +704,30 @@ class ApplicationLevelDto
704704

705705
$this->assertCount(1, $violations);
706706
}
707+
708+
public function test_it_parse_interfaces(): void
709+
{
710+
$code = <<< 'EOF'
711+
<?php
712+
namespace MyProject\AppBundle\Application;
713+
use Doctrine\ORM\QueryBuilder;
714+
interface BookRepositoryInterface
715+
{
716+
public function getBookList(): QueryBuilder;
717+
}
718+
EOF;
719+
720+
/** @var FileParser $fp */
721+
$fp = FileParserFactory::createFileParser(TargetPhpVersion::create('8.1'));
722+
$fp->parse($code, 'relativePathName');
723+
724+
$cd = $fp->getClassDescriptions();
725+
726+
$violations = new Violations();
727+
728+
$dependsOnTheseNamespaces = new DependsOnlyOnTheseNamespaces('MyProject\AppBundle\Application');
729+
$dependsOnTheseNamespaces->evaluate($cd[0], $violations, 'we want to add this rule for our software');
730+
731+
$this->assertCount(1, $violations);
732+
}
707733
}

tests/Unit/Expressions/ForClasses/ContainDocBlockLikeTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public function test_it_should_return_true_if_contains_doc_block(): void
2323
null,
2424
false,
2525
false,
26+
false,
2627
['/** */myDocBlock with other information']
2728
);
2829
$because = 'we want to add this rule for our software';
@@ -47,6 +48,7 @@ public function test_it_should_return_true_if_contains_doc_block_without_because
4748
null,
4849
false,
4950
false,
51+
false,
5052
['/** */myDocBlock with other information']
5153
);
5254
$violations = new Violations();
@@ -70,6 +72,7 @@ public function test_it_should_return_false_if_not_contains_doc_block(): void
7072
null,
7173
false,
7274
false,
75+
false,
7376
['/** */myDocBlock with other information']
7477
);
7578
$because = 'we want to add this rule for our software';

tests/Unit/Expressions/ForClasses/ExtendTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public function test_it_should_return_violation_error(): void
2222
[],
2323
FullyQualifiedClassName::fromString('My\AnotherClass'),
2424
false,
25+
false,
2526
false
2627
);
2728

@@ -45,6 +46,7 @@ public function test_it_should_return_violation_error_if_extend_is_null(): void
4546
[],
4647
null,
4748
false,
49+
false,
4850
false
4951
);
5052

0 commit comments

Comments
 (0)