mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Add new config: sealAllMethods (#3578)
* Add new config: sealAllMethods * Add some more tests * Fix codesniffer issue with preg_quote * Fix missing method in test Co-authored-by: Olle <noemail>
This commit is contained in:
parent
03e9649d49
commit
e1cc27f7a2
@ -70,6 +70,7 @@
|
||||
<xs:attribute name="usePhpDocMethodsWithoutMagicCall" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="usePhpDocPropertiesWithoutMagicCall" type="xs:boolean" default="false" />
|
||||
<xs:attribute name="skipChecksOnUnresolvableIncludes" type="xs:boolean" default="true" />
|
||||
<xs:attribute name="sealAllMethods" type="xs:boolean" default="false" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="ProjectFilesType">
|
||||
|
@ -286,6 +286,16 @@ When `true`, Psalm will skip checking classes, variables and functions after it
|
||||
|
||||
For backwards compatibility, this defaults to `true`, but if you do not rely on dynamically generated includes to cause classes otherwise unknown to Psalm to come into existence, it's recommended you set this to `false` in order to reliably detect errors that would be fatal to PHP at runtime.
|
||||
|
||||
#### sealAllMethods
|
||||
|
||||
```xml
|
||||
<psalm
|
||||
sealAllMethods="[bool]"
|
||||
>
|
||||
```
|
||||
|
||||
When `true`, Psalm will treat all classes as if they had sealed methods, meaning that if you implement the magic method `__call`, you also have to add `@method` for each magic method. Defaults to false.
|
||||
|
||||
### Running Psalm
|
||||
|
||||
#### autoloader
|
||||
|
@ -299,6 +299,11 @@ class Config
|
||||
*/
|
||||
public $skip_checks_on_unresolvable_includes = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $seal_all_methods = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
@ -785,7 +790,8 @@ class Config
|
||||
'ensureArrayStringOffsetsExist' => 'ensure_array_string_offsets_exist',
|
||||
'ensureArrayIntOffsetsExist' => 'ensure_array_int_offsets_exist',
|
||||
'reportMixedIssues' => 'show_mixed_issues',
|
||||
'skipChecksOnUnresolvableIncludes' => 'skip_checks_on_unresolvable_includes'
|
||||
'skipChecksOnUnresolvableIncludes' => 'skip_checks_on_unresolvable_includes',
|
||||
'sealAllMethods' => 'seal_all_methods'
|
||||
];
|
||||
|
||||
foreach ($booleanAttributes as $xmlName => $internalName) {
|
||||
|
@ -422,6 +422,7 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
$method_id,
|
||||
$class_storage,
|
||||
$context,
|
||||
$config,
|
||||
$all_intersection_return_type,
|
||||
$result
|
||||
);
|
||||
|
@ -20,6 +20,7 @@ class MissingMethodCallHandler
|
||||
MethodIdentifier $method_id,
|
||||
\Psalm\Storage\ClassLikeStorage $class_storage,
|
||||
Context $context,
|
||||
\Psalm\Config $config,
|
||||
?Type\Union $all_intersection_return_type,
|
||||
AtomicMethodCallAnalysisResult $result
|
||||
) : ?AtomicCallContext {
|
||||
@ -92,7 +93,7 @@ class MissingMethodCallHandler
|
||||
$context
|
||||
);
|
||||
|
||||
if ($class_storage->sealed_methods) {
|
||||
if ($class_storage->sealed_methods || $config->seal_all_methods) {
|
||||
$result->non_existent_magic_method_ids[] = $method_id;
|
||||
|
||||
return null;
|
||||
|
@ -789,4 +789,131 @@ class MagicMethodAnnotationTest extends TestCase
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testSealAllMethodsWithoutFoo()
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
class A {
|
||||
public function __call(string $method, array $args) {}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
$b = new B();
|
||||
$b->foo();
|
||||
'
|
||||
);
|
||||
|
||||
$error_message = 'UndefinedMagicMethod';
|
||||
$this->expectException(\Psalm\Exception\CodeException::class);
|
||||
$this->expectExceptionMessage($error_message);
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testSealAllMethodsWithFoo()
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
class A {
|
||||
public function __call(string $method, array $args) {}
|
||||
public function foo(): void {}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
$b = new B();
|
||||
$b->foo();
|
||||
'
|
||||
);
|
||||
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testSealAllMethodsWithFooInSubclass()
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
class A {
|
||||
public function __call(string $method, array $args) {}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
public function foo(): void {}
|
||||
}
|
||||
|
||||
$b = new B();
|
||||
$b->foo();
|
||||
'
|
||||
);
|
||||
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testSealAllMethodsWithFooAnnotated()
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = true;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
/** @method foo(): int */
|
||||
class A {
|
||||
public function __call(string $method, array $args) {}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
$b = new B();
|
||||
$b->foo();
|
||||
'
|
||||
);
|
||||
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testSealAllMethodsSetToFalse()
|
||||
{
|
||||
Config::getInstance()->seal_all_methods = false;
|
||||
|
||||
$this->addFile(
|
||||
'somefile.php',
|
||||
'<?php
|
||||
class A {
|
||||
public function __call(string $method, array $args) {}
|
||||
}
|
||||
|
||||
class B extends A {}
|
||||
|
||||
$b = new B();
|
||||
$b->foo();
|
||||
'
|
||||
);
|
||||
|
||||
$this->analyzeFile('somefile.php', new Context());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user