diff --git a/conf/config.neon b/conf/config.neon
index 6a8f4d6897..583cceac81 100644
--- a/conf/config.neon
+++ b/conf/config.neon
@@ -302,6 +302,16 @@ services:
 		tags:
 			- phpstan.parser.richParserNodeVisitor
 
+	-
+		class: PHPStan\Parser\VariadicMethodsVisitor
+		tags:
+			- phpstan.parser.richParserNodeVisitor
+
+	-
+		class: PHPStan\Parser\VariadicFunctionsVisitor
+		tags:
+			- phpstan.parser.richParserNodeVisitor
+
 	-
 		class: PHPStan\Node\Printer\ExprPrinter
 
@@ -634,9 +644,6 @@ services:
 		tags:
 			- phpstan.diagnoseExtension
 
-	-
-		class: PHPStan\Parser\FunctionCallStatementFinder
-
 	-
 		class: PHPStan\Process\CpuCoreCounter
 
diff --git a/src/Parser/FunctionCallStatementFinder.php b/src/Parser/FunctionCallStatementFinder.php
deleted file mode 100644
index 9a4c1dd6bb..0000000000
--- a/src/Parser/FunctionCallStatementFinder.php
+++ /dev/null
@@ -1,47 +0,0 @@
-<?php declare(strict_types = 1);
-
-namespace PHPStan\Parser;
-
-use PhpParser\Node;
-use PhpParser\Node\Expr\FuncCall;
-use PhpParser\Node\Name;
-use function in_array;
-use function is_array;
-
-final class FunctionCallStatementFinder
-{
-
-	/**
-	 * @param string[] $functionNames
-	 * @param mixed $statements
-	 */
-	public function findFunctionCallInStatements(array $functionNames, $statements): ?Node
-	{
-		foreach ($statements as $statement) {
-			if (is_array($statement)) {
-				$result = $this->findFunctionCallInStatements($functionNames, $statement);
-				if ($result !== null) {
-					return $result;
-				}
-			}
-
-			if (!($statement instanceof Node)) {
-				continue;
-			}
-
-			if ($statement instanceof FuncCall && $statement->name instanceof Name) {
-				if (in_array((string) $statement->name, $functionNames, true)) {
-					return $statement;
-				}
-			}
-
-			$result = $this->findFunctionCallInStatements($functionNames, $statement);
-			if ($result !== null) {
-				return $result;
-			}
-		}
-
-		return null;
-	}
-
-}
diff --git a/src/Parser/SimpleParser.php b/src/Parser/SimpleParser.php
index 713c1502ef..8fbd112742 100644
--- a/src/Parser/SimpleParser.php
+++ b/src/Parser/SimpleParser.php
@@ -15,6 +15,8 @@ final class SimpleParser implements Parser
 	public function __construct(
 		private \PhpParser\Parser $parser,
 		private NameResolver $nameResolver,
+		private VariadicMethodsVisitor $variadicMethodsVisitor,
+		private VariadicFunctionsVisitor $variadicFunctionsVisitor,
 	)
 	{
 	}
@@ -48,6 +50,8 @@ public function parseString(string $sourceCode): array
 
 		$nodeTraverser = new NodeTraverser();
 		$nodeTraverser->addVisitor($this->nameResolver);
+		$nodeTraverser->addVisitor($this->variadicMethodsVisitor);
+		$nodeTraverser->addVisitor($this->variadicFunctionsVisitor);
 
 		/** @var array<Node\Stmt> */
 		return $nodeTraverser->traverse($nodes);
