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
39 changes: 19 additions & 20 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ parameters:
path: src/Compiler.php

-
message: '#^Binary operation "\." between ''\<\?php \$'' and mixed results in an error\.$#'
message: '#^Binary operation "\." between ''\$this\-\>tag\-\>'' and mixed results in an error\.$#'
identifier: binaryOp.invalid
count: 1
path: src/Compiler.php

-
message: '#^Binary operation "\." between ''\<\?php \$this\-…'' and mixed results in an error\.$#'
message: '#^Binary operation "\." between ''\<\?php \$'' and mixed results in an error\.$#'
identifier: binaryOp.invalid
count: 1
path: src/Compiler.php
Expand Down Expand Up @@ -141,7 +141,7 @@ parameters:
-
message: '#^Binary operation "\." between mixed and string results in an error\.$#'
identifier: binaryOp.invalid
count: 3
count: 4
path: src/Compiler.php

-
Expand Down Expand Up @@ -186,6 +186,12 @@ parameters:
count: 1
path: src/Compiler.php

-
message: '#^Call to method get\(\) on an unknown class Phalcon\\Di\\DiInterface\.$#'
identifier: class.notFound
count: 1
path: src/Compiler.php

-
message: '#^Call to method getViewsDir\(\) on an unknown class Phalcon\\Mvc\\ViewBaseInterface\.$#'
identifier: class.notFound
Expand All @@ -195,7 +201,7 @@ parameters:
-
message: '#^Call to method has\(\) on an unknown class Phalcon\\Di\\DiInterface\.$#'
identifier: class.notFound
count: 1
count: 2
path: src/Compiler.php

-
Expand Down Expand Up @@ -237,7 +243,7 @@ parameters:
-
message: '#^Cannot access offset ''type'' on mixed\.$#'
identifier: offsetAccess.nonOffsetAccessible
count: 7
count: 9
path: src/Compiler.php

-
Expand Down Expand Up @@ -270,6 +276,12 @@ parameters:
count: 1
path: src/Compiler.php

-
message: '#^Cannot call method has\(\) on mixed\.$#'
identifier: method.nonObject
count: 1
path: src/Compiler.php

-
message: '#^Instanceof between string and Closure will always evaluate to false\.$#'
identifier: instanceof.alwaysFalse
Expand Down Expand Up @@ -567,7 +579,7 @@ parameters:
-
message: '#^Parameter \#1 \$expr of method Phalcon\\Volt\\Compiler\:\:expression\(\) expects array, mixed given\.$#'
identifier: argument.type
count: 31
count: 32
path: src/Compiler.php

-
Expand Down Expand Up @@ -631,7 +643,7 @@ parameters:
path: src/Compiler.php

-
message: '#^Parameter \#3 \$subject of function str_replace expects array\<string\>\|string, mixed given\.$#'
message: '#^Parameter \#3 \$subject of function preg_replace expects array\<float\|int\|string\>\|string, mixed given\.$#'
identifier: argument.type
count: 1
path: src/Compiler.php
Expand Down Expand Up @@ -768,12 +780,6 @@ parameters:
count: 1
path: src/Compiler.php

-
message: '#^Unreachable statement \- code above always terminates\.$#'
identifier: deadCode.unreachable
count: 1
path: src/Scanner/Scanner.php

-
message: '#^Property Phalcon\\Volt\\Tokens\:\:\$names type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
Expand Down Expand Up @@ -845,10 +851,3 @@ parameters:
identifier: notIdentical.alwaysTrue
count: 1
path: src/Utils.php

-
message: '#^Possibly invalid array key type string\|null\.$#'
identifier: offsetAccess.invalidOffset
count: 2
path: src/Compiler.php
reportUnmatched: false
4 changes: 4 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ includes:
- phpstan-baseline.neon

parameters:
# Pin the analyzed PHP version so the CI matrix (8.1-8.5) produces
# identical results regardless of the runtime PHP; keeps one baseline valid
# on every leg.
phpVersion: 80100
bootstrapFiles:
- phpunit.php
paths:
Expand Down
84 changes: 57 additions & 27 deletions src/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -811,13 +811,13 @@ public function compileEcho(array $statement): string
$expr = $statement['expr'];
$exprCode = $this->expression($expr);

