Skip to content
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Change Log

## [Unreleased][unreleased]
### Fixed
- Compatibility with new Latte versions

## [0.17.1] - 2024-07-18
### Updated
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"require": {
"php": ">=7.4 <8.4",
"ext-json": "*",
"phpstan/phpstan": "^1.10.50",
"phpstan/phpstan": "^1.12.13",
"phpstan/phpstan-nette": "^1.2.6",
"latte/latte": "^2.11.6 | ^3.0.4",
"nette/utils": "^3.2|^4.0",
Expand Down
12 changes: 1 addition & 11 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ parameters:
path: src/Compiler/Compiler/AbstractCompiler.php

-
message: '#^Parameter \#1 \$value of static method PhpParser\\BuilderHelpers\:\:normalizeValue\(\) expects array\|bool\|float\|int\|PhpParser\\Node\\Expr\|string\|null, mixed given\.$#'
message: '#^Parameter \#1 \$value of static method PhpParser\\BuilderHelpers\:\:normalizeValue\(\) expects .*, mixed given\.$#'
path: src/LinkProcessor/LinkParamsProcessor.php
-
messages:
Expand Down Expand Up @@ -145,16 +145,6 @@ parameters:
- '#^Although PHPStan\\Node\\InClassNode is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#'
- '#^Although PHPStan\\Node\\ClassMethod is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#'

-
messages:
-'#^Although PHPStan\\Rules\\MetadataRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#'
-'#^Although PHPStan\\Rules\\FileRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#'
-'#^Although PHPStan\\Rules\\LineRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#'
-'#^Although PHPStan\\Rules\\TipRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#'
-'#^Although PHPStan\\Rules\\IdentifierRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#'
-'#^Although PHPStan\\Rules\\NonIgnorableRuleError is covered by backward compatibility promise, this instanceof assumption might break because it''s not guaranteed to always stay the same\.$#'
path: src/Error/ErrorBuilder.php

# to be done later, no idea how to fix it now
-
message: '#^Method Efabrica\\PHPStanLatte\\Collector\\Collector\\AbstractCollector::collectItems\(\) should return array\<A of array\>\|null but returns array\<int, array\<string, mixed\>\>\.$#'
Expand Down
21 changes: 17 additions & 4 deletions src/Analyser/LatteContextAnalyser.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,11 @@ public function analyseFile(string $file): LatteContextData
try {
$collectedData = $collector->collectData($node, $scope);
} catch (Throwable $e) {
$fileErrors[] = RuleErrorBuilder::message(get_class($collector) . ' error: ' . $e->getMessage())->file($file)->line($node->getLine())->build();
$fileErrors[] = RuleErrorBuilder::message(get_class($collector) . ' error: ' . $e->getMessage())
->identifier('latte.collectorError')
->file($file)
->line($node->getLine())
->build();
continue;
}
if ($collectedData === null || $collectedData === []) {
Expand All @@ -116,12 +120,21 @@ public function analyseFile(string $file): LatteContextData
$scope = $this->scopeFactory->create(ScopeContext::create($file));
$this->nodeScopeResolver->processNodes($parserNodes, $scope, $nodeCallback);
} catch (Throwable $e) {
$fileErrors[] = RuleErrorBuilder::message('LatteContextAnalyser error: ' . $e->getMessage())->file($file)->build();
$fileErrors[] = RuleErrorBuilder::message('LatteContextAnalyser error: ' . $e->getMessage())
->identifier('latte.failed')
->file($file)
->build();
}
} elseif (is_dir($file)) {
$fileErrors[] = RuleErrorBuilder::message(sprintf('File %s is a directory.', $file))->file($file)->build();
$fileErrors[] = RuleErrorBuilder::message(sprintf('File %s is a directory.', $file))
->identifier('latte.fileError')
->file($file)
->build();
} else {
$fileErrors[] = RuleErrorBuilder::message(sprintf('File %s does not exist.', $file))->file($file)->build();
$fileErrors[] = RuleErrorBuilder::message(sprintf('File %s does not exist.', $file))
->identifier('latte.fileError')
->file($file)
->build();
}
return new LatteContextData($fileCollectedData, $fileErrors);
}
Expand Down
16 changes: 10 additions & 6 deletions src/Analyser/LatteContextData.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

use Efabrica\PHPStanLatte\LatteContext\CollectedData\CollectedError;
use Efabrica\PHPStanLatte\LatteContext\CollectedData\CollectedLatteContextObject;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\IdentifierRuleError;
use PHPStan\Rules\RuleErrorBuilder;

