Skip to content

Commit

Permalink
Fix named arguments for few multi-variant methods
Browse files Browse the repository at this point in the history
  • Loading branch information
schlndh committed Nov 20, 2023
1 parent 93af41b commit 808b637
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 11 deletions.
5 changes: 3 additions & 2 deletions src/Reflection/Dummy/ChangedTypeMethodReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ class ChangedTypeMethodReflection implements ExtendedMethodReflection

/**
* @param ParametersAcceptorWithPhpDocs[] $variants
* @param ParametersAcceptorWithPhpDocs[]|null $namedArgumentsVariants
*/
public function __construct(private ClassReflection $declaringClass, private ExtendedMethodReflection $reflection, private array $variants)
public function __construct(private ClassReflection $declaringClass, private ExtendedMethodReflection $reflection, private array $variants, private ?array $namedArgumentsVariants)
{
}

Expand Down Expand Up @@ -63,7 +64,7 @@ public function getVariants(): array

public function getNamedArgumentsVariants(): ?array
{
return null;
return $this->namedArgumentsVariants;
}

public function isDeprecated(): TrinaryLogic
Expand Down
7 changes: 5 additions & 2 deletions src/Reflection/Php/PhpClassReflectionExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ private function createMethod(
}
}
}
$variantsByType[$signatureType][] = $this->createNativeMethodVariant($methodSignature, $stubPhpDocParameterTypes, $stubPhpDocParameterVariadicity, $stubPhpDocReturnType, $phpDocParameterTypes, $phpDocReturnType, $phpDocParameterNameMapping, $stubPhpParameterOutTypes, $phpDocParameterOutTypes);
$variantsByType[$signatureType][] = $this->createNativeMethodVariant($methodSignature, $stubPhpDocParameterTypes, $stubPhpDocParameterVariadicity, $stubPhpDocReturnType, $phpDocParameterTypes, $phpDocReturnType, $phpDocParameterNameMapping, $stubPhpParameterOutTypes, $phpDocParameterOutTypes, $signatureType !== 'named');
}
}