if ($expr == Opcode::FCALL->value) {
if ($expr['type'] == Opcode::FCALL->value) {
if ($this->isTagFactory($expr)) {
$exprCode = $this->expression($expr, true);
}

$name = $expr['name'];
if ($name == Opcode::IDENTIFIER->value) {
if ($name['type'] == Opcode::IDENTIFIER->value) {
/**
* super() is a function however the return of this function
* must be output as it is
Expand All @@ -832,7 +832,7 @@ public function compileEcho(array $statement): string
* Echo statement
*/
if (true === $this->autoescape) {
return '<?= $this->escaper->escapeHtml(' . $exprCode . ')';
return '<?= $this->escaper->html(' . $exprCode . ') ?>';
}

return '<?= ' . $exprCode . ' ?>';
Expand Down Expand Up @@ -1014,7 +1014,7 @@ public function compileForeach(array $statement, bool $extendsMode = false): str
* Generate the loop context for the "foreach"
*/
if (isset($loopContext[$level])) {
$compilation .= '<?php $' . $prefixLevel . 'iterator = ' . $exprCode;
$compilation .= '<?php $' . $prefixLevel . 'iterator = ' . $exprCode . '; ';
$compilation .= '$' . $prefixLevel . 'incr = 0; ';
$compilation .= '$' . $prefixLevel . 'loop = new \stdClass(); ';
$compilation .= '$' . $prefixLevel . 'loop->self = &$' . $prefixLevel . 'loop; ';
Expand Down Expand Up @@ -1203,10 +1203,10 @@ public function compileInclude(array $statement): string
* Use partial
*/
if (!isset($statement['params'])) {
return '<?php $this->partial(' . $path . ')';
return '<?php $this->partial(' . $path . '); ?>';
}

return '<?php $this->partial(' . $pathExpr . ', ' . $this->expression($statement['params']) . ')';
return '<?php $this->partial(' . $path . ', ' . $this->expression($statement['params']) . '); ?>';
}

/**
Expand Down Expand Up @@ -1235,7 +1235,7 @@ public function compileMacro(array $statement, bool $extendsMode): string
* Register the macro
*/
$this->macros[$name] = $name;
$macroName = '$this->macros[\'' . $name . '\]';
$macroName = '$this->macros[\'' . $name . '\']';
$code = '<?php ';

if (!isset($statement['parameters'])) {
Expand Down Expand Up @@ -1263,7 +1263,7 @@ public function compileMacro(array $statement, bool $extendsMode): string
. $name . '" was called without parameter ' . $variableName . '\'); ';
}

$code .= ' } ) ';
$code .= ' } } ';
}

$code .= ' ?>';
Expand Down Expand Up @@ -1665,7 +1665,7 @@ final public function expression(array $expr, bool $doubleQuotes = false): strin
break;

case Opcode::ARRAY->value:
$exprCode = isset($expr['left']) ? '[' . $leftCode . ']' : [];
$exprCode = isset($expr['left']) ? '[' . $leftCode . ']' : '[]';
break;

case 258:
Expand Down Expand Up @@ -1717,19 +1717,19 @@ final public function expression(array $expr, bool $doubleQuotes = false): strin
break;

case 272:
$exprCode = $leftCode .= ' == ' . $rightCode;
$exprCode = $leftCode . ' == ' . $rightCode;
break;

case 273:
$exprCode = $leftCode .= ' != ' . $rightCode;
$exprCode = $leftCode . ' != ' . $rightCode;
break;

case 274:
$exprCode = $leftCode .= ' === ' . $rightCode;
$exprCode = $leftCode . ' === ' . $rightCode;
break;

case 275:
$exprCode = $leftCode .= ' !== ' . $rightCode;
$exprCode = $leftCode . ' !== ' . $rightCode;
break;

case Opcode::RANGE->value:
Expand Down Expand Up @@ -2018,15 +2018,27 @@ public function functionCall(array $expr, bool $doubleQuotes = false): string
return "''";
}

/**
* @todo This needs a lot of refactoring and will break a lot of
* applications if removed
*/
if ($name === 'preload') {
return '$this->preload(' . $arguments . ')';
}

/**
* Check if it's a method in Phalcon\Tag
* @todo This needs a lot of refactoring and will break a lot of
* applications if removed
*/
$method = lcfirst(
//\Phalcon\Text::camelize($name)
ucwords($name)
str_replace(['_', '-'], '', ucwords($name, '_-'))
);

$arrayHelpers = [
'link_to' => true,
'image' => true,
'form' => true,
'form_legacy' => true,
'submit_button' => true,
'radio_field' => true,
'check_field' => true,
Expand All @@ -2042,15 +2054,32 @@ public function functionCall(array $expr, bool $doubleQuotes = false): string
"image_input" => true,
];

/**
* Check if it's a method in Phalcon\Tag
*/
if (method_exists('Phalcon\\Tag', $method)) {
if (isset($arrayHelpers[$name])) {
return '$this->tag->' . $method . '([' . $arguments . '])';
return '\\Phalcon\\Tag::' . $method . '([' . $arguments . '])';
}

return '$this->tag->' . $method . '(' . $arguments . ')';
return '\\Phalcon\\Tag::' . $method . '(' . $arguments . ')';
}

/**
* These are for the TagFactory
*/
if ($this->container !== null && true === $this->container->has('tag')) {
$tagService = $this->container->get('tag');
if (true === $tagService->has($name)) {
/**
* recalculate the arguments because we need them double
* quoted
*/
if (isset($expr['arguments'])) {
$arguments = $this->expression($expr['arguments'], true);
} else {
$arguments = '';
}

return '$this->tag->' . $name . '(' . $arguments . ')';
}
}

/**
Expand Down Expand Up @@ -2080,11 +2109,11 @@ public function functionCall(array $expr, bool $doubleQuotes = false): string
}

if ($name === 'version') {
return 'Phalcon\\Version::get()';
return '(new Phalcon\\Support\\Version)->get()';
}

if ($name === 'version_id') {
return 'Phalcon\\Version::getId()';
return '(new Phalcon\\Support\\Version)->getId()';
}

/**
Expand Down Expand Up @@ -2349,9 +2378,8 @@ protected function getFinalPath(string $path): string
$viewsDirs = $this->view->getViewsDir();
if (is_array($viewsDirs)) {
foreach ($viewsDirs as $viewsDir) {
$path = $viewsDir . $path;
if (true === file_exists($path)) {
return $path;
if (true === file_exists($viewsDir . $path)) {
return $viewsDir . $path;
}
}

Expand Down Expand Up @@ -2752,7 +2780,9 @@ final protected function statementList(array $statements, bool $extendsMode = fa
*/
switch ($type) {
case Opcode::RAW_FRAGMENT->value:
$compilation .= $statement["value"];
if (isset($statement['value'])) {
$compilation .= $statement['value'];
}
break;

case Opcode::IF->value:
Expand Down
22 changes: 19 additions & 3 deletions src/Parser/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public function parse(string $code, string $templatePath = 'eval code'): array

$state = $parserStatus->getState();
$scannerStatus = ScannerStatus::OK;
$prevToken = 0;

while (($scannerStatus = $scanner->scanForToken()) === ScannerStatus::OK) {
$token = $scanner->getToken();
Expand Down Expand Up @@ -131,7 +132,8 @@ public function parse(string $code, string $templatePath = 'eval code'): array
$parser,
$parserStatus,
$token,
$state
$state,
$prevToken
),
CompilerOpcode::ENDSWITCH->value => $this->handleEndswitch($parser, $parserStatus, $state),
CompilerOpcode::RAW_FRAGMENT->value => $this->handleRawFragment(
Expand Down Expand Up @@ -181,6 +183,11 @@ public function parse(string $code, string $templatePath = 'eval code'): array
break;
}

// whitespace inside delimiters arrives as IGNORE; skip it
if ($opcode !== CompilerOpcode::IGNORE->value) {
$prevToken = $opcode;
}

$state->setEnd($state->getStart());
}

Expand Down Expand Up @@ -285,13 +292,22 @@ private function handleCase(phvolt_Parser $parser, Status $parserStatus): void
$parser->phvolt_(Opcode::CASE->value);
}

/**
* "default" is the {% default %} clause only when it is inside a switch
* and directly follows the opening delimiter; anywhere else (e.g. the
* |default() filter) it is a plain identifier.
*/
private function handleDefault(
phvolt_Parser $parser,
Status $parserStatus,
Token $token,
State $state
State $state,
int $prevToken
): void {
if ($state->getSwitchLevel() !== 0) {
if (
$state->getSwitchLevel() !== 0 &&
$prevToken === CompilerOpcode::OPEN_DELIMITER->value
) {
$parser->phvolt_(Opcode::DEFAULT->value);

return;
Expand Down
2 changes: 1 addition & 1 deletion src/Scanner/Scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,7 @@ public function scanForToken(): ScannerStatus
}

vv81:
$this->state->setCursor($this->state->getMarker());
$this->state->setCursor((int) $this->state->getMarker());
switch ($vvaccept) {
case 0:
goto vv5;
Expand Down
Loading