Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A string after strlen > 0 check should be a non-empty-string #7387

Open
MauricioFauth opened this issue Jan 13, 2022 · 4 comments
Open

A string after strlen > 0 check should be a non-empty-string #7387

MauricioFauth opened this issue Jan 13, 2022 · 4 comments

Comments

@MauricioFauth
Copy link
Contributor

https://psalm.dev/r/ca291dd273

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/ca291dd273
<?php

/**
 * @return non-empty-string
 */
function nonEmptyString(string $str): string {
    return strlen($str) > 0 ? $str : 'string';
}

/**
 * @return non-empty-string
 */
function nonEmptyMbString(string $str): string {
    return mb_strlen($str) > 0 ? $str : 'string';
}
Psalm output (using commit f439d65):

INFO: LessSpecificReturnStatement - 7:12 - The type 'string' is more general than the declared return type 'non-empty-string' for nonEmptyString

INFO: MoreSpecificReturnType - 4:12 - The declared return type 'non-empty-string' for nonEmptyString is more specific than the inferred return type 'string'

INFO: LessSpecificReturnStatement - 14:12 - The type 'string' is more general than the declared return type 'non-empty-string' for nonEmptyMbString

INFO: MoreSpecificReturnType - 11:12 - The declared return type 'non-empty-string' for nonEmptyMbString is more specific than the inferred return type 'string'

@orklah
Copy link
Collaborator

orklah commented Jan 13, 2022

Good idea!

This is handled in AssertionFinder. The role of this class is to find any hint it can use to refine a variable type. For example if(!empty($a)) will generate an assertion !empty. That way, once we enter the AssertionReconciler, we'll be able to refine the type of $a (previously stdClass|null) into stdClass.

AssertionFinder has 4 main methods:
getGreaterAssertions (for cases like $a > 5)
getLesserAssertions (for $a < 5)
scrapeInequalityAssertions (for $a !== 5)
scrapeEqualityAssertions (for $a === 5)
So every case must be taken into account for (mb_?)strlen

What you want to do is actually closer to what we already have with count (for example in if(count($arr) > 0), so you need something similar to that.

the count() case is handled here for getGreaterAssertions:

$count_inequality_position = self::hasLessThanCountEqualityCheck($conditional, $max_count);

The method we call must detect when count() > 5 is used, and then extract an assertion from that

In your case, you'll want to detect any strlen used on a string and then deduct if you can infer something from it.
Here are the assertions you should use:

  • strlen($a) > 5 should create an assertion !empty (to transform string into non-empty-string
  • strlen($a) == 1 should create an assertion !empty
  • strlen($a) != 0 should create an assertion !empty

So this means you don't have to change anything in getLesserAssertions.

Don't hesitate to ask questions or to ping me for more help or explanations!

LeoVie added a commit to LeoVie/psalm that referenced this issue Nov 25, 2022
LeoVie added a commit to LeoVie/psalm that referenced this issue Nov 27, 2022
LeoVie added a commit to LeoVie/psalm that referenced this issue Dec 13, 2022
LeoVie added a commit to LeoVie/psalm that referenced this issue Dec 16, 2022
LeoVie added a commit to LeoVie/psalm that referenced this issue Dec 16, 2022
LeoVie added a commit to LeoVie/psalm that referenced this issue Jan 30, 2023
orklah added a commit that referenced this issue Jan 30, 2023
#7387 Add asserting non-empty-string by strlen
@theodorejb
Copy link
Contributor

Should this be closed now?

@weirdan weirdan closed this as completed Feb 3, 2023
weirdan added a commit to weirdan/psalm that referenced this issue Feb 21, 2023
weirdan added a commit to weirdan/psalm that referenced this issue Feb 21, 2023
@weirdan
Copy link
Collaborator

weirdan commented Feb 21, 2023

The PR implementing this has been reverted, so I'm reopening the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants