Skip to content
Closed
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
1 change: 1 addition & 0 deletions conf/config.neon
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ parameters:
phpStormStubsNodesCountMax: 128
memberCacheKeysMax: 2048
resolvedLocalTypeAliasesCountMax: 2048
parsedPhpDocCountMax: 1024
reportUnmatchedIgnoredErrors: true
reportIgnoresWithoutComments: false
typeAliases: []
Expand Down
3 changes: 2 additions & 1 deletion conf/parametersSchema.neon
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ parametersSchema:
nameScopeMapMemoryCacheCountMax: int(),
phpStormStubsNodesCountMax: int(),
memberCacheKeysMax: int(),
resolvedLocalTypeAliasesCountMax: int()
resolvedLocalTypeAliasesCountMax: int(),
parsedPhpDocCountMax: int()
])
reportUnmatchedIgnoredErrors: bool()
reportIgnoresWithoutComments: bool()
Expand Down
25 changes: 24 additions & 1 deletion src/PhpDoc/PhpDocStringResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace PHPStan\PhpDoc;

use PHPStan\DependencyInjection\AutowiredParameter;
use PHPStan\DependencyInjection\AutowiredService;
use PHPStan\Internal\LruCache;
use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
Expand All @@ -12,16 +14,37 @@
final class PhpDocStringResolver
{

public function __construct(private Lexer $phpDocLexer, private PhpDocParser $phpDocParser)
/**
* FileTypeMapper and the rules that validate PHPDocs parse the same strings, often one right after
* another. The parsed nodes are not modified afterwards, so equal strings can share one node.
*
* @var LruCache<PhpDocNode>
*/
private LruCache $parsedPhpDocs;

public function __construct(
private Lexer $phpDocLexer,
private PhpDocParser $phpDocParser,
#[AutowiredParameter(ref: '%cache.parsedPhpDocCountMax%')]
int $parsedPhpDocCountMax,
)
{
$this->parsedPhpDocs = new LruCache($parsedPhpDocCountMax);
}

public function resolve(string $phpDocString): PhpDocNode
{
$phpDocNode = $this->parsedPhpDocs->get($phpDocString);
if ($phpDocNode !== null) {
return $phpDocNode;
}

$tokens = new TokenIterator($this->phpDocLexer->tokenize($phpDocString));
$phpDocNode = $this->phpDocParser->parse($tokens);
$tokens->consumeTokenType(Lexer::TOKEN_END); // @phpstan-ignore missingType.checkedException

$this->parsedPhpDocs->set($phpDocString, $phpDocNode, 0);

return $phpDocNode;
}

Expand Down
12 changes: 3 additions & 9 deletions src/Rules/PhpDoc/InvalidPHPStanDocTagRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\DependencyInjection\ValidatesStubFiles;
use PHPStan\Node\VirtualNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\PhpDoc\PhpDocStringResolver;
use PHPStan\Rules\MultipleNodeTypesRule;
use PHPStan\Rules\RuleErrorBuilder;
use function in_array;
Expand Down Expand Up @@ -70,10 +68,7 @@ final class InvalidPHPStanDocTagRule implements MultipleNodeTypesRule
'@phpstan-all-methods-impure',
];

public function __construct(
private Lexer $phpDocLexer,
private PhpDocParser $phpDocParser,
)
public function __construct(private PhpDocStringResolver $phpDocStringResolver)
{
}

Expand Down Expand Up @@ -111,8 +106,7 @@ public function processNode(Node $node, Scope $scope): array
return [];
}
$phpDocString = $docComment->getText();
$tokens = new TokenIterator($this->phpDocLexer->tokenize($phpDocString));
$phpDocNode = $this->phpDocParser->parse($tokens);
$phpDocNode = $this->phpDocStringResolver->resolve($phpDocString);

