mirror of
https://github.com/danog/psalm.git
synced 2025-01-21 21:31:13 +01:00
Prevent string being used in non-empty-string location
This commit is contained in:
parent
07aaa3f99d
commit
cc9e0fab67
@ -561,10 +561,6 @@ class BinaryOpAnalyzer
|
||||
$context->vars_possibly_in_scope
|
||||
);
|
||||
} elseif ($stmt instanceof PhpParser\Node\Expr\BinaryOp\Concat) {
|
||||
$stmt_type = Type::getString();
|
||||
|
||||
$statements_analyzer->node_data->setType($stmt, $stmt_type);
|
||||
|
||||
if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->left, $context) === false) {
|
||||
return false;
|
||||
}
|
||||
@ -573,16 +569,31 @@ class BinaryOpAnalyzer
|
||||
return false;
|
||||
}
|
||||
|
||||
$stmt_left_type = $statements_analyzer->node_data->getType($stmt->left);
|
||||
$stmt_right_type = $statements_analyzer->node_data->getType($stmt->right);
|
||||
|
||||
if ($stmt_left_type
|
||||
&& $stmt_right_type
|
||||
&& $stmt_left_type->getId() === 'non-empty-string'
|
||||
&& $stmt_right_type->getId() === 'non-empty-string'
|
||||
) {
|
||||
$stmt_type = new Type\Union([new Type\Atomic\TNonEmptyString()]);
|
||||
} else {
|
||||
$stmt_type = Type::getString();
|
||||
}
|
||||
|
||||
$statements_analyzer->node_data->setType($stmt, $stmt_type);
|
||||
|
||||
if ($codebase->taint) {
|
||||
$sources = [];
|
||||
$either_tainted = 0;
|
||||
|
||||
if ($stmt_left_type = $statements_analyzer->node_data->getType($stmt->left)) {
|
||||
if ($stmt_left_type) {
|
||||
$sources = $stmt_left_type->sources ?: [];
|
||||
$either_tainted = $stmt_left_type->tainted;
|
||||
}
|
||||
|
||||
if ($stmt_right_type = $statements_analyzer->node_data->getType($stmt->right)) {
|
||||
if ($stmt_right_type) {
|
||||
$sources = array_merge($sources, $stmt_right_type->sources ?: []);
|
||||
$either_tainted = $either_tainted | $stmt_right_type->tainted;
|
||||
}
|
||||
|
@ -767,6 +767,16 @@ class TypeAnalyzer
|
||||
}
|
||||
}
|
||||
|
||||
if ($container_type_part instanceof TNonEmptyString
|
||||
&& get_class($input_type_part) === TString::class
|
||||
) {
|
||||
if ($atomic_comparison_result) {
|
||||
$atomic_comparison_result->type_coerced = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($input_type_part->shallowEquals($container_type_part)
|
||||
|| ($input_type_part instanceof Type\Atomic\TCallableObjectLikeArray
|
||||
&& $container_type_part instanceof TArray)
|
||||
@ -1154,16 +1164,6 @@ class TypeAnalyzer
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($container_type_part instanceof TNonEmptyString
|
||||
&& get_class($input_type_part) === TString::class
|
||||
) {
|
||||
if ($atomic_comparison_result) {
|
||||
$atomic_comparison_result->type_coerced = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($container_type_part instanceof TNonEmptyString
|
||||
&& $input_type_part instanceof TLiteralString
|
||||
&& $input_type_part->value === ''
|
||||
|
@ -7,18 +7,18 @@ use Psalm\Type\Union;
|
||||
class TemplateResult
|
||||
{
|
||||
/**
|
||||
* @var array<string, array<non-empty-string, array{0: Union}>>
|
||||
* @var array<string, array<string, array{0: Union}>>
|
||||
*/
|
||||
public $template_types;
|
||||
|
||||
/**
|
||||
* @var array<string, array<non-empty-string, array{0: Union, 1?: int}>>
|
||||
* @var array<string, array<string, array{0: Union, 1?: int}>>
|
||||
*/
|
||||
public $generic_params;
|
||||
|
||||
/**
|
||||
* @param array<string, array<non-empty-string, array{0: Union}>> $template_types
|
||||
* @param array<string, array<non-empty-string, array{0: Union, 1?: int}>> $generic_params
|
||||
* @param array<string, array<string, array{0: Union}>> $template_types
|
||||
* @param array<string, array<string, array{0: Union, 1?: int}>> $generic_params
|
||||
*/
|
||||
public function __construct(array $template_types, array $generic_params)
|
||||
{
|
||||
|
@ -14,13 +14,10 @@ class TTemplateIndexedAccess extends \Psalm\Type\Atomic
|
||||
public $offset_param_name;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
* @var string
|
||||
*/
|
||||
public $defining_class;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $defining_class
|
||||
*/
|
||||
public function __construct(
|
||||
string $array_param_name,
|
||||
string $offset_param_name,
|
||||
|
@ -9,13 +9,10 @@ class TTemplateKeyOf extends TArrayKey
|
||||
public $param_name;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
* @var string
|
||||
*/
|
||||
public $defining_class;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $defining_class
|
||||
*/
|
||||
public function __construct(
|
||||
string $param_name,
|
||||
string $defining_class
|
||||
|
@ -24,12 +24,12 @@ class TTemplateParam extends \Psalm\Type\Atomic
|
||||
public $as;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
* @var string
|
||||
*/
|
||||
public $defining_class;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $defining_class
|
||||
* @param string $defining_class
|
||||
*/
|
||||
public function __construct(string $param_name, Union $extends, string $defining_class)
|
||||
{
|
||||
|
@ -19,14 +19,10 @@ class TTemplateParamClass extends TClassString
|
||||
public $as_type;
|
||||
|
||||
/**
|
||||
* @var non-empty-string
|
||||
* @var string
|
||||
*/
|
||||
public $defining_class;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $defining_class
|
||||
* @param string $param_name
|
||||
*/
|
||||
public function __construct(
|
||||
string $param_name,
|
||||
string $as,
|
||||
|
@ -1091,7 +1091,7 @@ class Union
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, array<non-empty-string, array{Type\Union, 1?:int}>> $template_types
|
||||
* @param array<string, array<string, array{Type\Union, 1?:int}>> $template_types
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
@ -2872,6 +2872,23 @@ class ConditionalTest extends \Psalm\Tests\TestCase
|
||||
}',
|
||||
'error_message' => 'TypeDoesNotContainType',
|
||||
],
|
||||
'nonEmptyString' => [
|
||||
'<?php
|
||||
/**
|
||||
* @psalm-param non-empty-string $name
|
||||
*/
|
||||
function sayHello(string $name) : void {
|
||||
echo "Hello " . $name;
|
||||
}
|
||||
|
||||
function takeInput() : void {
|
||||
if (isset($_GET["name"]) && is_string($_GET["name"])) {
|
||||
$name = trim($_GET["name"]);
|
||||
sayHello($name);
|
||||
}
|
||||
}',
|
||||
'error_message' => 'ArgumentTypeCoercion',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user