final class LatteContextData
{
/** @var array<RuleError> */
/** @var list<IdentifierRuleError> */
private array $errors;

/** @var array<CollectedLatteContextObject> */
Expand All @@ -22,7 +22,7 @@ final class LatteContextData

/**
* @param array<CollectedLatteContextObject> $collectedData
* @param array<RuleError> $errors
* @param list<IdentifierRuleError> $errors
*/
public function __construct(array $collectedData, array $errors)
{
Expand All @@ -34,21 +34,25 @@ public function __construct(array $collectedData, array $errors)
}

/**
* @return array<RuleError>
* @return list<IdentifierRuleError>
*/
public function getErrors(): array
{
return $this->errors;
}

/**
* @return array<RuleError>
* @return list<IdentifierRuleError>
*/
public function getCollectedErrors(): array
{
$errors = [];
foreach ($this->getCollectedData(CollectedError::class) as $collectedError) {
$errors[] = RuleErrorBuilder::message($collectedError->getMessage())->file($collectedError->getFile())->line($collectedError->getLine() ?? -1)->build();
$errors[] = RuleErrorBuilder::message($collectedError->getMessage())
->identifier('latte.error')
->file($collectedError->getFile())
->line($collectedError->getLine() ?? -1)
->build();
}
return $errors;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function leaveNode(Node $node): ?array
$parameters = [];
$pattern = '/(?<define>{define\s+(?<block_name>.*?)\s*,?\s+(?<parameters>.*)})\s+on line (?<line>\d+)/s';
preg_match($pattern, $comment->getText(), $match);
if (isset($match['parameters'])) {
if (isset($match['define']) && isset($match['block_name']) &&isset($match['parameters'])) {
$define = $match['define'];

$typesAndVariablesPattern = '/(?<type>[\?\\\[\]\<\>[:alnum:]]*)[ ]*\$(?<variable>[[:alnum:]]+)/s';
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/NodeVisitor/LinkNodeVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\LNumber;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Echo_;
use PhpParser\Node\Stmt\If_;
use PhpParser\NodeVisitorAbstract;
Expand Down Expand Up @@ -143,7 +143,7 @@ private function prepareNodes(MethodCall $methodCall, array $attributes): ?array
}

return [
new If_(new Identical(new FuncCall(new Name('mt_rand')), new LNumber(0)), [
new If_(new Identical(new FuncCall(new Name('uniqid')), new String_('random')), [
'stmts' => $expressions,
], $attributes),
];
Expand Down
15 changes: 9 additions & 6 deletions src/Error/ErrorBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use PHPStan\Rules\LineRuleError;
use PHPStan\Rules\MetadataRuleError;
use PHPStan\Rules\NonIgnorableRuleError;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Rules\TipRuleError;

Expand Down Expand Up @@ -52,6 +51,9 @@ final class ErrorBuilder
'/PHPDoc tag @var for variable \$__variables__ has no value type specified in iterable type array\./', // fake variable $__variables__ can have not specified array type
'/Cannot call method startTag\(\) on Nette\\\\Utils\\\\Html\|string\./', // nette/forms error https://github.com/nette/forms/issues/308
'/Cannot call method endTag\(\) on Nette\\\\Utils\\\\Html\|string\./', // nette/forms error https://github.com/nette/forms/issues/308
'/Variable .* on left side of \?\?= is never defined./',
'/Variable .* on left side of \?\?= always exists and is not nullable./',
'/Property Latte\\\\Runtime\\\\Template::\$parentName .* does not accept mixed./',
];

/** @var string[] */
Expand Down Expand Up @@ -89,7 +91,7 @@ public function __construct(

/**
* @param Error[] $originalErrors
* @return RuleError[]
* @return IdentifierRuleError[]
*/
public function buildErrors(array $originalErrors, string $templatePath, ?string $compiledTemplatePath, ?string $context = null): array
{
Expand All @@ -110,7 +112,7 @@ public function buildErrors(array $originalErrors, string $templatePath, ?string
return $errors;
}

public function buildError(Error $originalError, string $templatePath, ?string $compiledTemplatePath, ?string $context = null): ?RuleError
public function buildError(Error $originalError, string $templatePath, ?string $compiledTemplatePath, ?string $context = null): ?IdentifierRuleError
{
$lineMap = $compiledTemplatePath ? $this->lineMapper->getLineMap($compiledTemplatePath) : new LineMap();

Expand All @@ -119,6 +121,7 @@ public function buildError(Error $originalError, string $templatePath, ?string $

$ruleErrorBuilder = RuleErrorBuilder::message($error->getMessage())
->file($templatePath)
->identifier('latte.error')
->metadata(array_merge($originalError->getMetadata(), [
'context' => $context === '' ? null : $context,
'is_warning' => $this->isWarning($error->getMessage()),
Expand All @@ -138,8 +141,8 @@ public function buildError(Error $originalError, string $templatePath, ?string $
}

/**
* @param RuleError[] $ruleErrors
* @return RuleError[]
* @param IdentifierRuleError[] $ruleErrors
* @return list<IdentifierRuleError>
*/
public function buildRuleErrors(array $ruleErrors): array
{
Expand Down Expand Up @@ -182,7 +185,7 @@ public function buildRuleErrors(array $ruleErrors): array
return $newRuleErrors;
}

private function errorSignature(RuleError $error): string
private function errorSignature(IdentifierRuleError $error): string
{
$values = (array)$error;
unset($values['metadata']);
Expand Down
2 changes: 1 addition & 1 deletion src/Error/Transformer/BlockParameterErrorTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ final class BlockParameterErrorTransformer implements ErrorTransformerInterface
public function transform(Error $error): Error
{
preg_match(self::BLOCK_METHOD, $error->getMessage(), $match);
if (isset($match['block'])) {
if (isset($match[0]) && isset($match['block'])) {
$block = lcfirst(str_replace('_', '-', $match['block']));
$message = $error->getMessage();
// replace method name to block name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ protected function getClassResult(ReflectionClass $reflectionClass, LatteContext
!$latteContext->methodFinder()->hasAnyAlwaysTerminated($reflectionClass->getName(), $reflectionMethod->getName())
) {
$result->addErrorFromBuilder(RuleErrorBuilder::message("Cannot resolve latte template for {$reflectionClass->getShortName()}::{$reflectionMethod->getName()}().")
->identifier('latte.cannotResolve')
->file($reflectionClass->getFileName() ?? 'unknown')
->line($reflectionMethod->getStartLine()));
}
Expand Down
15 changes: 10 additions & 5 deletions src/LatteTemplateResolver/LatteTemplateResolverResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@
use Efabrica\PHPStanLatte\LatteContext\CollectedData\CollectedTemplateRender;
use Efabrica\PHPStanLatte\Template\Template;
use Efabrica\PHPStanLatte\Template\TemplateContext;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\IdentifierRuleError;
use PHPStan\Rules\RuleErrorBuilder;

final class LatteTemplateResolverResult
{
/** @var array<string, Template> */
private array $templates = [];

/** @var RuleError[] */
/** @var IdentifierRuleError[] */
private array $errors = [];

/**
* @param Template[] $templates
* @param RuleError[] $errors
* @param IdentifierRuleError[] $errors
*/
public function __construct(array $templates = [], array $errors = [])
{
Expand All @@ -39,7 +39,7 @@ public function getTemplates(): array
}

/**
* @return RuleError[]
* @return IdentifierRuleError[]
*/
public function getErrors(): array
{
Expand All @@ -51,11 +51,14 @@ public function addTemplate(Template $template): void
$this->templates[$template->getSignatureHash()] = $template;
}

public function addError(RuleError $error): void
public function addError(IdentifierRuleError $error): void
{
$this->errors[] = $error;
}

/**
* @param RuleErrorBuilder<IdentifierRuleError> $error
*/
public function addErrorFromBuilder(RuleErrorBuilder $error): void
{
$this->errors[] = $error->build();
Expand All @@ -69,11 +72,13 @@ public function addTemplateFromRender(CollectedTemplateRender $templateRender, T
$templatePath = $templateRender->getTemplatePath();
if ($templatePath === null) {
$this->addErrorFromBuilder(RuleErrorBuilder::message('Cannot resolve rendered latte template.')
->identifier('latte.cannotResolve')
->file($templateRender->getFile())
->line($templateRender->getLine()));
return;
} elseif (!is_file($templatePath)) {
$this->addErrorFromBuilder(RuleErrorBuilder::message('Rendered latte template ' . $templatePath . ' does not exist.')
->identifier('latte.notFound')
->file($templateRender->getFile())
->line($templateRender->getLine()));
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,9 @@ protected function getClassResult(ReflectionClass $reflectionClass, LatteContext
foreach ($actionDefinition['templatePaths'] as $template) {
if ($template === null) {
$result->addErrorFromBuilder(RuleErrorBuilder::message('Cannot automatically resolve latte template from expression.')
->file($reflectionClass->getFileName() ?? 'unknown')
->line($actionDefinition['line']));
->identifier('latte.cannotResolve')
->file($reflectionClass->getFileName() ?? 'unknown')
->line($actionDefinition['line']));
continue;
}
$result->addTemplate(new Template($template, $reflectionClass->getName(), $actionName, $actionDefinition['templateContext']));
Expand All @@ -143,6 +144,7 @@ protected function getClassResult(ReflectionClass $reflectionClass, LatteContext
if ($actionDefinition['defaultTemplate'] === null) {
if (!$actionDefinition['terminated'] && $actionDefinition['templatePaths'] === []) { // might not be rendered at all (for example redirect or use set template path)
$result->addErrorFromBuilder(RuleErrorBuilder::message("Cannot resolve latte template for action $actionName")
->identifier('latte.cannotResolve')
->file($reflectionClass->getFileName() ?? 'unknown')
->line($actionDefinition['line'])
->identifier($actionName));
Expand Down
8 changes: 6 additions & 2 deletions src/LinkProcessor/PresenterActionLinkProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,12 @@ public function createLinkExpressions(string $targetName, array $linkParams, arr
if (!$presenterFactory instanceof PresenterFactory) {
return [];
}
$presenterClassName = $presenterFactory->formatPresenterClass($presenterWithModule);
if ($presenterClassName === '') {
if ($presenterWithModule) {
$presenterClassName = $presenterFactory->formatPresenterClass($presenterWithModule);
} else {
$presenterClassName = $this->actualClass;
}
if ($presenterClassName === '' || $presenterClassName === null) {
return [];
}
if (!$this->reflectionProvider->hasClass($presenterClassName)) {
Expand Down
12 changes: 8 additions & 4 deletions src/Rule/LatteTemplatesRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
use PHPStan\Analyser\Scope;
use PHPStan\Collectors\Registry as CollectorsRegistry;
use PHPStan\Node\CollectedDataNode;
use PHPStan\Rules\IdentifierRuleError;
use PHPStan\Rules\Registry as RuleRegistry;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\ShouldNotHappenException;
use Throwable;
Expand Down Expand Up @@ -123,11 +123,14 @@ public function processNode(Node $collectedDataNode, Scope $scope): array
$errors = array_merge(array_filter($errors), $this->analyseTemplates($compiledTemplates));

if (count($errors) > 1000) {
$errors[] = RuleErrorBuilder::message('Too many errors in latte.')->build();
$errors[] = RuleErrorBuilder::message('Too many errors in latte.')
->identifier('latte.tooManyErrors')
->build();
}

foreach ($this->analysedTemplatesRegistry->getReportedUnanalysedTemplates() as $templatePath) {
$errors[] = RuleErrorBuilder::message('Latte template ' . pathinfo($templatePath, PATHINFO_BASENAME) . ' was not analysed.')
->identifier('latte.unanalysedTemplate')
->file($templatePath)
->tip('Please make sure your template path is correct. If you use some non-standard way of resolving your templates, read our extension guide https://github.com/efabrica-team/phpstan-latte/blob/main/docs/extension.md#template-resolvers')
->build();
Expand All @@ -138,7 +141,7 @@ public function processNode(Node $collectedDataNode, Scope $scope): array

/**
* @param Template[] $templates
* @param array<?RuleError> $errors
* @param array<?IdentifierRuleError> $errors
* @param array<string, int> $alreadyAnalysedInParents
* @return array<string, Template> path of compiled template => Template
* @throws ShouldNotHappenException
Expand Down Expand Up @@ -170,6 +173,7 @@ private function compileTemplates(array $templates, array &$errors, array &$alre
$compiledTemplates[$compileFilePath] = $template;
} catch (CompileException $e) {
$ruleErrorBuilder = RuleErrorBuilder::message($e->getMessage())
->identifier('latte.compileError')
->file($template->getPath())
->metadata(['context' => $context]);
if ($e->sourceLine) {
Expand Down Expand Up @@ -236,7 +240,7 @@ private function compileTemplates(array $templates, array &$errors, array &$alre

/**
* @param array<string, Template> $templates
* @return RuleError[]
* @return IdentifierRuleError[]
*/
private function analyseTemplates(array $templates): array
{
Expand Down
Loading
Loading