1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 04:45:20 +01:00
Commit Graph

116 Commits

Author SHA1 Message Date
orklah
54cd529642
Merge pull request #9170 from mmcev106/filter-var-pure
Added @psalm-pure to filter_var()
2023-02-02 23:39:06 +01:00
Mark McEver
b5781c34e8 Fixed a case where the conditional taint, specialize, & flow features were not playing nicely together 2023-02-01 15:41:52 -06:00
Mark McEver
bb2cf1f30a Added @psalm-pure to filter_var() 2023-01-23 15:09:29 -06:00
Ryan Bonham
cb204edcdd
Correct Stubs for PHP 7 and PHP 8 2023-01-07 12:38:49 -05:00
Ryan Bonham
0d360419b7
Update Call Maps and Signature for get_headers 2023-01-06 19:24:00 -05:00
orklah
790c30959d
Merge pull request #9016 from Ocramius/feature/#5039-more-refined-types-for-explode-core-function
Refined `explode()` types
2022-12-29 10:23:18 +01:00
Mark McEver
53c3f1ebb3 Prevent other DB escaping functions from escaping non-sql taints 2022-12-28 14:19:01 -06:00
Mark McEver
69f31dcd4a Prevent mysqli escaping functions from escaping non-sql taints 2022-12-28 13:39:01 -06:00
Marco Pivetta
c0c0116809 Using list{0: string, 1?: string} syntax for more precise array key types
Thanks to @orklah's feedback, the `explode()` return type is now much more precise too.

Ref: https://github.com/vimeo/psalm/pull/9016#discussion_r1058458616
2022-12-28 17:48:33 +01:00
Marco Pivetta
bfded43614 Ensure that explode($d, lowercase-string) produces list<lowercase-string> types
This specific distinction seems to be very important for Psalm, as `explode()` and
`lowercase-string` are used aggressively across the codebase.

Also, this change expands the baseline by a few entries, since some of the code locations
instide Psalm itself have un-checked list destructuring operations, as well as array
access calls on potentially undefined array keys produced by `explode()`, which were
previously just `list<string>`, and are now `array{0: string, 1?: string}`, which is
a bit more precise.
2022-12-28 17:26:25 +01:00
Marco Pivetta
04999b172a Refined explode() types
Fixes #5039

This patch removes the need for a custom function return type
provider for `explode()`, and instead replaces all that with a single
stub for the `explode()` function, which provides types for some of
the most common `$limit` input values.

With this change, the `$delimiter` is enforced to be a `non-empty-string`,
which will lead to downstream consumers having to adjust some code accordingly,
but that shouldn't affect the most common scenario of exploding a string
based with a constant `literal-string` delimiter, which most PHP devs tend to do.

This change didn't come with an accompanying test, since that would be a bit
wasteful, but it was verified locally with following script:

```php
<?php

$possible0  = explode(',', 'hello, world', -100);
$possible1  = explode(',', 'hello, world', -1);
$possible2  = explode(',', 'hello, world', 0);
$possible3  = explode(',', 'hello, world', 1);
$possible4  = explode(',', 'hello, world', 2);
$possible5  = explode(',', 'hello, world', 3);
$possible6  = explode(',', 'hello, world', 4);
try {
    $impossible1 = explode('', '', -1);
} catch (Throwable $impossible1) {}

$traced = [$possible0, $possible1, $possible2, $possible3, $possible4, $possible5, $possible6, $impossible1];

/** @psalm-trace $traced */

var_dump($traced);

return $traced;
```

Running psalm locally, this produces:

```
psalm on  feature/#5039-more-refined-types-for-explode-core-function [?] via 🐘 v8.1.13 via ❄️  impure (nix-shell)
❯ ./psalm --no-cache explode.php
Target PHP version: 7.4 (inferred from composer.json) Extensions enabled: dom, simplexml (unsupported extensions: ctype, json, libxml, mbstring, tokenizer)
Scanning files...
Analyzing files...

░

To whom it may concern: Psalm cannot detect unused classes, methods and properties
when analyzing individual files and folders. Run on the full project to enable
complete unused code detection.

ERROR: InvalidArgument - explode.php:11:28 - Argument 1 of explode expects non-empty-string, but '' provided (see https://psalm.dev/004)
    $impossible1 = explode('', '', -1);

ERROR: PossiblyUndefinedGlobalVariable - explode.php:14:96 - Possibly undefined global variable $impossible1 defined in try block (see https://psalm.dev/126)
$traced = [$possible0, $possible1, $possible2, $possible3, $possible4, $possible5, $possible6, $impossible1];

ERROR: ForbiddenCode - explode.php:18:1 - Unsafe var_dump (see https://psalm.dev/002)
/** @psalm-trace $traced */

var_dump($traced);

ERROR: Trace - explode.php:18:1 - $traced: list{0: array<never, never>, 1: non-empty-list<string>, 2: list{string}, 3: list{string}, 4: array{0: string, 1?: string}, 5: array{0: string, 1?: string, 2?: string}, 6: non-empty-list<string>, 7?: Throwable|non-empty-list<string>} (see https://psalm.dev/224)
/** @psalm-trace $traced */

var_dump($traced);

------------------------------
4 errors found
------------------------------

Checks took 6.31 seconds and used 265.386MB of memory
Psalm was unable to infer types in the codebase
```

The actual runtime behavior on PHP 8.x: https://3v4l.org/0NKlW

