diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 4ca9c86329..99af24c9d9 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -270,6 +270,10 @@ jobs: cd e2e/baseline-uninit-prop-trait ../../bin/phpstan analyse --configuration test-no-baseline.neon --generate-baseline test-baseline.neon ../../bin/phpstan analyse --configuration test.neon + - script: | + cd e2e/discussion-11362 + composer install + ../../bin/phpstan steps: - name: "Checkout" diff --git a/e2e/discussion-11362/.gitignore b/e2e/discussion-11362/.gitignore new file mode 100644 index 0000000000..61ead86667 --- /dev/null +++ b/e2e/discussion-11362/.gitignore @@ -0,0 +1 @@ +/vendor diff --git a/e2e/discussion-11362/composer.json b/e2e/discussion-11362/composer.json new file mode 100644 index 0000000000..114bec3040 --- /dev/null +++ b/e2e/discussion-11362/composer.json @@ -0,0 +1,24 @@ +{ + "config": { + "preferred-install": { + "*": "dist", + "repro/*": "source" + }, + "sort-packages": true + }, + "minimum-stability": "dev", + "prefer-stable": true, + "repositories": [ + { + "type": "path", + "url": "./packages/*/" + } + ], + "require": { + "repro/site": "@dev", + "php": "^8.1" + }, + "require-dev": { + "phpstan/phpstan": "1.11.7" + } +} diff --git a/e2e/discussion-11362/composer.lock b/e2e/discussion-11362/composer.lock new file mode 100644 index 0000000000..b893bfb8cc --- /dev/null +++ b/e2e/discussion-11362/composer.lock @@ -0,0 +1,103 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "49a30c2374c218ffcab0e58fd0628fab", + "packages": [ + { + "name": "repro/site", + "version": "dev-main", + "dist": { + "type": "path", + "url": "./packages/site", + "reference": "0f4b564a39e8ff3758c1d96a2a5d4b72dea08b23" + }, + "require": { + "php": "^8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Repro\\Site\\": "Classes" + } + }, + "transport-options": { + "relative": true + } + } + ], + "packages-dev": [ + { + "name": "phpstan/phpstan", + "version": "1.11.7", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "52d2bbfdcae7f895915629e4694e9497d0f8e28d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/52d2bbfdcae7f895915629e4694e9497d0f8e28d", + "reference": "52d2bbfdcae7f895915629e4694e9497d0f8e28d", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2024-07-06T11:17:41+00:00" + } + ], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": { + "repro/site": 20 + }, + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": "^8.1" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/e2e/discussion-11362/packages/site/Classes/Domain/Model/ContentPage.php b/e2e/discussion-11362/packages/site/Classes/Domain/Model/ContentPage.php new file mode 100644 index 0000000000..4ca5833958 --- /dev/null +++ b/e2e/discussion-11362/packages/site/Classes/Domain/Model/ContentPage.php @@ -0,0 +1,59 @@ +parentIssue; + } + + public function getParentLesson(): ?Lesson + { + return $this->parentLesson; + } + + public function getTitle(): string + { + return $this->title; + } + + public function getType(): string + { + return $this->type; + } + + public function getNavigationVisible(): bool + { + return $this->navigationVisible; + } + + public function getNavigationColor(): string + { + return $this->navigationColor; + } +} + diff --git a/e2e/discussion-11362/packages/site/Classes/Domain/Model/Issue.php b/e2e/discussion-11362/packages/site/Classes/Domain/Model/Issue.php new file mode 100644 index 0000000000..8343551215 --- /dev/null +++ b/e2e/discussion-11362/packages/site/Classes/Domain/Model/Issue.php @@ -0,0 +1,45 @@ +parentSchoolYear; + } + + public function getTitle(): string + { + return $this->title; + } + + public function getStartDate(): int + { + return $this->startDate; + } + + public function getHolidayTitle(): string + { + return $this->holidayTitle; + } +} diff --git a/e2e/discussion-11362/packages/site/Classes/Domain/Model/Lesson.php b/e2e/discussion-11362/packages/site/Classes/Domain/Model/Lesson.php new file mode 100644 index 0000000000..e00f2f0efb --- /dev/null +++ b/e2e/discussion-11362/packages/site/Classes/Domain/Model/Lesson.php @@ -0,0 +1,29 @@ +schoolLevel; + } + + public function getParentIssue(): ?Issue + { + return $this->parentIssue; + } + + public function getLessonNumber(): int + { + return $this->lessonNumber; + } +} diff --git a/e2e/discussion-11362/packages/site/Classes/Domain/Model/SchoolLevel.php b/e2e/discussion-11362/packages/site/Classes/Domain/Model/SchoolLevel.php new file mode 100644 index 0000000000..5c326ca596 --- /dev/null +++ b/e2e/discussion-11362/packages/site/Classes/Domain/Model/SchoolLevel.php @@ -0,0 +1,15 @@ +title; + } +} diff --git a/e2e/discussion-11362/packages/site/Classes/Domain/Model/SchoolYear.php b/e2e/discussion-11362/packages/site/Classes/Domain/Model/SchoolYear.php new file mode 100644 index 0000000000..a86f5bf575 --- /dev/null +++ b/e2e/discussion-11362/packages/site/Classes/Domain/Model/SchoolYear.php @@ -0,0 +1,40 @@ +startDate; + } + + public function getEndDate(): int + { + return $this->endDate; + } + + public function getIntroStartDate(): int + { + return $this->introStartDate; + } + + public function getIntroEndDate(): int + { + return $this->introEndDate; + } +} diff --git a/e2e/discussion-11362/packages/site/composer.json b/e2e/discussion-11362/packages/site/composer.json new file mode 100644 index 0000000000..ca413c1c8d --- /dev/null +++ b/e2e/discussion-11362/packages/site/composer.json @@ -0,0 +1,11 @@ +{ + "autoload": { + "psr-4": { + "Repro\\Site\\": "Classes" + } + }, + "name": "repro/site", + "require": { + "php": "^8.1" + } +} diff --git a/e2e/discussion-11362/phpstan.neon b/e2e/discussion-11362/phpstan.neon new file mode 100644 index 0000000000..d9a4bd0ab3 --- /dev/null +++ b/e2e/discussion-11362/phpstan.neon @@ -0,0 +1,11 @@ +parameters: + excludePaths: + analyseAndScan: + - .git + analyse: + - vendor + + level: 1 + + paths: + - . diff --git a/src/Parser/PathRoutingParser.php b/src/Parser/PathRoutingParser.php index 436416bcf9..def6786f5e 100644 --- a/src/Parser/PathRoutingParser.php +++ b/src/Parser/PathRoutingParser.php @@ -4,7 +4,14 @@ use PHPStan\File\FileHelper; use function array_fill_keys; +use function array_slice; +use function count; +use function explode; +use function implode; +use function is_link; +use function realpath; use function str_contains; +use const DIRECTORY_SEPARATOR; class PathRoutingParser implements Parser { @@ -41,6 +48,24 @@ public function parseFile(string $file): array $file = $this->fileHelper->normalizePath($file); if (!isset($this->analysedFiles[$file])) { + // check symlinked file that still might be in analysedFiles + $pathParts = explode(DIRECTORY_SEPARATOR, $file); + for ($i = count($pathParts); $i > 1; $i--) { + $joinedPartOfPath = implode(DIRECTORY_SEPARATOR, array_slice($pathParts, 0, $i)); + if (!@is_link($joinedPartOfPath)) { + continue; + } + + $realFilePath = realpath($file); + if ($realFilePath !== false) { + $normalizedRealFilePath = $this->fileHelper->normalizePath($realFilePath); + if (isset($this->analysedFiles[$normalizedRealFilePath])) { + return $this->currentPhpVersionRichParser->parseFile($file); + } + } + break; + } + return $this->currentPhpVersionSimpleParser->parseFile($file); }