Skip to content

Commit

Permalink
Merge pull request #7242 from zoonru/seal_all_properties
Browse files Browse the repository at this point in the history
PHP 8.2: seal all properties configuration
  • Loading branch information
orklah committed Jan 10, 2022
2 parents 611583c + b9e3979 commit af37af7
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 3 deletions.
1 change: 1 addition & 0 deletions config.xsd
Expand Up @@ -95,6 +95,7 @@
<xs:attribute name="usePhpDocPropertiesWithoutMagicCall" type="xs:boolean" default="false" />
<xs:attribute name="skipChecksOnUnresolvableIncludes" type="xs:boolean" default="false" />
<xs:attribute name="sealAllMethods" type="xs:boolean" default="false" />
<xs:attribute name="sealAllProperties" type="xs:boolean" default="false" />
<xs:attribute name="runTaintAnalysis" type="xs:boolean" default="false" />
<xs:attribute name="usePhpStormMetaPath" type="xs:boolean" default="true" />
<xs:attribute name="allowInternalNamedArgumentCalls" type="xs:boolean" default="true" />
Expand Down
10 changes: 10 additions & 0 deletions docs/running_psalm/configuration.md
Expand Up @@ -305,6 +305,16 @@ This defaults to `false`.

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.

#### sealAllProperties

```xml
<psalm
sealAllProperties="[bool]"
>
```

When `true`, Psalm will treat all classes as if they had sealed properties, meaning that Psalm will disallow getting and setting any properties not contained in a list of `@property` (or `@property-read`/`@property-write`) annotations and not explicitly defined as a `property`. Defaults to false.

#### runTaintAnalysis

```xml
Expand Down
6 changes: 6 additions & 0 deletions src/Psalm/Config.php
Expand Up @@ -346,6 +346,11 @@ class Config
*/
public $seal_all_methods = false;

/**
* @var bool
*/
public $seal_all_properties = false;

/**
* @var bool
*/
Expand Down Expand Up @@ -907,6 +912,7 @@ private static function fromXmlAndPaths(
'reportMixedIssues' => 'show_mixed_issues',
'skipChecksOnUnresolvableIncludes' => 'skip_checks_on_unresolvable_includes',
'sealAllMethods' => 'seal_all_methods',
'sealAllProperties' => 'seal_all_properties',
'runTaintAnalysis' => 'run_taint_analysis',
'usePhpStormMetaPath' => 'use_phpstorm_meta_path',
'allowInternalNamedArgumentsCalls' => 'allow_internal_named_arg_calls',
Expand Down
Expand Up @@ -548,7 +548,7 @@ private static function getMagicGetterOrSetterProperty(
case '__set':
// If `@psalm-seal-properties` is set, the property must be defined with
// a `@property` annotation
if ($class_storage->sealed_properties
if (($class_storage->sealed_properties || $codebase->config->seal_all_properties)
&& !isset($class_storage->pseudo_property_set_types['$' . $prop_name])
&& IssueBuffer::accepts(
new UndefinedThisPropertyAssignment(
Expand Down Expand Up @@ -647,7 +647,7 @@ private static function getMagicGetterOrSetterProperty(
case '__get':
// If `@psalm-seal-properties` is set, the property must be defined with
// a `@property` annotation
if ($class_storage->sealed_properties
if (($class_storage->sealed_properties || $codebase->config->seal_all_properties)
&& !isset($class_storage->pseudo_property_get_types['$' . $prop_name])
&& IssueBuffer::accepts(
new UndefinedThisPropertyFetch(
Expand Down
Expand Up @@ -676,7 +676,9 @@ private static function propertyFetchCanBeAnalyzed(
* If we have an explicit list of all allowed magic properties on the class, and we're
* not in that list, fall through
*/
if (!$class_storage->sealed_properties && !$override_property_visibility) {
if (!($class_storage->sealed_properties || $codebase->config->seal_all_properties)
&& !$override_property_visibility
) {
return false;
}

Expand Down
25 changes: 25 additions & 0 deletions tests/MagicPropertyTest.php
Expand Up @@ -4,6 +4,7 @@

use Psalm\Config;
use Psalm\Context;
use Psalm\Exception\CodeException;
use Psalm\Tests\Traits\InvalidCodeAnalysisTestTrait;
use Psalm\Tests\Traits\ValidCodeAnalysisTestTrait;

Expand Down Expand Up @@ -1159,4 +1160,28 @@ class A {
],
];
}

public function testSealAllMethodsWithoutFoo(): void
{
Config::getInstance()->seal_all_properties = true;

$this->addFile(
'somefile.php',
'<?php
class A {
public function __get(string $name) {}
}
class B extends A {}
$b = new B();
$result = $b->foo;
'
);

$error_message = 'UndefinedMagicPropertyFetch';
$this->expectException(CodeException::class);
$this->expectExceptionMessage($error_message);
$this->analyzeFile('somefile.php', new Context());
}
}

0 comments on commit af37af7

Please sign in to comment.