1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00
Commit Graph

280 Commits

Author SHA1 Message Date
Vincent Langlet
50cf28fba1 Fix getParentClass stub 2022-12-18 19:36:13 +01:00
Vincent Langlet
9b5630bea4 Fix ReflectionClass stub 2022-12-18 19:07:41 +01:00
098d5020d0 array_merge_recursive 2022-12-18 14:52:44 +01:00
1dd062a810 Fix #2481 2022-12-18 14:50:51 +01:00
fluffycondor
9a22d682f5 Simplify conditional return 2022-12-18 17:15:24 +06:00
fluffycondor
987981b12a Make sprintf return non-empty-string when arguments non-empty-strings too 2022-12-18 16:53:19 +06:00
Alies Lapatsin
1115cfb980 Merge branch 'master' into php-ext-with-deprecation
# Conflicts:
#	src/Psalm/Config.php
2022-12-12 23:49:01 +01:00
Alies Lapatsin
16ab9f786b Unify a way how to load stubs for extentions 2022-12-10 17:02:47 +01:00
Marco Pivetta
ed2cde1b93 Mark Reflection(Method|Property)#setAccessible() as pure starting from PHP 8.1 onwards
This will highlight unused code.

Ref: https://github.com/php/php-src/pull/5412
Ref: https://wiki.php.net/rfc/make-reflection-setaccessible-no-op
Ref: https://github.com/php/php-src/pull/5411

Example https://3v4l.org/PNeeZ

```php
<?php

class Foo {
    private $bar = 'baz';
    private function taz() { return 'waz'; }
}

//var_dump((new ReflectionProperty(Foo::class, 'bar'))->getValue(new Foo));
//var_dump((new ReflectionMethod(Foo::class, 'taz'))->invoke(new Foo));
```

Produces (starting from PHP 8.1):

```
string(3) "baz"
string(3) "waz"
```
2022-12-07 14:22:15 +01:00
Marco Pivetta
93c5df6bfc Refine ReflectionUnionType and ReflectionIntersectionType for PHP 8.1 and PHP 8.2
* in PHP 8.0, `ReflectionUnionType` is composed on `ReflectionNamedType`s
* in PHP 8.1, `ReflectionIntersectionType` is composed of `ReflectionNamedType`s
* in PHP 8.2, `ReflectionUnionType` is composed of `ReflectionIntersectionType|ReflectionNamedType`s

Slight variations for each PHP version.

As per local testing, this doesn't work yet.

## Local testing setup:
I did some digging to make sure that the stubs work as expected.

Here's what I did to validate this patch locally (since I don't think it can really be fully automated)

## Create a dummy file to verify used symbols

```php
<?php

namespace Testing;

/** @return \ReflectionClass<\stdClass> */
function getAClass(): \ReflectionClass { throw new \Exception('irrelevant'); }
function getAnUnionType(): \ReflectionUnionType { throw new \Exception('irrelevant'); }
function getAnIntersectionType(): \ReflectionIntersectionType { throw new \Exception('irrelevant'); }

// verifying that `getName()` is stubbed in all versions: this should always be a `class-string<\stdClass>`
$name = getAClass()->getName();
// union types should appear starting with PHP 8.0. Starting with PHP 8.2, they allow for intersections.
$unionTypes = getAnUnionType()->getTypes();
// intersection types should appear starting with PHP 8.1
$intersectionTypes = getAnIntersectionType()->getTypes();

$results = [$name, $unionTypes, $intersectionTypes];

/** @psalm-trace $results */ // tracing this will show us the differences between versions
return $results;
```

## Run the script against various `vimeo/psalm` versions

```sh
docker run --rm -ti -v $(pwd):/app -w /app php:7.4 ./psalm --php-version=7.4 --no-cache reflection-test.php | grep Trace

docker run --rm -ti -v $(pwd):/app -w /app php:8.0 ./psalm --php-version=8.0 --no-cache reflection-test.php | grep Trace

docker run --rm -ti -v $(pwd):/app -w /app php:8.1 ./psalm --php-version=8.1 --no-cache reflection-test.php | grep Trace

docker run --rm -ti -v $(pwd):/app -w /app php:8.2.0RC7-cli ./psalm --php-version=8.2 --no-cache reflection-test.php | grep Trace

```

