1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 13:51:54 +01:00

Merge pull request #8155 from Nicelocal/prohibition_analyzer_clone

Run method call prohibition analyzer when cloning
This commit is contained in:
orklah 2022-06-25 01:31:00 +02:00 committed by GitHub
commit 8b7bc07ad6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 4 deletions

View File

@ -6,6 +6,7 @@ use PhpParser;
use Psalm\CodeLocation;
use Psalm\Context;
use Psalm\Internal\Analyzer\MethodAnalyzer;
use Psalm\Internal\Analyzer\Statements\Expression\Call\Method\MethodCallProhibitionAnalyzer;
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\MethodIdentifier;
@ -39,6 +40,7 @@ class CloneAnalyzer
return false;
}
$location = new CodeLocation($statements_analyzer->getSource(), $stmt);
$stmt_expr_type = $statements_analyzer->node_data->getType($stmt->expr);
if ($stmt_expr_type) {
@ -71,7 +73,7 @@ class CloneAnalyzer
$does_method_exist = $codebase_methods->methodExists(
$clone_method_id,
$context->calling_method_id,
new CodeLocation($statements_analyzer->getSource(), $stmt)
$location
);
$is_method_visible = MethodAnalyzer::isMethodVisible(
$clone_method_id,
@ -81,6 +83,14 @@ class CloneAnalyzer
if ($does_method_exist && !$is_method_visible) {
$invalid_clones[] = $clone_type_part->getId();
} else {
MethodCallProhibitionAnalyzer::analyze(
$codebase,
$context,
$clone_method_id,
$statements_analyzer->getNamespace(),
$location,
$statements_analyzer->getSuppressedIssues()
);
$possibly_valid = true;
$immutable_cloned = true;
}
@ -108,7 +118,7 @@ class CloneAnalyzer
IssueBuffer::maybeAdd(
new MixedClone(
'Cannot clone mixed',
new CodeLocation($statements_analyzer->getSource(), $stmt)
$location
),
$statements_analyzer->getSuppressedIssues()
);
@ -119,7 +129,7 @@ class CloneAnalyzer
IssueBuffer::maybeAdd(
new PossiblyInvalidClone(
'Cannot clone ' . $invalid_clones[0],
new CodeLocation($statements_analyzer->getSource(), $stmt)
$location
),
$statements_analyzer->getSuppressedIssues()
);
@ -127,7 +137,7 @@ class CloneAnalyzer
IssueBuffer::maybeAdd(
new InvalidClone(
'Cannot clone ' . $invalid_clones[0],
new CodeLocation($statements_analyzer->getSource(), $stmt)
$location
),
$statements_analyzer->getSuppressedIssues()
);

View File

@ -26,6 +26,16 @@ class DeprecatedAnnotationTest extends TestCase
}
}',
],
'deprecatedCloneMethod' => [
'code' => '<?php
class Foo {
/**
* @deprecated
*/
public function __clone() {
}
}',
],
'deprecatedClassUsedInsideClass' => [
'code' => '<?php
/**
@ -114,6 +124,20 @@ class DeprecatedAnnotationTest extends TestCase
Foo::barBar();',
'error_message' => 'DeprecatedMethod',
],
'deprecatedCloneMethodWithCall' => [
'code' => '<?php
class Foo {
/**
* @deprecated
*/
public function __clone() {
}
}
$a = new Foo;
$aa = clone $a;',
'error_message' => 'DeprecatedMethod',
],
'deprecatedClassWithStaticCall' => [
'code' => '<?php
/**

View File

@ -586,6 +586,28 @@ class InternalAnnotationTest extends TestCase
}',
'error_message' => 'The method A\Foo::barBar is internal to A but called from B\Bat',
],
'internalCloneMethodWithCall' => [
'code' => '<?php
namespace A {
class Foo {
/**
* @internal
*/
public function __clone() {
}
}
}
namespace B {
class Bat {
public function batBat(): void {
$a = new \A\Foo;
$aa = clone $a;
}
}
}',
'error_message' => 'The method A\Foo::__clone is internal to A but called from B\Bat',
],
'internalMethodWithCallFromRootNamespace' => [
'code' => '<?php
namespace A {