```
array(8) {
  [0]=>
  array(0) {
  }
  [1]=>
  array(1) {
    [0]=>
    string(5) "hello"
  }
  [2]=>
  array(1) {
    [0]=>
    string(12) "hello, world"
  }
  [3]=>
  array(1) {
    [0]=>
    string(12) "hello, world"
  }
  [4]=>
  array(2) {
    [0]=>
    string(5) "hello"
    [1]=>
    string(6) " world"
  }
  [5]=>
  array(2) {
    [0]=>
    string(5) "hello"
    [1]=>
    string(6) " world"
  }
  [6]=>
  array(2) {
    [0]=>
    string(5) "hello"
    [1]=>
    string(6) " world"
  }
  [7]=>
  object(ValueError)#1 (7) {
    ["message":protected]=>
    string(51) "explode(): Argument #1 ($separator) cannot be empty"
    ["string":"Error":private]=>
    string(0) ""
    ["code":protected]=>
    int(0)
    ["file":protected]=>
    string(9) "/in/0NKlW"
    ["line":protected]=>
    int(11)
    ["trace":"Error":private]=>
    array(1) {
      [0]=>
      array(4) {
        ["file"]=>
        string(9) "/in/0NKlW"
        ["line"]=>
        int(11)
        ["function"]=>
        string(7) "explode"
        ["args"]=>
        array(3) {
          [0]=>
          string(0) ""
          [1]=>
          string(0) ""
          [2]=>
          int(-1)
        }
      }
    }
    ["previous":"Error":private]=>
    NULL
  }
}
```

On PHP 7:

```
Warning: explode(): Empty delimiter in /in/0NKlW on line 11
array(8) {
  [0]=>
  array(0) {
  }
  [1]=>
  array(1) {
    [0]=>
    string(5) "hello"
  }
  [2]=>
  array(1) {
    [0]=>
    string(12) "hello, world"
  }
  [3]=>
  array(1) {
    [0]=>
    string(12) "hello, world"
  }
  [4]=>
  array(2) {
    [0]=>
    string(5) "hello"
    [1]=>
    string(6) " world"
  }
  [5]=>
  array(2) {
    [0]=>
    string(5) "hello"
    [1]=>
    string(6) " world"
  }
  [6]=>
  array(2) {
    [0]=>
    string(5) "hello"
    [1]=>
    string(6) " world"
  }
  [7]=>
  bool(false)
}
```
2022-12-28 17:11:40 +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
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
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
748a74bb2c Merge remote-tracking branch 'origin/4.x' into HEAD 2022-10-16 13:41:27 +02:00
Aleksandr Zhuravlev
d7097281ba trim(), ltrim(), rtrim() now keep lowercase string attribute 2022-08-31 21:02:20 +12: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
Corey Taylor
f28ac73777 Fix nullable return types for CallMap functions 2022-07-13 22:44:38 -05:00
AndrolGenhald
285740a753 Merge branch '4.x' 2022-07-07 15:01:38 -05:00
Adrien Foulon
6c49dad38c
fix: ltrim may return class-string #8218
Fixes #8218
2022-07-06 02:36:20 +02:00
Bruce Weirdan
e0acf22e40
Merge branch '4.x' into update-master 2022-05-28 14:49:12 -04:00
hirokinoue
4fc34d998b improve @return annotation of join() 2022-05-14 23:47:46 +09:00
hirokinoue
91640e7e90 improve @return annotation of implode() 2022-05-14 23:44:43 +09:00
Markus Staab
3c837e5d9a
fix missing is_a() parameter type 2022-05-12 15:37:29 +02:00
hirokinoue
2b34b1228b handle the non-empty case for usort() 2022-04-29 00:36:28 +09:00
hirokinoue
8c64bddf29 handle the non-empty case for uksort() 2022-04-29 00:23:57 +09:00
hirokinoue
37bf36d475 handle the non-empty case for uasort() 2022-04-28 23:49:32 +09:00
hirokinoue
95b5e8cb56 handle the non-empty case for shuffle() 2022-04-28 23:07:43 +09:00
hirokinoue
1605b18678 handle the non-empty case for rsort() 2022-04-28 23:01:17 +09:00
hirokinoue
0770f0128c improve syntax 2022-04-28 22:44:39 +09:00
Matt Brown
043bbfbbb4 Remove useless array casting as CallMap for stream_select is reset. 2022-04-27 01:40:51 -04:00
hirokinoue
37c53ee783 handle the non-empty case for sort() 2022-04-23 22:51:50 +09:00
Nicolas Giraud
0dc435409c Replace changes in the CallMap for stream_select by a stub. 2022-03-11 08:52:36 +01:00
Mark McEver
828b093964 Prevent unnecessary filter_var() warnings on primitive types 2022-02-15 14:13:44 -06:00
Patrick Remy
8cd5ccd076
feat: make value-of<T> capable for template types 2022-01-27 22:28:40 +01:00
Patrick Remy
2880d046ce
feat: make key-of/value-of usable with non-const arrays 2022-01-27 22:22:14 +01:00
orklah
0747b48d06
remove TEmpty 2022-01-03 04:09:59 +02:00
Bruce Weirdan
3cce69189f
array_count_values return type for uncertain arrays
Fixes vimeo/psalm#7114
2021-12-10 02:45:58 +02:00
marcosh
07224e7d31 abs should always return a positive integer 2021-12-07 11:52:13 +01:00
Bruce Weirdan
9c324a7d74
Refined strlen() return type to not include negative ints
Fixes vimeo/psalm#7062
2021-12-05 21:35:58 +02:00
Bruce Weirdan
dc271fe25c
Consider emptiness for array_count_values()
Fixes vimeo/psalm#7044
2021-12-02 04:51:06 +02:00
ralila
d57c246c93 Add stub for preg_match 2021-11-29 14:21:58 +01:00
ralila
e5ed2e7066 Add @psalm-ignore-falsable-return to the stub 2021-11-14 10:59:24 +01:00