## Evaluate output

```
❯ docker run --rm -ti -v $(pwd):/app -w /app php:7.4 ./psalm --php-version=7.4 --no-cache reflection-test.php | grep Trace
ERROR: Trace - reflection-test.php:20:1 - $results: list{class-string<stdClass>, mixed, mixed} (see https://psalm.dev/224)

❯ docker run --rm -ti -v $(pwd):/app -w /app php:8.0 ./psalm --php-version=8.0 --no-cache reflection-test.php | grep Trace
ERROR: Trace - reflection-test.php:20:1 - $results: list{class-string<stdClass>, non-empty-list<ReflectionNamedType>, mixed} (see https://psalm.dev/224)

❯ docker run --rm -ti -v $(pwd):/app -w /app php:8.1 ./psalm --php-version=8.1 --no-cache reflection-test.php | grep Trace
ERROR: Trace - reflection-test.php:20:1 - $results: list{class-string<stdClass>, non-empty-list<ReflectionNamedType>, non-empty-list<ReflectionNamedType>} (see https://psalm.dev/224)

psalm on  feature/#8720-improve-types-and-purity-for-reflection-symbols [!?] via 🐘 v8.1.13 via ❄️  impure (nix-shell) took 4s
❯ docker run --rm -ti -v $(pwd):/app -w /app php:8.2.0RC7-cli ./psalm --php-version=8.2 --no-cache reflection-test.php | grep Trace
ERROR: Trace - reflection-test.php:20:1 - $results: list{class-string<stdClass>, non-empty-list<ReflectionNamedType>, non-empty-list<ReflectionNamedType>} (see https://psalm.dev/224)
```
2022-12-06 18:26:50 +01:00
Marco Pivetta
79a1a8b26c Removed templated parameters from ReflectionClass#isInstance()
These templates were leading to false positives: assuming
an `object` is given as input, the inferred return
type would always have been `true`, which is obviously
not valid.

Removing them is the healthier alternative, for now.

Ref: https://github.com/vimeo/psalm/pull/8722#discussion_r1027102713
2022-12-06 11:21:09 +01:00
Marco Pivetta
d9a0cc5311 Prevent usage of callable objects in ReflectionFunction::__construct()
As per @weirdan's feedback, we can prevent
the usage of `object` instances that
implement `__invoke()`, as well as `array`
callables, by declaring the ctor argument of
`ReflectionFunction` to be either a real `Closure`,
or a `callable-string`.

While this may not be 100% of scenarios, it is a
healthy way to identify errors in userland.

Ref: https://github.com/vimeo/psalm/pull/8722#discussion_r1027151421
2022-12-06 11:19:16 +01:00
Marco Pivetta
d5cccbade2 Marking ReflectionProperty#$name as string rather than non-empty-string
Because @weirdan is a party pooper (they poop at the parties)

Ref: https://www.youtube.com/watch?v=gjwofYhUJEM
Ref: https://github.com/vimeo/psalm/pull/8722#discussion_r1027151708
2022-12-06 11:12:01 +01:00
Marco Pivetta
322cff6f43 Declaring more precise types and purity boundaries on ext-reflection symbols in .phpstub files
Also:

 * added PHP 8.2 stubs
 * refined types to make impossible scenarios more clear (like `ReflectionIntersectionType#allowsNull()`)