Expand Down Expand Up @@ -796,6 +796,7 @@ private function createNativeMethodVariant(
array $phpDocParameterNameMapping,
array $stubPhpDocParameterOutTypes,
array $phpDocParameterOutTypes,
bool $usePhpDocParameterNames,
): FunctionVariantWithPhpDocs
{
$parameters = [];
Expand All @@ -820,7 +821,9 @@ private function createNativeMethodVariant(
}

$parameters[] = new NativeParameterWithPhpDocsReflection(
$phpDocParameterName,
$usePhpDocParameterNames
? $phpDocParameterName
: $parameterSignature->getName(),
$parameterSignature->isOptional(),
$type ?? $parameterSignature->getType(),
$phpDocType ?? new MixedType(),
Expand Down
8 changes: 7 additions & 1 deletion src/Reflection/SignatureMap/Php8SignatureMapProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,14 @@ private function getMergedSignatures(FunctionSignature $nativeSignature, array $
continue 2;
}

// it seems that variadic parameters cannot be named in native functions/methods.
$nativeParam = $nativeParams[$i];
if ($nativeParam->isVariadic()) {
break;
}

$parameters[] = new ParameterSignature(
$nativeParams[$i]->getName(),
$nativeParam->getName(),
$functionParam->isOptional(),
$functionParam->getType(),
$functionParam->getNativeType(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public function withCalledOnType(Type $type): UnresolvedMethodPrototypeReflectio

private function transformMethodWithStaticType(ClassReflection $declaringClass, ExtendedMethodReflection $method): ExtendedMethodReflection
{
$variants = array_map(fn (ParametersAcceptorWithPhpDocs $acceptor): ParametersAcceptorWithPhpDocs => new FunctionVariantWithPhpDocs(
$variantFn = fn (ParametersAcceptorWithPhpDocs $acceptor): ParametersAcceptorWithPhpDocs => new FunctionVariantWithPhpDocs(
$acceptor->getTemplateTypeMap(),
$acceptor->getResolvedTemplateTypeMap(),
array_map(
Expand All @@ -104,9 +104,14 @@ private function transformMethodWithStaticType(ClassReflection $declaringClass,
$this->transformStaticType($acceptor->getPhpDocReturnType()),
$this->transformStaticType($acceptor->getNativeReturnType()),
$acceptor->getCallSiteVarianceMap(),
), $method->getVariants());
);
$variants = array_map($variantFn, $method->getVariants());
$namedArgumentVariants = $method->getNamedArgumentsVariants();
$namedArgumentVariants = $namedArgumentVariants !== null
? array_map($variantFn, $namedArgumentVariants)
: null;

return new ChangedTypeMethodReflection($declaringClass, $method, $variants);
return new ChangedTypeMethodReflection($declaringClass, $method, $variants, $namedArgumentVariants);
}

private function transformStaticType(Type $type): Type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public function withCalledOnType(Type $type): UnresolvedMethodPrototypeReflectio

private function transformMethodWithStaticType(ClassReflection $declaringClass, ExtendedMethodReflection $method): ExtendedMethodReflection
{
$variants = array_map(fn (ParametersAcceptorWithPhpDocs $acceptor): ParametersAcceptorWithPhpDocs => new FunctionVariantWithPhpDocs(
$variantFn = fn (ParametersAcceptorWithPhpDocs $acceptor): ParametersAcceptorWithPhpDocs => new FunctionVariantWithPhpDocs(
$acceptor->getTemplateTypeMap(),
$acceptor->getResolvedTemplateTypeMap(),
array_map(
Expand All @@ -99,9 +99,14 @@ private function transformMethodWithStaticType(ClassReflection $declaringClass,
$this->transformStaticType($acceptor->getPhpDocReturnType()),
$this->transformStaticType($acceptor->getNativeReturnType()),
$acceptor->getCallSiteVarianceMap(),
), $method->getVariants());
);
$variants = array_map($variantFn, $method->getVariants());
$namedArgumentsVariants = $method->getNamedArgumentsVariants();
$namedArgumentsVariants = $namedArgumentsVariants !== null
? array_map($variantFn, $namedArgumentsVariants)
: null;

return new ChangedTypeMethodReflection($declaringClass, $method, $variants);
return new ChangedTypeMethodReflection($declaringClass, $method, $variants, $namedArgumentsVariants);
}

private function transformStaticType(Type $type): Type
Expand Down
39 changes: 39 additions & 0 deletions tests/PHPStan/Rules/Methods/CallMethodsRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3079,4 +3079,43 @@ public function testTypedClassConstants(): void
$this->analyse([__DIR__ . '/data/return-type-class-constant.php'], []);
}

public function testNamedParametersForMultiVariantFunctions(): void
{
if (PHP_VERSION_ID < 80000) {
$this->markTestSkipped('Test requires PHP 8.0');
}

$this->checkThisOnly = false;
$this->checkNullables = true;
$this->checkUnionTypes = true;
$this->checkExplicitMixed = true;

$this->analyse([__DIR__ . '/data/call-methods-named-params-multivariant.php'], [
[
'Unknown parameter $options in call to method XSLTProcessor::setParameter().',
10,
],
[
'Missing parameter $name (array) in call to method XSLTProcessor::setParameter().',
10,
],
[
'Unknown parameter $colno in call to method PDO::query().',
15,
],
[
'Unknown parameter $className in call to method PDO::query().',
17,
],
[
'Unknown parameter $constructorArgs in call to method PDO::query().',
17,
],
[
'Unknown parameter $className in call to method PDOStatement::setFetchMode().',
22,
],
]);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php declare(strict_types=1); // lint >= 8.0

namespace CallMethodsNamedParamsMultivariant;


$xslt = new \XSLTProcessor();
$xslt->setParameter(namespace: 'ns', name:'aaa', value: 'bbb');
$xslt->setParameter(namespace: 'ns', name: ['aaa' => 'bbb']);
// wrong
$xslt->setParameter(namespace: 'ns', options: ['aaa' => 'bbb']);

$pdo = new \PDO('123');
$pdo->query(query: 'SELECT 1', fetchMode: \PDO::FETCH_ASSOC);
// wrong
$pdo->query(query: 'SELECT 1', fetchMode: \PDO::FETCH_ASSOC, colno: 1);
// wrong
$pdo->query(query: 'SELECT 1', fetchMode: \PDO::FETCH_ASSOC, className: 'Foo', constructorArgs: []);

$stmt = new \PDOStatement();
$stmt->setFetchMode(mode: 5);
// wrong
$stmt->setFetchMode(mode: 5, className: 'aa');

0 comments on commit 808b637

Please sign in to comment.