mirror of
https://github.com/danog/psalm-plugin-symfony.git
synced 2024-12-02 09:27:46 +01:00
[Twig taint analysis] Support AbstractController::render()
and Symfony+custom twig extensions (#245)
* Allow analysing twig templates with custom extensions * Add support for AbstractController::render() and ::renderView()
This commit is contained in:
parent
f5348e9a7c
commit
44f9a695cd
@ -22,6 +22,7 @@ use Psalm\SymfonyPsalmPlugin\Twig\CachedTemplatesMapping;
|
|||||||
use Psalm\SymfonyPsalmPlugin\Twig\CachedTemplatesTainter;
|
use Psalm\SymfonyPsalmPlugin\Twig\CachedTemplatesTainter;
|
||||||
use Psalm\SymfonyPsalmPlugin\Twig\TemplateFileAnalyzer;
|
use Psalm\SymfonyPsalmPlugin\Twig\TemplateFileAnalyzer;
|
||||||
use SimpleXMLElement;
|
use SimpleXMLElement;
|
||||||
|
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||||
use Symfony\Component\HttpKernel\Kernel;
|
use Symfony\Component\HttpKernel\Kernel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,6 +66,21 @@ class Plugin implements PluginEntryPointInterface
|
|||||||
$containerMeta = new ContainerMeta((array) $config->containerXml);
|
$containerMeta = new ContainerMeta((array) $config->containerXml);
|
||||||
ContainerHandler::init($containerMeta);
|
ContainerHandler::init($containerMeta);
|
||||||
|
|
||||||
|
try {
|
||||||
|
TemplateFileAnalyzer::initExtensions(array_filter(array_map(function (array $m) use ($containerMeta) {
|
||||||
|
if ('addExtension' !== $m[0]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return $containerMeta->get($m[1][0])->getClass();
|
||||||
|
} catch (ServiceNotFoundException $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}, $containerMeta->get('twig')->getMethodCalls())));
|
||||||
|
} catch (ServiceNotFoundException $e) {
|
||||||
|
}
|
||||||
|
|
||||||
require_once __DIR__.'/Handler/ParameterBagHandler.php';
|
require_once __DIR__.'/Handler/ParameterBagHandler.php';
|
||||||
ParameterBagHandler::init($containerMeta);
|
ParameterBagHandler::init($containerMeta);
|
||||||
$api->registerHooksFromClass(ParameterBagHandler::class);
|
$api->registerHooksFromClass(ParameterBagHandler::class);
|
||||||
|
@ -17,6 +17,7 @@ use Psalm\StatementsSource;
|
|||||||
use Psalm\SymfonyPsalmPlugin\Exception\TemplateNameUnresolvedException;
|
use Psalm\SymfonyPsalmPlugin\Exception\TemplateNameUnresolvedException;
|
||||||
use Psalm\Type\Atomic\TKeyedArray;
|
use Psalm\Type\Atomic\TKeyedArray;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Twig\Environment;
|
use Twig\Environment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,7 +35,7 @@ class AnalyzedTemplatesTainter implements AfterMethodCallAnalysisInterface
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
null === $codebase->taint_flow_graph
|
null === $codebase->taint_flow_graph
|
||||||
|| !$expr instanceof MethodCall || $method_id !== Environment::class.'::render' || empty($expr->args)
|
|| !$expr instanceof MethodCall || !\in_array($method_id, [Environment::class.'::render', AbstractController::class.'::render', AbstractController::class.'::renderView'], true) || empty($expr->args)
|
||||||
|| !isset($expr->args[0]->value)
|
|| !isset($expr->args[0]->value)
|
||||||
|| !isset($expr->args[1]->value)
|
|| !isset($expr->args[1]->value)
|
||||||
) {
|
) {
|
||||||
|
@ -7,6 +7,7 @@ namespace Psalm\SymfonyPsalmPlugin\Twig;
|
|||||||
use Psalm\Context as PsalmContext;
|
use Psalm\Context as PsalmContext;
|
||||||
use Psalm\Internal\Analyzer\FileAnalyzer;
|
use Psalm\Internal\Analyzer\FileAnalyzer;
|
||||||
use Twig\Environment;
|
use Twig\Environment;
|
||||||
|
use Twig\Extension\ExtensionInterface;
|
||||||
use Twig\Loader\FilesystemLoader;
|
use Twig\Loader\FilesystemLoader;
|
||||||
use Twig\NodeTraverser;
|
use Twig\NodeTraverser;
|
||||||
|
|
||||||
@ -22,6 +23,16 @@ class TemplateFileAnalyzer extends FileAnalyzer
|
|||||||
*/
|
*/
|
||||||
private static $rootPath = 'templates';
|
private static $rootPath = 'templates';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var list<class-string>
|
||||||
|
*/
|
||||||
|
private static $extensionClasses = [];
|
||||||
|
|
||||||
|
public static function initExtensions(array $extensionClasses): void
|
||||||
|
{
|
||||||
|
self::$extensionClasses = $extensionClasses;
|
||||||
|
}
|
||||||
|
|
||||||
public function analyze(
|
public function analyze(
|
||||||
PsalmContext $file_context = null,
|
PsalmContext $file_context = null,
|
||||||
PsalmContext $global_context = null
|
PsalmContext $global_context = null
|
||||||
@ -41,6 +52,11 @@ class TemplateFileAnalyzer extends FileAnalyzer
|
|||||||
'optimizations' => 0,
|
'optimizations' => 0,
|
||||||
'strict_variables' => false,
|
'strict_variables' => false,
|
||||||
]);
|
]);
|
||||||
|
foreach (self::$extensionClasses as $extensionClass) {
|
||||||
|
if (class_exists($extensionClass) && is_a($extensionClass, ExtensionInterface::class, true)) {
|
||||||
|
$twig->addExtension((new \ReflectionClass($extensionClass))->newInstanceWithoutConstructor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$local_file_name = str_replace(self::$rootPath.'/', '', $this->file_name);
|
$local_file_name = str_replace(self::$rootPath.'/', '', $this->file_name);
|
||||||
$twig_source = $loader->getSourceContext($local_file_name);
|
$twig_source = $loader->getSourceContext($local_file_name);
|
||||||
|
Loading…
Reference in New Issue
Block a user