mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
psalm-internal - extract function NamespaceAnalyzer::isWithin
Also adjust behaviour so things can be internal to classes, not just to namespace, and namespace comparision is case insensitive
This commit is contained in:
parent
cd673538f1
commit
14843ed58a
@ -212,7 +212,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
|
||||
}
|
||||
|
||||
if ($parent_class_storage->psalm_internal &&
|
||||
strpos($fq_class_name, trim($parent_class_storage->psalm_internal, '\\') . '\\') !== 0
|
||||
! NamespaceAnalyzer::isWithin($fq_class_name, $parent_class_storage->psalm_internal)
|
||||
) {
|
||||
if (IssueBuffer::accepts(
|
||||
new InternalClass(
|
||||
|
@ -212,7 +212,8 @@ class MethodAnalyzer extends FunctionLikeAnalyzer
|
||||
&& !$context->collect_initializations
|
||||
&& !$context->collect_mutations
|
||||
) {
|
||||
if (strpos($context->self, trim($storage->psalm_internal, '\\') . '\\') !== 0) {
|
||||
if (! NamespaceAnalyzer::isWithin($context->self, $storage->psalm_internal)
|
||||
) {
|
||||
if (IssueBuffer::accepts(
|
||||
new InternalMethod(
|
||||
'The method ' . $codebase_methods->getCasedMethodId($method_id) .
|
||||
|
@ -166,4 +166,20 @@ class NamespaceAnalyzer extends SourceAnalyzer implements StatementsSource
|
||||
{
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $namespace Generally a namespace, but may also be a fully qualified class name (FQCN)_.
|
||||
* @param string $className Generally a FQCN, but may be a FQCN
|
||||
*
|
||||
* Returns true if $className is the same as, or starts with $namespace, in a case-insensitive comparision.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isWithin(string $className, string $namespace): bool
|
||||
{
|
||||
$className = strtolower(trim($className, '\\') . '\\');
|
||||
$namespace = strtolower(trim($namespace, '\\') . '\\');
|
||||
|
||||
return $className === $namespace || strpos($className, $namespace) === 0;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use PhpParser;
|
||||
use PhpParser\Node\Expr\PropertyFetch;
|
||||
use PhpParser\Node\Stmt\PropertyProperty;
|
||||
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
|
||||
use Psalm\Internal\Analyzer\NamespaceAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
|
||||
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
||||
use Psalm\Internal\Analyzer\TypeAnalyzer;
|
||||
@ -497,7 +498,7 @@ class PropertyAssignmentAnalyzer
|
||||
}
|
||||
|
||||
if ($property_storage->psalm_internal && $context->self) {
|
||||
if (strpos($context->self, trim($property_storage->psalm_internal, '\\') . '\\') !== 0) {
|
||||
if (! NamespaceAnalyzer::isWithin($context->self, $property_storage->psalm_internal)) {
|
||||
if (IssueBuffer::accepts(
|
||||
new InternalProperty(
|
||||
$property_id . ' is marked internal to ' . $property_storage->psalm_internal,
|
||||
|
@ -5,6 +5,7 @@ use PhpParser;
|
||||
use Psalm\Internal\Analyzer\ClassAnalyzer;
|
||||
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
|
||||
use Psalm\Internal\Analyzer\MethodAnalyzer;
|
||||
use Psalm\Internal\Analyzer\NamespaceAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
|
||||
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
||||
use Psalm\CodeLocation;
|
||||
@ -310,7 +311,7 @@ class NewAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\CallAna
|
||||
|
||||
|
||||
if ($storage->psalm_internal && $context->self) {
|
||||
if (strpos($context->self, trim($storage->psalm_internal, '\\') . '\\') !== 0) {
|
||||
if (! NamespaceAnalyzer::isWithin($context->self, $storage->psalm_internal)) {
|
||||
if (IssueBuffer::accepts(
|
||||
new InternalClass(
|
||||
$fq_class_name . ' is marked internal to ' . $storage->psalm_internal,
|
||||
|
@ -4,6 +4,7 @@ namespace Psalm\Internal\Analyzer\Statements\Expression\Call;
|
||||
use PhpParser;
|
||||
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
|
||||
use Psalm\Internal\Analyzer\MethodAnalyzer;
|
||||
use Psalm\Internal\Analyzer\NamespaceAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
|
||||
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
||||
use Psalm\CodeLocation;
|
||||
@ -581,7 +582,7 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
|
||||
|
||||
if ($class_storage->psalm_internal
|
||||
&& $context->self
|
||||
&& strpos($context->self, trim($class_storage->psalm_internal, '\\') . '\\') !== 0
|
||||
&& ! NamespaceAnalyzer::isWithin($context->self, $class_storage->psalm_internal)
|
||||
) {
|
||||
if (IssueBuffer::accepts(
|
||||
new InternalClass(
|
||||
|
@ -4,6 +4,7 @@ namespace Psalm\Internal\Analyzer\Statements\Expression\Fetch;
|
||||
use PhpParser;
|
||||
use Psalm\Internal\Analyzer\ClassLikeAnalyzer;
|
||||
use Psalm\Internal\Analyzer\FunctionLikeAnalyzer;
|
||||
use Psalm\Internal\Analyzer\NamespaceAnalyzer;
|
||||
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
|
||||
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
||||
use Psalm\CodeLocation;
|
||||
@ -595,7 +596,7 @@ class PropertyFetchAnalyzer
|
||||
}
|
||||
|
||||
if ($property_storage->psalm_internal && $context->self) {
|
||||
if (strpos($context->self, trim($property_storage->psalm_internal, '\\') . '\\') !== 0) {
|
||||
if (! NamespaceAnalyzer::isWithin($context->self, $property_storage->psalm_internal)) {
|
||||
if (IssueBuffer::accepts(
|
||||
new InternalProperty(
|
||||
$property_id . ' is marked internal to ' . $property_storage->psalm_internal,
|
||||
|
@ -33,6 +33,42 @@ class PsalmInternalAnnotationTest extends TestCase
|
||||
}
|
||||
}',
|
||||
],
|
||||
'internalMethodWithCallWithCaseMisMatched' => [
|
||||
'<?php
|
||||
namespace A\B {
|
||||
class Foo {
|
||||
/**
|
||||
* @psalm-internal A\B
|
||||
*/
|
||||
public static function barBar(): void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace a\b\c {
|
||||
class Bat {
|
||||
public function batBat() : void {
|
||||
\A\B\Foo::barBar();
|
||||
}
|
||||
}
|
||||
}',
|
||||
],
|
||||
'internalToClassMethodWithCall' => [
|
||||
'<?php
|
||||
namespace A\B {
|
||||
class Foo {
|
||||
/**
|
||||
* @psalm-internal A\B\Foo
|
||||
*/
|
||||
public static function barBar(): void {
|
||||
}
|
||||
|
||||
public static function foo(): void {
|
||||
self::barBar();
|
||||
}
|
||||
}
|
||||
}',
|
||||
],
|
||||
'internalClassWithStaticCall' => [
|
||||
'<?php
|
||||
namespace A\B {
|
||||
@ -204,6 +240,27 @@ class PsalmInternalAnnotationTest extends TestCase
|
||||
}',
|
||||
'error_message' => 'The method A\B\Foo::barBar has been marked as internal to A\B',
|
||||
],
|
||||
'internalToClassMethodWithCall' => [
|
||||
'<?php
|
||||
namespace A\B {
|
||||
class Foo {
|
||||
/**
|
||||
* @psalm-internal A\B\Foo
|
||||
*/
|
||||
public static function barBar(): void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace A\C {
|
||||
class Bat {
|
||||
public function batBat(): void {
|
||||
\A\B\Foo::barBar();
|
||||
}
|
||||
}
|
||||
}',
|
||||
'error_message' => 'The method A\B\Foo::barBar has been marked as internal to A\B\Foo',
|
||||
],
|
||||
'internalClassWithStaticCall' => [
|
||||
'<?php
|
||||
namespace A\B {
|
||||
|
Loading…
Reference in New Issue
Block a user