diff --git a/src/Parser/VariadicFunctionsVisitor.php b/src/Parser/VariadicFunctionsVisitor.php
new file mode 100644
index 0000000000..5276d0eb47
--- /dev/null
+++ b/src/Parser/VariadicFunctionsVisitor.php
@@ -0,0 +1,94 @@
+<?php declare(strict_types = 1);
+
+namespace PHPStan\Parser;
+
+use PhpParser\Node;
+use PhpParser\Node\Name;
+use PhpParser\NodeVisitorAbstract;
+use PHPStan\Reflection\ParametersAcceptor;
+use function array_filter;
+use function array_key_exists;
+use function in_array;
+
+final class VariadicFunctionsVisitor extends NodeVisitorAbstract
+{
+
+	private ?Node $topNode = null;
+
+	private ?string $inNamespace = null;
+
+	private ?string $inFunction = null;
+
+	/** @var array<string, bool> */
+	public static array $cache = [];
+
+	/** @var array<string, bool> */
+	private array $variadicFunctions = [];
+
+	public const ATTRIBUTE_NAME = 'variadicFunctions';
+
+	public function beforeTraverse(array $nodes): ?array
+	{
+		$this->topNode = null;
+		$this->variadicFunctions = [];
+		$this->inNamespace = null;
+		$this->inFunction = null;
+
+		return null;
+	}
+
+	public function enterNode(Node $node): ?Node
+	{
+		if ($this->topNode === null) {
+			$this->topNode = $node;
+		}
+
+		if ($node instanceof Node\Stmt\Namespace_ && $node->name !== null) {
+			$this->inNamespace = $node->name->toString();
+		}
+
+		if ($node instanceof Node\Stmt\Function_) {
+			$this->inFunction = $this->inNamespace !== null ? $this->inNamespace . '\\' . $node->name->name : $node->name->name;
+		}
+
+		if (
+			$this->inFunction !== null
+			&& $node instanceof Node\Expr\FuncCall
+			&& $node->name instanceof Name
+			&& in_array((string) $node->name, ParametersAcceptor::VARIADIC_FUNCTIONS, true)
+			&& !array_key_exists($this->inFunction, $this->variadicFunctions)
+		) {
+			$this->variadicFunctions[$this->inFunction] = true;
+		}
+
+		return null;
+	}
+
+	public function leaveNode(Node $node): ?Node
+	{
+		if ($node instanceof Node\Stmt\Namespace_ && $node->name !== null) {
+			$this->inNamespace = null;
+		}
+
+		if ($node instanceof Node\Stmt\Function_ && $this->inFunction !== null) {
+			$this->variadicFunctions[$this->inFunction] ??= false;
+			$this->inFunction = null;
+		}
+
+		return null;
+	}
+
+	public function afterTraverse(array $nodes): ?array
+	{
+		if ($this->topNode !== null && $this->variadicFunctions !== []) {
+			foreach ($this->variadicFunctions as $name => $variadic) {
+				self::$cache[$name] = $variadic;
+			}
+			$functions = array_filter($this->variadicFunctions, static fn (bool $variadic) => $variadic);
+			$this->topNode->setAttribute(self::ATTRIBUTE_NAME, $functions);
+		}
+
+		return null;
+	}
+
+}
diff --git a/src/Parser/VariadicMethodsVisitor.php b/src/Parser/VariadicMethodsVisitor.php
new file mode 100644
index 0000000000..50882efc54
--- /dev/null
+++ b/src/Parser/VariadicMethodsVisitor.php
@@ -0,0 +1,125 @@
+<?php declare(strict_types = 1);
+
+namespace PHPStan\Parser;
+
+use PhpParser\Node;
+use PhpParser\Node\Name;
+use PhpParser\Node\Stmt\ClassMethod;
+use PhpParser\NodeVisitorAbstract;
+use PHPStan\Reflection\ParametersAcceptor;
+use function array_key_exists;
+use function array_pop;
+use function count;
+use function in_array;
+use function sprintf;
+
+final class VariadicMethodsVisitor extends NodeVisitorAbstract
+{
+
+	public const ATTRIBUTE_NAME = 'variadicMethods';
+
+	public const ANONYMOUS_CLASS_PREFIX = 'class@anonymous';
+
+	private ?Node $topNode = null;
+
+	private ?string $inNamespace = null;
+
+	/** @var array<string> */
+	private array $classStack = [];
+
+	private ?string $inMethod = null;
+
+	/** @var array<string, array<string, true>> */
+	public static array $cache = [];
+
+	/** @var array<string, array<string, true>> */
+	private array $variadicMethods = [];
+
+	public function beforeTraverse(array $nodes): ?array
+	{
+		$this->topNode = null;
+		$this->variadicMethods = [];
+		$this->inNamespace = null;
+		$this->classStack = [];
+		$this->inMethod = null;
+
+		return null;
+	}
+
+	public function enterNode(Node $node): ?Node
+	{
+		if ($this->topNode === null) {
+			$this->topNode = $node;
+		}
+
+		if ($node instanceof Node\Stmt\Namespace_ && $node->name !== null) {
+			$this->inNamespace = $node->name->toString();
+		}
+
+		if ($node instanceof Node\Stmt\ClassLike) {
+			if (!$node->name instanceof Node\Identifier) {
+				$className = sprintf('%s:%s:%s', self::ANONYMOUS_CLASS_PREFIX, $node->getStartLine(), $node->getEndLine());
+				$this->classStack[] = $className;
+			} else {
+				$className = $node->name->name;
+				$this->classStack[] = $this->inNamespace !== null ? $this->inNamespace . '\\' . $className : $className;
+			}
+		}
+
+		if ($node instanceof ClassMethod) {
+			$this->inMethod = $node->name->name;
+		}
+
+		if (
+			$this->inMethod !== null
+			&& $node instanceof Node\Expr\FuncCall
+			&& $node->name instanceof Name
+			&& in_array((string) $node->name, ParametersAcceptor::VARIADIC_FUNCTIONS, true)
+		) {
+			$lastClass = $this->classStack[count($this->classStack) - 1] ?? null;
+			if ($lastClass !== null) {
+				if (
+					!array_key_exists($lastClass, $this->variadicMethods)
+					|| !array_key_exists($this->inMethod, $this->variadicMethods[$lastClass])
+				) {
+					$this->variadicMethods[$lastClass][$this->inMethod] = true;
+				}
+			}
+
+		}
+
+		return null;
+	}
+
+	public function leaveNode(Node $node): ?Node
+	{
+		if ($node instanceof ClassMethod) {
+			$this->inMethod = null;
+		}
+
+		if ($node instanceof Node\Stmt\ClassLike) {
+			array_pop($this->classStack);
+		}
+
+		if ($node instanceof Node\Stmt\Namespace_ && $node->name !== null) {
+			$this->inNamespace = null;
+		}
+
+		return null;
+	}
+
+	public function afterTraverse(array $nodes): ?array
+	{
+		if ($this->topNode !== null && $this->variadicMethods !== []) {
+			foreach ($this->variadicMethods as $class => $methods) {
+				foreach ($methods as $name => $variadic) {
+					self::$cache[$class][$name] = $variadic;
+				}
+			}
+			$this->topNode->setAttribute(self::ATTRIBUTE_NAME, $this->variadicMethods);
+		}
+
+		return null;
+	}
+
+}
diff --git a/src/Reflection/Php/PhpFunctionReflection.php b/src/Reflection/Php/PhpFunctionReflection.php
index e28f19f879..e8fbc2e824 100644
--- a/src/Reflection/Php/PhpFunctionReflection.php
+++ b/src/Reflection/Php/PhpFunctionReflection.php
@@ -2,20 +2,16 @@
 
 namespace PHPStan\Reflection\Php;
 
