Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ jobs:
fail-fast: false
matrix:
include:
- script: bash e2e/result-cache-name-scopes/test.sh
php-version: '8.3'
- script: |
cd e2e/result-cache-1
echo -n > phpstan-baseline.neon
Expand Down Expand Up @@ -1682,7 +1684,7 @@ jobs:
uses: "shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962" # 2.40.0
with:
coverage: "none"
php-version: "8.2"
php-version: ${{ matrix.php-version || '8.2' }}
extensions: mbstring
ini-values: memory_limit=256M

Expand Down Expand Up @@ -2166,6 +2168,9 @@ jobs:
../bashunit -a not_contains 'parallel worker' "$(grep -F 'parallel worker' "$RUNNER_TEMP/small-shm.txt" || true)"
diff "$RUNNER_TEMP/reference.txt" "$RUNNER_TEMP/small-shm.txt"

- name: "Verify PHPDoc name scopes survive partial analyses"
run: bash e2e/result-cache-name-scopes/test.sh

turbo-fork-unsafe-extension-e2e-tests:
name: "Turbo fork-unsafe extension E2E tests"
runs-on: "ubuntu-latest"
Expand Down
11 changes: 11 additions & 0 deletions conf/parsers.neon
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ services:
factory: @pathRoutingParser
autowired: false

# Persist complete name scopes independently of the analysed paths, while
# retaining the PHP 8 parser routing for version-independent stub files.
fileTypeMapperParser:
class: PHPStan\Parser\PathRoutingParser
arguments:
currentPhpVersionRichParser: @cachedRichParser
currentPhpVersionSimpleParser: @cachedRichParser
php8Parser: @php8Parser
singleReflectionFile: null
autowired: false

freshStubParser:
class: PHPStan\Parser\StubParser
arguments:
Expand Down
6 changes: 6 additions & 0 deletions e2e/result-cache-name-scopes/phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
parameters:
level: max
paths:
- src
scanFiles:
- src/helpers.php
28 changes: 28 additions & 0 deletions e2e/result-cache-name-scopes/src/helpers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php // lint >= 8.3

declare(strict_types=1);

interface Inbox
{
/** @return list<string> */
public function search(string $words): array;
}

/**
* @param Closure(string): list<string> $search
*/
function inbox(Closure $search): Inbox
{
return new readonly class($search) implements Inbox
{
/**
* @param Closure(string): list<string> $search
*/
public function __construct(private Closure $search) {}

public function search(string $words): array
{
return ($this->search)($words);
}
};
}
8 changes: 8 additions & 0 deletions e2e/result-cache-name-scopes/src/usage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

declare(strict_types=1);

function usage(): void
{
inbox(static fn (string $words): array => [$words])->search('a b');
}
15 changes: 15 additions & 0 deletions e2e/result-cache-name-scopes/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -euo pipefail

cd "$(dirname "$0")"

COLD_CACHE=$(mktemp -d)
WARM_CACHE=$(mktemp -d)
for CACHE in "$COLD_CACHE" "$WARM_CACHE"; do
printf 'includes:\n\t- %s/phpstan.neon\nparameters:\n\ttmpDir: %s\n' "$PWD" "$CACHE" > "$CACHE/phpstan.neon"
done

../../bin/phpstan analyse --debug --no-progress --error-format=raw -c "$COLD_CACHE/phpstan.neon"
../../bin/phpstan analyse --debug --no-progress --error-format=raw -c "$WARM_CACHE/phpstan.neon" src/usage.php
../../bin/phpstan clear-result-cache -q -c "$WARM_CACHE/phpstan.neon"
../../bin/phpstan analyse --debug --no-progress --error-format=raw -c "$WARM_CACHE/phpstan.neon"
5 changes: 3 additions & 2 deletions src/Type/FileTypeMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ final class FileTypeMapper

public function __construct(
private ReflectionProviderProvider $reflectionProviderProvider,
#[AutowiredParameter(ref: '@defaultAnalysisParser')]
#[AutowiredParameter(ref: '@fileTypeMapperParser')]
private Parser $phpParser,
private PhpDocStringResolver $phpDocStringResolver,
private PhpDocNodeResolver $phpDocNodeResolver,
Expand Down Expand Up @@ -371,7 +371,8 @@ private function getNameScopeMap(string $fileName): array
// and the content hashes cannot tell them apart from real ones.
// v7: IntermediaryNameScope refers to a NamespaceUses shared with the other name scopes
// created under the same use statements
$variableCacheKey = sprintf('v7-%s', ComposerHelper::getPhpDocParserVersion());
// v8: earlier entries can lack name scopes for classes inside cleaned function bodies.
$variableCacheKey = sprintf('v8-%s', ComposerHelper::getPhpDocParserVersion());
$cached = $this->loadCachedPhpDocNodeMap($cacheKey, $variableCacheKey);
if ($cached === null) {
[$nameScopeMap, $files] = $this->createPhpDocNodeMap($fileName, null, null, [], $fileName);
Expand Down
Loading