This is a first attempt at refining these types: the structure of these stubs is quite confusing to me,
so I don't know if this approach is correct, and if the stubs are merged together, or if entire symbols
need to be completely re-declared for each PHP version.
2022-12-06 11:08:30 +01:00
Mark McEver
9764803c55 Allowed taints to pass through urlencode() 2022-12-05 17:25:36 -06:00
Matthew Brown
8d36bdc3ed
Make array shapes strict by default (#8701)
* Make array shapes strict by default

* Fix PSL tests
2022-11-11 20:14:21 -05:00
68a5511057 Merge remote-tracking branch 'origin/4.x' into HEAD 2022-11-08 10:25:04 +01:00
Marco Pivetta
5e9b921fc6 Making json_encode() always produce a non-empty-string, when successful
`json_encode()` never produces `''` as a value: that would be invalid JSON anyway
2022-11-07 20:42:47 +01:00
1986c8b4a8
Add support for strict arrays, fix type alias intersection, fix array_is_list assertion on non-lists (#8395)
* Immutable CodeLocation

* Remove excess clones

* Remove external clones

* Remove leftover clones

* Fix final clone issue

* Immutable storages

* Refactoring

* Fixes

* Fixes

* Fix

* Fix

* Fixes

* Simplify

* Fixes

* Fix

* Fixes

* Update

* Fix

* Cache global types

* Fix

* Update

* Update

* Fixes

* Fixes

* Refactor

* Fixes

* Fix

* Fix

* More caching

* Fix

* Fix

* Update

* Update

* Fix

* Fixes

* Update

* Refactor

* Update

* Fixes

* Break one more test

* Fix

* FIx

* Fix

* Fix

* Fix

* Fix

* Improve performance and readability

* Equivalent logic

* Fixes

* Revert

* Revert "Revert"

This reverts commit f9175100c8452c80559234200663fd4c4f4dd889.

* Fix

* Fix reference bug

* Make default TypeVisitor immutable

* Bugfix

* Remove clones

* Partial refactoring

* Refactoring

* Fixes

* Fix

* Fixes

* Fixes

* cs-fix

* Fix final bugs

* Add test

* Misc fixes

* Update

* Fixes

* Experiment with removing different property

* revert "Experiment with removing different property"

This reverts commit ac1156e077fc4ea633530d51096d27b6e88bfdf9.

* Uniform naming

* Uniform naming

* Hack hotfix

* Clean up $_FILES ref #8621

* Undo hack, try fixing properly

* Helper method

* Remove redundant call

* Partially fix bugs

* Cleanup

* Change defaults

* Fix bug

* Fix (?, hope this doesn't break anything else)

* cs-fix

* Review fixes

* Bugfix

* Bugfix

* Improve logic

* Add support for list{} and callable-list{} types, properly implement array_is_list assertions (fixes #8389)

* Default to sealed arrays

* Fix array_merge bug

* Fixes

* Fix

* Sealed type checks

* Properly infer properties-of and get_object_vars on final classes

* Fix array_map zipping

* Fix tests

* Fixes

* Fixes

* Fix more stuff

* Recursively resolve type aliases

* Fix typo

* Fixes

* Fix array_is_list assertion on keyed array

* Add BC docs

* Fixes

* fix

* Update

* Update

* Update

* Update

* Seal arrays with count assertions

* Fix #8528

* Fix

* Update

* Improve sealed array foreach logic

* get_object_vars on template properties

* Fix sealed array assertion reconciler logic

* Improved reconciler

* Add tests

* Single source of truth for test types

* Fix tests

* Fixup tests

* Fixup tests

* Fixup tests

* Update

* Fix tests

* Fix tests

* Final fixes

* Fixes

* Use list syntax only when needed

* Fix tests

* Cs-fix

* Update docs

* Update docs

* Update docs

* Update docs

* Update docs

* Document missing types

* Update docs

* Improve class-string-map docs

* Update

* Update

* I love working on psalm :)

* Keep arrays unsealed by default

* Fixup tests

* Fix syntax mistake

* cs-fix

* Fix typo

* Re-import missing types

* Keep strict types only in return types

* argc/argv fixes

* argc/argv fixes

* Fix test

* Comment-out valinor code, pinging @romm pls merge https://github.com/CuyZ/Valinor/pull/246 so we can add valinor to the psalm docs :)
2022-11-05 22:34:42 +01:00
Alies Lapatsin
d9a08ec047 Add stubs for ext-random (PHP 8.2) 2022-11-02 15:59:56 +03:00
William Owen O. Ponce
77b3962b94 Fix typo 2022-10-31 23:09:07 +08:00
Thomas Gerbet
62e92fb0cf Add stubs for ext-ffi
See #8612
2022-10-25 19:59:44 +02:00
orklah
e8e8777561
Merge pull request #8592 from gphargreaves/#7810/improve-reflection-stubs
#7810/improve reflection stubs
2022-10-18 00:09:06 +02:00
orklah
48b8efde99
Merge pull request #8584 from boesing/feature/8521
Enhance type detection for internal php functions `key`, `current`, `end` and `reset`
2022-10-18 00:07:13 +02:00
Maximilian Bösing
7f35bff0d9
feature: enhance type detection for internal php functions key, current, end and reset
Signed-off-by: Maximilian Bösing <2189546+boesing@users.noreply.github.com>
2022-10-17 20:24:40 +02:00
Greg Hargreaves
45bb58ebfa Add stub for reflection property isReadOnly 2022-10-17 00:46:19 +01:00
Greg Hargreaves
ea39a6e674 Fixes #7810 2022-10-17 00:33:26 +01:00
cbd1a27ea7
Merge branch 'master' into merge_4.x 2022-10-16 13:49:21 +02:00
b79c43a288 Merge remote-tracking branch 'origin/4.x' into merge_4.x 2022-10-16 13:42:43 +02:00
748a74bb2c Merge remote-tracking branch 'origin/4.x' into HEAD 2022-10-16 13:41:27 +02:00
ADmad
9bd4d7a740 Fix template param for SplDoublyLinkedList.
It's key is always an integer.
2022-10-14 11:54:53 +05:30
Greg Hargreaves
ef0d2256a6 Remove link to php-src as was part of the documented reason for the return type false 2022-10-14 00:56:20 +01:00
Greg Hargreaves
f573ef5163 Correct return type of DateTimeImmutable sub method stub 2022-10-14 00:49:57 +01:00
kkmuffme
88ba8452c4 some more string values 2022-10-09 17:01:38 +02:00
kkmuffme
5bfc0f960b force $value to be string
technically all stringable types work https://github.com/phpredis/phpredis/issues/1735#event-7529843256 however they're all cast to string implicitly, which unevitably leads to unexpected results (see riskyCast,...)
2022-10-09 16:53:30 +02:00
kkmuffme
47317205c1 small improvement for return type of mGet 2022-10-09 16:51:26 +02:00
kkmuffme
dfa82366d7 add false return type to additional phpredis functions
address https://github.com/phpredis/phpredis/pull/2120#issuecomment-1166644919 - weedwacker method, as I don't have time to check it all one by one
2022-10-09 16:46:43 +02:00
orklah
5108834088
Merge pull request #8136 from sergkash7/patch-1
Update phpredis.phpstub
2022-09-09 07:47:53 +02:00
Aleksandr Zhuravlev
d7097281ba trim(), ltrim(), rtrim() now keep lowercase string attribute 2022-08-31 21:02:20 +12:00
Tim Düsterhus
3c2018a1e0 Configure a correct attribute target in stubs/CoreGenericClasses.phpstub 2022-08-24 21:32:26 +02:00
Thomas Gerbet
4b1adaafec Allow *bin2hex and *bin2base64 functions to keep non-empty-string type
Those functions should not return a string when they receive a
non-empty-string in input.

The following example is expected to work:
```php
<?php

/**
 * @param non-empty-string $i
 */
function takesNonEmptyString(string $i): void {
    echo $i;
}

takesNonEmptyString(bin2hex("a"));
takesNonEmptyString(base64_encode("a"));
```
2022-08-23 16:38:17 +02:00
Markus Staab
63915d1e2c added SensitiveParameter, AllowDynamicProperties php 8.2 attributes 2022-08-22 16:44:55 +02:00
Marco Pivetta
13828771c7 Removed DateTimeImmutable::createFromInterface() from stubs
While there is value in declaring `DateTimeImmutable::createFromInterface()` as mutation-free in
a stub, this method was introduced in PHP 8.0, so we cannot really declare it in a stub.

For now, we drop it, as the value of its stub declaration is much lower than the problems it
introduces through its conditional existence.
2022-08-05 13:28:53 +02:00
Marco Pivetta
68ffae097e Simplified DateTimeImmutable::format(): always returns a string
Also:

 * a non-empty format string will always lead to `non-empty-string`
 * it seems that you can throw **everything** at `DateTimeInterface#format()`, even null bytes,
   and it will always produce a `string`
2022-08-05 13:21:28 +02:00
Marco Pivetta
aaac9ccb90 Removed DateTimeImmutable::setTimestamp() from the CallMap: fully covered by stub
Also simplified the return type from `static|false` to `static`, since
the method throws at all times, on failure.

On PHP 7.x, it could only fail if an invalid type was passed in, which is
not really valid anyway, from a type perspective.

Ref (PHP 8.1.x): 32d55f7422/ext/date/php_date.c (L3353-L3369)
Ref (PHP 7.0.33): bf574c2b67/ext/date/php_date.c (L3596-L3612)
2022-08-05 12:50:51 +02:00
Marco Pivetta
964f64a500 Removed DateTimeImmutable::setISODate() from the CallMap: fully covered by stub
Also simplified the return type from `static|false` to `static`, since
the method throws at all times, on failure.

On PHP 7.x, it could only fail if an invalid type was passed in, which is
not really valid anyway, from a type perspective.

Ref (PHP 8.1.x): 32d55f7422/ext/date/php_date.c (L3308-L3324)
Ref (PHP 7.0.33): bf574c2b67/ext/date/php_date.c (L3549-L3565)
2022-08-05 12:49:45 +02:00
Marco Pivetta
0a6c9d0177 Removed DateTimeImmutable::setDate() from the CallMap: fully covered by stub
Also simplified the return type from `static|false` to `static`, since
the method throws at all times, on failure.

On PHP 7.x, it could only fail if an invalid type was passed in, which is
not really valid anyway, from a type perspective.

Ref (PHP 8.1.x): 32d55f7422/ext/date/php_date.c (L3258-L3274)
Ref (PHP 7.0.33): bf574c2b67/ext/date/php_date.c (L3496-L3512)
2022-08-05 12:48:29 +02:00
Marco Pivetta
e61c593a2c Removed DateTimeImmutable::setTime() from the CallMap: fully covered by stub
Also simplified the return type from `static|false` to `static`, since
the method throws at all times, on failure.

On PHP 7.x, it could only fail if an invalid type was passed in, which is
not really valid anyway, from a type perspective.

Ref (PHP 8.1.x): 32d55f7422/ext/date/php_date.c (L3212-L3228)
Ref (PHP 7.0.33): bf574c2b67/ext/date/php_date.c (L3447-L3463)
2022-08-05 12:47:04 +02:00
Marco Pivetta
4fe554d6d2 Removed DateTimeImmutable::setTimezone() from the CallMap: fully covered by stub
Also simplified the return type from `static|false` to `static`, since
the method throws at all times, on failure.

On PHP 7.x, it could only fail if an invalid type was passed in, which is
not really valid anyway, from a type perspective.

Ref (PHP 8.2.x): 534127d3b2/ext/date/php_date.c (L3291-L3307)
Ref (PHP 8.2.x): 534127d3b2/ext/date/php_date.stub.php (L517-L518)
Ref (PHP 7.0.33): bf574c2b67/ext/date/php_date.c (L3363-L3379)
2022-08-05 12:42:45 +02:00
Marco Pivetta
7cd3d49dc4 Removed DateTimeImmutable::modify() from the CallMap: fully covered by stub
Also expanded the return type from `static` to `static|false`, since the
operation can fail (with a warning too), such as in following example:

https://3v4l.org/Xrjlc

```php
<?php

var_dump(
    (new DateTimeImmutable())
        ->modify('potato')
);
```

Produces

```
Warning: DateTimeImmutable::modify(): Failed to parse time string (potato) at position 0 (p): The timezone could not be found in the database in /in/Xrjlc on line 6
bool(false)
```

Ref: 534127d3b2/ext/date/php_date.stub.php (L508-L509)
2022-08-05 12:37:24 +02:00