$errors = [];
foreach ($phpDocNode->getTags() as $phpDocTag) {
Expand Down
12 changes: 3 additions & 9 deletions src/Rules/PhpDoc/InvalidPhpDocTagValueRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@
use PHPStan\DependencyInjection\RegisteredRule;
use PHPStan\DependencyInjection\ValidatesStubFiles;
use PHPStan\Node\VirtualNode;
use PHPStan\PhpDoc\PhpDocStringResolver;
use PHPStan\PhpDocParser\Ast\PhpDoc\InvalidTagValueNode;
use PHPStan\PhpDocParser\Ast\PhpDoc\TypeAliasTagValueNode;
use PHPStan\PhpDocParser\Ast\Type\InvalidTypeNode;
use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDocParser\Parser\TokenIterator;
use PHPStan\Rules\MultipleNodeTypesRule;
use PHPStan\Rules\RuleErrorBuilder;
use function sprintf;
Expand All @@ -27,10 +25,7 @@
final class InvalidPhpDocTagValueRule implements MultipleNodeTypesRule
{

public function __construct(
private Lexer $phpDocLexer,
private PhpDocParser $phpDocParser,
)
public function __construct(private PhpDocStringResolver $phpDocStringResolver)
{
}

Expand Down Expand Up @@ -69,8 +64,7 @@ public function processNode(Node $node, Scope $scope): array
}

$phpDocString = $docComment->getText();
$tokens = new TokenIterator($this->phpDocLexer->tokenize($phpDocString));
$phpDocNode = $this->phpDocParser->parse($tokens);
$phpDocNode = $this->phpDocStringResolver->resolve($phpDocString);

$errors = [];
foreach ($phpDocNode->getTags() as $phpDocTag) {
Expand Down
22 changes: 22 additions & 0 deletions tests/PHPStan/PhpDoc/PhpDocStringResolverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

namespace PHPStan\PhpDoc;

use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\ParserException;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\Testing\PHPStanTestCase;

class PhpDocStringResolverTest extends PHPStanTestCase
Expand All @@ -17,4 +19,24 @@ public function testConsumeEnd(): void
$phpDocStringResolver->resolve('/** @param int $test */ test');
}

public function testEqualStringsShareOneNode(): void
{
$phpDocStringResolver = $this->createPhpDocStringResolver();

$node = $phpDocStringResolver->resolve('/** @param int $test */');
$this->assertSame($node, $phpDocStringResolver->resolve('/** @param int $test */'));
$this->assertNotSame($node, $phpDocStringResolver->resolve('/** @param string $test */'));
}

private function createPhpDocStringResolver(): PhpDocStringResolver
{
$container = self::getContainer();

return new PhpDocStringResolver(
$container->getByType(Lexer::class),
$container->getByType(PhpDocParser::class),
1024,
);
}

}
7 changes: 2 additions & 5 deletions tests/PHPStan/Rules/PhpDoc/InvalidPHPStanDocTagRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

namespace PHPStan\Rules\PhpDoc;

use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDoc\PhpDocStringResolver;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use PHPUnit\Framework\Attributes\RequiresPhp;
Expand All @@ -16,10 +15,8 @@ class InvalidPHPStanDocTagRuleTest extends RuleTestCase

protected function getRule(): Rule
{
$container = self::getContainer();
return new InvalidPHPStanDocTagRule(
$container->getByType(Lexer::class),
$container->getByType(PhpDocParser::class),
self::getContainer()->getByType(PhpDocStringResolver::class),
);
}

Expand Down
7 changes: 2 additions & 5 deletions tests/PHPStan/Rules/PhpDoc/InvalidPhpDocTagValueRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

namespace PHPStan\Rules\PhpDoc;

use PHPStan\PhpDocParser\Lexer\Lexer;
use PHPStan\PhpDocParser\Parser\PhpDocParser;
use PHPStan\PhpDoc\PhpDocStringResolver;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use PHPUnit\Framework\Attributes\RequiresPhp;
Expand All @@ -16,10 +15,8 @@ class InvalidPhpDocTagValueRuleTest extends RuleTestCase

protected function getRule(): Rule
{
$container = self::getContainer();
return new InvalidPhpDocTagValueRule(
$container->getByType(Lexer::class),
$container->getByType(PhpDocParser::class),
self::getContainer()->getByType(PhpDocStringResolver::class),
);
}

Expand Down
Loading