mirror of
https://github.com/danog/psalm-plugin-symfony.git
synced 2024-11-29 20:19:09 +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\TemplateFileAnalyzer;
|
||||
use SimpleXMLElement;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
|
||||
/**
|
||||
@ -65,6 +66,21 @@ class Plugin implements PluginEntryPointInterface
|
||||
$containerMeta = new ContainerMeta((array) $config->containerXml);
|
||||
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';
|
||||
ParameterBagHandler::init($containerMeta);
|
||||
$api->registerHooksFromClass(ParameterBagHandler::class);
|
||||
|
@ -17,6 +17,7 @@ use Psalm\StatementsSource;
|
||||
use Psalm\SymfonyPsalmPlugin\Exception\TemplateNameUnresolvedException;
|
||||
use Psalm\Type\Atomic\TKeyedArray;
|
||||
use RuntimeException;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Twig\Environment;
|
||||
|
||||
/**
|
||||
@ -34,7 +35,7 @@ class AnalyzedTemplatesTainter implements AfterMethodCallAnalysisInterface
|
||||
|
||||
if (
|
||||
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[1]->value)
|
||||
) {
|
||||
|
@ -7,6 +7,7 @@ namespace Psalm\SymfonyPsalmPlugin\Twig;
|
||||
use Psalm\Context as PsalmContext;
|
||||
use Psalm\Internal\Analyzer\FileAnalyzer;
|
||||
use Twig\Environment;
|
||||
use Twig\Extension\ExtensionInterface;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
use Twig\NodeTraverser;
|
||||
|
||||
@ -22,6 +23,16 @@ class TemplateFileAnalyzer extends FileAnalyzer
|
||||
*/
|
||||
private static $rootPath = 'templates';
|
||||
|
||||
/**
|
||||
* @var list<class-string>
|
||||
*/
|
||||
private static $extensionClasses = [];
|
||||
|
||||
public static function initExtensions(array $extensionClasses): void
|
||||
{
|
||||
self::$extensionClasses = $extensionClasses;
|
||||
}
|
||||
|
||||
public function analyze(
|
||||
PsalmContext $file_context = null,
|
||||
PsalmContext $global_context = null
|
||||
@ -41,6 +52,11 @@ class TemplateFileAnalyzer extends FileAnalyzer
|
||||
'optimizations' => 0,
|
||||
'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);
|
||||
$twig_source = $loader->getSourceContext($local_file_name);
|
||||
|
Loading…
Reference in New Issue
Block a user