From 9e090281fcd759740db9a0d380fa10f770f35215 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sun, 28 Jul 2019 15:46:37 +0200 Subject: [PATCH 1/3] [NodeTypeResolver] Add phpunit extension --- composer.json | 3 ++- .../DependencyInjection/PHPStanServicesFactory.php | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 088e0fe790d0..a0e201aa5f7f 100644 --- a/composer.json +++ b/composer.json @@ -20,6 +20,7 @@ "nikic/php-parser": "^4.2.2", "phpstan/phpdoc-parser": "^0.3.4", "phpstan/phpstan": "^0.11.6", + "phpstan/phpstan-phpunit": "^0.11.2", "sebastian/diff": "^3.0", "symfony/console": "^3.4|^4.2", "symfony/dependency-injection": "^3.4|^4.2", @@ -171,4 +172,4 @@ "dev-master": "0.5-dev" } } -} \ No newline at end of file +} diff --git a/packages/NodeTypeResolver/src/DependencyInjection/PHPStanServicesFactory.php b/packages/NodeTypeResolver/src/DependencyInjection/PHPStanServicesFactory.php index 6f41d5199e03..6cd8a0d97682 100644 --- a/packages/NodeTypeResolver/src/DependencyInjection/PHPStanServicesFactory.php +++ b/packages/NodeTypeResolver/src/DependencyInjection/PHPStanServicesFactory.php @@ -18,8 +18,16 @@ final class PHPStanServicesFactory public function __construct() { - $this->container = (new ContainerFactory(getcwd())) - ->create(sys_get_temp_dir(), [], []); + $containerFactory = new ContainerFactory(getcwd()); + $additionalConfigFiles = []; + + // possible path collision for Docker + $phpstanPhpunitExtensionConfig = getcwd() . '/vendor/phpstan/phpstan-phpunit/extension.neon'; + if (file_exists($phpstanPhpunitExtensionConfig)) { + $additionalConfigFiles[] = $phpstanPhpunitExtensionConfig; + } + + $this->container = $containerFactory->create(sys_get_temp_dir(), $additionalConfigFiles, []); } public function createBroker(): Broker From cbb0c5ebc68e0758cfdea88e49ca44b2e5716e66 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sun, 28 Jul 2019 15:52:31 +0200 Subject: [PATCH 2/3] add IntersectionType to StaticTypeToStringResolver --- .../NodeTypeResolver/src/StaticTypeToStringResolver.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/NodeTypeResolver/src/StaticTypeToStringResolver.php b/packages/NodeTypeResolver/src/StaticTypeToStringResolver.php index 3af02e31839a..2ed7f7263193 100644 --- a/packages/NodeTypeResolver/src/StaticTypeToStringResolver.php +++ b/packages/NodeTypeResolver/src/StaticTypeToStringResolver.php @@ -8,6 +8,7 @@ use PHPStan\Type\ClosureType; use PHPStan\Type\FloatType; use PHPStan\Type\IntegerType; +use PHPStan\Type\IntersectionType; use PHPStan\Type\NullType; use PHPStan\Type\ObjectType; use PHPStan\Type\ObjectWithoutClassType; @@ -57,6 +58,14 @@ function (UnionType $unionType): array { return $types; }, + function (IntersectionType $intersectionType): array { + $types = []; + foreach ($intersectionType->getTypes() as $singleStaticType) { + $types = array_merge($types, $this->resolveObjectType($singleStaticType)); + } + + return $types; + }, function (ObjectType $objectType): array { // the must be absolute, since we have no other way to check absolute/local path return ['\\' . $objectType->getClassName()]; From c7a3d5d8fd542d0561b1aa718458c85426b0767b Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sun, 28 Jul 2019 15:58:54 +0200 Subject: [PATCH 3/3] improve preslashing for intersection types in DocBlockManipulator --- .../NodeAnalyzer/DocBlockManipulator.php | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockManipulator.php b/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockManipulator.php index af58b07a2bd6..d36302ce7505 100644 --- a/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockManipulator.php +++ b/packages/NodeTypeResolver/src/PhpDoc/NodeAnalyzer/DocBlockManipulator.php @@ -217,7 +217,6 @@ public function getParamTypeInfos(Node $node): array $phpDocInfo = $this->createPhpDocInfoFromNode($node); $types = $phpDocInfo->getParamTagValues(); - if ($types === []) { return []; } @@ -551,10 +550,8 @@ public function createPhpDocInfoFromNode(Node $node): PhpDocInfo */ private function addTypeSpecificTag(Node $node, string $name, string $type): void { - // prefix possible class name - if (! $this->typeAnalyzer->isPhpReservedType($type)) { - $type = '\\' . ltrim($type, '\\'); - } + // preffix possible class name + $type = $this->preslashFullyQualifiedNames($type); // there might be no phpdoc at all if ($node->getDocComment() !== null) { @@ -683,4 +680,28 @@ private function processFqnNameImport( return $attributeAwareNode; } + + private function preslashFullyQualifiedNames(string $type): string + { + $joinChar = '|'; // default + if (Strings::contains($type, '|')) { // intersection + $types = explode('|', $type); + $joinChar = '|'; + } elseif (Strings::contains($type, '&')) { // union + $types = explode('&', $type); + $joinChar = '&'; + } else { + $types = [$type]; + } + + foreach ($types as $key => $singleType) { + if ($this->typeAnalyzer->isPhpReservedType($singleType)) { + continue; + } + + $types[$key] = '\\' . ltrim($singleType, '\\'); + } + + return implode($joinChar, $types); + } }