-use PhpParser\Node;
-use PhpParser\Node\Stmt\Function_;
 use PHPStan\BetterReflection\Reflection\Adapter\ReflectionFunction;
 use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter;
-use PHPStan\Cache\Cache;
-use PHPStan\Parser\FunctionCallStatementFinder;
 use PHPStan\Parser\Parser;
+use PHPStan\Parser\VariadicFunctionsVisitor;
 use PHPStan\Reflection\Assertions;
 use PHPStan\Reflection\ExtendedFunctionVariant;
 use PHPStan\Reflection\ExtendedParameterReflection;
 use PHPStan\Reflection\ExtendedParametersAcceptor;
 use PHPStan\Reflection\FunctionReflection;
 use PHPStan\Reflection\InitializerExprTypeResolver;
-use PHPStan\Reflection\ParametersAcceptor;
 use PHPStan\TrinaryLogic;
 use PHPStan\Type\Generic\TemplateTypeMap;
 use PHPStan\Type\MixedType;
@@ -23,11 +19,9 @@
 use PHPStan\Type\TypehintHelper;
 use function array_key_exists;
 use function array_map;
-use function filemtime;
+use function count;
 use function is_array;
 use function is_file;
-use function sprintf;
-use function time;
 
 final class PhpFunctionReflection implements FunctionReflection
 {
@@ -35,6 +29,8 @@ final class PhpFunctionReflection implements FunctionReflection
 	/** @var list<ExtendedFunctionVariant>|null */
 	private ?array $variants = null;
 
+	private ?bool $containsVariadicCalls = null;
+
 	/**
 	 * @param array<string, Type> $phpDocParameterTypes
 	 * @param array<string, Type> $phpDocParameterOutTypes
@@ -45,8 +41,6 @@ public function __construct(
 		private InitializerExprTypeResolver $initializerExprTypeResolver,
 		private ReflectionFunction $reflection,
 		private Parser $parser,
-		private FunctionCallStatementFinder $functionCallStatementFinder,
-		private Cache $cache,
 		private TemplateTypeMap $templateTypeMap,
 		private array $phpDocParameterTypes,
 		private ?Type $phpDocReturnType,
@@ -139,67 +133,33 @@ private function getParameters(): array
 	private function isVariadic(): bool
 	{
 		$isNativelyVariadic = $this->reflection->isVariadic();
-		if (!$isNativelyVariadic && $this->reflection
-			->getFileName() !== false) {
-			$fileName = $this->reflection->getFileName();
-			if (is_file($fileName)) {
-				$functionName = $this->reflection->getName();
-				$modifiedTime = filemtime($fileName);
-				if ($modifiedTime === false) {
-					$modifiedTime = time();
-				}
-				$variableCacheKey = sprintf('%d-v4', $modifiedTime);
-				$key = sprintf('variadic-function-%s-%s', $functionName, $fileName);
-				$cachedResult = $this->cache->load($key, $variableCacheKey);
-				if ($cachedResult === null) {
-					$nodes = $this->parser->parseFile($fileName);
-					$result = !$this->containsVariadicFunction($nodes)->no();
-					$this->cache->save($key, $variableCacheKey, $result);
-					return $result;
-				}
+		if (!$isNativelyVariadic && $this->reflection->getFileName() !== false && !$this->isBuiltin()) {
+			$filename = $this->reflection->getFileName();
 
-				return $cachedResult;
+			if ($this->containsVariadicCalls !== null) {
+				return $this->containsVariadicCalls;
 			}
-		}
-
-		return $isNativelyVariadic;
-	}
 
-	/**
-	 * @param Node[]|scalar[]|Node $node
-	 */
-	private function containsVariadicFunction(array|Node $node): TrinaryLogic
-	{
-		$result = TrinaryLogic::createMaybe();
-
-		if ($node instanceof Node) {
-			if ($node instanceof Function_) {
-				$functionName = (string) $node->namespacedName;
-
-				if ($functionName === $this->reflection->getName()) {
-					return TrinaryLogic::createFromBoolean($this->isFunctionNodeVariadic($node));
-				}
+			if (array_key_exists($this->reflection->getName(), VariadicFunctionsVisitor::$cache)) {
+				return $this->containsVariadicCalls = VariadicFunctionsVisitor::$cache[$this->reflection->getName()];
 			}
 
-			foreach ($node->getSubNodeNames() as $subNodeName) {
-				$innerNode = $node->{$subNodeName};
-				if (!$innerNode instanceof Node && !is_array($innerNode)) {
-					continue;
-				}
+			$nodes = $this->parser->parseFile($filename);
+			if (count($nodes) > 0) {
+				$variadicFunctions = $nodes[0]->getAttribute(VariadicFunctionsVisitor::ATTRIBUTE_NAME);
 
-				$result = $result->and($this->containsVariadicFunction($innerNode));
-			}
-		} elseif (is_array($node)) {
-			foreach ($node as $subNode) {
-				if (!$subNode instanceof Node) {
-					continue;
+				if (
+					is_array($variadicFunctions)
+					&& array_key_exists($this->reflection->getName(), $variadicFunctions)
+				) {
+					return $this->containsVariadicCalls = $variadicFunctions[$this->reflection->getName()];
 				}
-
-				$result = $result->and($this->containsVariadicFunction($subNode));
 			}
+
+			return $this->containsVariadicCalls = false;
 		}
 
-		return $result;
+		return $isNativelyVariadic;
 	}
 
 	private function getReturnType(): Type
@@ -296,19 +256,4 @@ public function acceptsNamedArguments(): TrinaryLogic
 		return TrinaryLogic::createFromBoolean($this->acceptsNamedArguments);
 	}
 
-	private function isFunctionNodeVariadic(Function_ $node): bool
-	{
-		foreach ($node->params as $parameter) {
-			if ($parameter->variadic) {
-				return true;
-			}
-		}
-
-		if ($this->functionCallStatementFinder->findFunctionCallInStatements(ParametersAcceptor::VARIADIC_FUNCTIONS, $node->getStmts()) !== null) {
-			return true;
-		}
-
-		return false;
-	}
-
 }
diff --git a/src/Reflection/Php/PhpMethodReflection.php b/src/Reflection/Php/PhpMethodReflection.php
index d0e008a7ed..53f5d80054 100644
--- a/src/Reflection/Php/PhpMethodReflection.php
+++ b/src/Reflection/Php/PhpMethodReflection.php
@@ -2,16 +2,10 @@
 
 namespace PHPStan\Reflection\Php;
 
-use PhpParser\Node;
-use PhpParser\Node\Stmt\ClassMethod;
-use PhpParser\Node\Stmt\Declare_;
-use PhpParser\Node\Stmt\Function_;
-use PhpParser\Node\Stmt\Namespace_;
 use PHPStan\BetterReflection\Reflection\Adapter\ReflectionMethod;
 use PHPStan\BetterReflection\Reflection\Adapter\ReflectionParameter;
-use PHPStan\Cache\Cache;
-use PHPStan\Parser\FunctionCallStatementFinder;
 use PHPStan\Parser\Parser;
+use PHPStan\Parser\VariadicMethodsVisitor;
 use PHPStan\Reflection\Assertions;
 use PHPStan\Reflection\ClassMemberReflection;
 use PHPStan\Reflection\ClassReflection;
@@ -21,7 +15,6 @@
 use PHPStan\Reflection\ExtendedParametersAcceptor;
 use PHPStan\Reflection\InitializerExprTypeResolver;
 use PHPStan\Reflection\MethodPrototypeReflection;
-use PHPStan\Reflection\ParametersAcceptor;
 use PHPStan\Reflection\ReflectionProvider;
 use PHPStan\TrinaryLogic;
 use PHPStan\Type\ArrayType;
@@ -36,14 +29,14 @@
 use PHPStan\Type\TypehintHelper;
 use PHPStan\Type\VoidType;
 use ReflectionException;
+use function array_key_exists;
 use function array_map;
+use function count;
 use function explode;
-use function filemtime;
 use function in_array;
-use function is_bool;
+use function is_array;
 use function sprintf;
 use function strtolower;
-use function time;
 use const PHP_VERSION_ID;
 
 /**
@@ -62,6 +55,8 @@ final class PhpMethodReflection implements ExtendedMethodReflection
 	/** @var list<ExtendedFunctionVariant>|null */
 	private ?array $variants = null;
 
+	private ?bool $containsVariadicCalls = null;
+
 	/**
 	 * @param Type[] $phpDocParameterTypes
 	 * @param Type[] $phpDocParameterOutTypes
@@ -75,8 +70,6 @@ public function __construct(
 		private ReflectionMethod $reflection,
 		private ReflectionProvider $reflectionProvider,
 		private Parser $parser,
-		private FunctionCallStatementFinder $functionCallStatementFinder,
-		private Cache $cache,
 		private TemplateTypeMap $templateTypeMap,
 		private array $phpDocParameterTypes,
 		private ?Type $phpDocReturnType,
@@ -252,82 +245,40 @@ private function isVariadic(): bool
 			$filename = $this->declaringTrait->getFileName();
 		}
 
-		if (!$isNativelyVariadic && $filename !== null) {
-			$modifiedTime = @filemtime($filename);
-			if ($modifiedTime === false) {
-				$modifiedTime = time();
-			}
-			$key = sprintf('variadic-method-%s-%s-%s', $declaringClass->getName(), $this->reflection->getName(), $filename);
-			$variableCacheKey = sprintf('%d-v4', $modifiedTime);
-			$cachedResult = $this->cache->load($key, $variableCacheKey);
-			if ($cachedResult === null || !is_bool($cachedResult)) {
-				$nodes = $this->parser->parseFile($filename);
-				$result = $this->callsFuncGetArgs($declaringClass, $nodes);
-				$this->cache->save($key, $variableCacheKey, $result);
-				return $result;
+		if (!$isNativelyVariadic && $filename !== null && !$this->declaringClass->isBuiltin()) {
+			if ($this->containsVariadicCalls !== null) {
+				return $this->containsVariadicCalls;
 			}
 
-			return $cachedResult;
-		}
-
-		return $isNativelyVariadic;
-	}
-
-	/**
-	 * @param Node[] $nodes
-	 */
-	private function callsFuncGetArgs(ClassReflection $declaringClass, array $nodes): bool
-	{
-		foreach ($nodes as $node) {
-			if (
-				$node instanceof Node\Stmt\ClassLike
-			) {
-				if (!isset($node->namespacedName)) {
-					continue;
-				}
-				if ($declaringClass->getName() !== (string) $node->namespacedName) {
-					continue;
-				}
-				if ($this->callsFuncGetArgs($declaringClass, $node->stmts)) {
-					return true;
-				}
-				continue;
+			$className = $declaringClass->getName();
+			if ($declaringClass->isAnonymous()) {
+				$className = sprintf('%s:%s:%s', VariadicMethodsVisitor::ANONYMOUS_CLASS_PREFIX, $declaringClass->getNativeReflection()->getStartLine(), $declaringClass->getNativeReflection()->getEndLine());
 			}
-
-			if ($node instanceof ClassMethod) {
-				if ($node->getStmts() === null) {
-					continue; // interface
-				}
-
-				$methodName = $node->name->name;
-				if ($methodName === $this->reflection->getName()) {
-					return $this->functionCallStatementFinder->findFunctionCallInStatements(ParametersAcceptor::VARIADIC_FUNCTIONS, $node->getStmts()) !== null;
+			if (array_key_exists($className, VariadicMethodsVisitor::$cache)) {
+				if (array_key_exists($this->reflection->getName(), VariadicMethodsVisitor::$cache[$className])) {
+					return $this->containsVariadicCalls = VariadicMethodsVisitor::$cache[$className][$this->reflection->getName()];
 				}
 
-				continue;
+				return $this->containsVariadicCalls = false;
 			}
 
-			if ($node instanceof Function_) {
-				continue;
-			}
+			$nodes = $this->parser->parseFile($filename);
+			if (count($nodes) > 0) {
+				$variadicMethods = $nodes[0]->getAttribute(VariadicMethodsVisitor::ATTRIBUTE_NAME);
 
-			if ($node instanceof Namespace_) {
-				if ($this->callsFuncGetArgs($declaringClass, $node->stmts)) {
-					return true;
+				if (
+					is_array($variadicMethods)
+					&& array_key_exists($className, $variadicMethods)
+					&& array_key_exists($this->reflection->getName(), $variadicMethods[$className])
+				) {
+					return $this->containsVariadicCalls = $variadicMethods[$className][$this->reflection->getName()];
 				}
-				continue;
-			}
-
-			if (!$node instanceof Declare_ || $node->stmts === null) {
-				continue;
 			}
 
-			if ($this->callsFuncGetArgs($declaringClass, $node->stmts)) {
-				return true;
-			}
+			return $this->containsVariadicCalls = false;
 		}
 
-		return false;
+		return $isNativelyVariadic;
 	}
 
 	public function isPrivate(): bool
diff --git a/tests/PHPStan/Parser/CleaningParserTest.php b/tests/PHPStan/Parser/CleaningParserTest.php
index 692ea7b699..835486fdc2 100644
--- a/tests/PHPStan/Parser/CleaningParserTest.php
+++ b/tests/PHPStan/Parser/CleaningParserTest.php
@@ -68,6 +68,8 @@ public function testParse(
 			new SimpleParser(
 				new Php7(new Emulative()),
 				new NameResolver(),
+				new VariadicMethodsVisitor(),
+				new VariadicFunctionsVisitor(),
 			),
 			new PhpVersion($phpVersionId),
 		);
diff --git a/tests/PHPStan/Parser/ParserTest.php b/tests/PHPStan/Parser/ParserTest.php
new file mode 100644
index 0000000000..94fe9a406b
--- /dev/null
+++ b/tests/PHPStan/Parser/ParserTest.php
@@ -0,0 +1,99 @@
+<?php declare(strict_types = 1);
+
+namespace PHPStan\Parser;
+
+use PHPStan\Testing\PHPStanTestCase;
+use function count;
+
+/**
+ * @covers \PHPStan\Parser\RichParser
+ * @covers \PHPStan\Parser\SimpleParser
+ */
+class ParserTest extends PHPStanTestCase
+{
+
+	public function dataVariadicCallLikes(): iterable
+	{
+		yield [
+			__DIR__ . '/data/variadic-functions.php',
+			VariadicFunctionsVisitor::ATTRIBUTE_NAME,
+			[
+				'VariadicFunctions\implicit_variadic_fn1' => true,
+			],
+		];
+
+		yield [
+			__DIR__ . '/data/variadic-methods.php',
+			VariadicMethodsVisitor::ATTRIBUTE_NAME,
+			[
+				'VariadicMethod\X' => [
+					'implicit_variadic_fn1' => true,
+				],
+				'VariadicMethod\Z' => [
+					'implicit_variadic_fnZ' => true,
+				],
+				'class@anonymous:20:30' => [
+					'implicit_variadic_subZ' => true,
+				],
+				'class@anonymous:42:52' => [
+					'implicit_variadic_fn' => true,
+				],
+				'class@anonymous:54:58' => [
+					'implicit_variadic_fn' => true,
+				],
+				'class@anonymous:61:68' => [
+					'implicit_variadic_fn' => true,
+				],
+			],
+		];
+
+		yield [
+			__DIR__ . '/data/variadic-methods-in-enum.php',
+			VariadicMethodsVisitor::ATTRIBUTE_NAME,
+			[
+				'VariadicMethodEnum\X' => [
+					'implicit_variadic_fn1' => true,
+				],
+			],
+		];
+	}
+
+	/**
+	 * @dataProvider dataVariadicCallLikes
+	 * @param array<string, true>|array<string, array<string, true>> $expectedVariadics
+	 * @throws ParserErrorsException
+	 */
+	public function testSimpleParserVariadicCallLikes(string $file, string $attributeName, array $expectedVariadics): void
+	{
+		/** @var SimpleParser $parser */
+		$parser = self::getContainer()->getService('currentPhpVersionSimpleParser');
+		$ast = $parser->parseFile($file);
+		$variadics = $ast[0]->getAttribute($attributeName);
+		$this->assertIsArray($variadics);
+		$this->assertCount(count($expectedVariadics), $variadics);
+		foreach ($expectedVariadics as $key => $expectedVariadic) {
+			$this->assertArrayHasKey($key, $variadics);
+			$this->assertSame($expectedVariadic, $variadics[$key]);
+		}
+	}
+
+	/**
+	 * @dataProvider dataVariadicCallLikes
+	 * @param array<string, true>|array<string, array<string, true>> $expectedVariadics
+	 * @throws ParserErrorsException
+	 */
+	public function testRichParserVariadicCallLikes(string $file, string $attributeName, array $expectedVariadics): void
+	{
+		/** @var RichParser $parser */
+		$parser = self::getContainer()->getService('currentPhpVersionRichParser');
+		$ast = $parser->parseFile($file);
+		$variadics = $ast[0]->getAttribute($attributeName);
+		$this->assertIsArray($variadics);
+		$this->assertCount(count($expectedVariadics), $variadics);
+		foreach ($expectedVariadics as $key => $expectedVariadic) {
+			$this->assertArrayHasKey($key, $variadics);
+			$this->assertSame($expectedVariadic, $variadics[$key]);
+		}
+	}
+
+}
diff --git a/tests/PHPStan/Parser/data/variadic-functions.php b/tests/PHPStan/Parser/data/variadic-functions.php
new file mode 100644
index 0000000000..d1a572e1e0
--- /dev/null
+++ b/tests/PHPStan/Parser/data/variadic-functions.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace VariadicFunctions;
+
+function variadic_fn1(...$v) {
+}
+
+function nonvariadic()
+{
+}
+
+if (rand(0,1)) {
+	function maybe_variadic_fn1($v)
+	{
+	}
+} else {
+	function maybe_variadic_fn1(...$v)
+	{
+	}
+}
+
+(function() {})();
+
+$y = 1;
+$fn2 = function ($x) use ($y) {
+	return $x + $y;
+};
+
+function implicit_variadic_fn1() {
+	$args = func_get_args();
+}
diff --git a/tests/PHPStan/Parser/data/variadic-methods-in-enum.php b/tests/PHPStan/Parser/data/variadic-methods-in-enum.php
new file mode 100644
index 0000000000..03594920e0
--- /dev/null
+++ b/tests/PHPStan/Parser/data/variadic-methods-in-enum.php
@@ -0,0 +1,16 @@
+<?php // lint >= 8.1
+
+namespace VariadicMethodEnum;
+
+enum X {
+
+	function non_variadic_fn1($v) {
+	}
+
+	function variadic_fn1(...$v) {
+	}
+
+	function implicit_variadic_fn1() {
+		$args = func_get_args();
+	}
+}
diff --git a/tests/PHPStan/Parser/data/variadic-methods.php b/tests/PHPStan/Parser/data/variadic-methods.php
new file mode 100644
index 0000000000..da6135b967
--- /dev/null
+++ b/tests/PHPStan/Parser/data/variadic-methods.php
@@ -0,0 +1,68 @@
+<?php
+
+namespace VariadicMethod;
+
+class X {
+
+	function non_variadic_fn1($v) {
+	}
+
+	function variadic_fn1(...$v) {
+	}
+
+	function implicit_variadic_fn1() {
+		$args = func_get_args();
+	}
+}
+
+class Z {
+	function non_variadic_fnZ($v) {
+		return $x = new class {
+			function non_variadic_fn_subZ($v) {
+			}
+
+			function variadic_fn_subZ(...$v) {
+			}
+
+			function implicit_variadic_subZ() {
+				$args = func_get_args();
+			}
+		};
+	}
+
+	function variadic_fnZ(...$v) {
+	}
+
+	function implicit_variadic_fnZ() {
+		$args = func_get_args();
+	}
+}
+
+
+$x = new class {
+	function non_variadic_fn($v) {
+	}
+
+	function variadic_fn(...$v) {
+	}
+
+	function implicit_variadic_fn() {
+		$args = func_get_args();
+	}
+};
+
+$c = new class (new class {}) {
+	function implicit_variadic_fn() {
+		$args = func_get_args();
+	}
+};
+
+
+$c = new class () {
+	function nestedClass() {
+		$nested = new class () {};
+	}
+	function implicit_variadic_fn() {
+		$args = func_get_args();
+	}
+};
diff --git a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php
index 7342c880fe..3ddc7db072 100644
--- a/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php
+++ b/tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php
@@ -3412,4 +3412,19 @@ public function testBug1953(): void
 		]);
 	}
 
+	public function testBug11559c(): void
+	{
+		$this->checkThisOnly = false;
+		$this->checkNullables = true;
+		$this->checkUnionTypes = true;
+		$this->checkExplicitMixed = true;
+
+		$this->analyse([__DIR__ . '/data/bug-11559c.php'], [
+			[
+				'Method class@anonymous/tests/PHPStan/Rules/Methods/data/bug-11559c.php:6:1::regular_fn() invoked with 3 parameters, 1 required.',
+				15,
+			],
+		]);
+	}
+
 }
diff --git a/tests/PHPStan/Rules/Methods/data/bug-11559c.php b/tests/PHPStan/Rules/Methods/data/bug-11559c.php
new file mode 100644
index 0000000000..54e3ba27b0
--- /dev/null
+++ b/tests/PHPStan/Rules/Methods/data/bug-11559c.php
@@ -0,0 +1,16 @@
+<?php
+
+namespace Bug11559c;
+
+function doFoo() {
+	$c = new class (new class {}) {
+		function implicit_variadic_fn() {
+			$args = func_get_args();
+		}
+		function regular_fn(int $i) {
+		}
+	};
+
+	$c->implicit_variadic_fn(1, 2, 3);
+	$c->regular_fn(1, 2, 3);
+}