mirror of
https://github.com/danog/psalm.git
synced 2024-11-27 12:55:26 +01:00
Infer literal string from encapsed (interpolated) string.
This commit is contained in:
parent
9b4c8cb53f
commit
450409f045
@ -3,6 +3,7 @@
|
|||||||
namespace Psalm\Internal\Analyzer\Statements\Expression;
|
namespace Psalm\Internal\Analyzer\Statements\Expression;
|
||||||
|
|
||||||
use PhpParser;
|
use PhpParser;
|
||||||
|
use PhpParser\Node\Scalar\EncapsedStringPart;
|
||||||
use Psalm\CodeLocation;
|
use Psalm\CodeLocation;
|
||||||
use Psalm\Context;
|
use Psalm\Context;
|
||||||
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
|
use Psalm\Internal\Analyzer\Statements\ExpressionAnalyzer;
|
||||||
@ -29,6 +30,8 @@ class EncapsulatedStringAnalyzer
|
|||||||
|
|
||||||
$all_literals = true;
|
$all_literals = true;
|
||||||
|
|
||||||
|
$literal_string = "";
|
||||||
|
|
||||||
foreach ($stmt->parts as $part) {
|
foreach ($stmt->parts as $part) {
|
||||||
if ($part instanceof PhpParser\Node\Scalar\EncapsedStringPart
|
if ($part instanceof PhpParser\Node\Scalar\EncapsedStringPart
|
||||||
&& $part->value
|
&& $part->value
|
||||||
@ -42,7 +45,7 @@ class EncapsulatedStringAnalyzer
|
|||||||
|
|
||||||
$part_type = $statements_analyzer->node_data->getType($part);
|
$part_type = $statements_analyzer->node_data->getType($part);
|
||||||
|
|
||||||
if ($part_type) {
|
if ($part_type !== null) {
|
||||||
$casted_part_type = CastAnalyzer::castStringAttempt(
|
$casted_part_type = CastAnalyzer::castStringAttempt(
|
||||||
$statements_analyzer,
|
$statements_analyzer,
|
||||||
$context,
|
$context,
|
||||||
@ -54,6 +57,14 @@ class EncapsulatedStringAnalyzer
|
|||||||
$all_literals = false;
|
$all_literals = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($literal_string !== null) {
|
||||||
|
if ($casted_part_type->isSingleLiteral()) {
|
||||||
|
$literal_string .= $casted_part_type->getSingleLiteral();
|
||||||
|
} else {
|
||||||
|
$literal_string = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($statements_analyzer->data_flow_graph
|
if ($statements_analyzer->data_flow_graph
|
||||||
&& !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())
|
&& !in_array('TaintedInput', $statements_analyzer->getSuppressedIssues())
|
||||||
) {
|
) {
|
||||||
@ -82,11 +93,20 @@ class EncapsulatedStringAnalyzer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} elseif ($part instanceof EncapsedStringPart) {
|
||||||
|
if ($literal_string !== null) {
|
||||||
|
$literal_string .= $part->value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$all_literals = false;
|
||||||
|
$literal_string = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($non_empty) {
|
if ($non_empty) {
|
||||||
if ($all_literals) {
|
if ($literal_string !== null) {
|
||||||
|
$new_type = Type::getString($literal_string);
|
||||||
|
} elseif ($all_literals) {
|
||||||
$new_type = new Union([new TNonEmptyNonspecificLiteralString()]);
|
$new_type = new Union([new TNonEmptyNonspecificLiteralString()]);
|
||||||
} else {
|
} else {
|
||||||
$new_type = new Union([new TNonEmptyString()]);
|
$new_type = new Union([new TNonEmptyString()]);
|
||||||
|
@ -1329,6 +1329,32 @@ class Union implements TypeNode
|
|||||||
|| isset($this->types['true']);
|
|| isset($this->types['true']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isSingleLiteral(): bool
|
||||||
|
{
|
||||||
|
return count($this->types) === 1
|
||||||
|
&& count($this->literal_int_types)
|
||||||
|
+ count($this->literal_string_types)
|
||||||
|
+ count($this->literal_float_types) === 1
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TLiteralInt|TLiteralString|TLiteralFloat
|
||||||
|
*/
|
||||||
|
public function getSingleLiteral()
|
||||||
|
{
|
||||||
|
if (!$this->isSingleLiteral()) {
|
||||||
|
throw new InvalidArgumentException("Not a single literal");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ($literal = reset($this->literal_int_types)) !== false
|
||||||
|
? $literal
|
||||||
|
: (($literal = reset($this->literal_string_types)) !== false
|
||||||
|
? $literal
|
||||||
|
: reset($this->literal_float_types))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
public function hasLiteralString(): bool
|
public function hasLiteralString(): bool
|
||||||
{
|
{
|
||||||
return count($this->literal_string_types) > 0;
|
return count($this->literal_string_types) > 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user