2016-10-22 19:23:18 +02:00
|
|
|
<?php
|
2018-11-06 03:57:36 +01:00
|
|
|
namespace Psalm\Internal\Analyzer\Statements;
|
2016-10-22 19:23:18 +02:00
|
|
|
|
|
|
|
use PhpParser;
|
2021-06-08 04:55:21 +02:00
|
|
|
use Psalm\CodeLocation;
|
|
|
|
use Psalm\Config;
|
|
|
|
use Psalm\Context;
|
2018-11-06 03:57:36 +01:00
|
|
|
use Psalm\Internal\Analyzer\ClosureAnalyzer;
|
|
|
|
use Psalm\Internal\Analyzer\Statements\Expression\Call\FunctionCallAnalyzer;
|
|
|
|
use Psalm\Internal\Analyzer\Statements\Expression\Call\MethodCallAnalyzer;
|
|
|
|
use Psalm\Internal\Analyzer\Statements\Expression\Call\NewAnalyzer;
|
|
|
|
use Psalm\Internal\Analyzer\Statements\Expression\Call\StaticCallAnalyzer;
|
|
|
|
use Psalm\Internal\Analyzer\StatementsAnalyzer;
|
2021-08-29 00:26:52 +02:00
|
|
|
use Psalm\Internal\Codebase\VariableUseGraph;
|
|
|
|
use Psalm\Internal\DataFlow\DataFlowNode;
|
2018-11-12 16:46:55 +01:00
|
|
|
use Psalm\Internal\FileManipulation\FileManipulationBuffer;
|
2016-10-22 19:23:18 +02:00
|
|
|
use Psalm\Issue\ForbiddenCode;
|
2016-11-06 01:53:39 +01:00
|
|
|
use Psalm\Issue\UnrecognizedExpression;
|
2016-11-02 07:29:00 +01:00
|
|
|
use Psalm\IssueBuffer;
|
2021-01-06 15:05:53 +01:00
|
|
|
use Psalm\Plugin\EventHandler\Event\AfterExpressionAnalysisEvent;
|
2016-10-22 19:23:18 +02:00
|
|
|
use Psalm\Type;
|
2021-06-08 04:55:21 +02:00
|
|
|
|
|
|
|
use function get_class;
|
2019-06-26 22:52:29 +02:00
|
|
|
use function in_array;
|
|
|
|
use function strtolower;
|
2016-10-22 19:23:18 +02:00
|
|
|
|
2018-12-02 00:37:49 +01:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*/
|
2018-11-06 03:57:36 +01:00
|
|
|
class ExpressionAnalyzer
|
2016-10-22 19:23:18 +02:00
|
|
|
{
|
2017-01-07 21:09:47 +01:00
|
|
|
public static function analyze(
|
2018-11-11 18:01:14 +01:00
|
|
|
StatementsAnalyzer $statements_analyzer,
|
2016-10-22 19:23:18 +02:00
|
|
|
PhpParser\Node\Expr $stmt,
|
|
|
|
Context $context,
|
2020-05-18 21:13:27 +02:00
|
|
|
bool $array_assignment = false,
|
2020-09-07 01:36:47 +02:00
|
|
|
?Context $global_context = null,
|
2019-11-25 17:44:54 +01:00
|
|
|
bool $from_stmt = false
|
2020-05-18 21:13:27 +02:00
|
|
|
) : bool {
|
2018-11-11 18:01:14 +01:00
|
|
|
$codebase = $statements_analyzer->getCodebase();
|
2018-11-06 03:57:36 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if (self::handleExpression(
|
|
|
|
$statements_analyzer,
|
|
|
|
$stmt,
|
|
|
|
$context,
|
|
|
|
$array_assignment,
|
|
|
|
$global_context,
|
|
|
|
$from_stmt
|
|
|
|
) === false
|
2019-09-01 06:56:46 +02:00
|
|
|
) {
|
2020-05-18 21:13:27 +02:00
|
|
|
return false;
|
2016-10-22 19:23:18 +02:00
|
|
|
}
|
|
|
|
|
2018-06-26 00:02:05 +02:00
|
|
|
if (!$context->inside_conditional
|
|
|
|
&& ($stmt instanceof PhpParser\Node\Expr\BinaryOp
|
|
|
|
|| $stmt instanceof PhpParser\Node\Expr\Instanceof_
|
|
|
|
|| $stmt instanceof PhpParser\Node\Expr\Assign
|
|
|
|
|| $stmt instanceof PhpParser\Node\Expr\BooleanNot
|
|
|
|
|| $stmt instanceof PhpParser\Node\Expr\Empty_
|
|
|
|
|| $stmt instanceof PhpParser\Node\Expr\Isset_
|
|
|
|
|| $stmt instanceof PhpParser\Node\Expr\FuncCall)
|
|
|
|
) {
|
2019-11-25 17:44:54 +01:00
|
|
|
$assertions = $statements_analyzer->node_data->getAssertions($stmt);
|
|
|
|
|
|
|
|
if ($assertions === null) {
|
2020-11-19 20:32:49 +01:00
|
|
|
$negate = $context->inside_negation;
|
|
|
|
|
|
|
|
while ($stmt instanceof PhpParser\Node\Expr\BooleanNot) {
|
|
|
|
$stmt = $stmt->expr;
|
|
|
|
$negate = !$negate;
|
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
Expression\AssertionFinder::scrapeAssertions(
|
2019-11-25 17:44:54 +01:00
|
|
|
$stmt,
|
|
|
|
$context->self,
|
|
|
|
$statements_analyzer,
|
2020-07-10 22:49:45 +02:00
|
|
|
$codebase,
|
2020-11-19 20:32:49 +01:00
|
|
|
$negate,
|
2020-07-10 22:49:45 +02:00
|
|
|
true,
|
|
|
|
false
|
2019-11-25 17:44:54 +01:00
|
|
|
);
|
|
|
|
}
|
2020-05-18 21:13:27 +02:00
|
|
|
}
|
2016-10-22 19:23:18 +02:00
|
|
|
|
2021-01-06 15:05:53 +01:00
|
|
|
$event = new AfterExpressionAnalysisEvent(
|
|
|
|
$stmt,
|
|
|
|
$context,
|
|
|
|
$statements_analyzer,
|
|
|
|
$codebase,
|
|
|
|
[]
|
|
|
|
);
|
2018-05-08 23:43:26 +02:00
|
|
|
|
2021-01-06 15:05:53 +01:00
|
|
|
if ($codebase->config->eventDispatcher->dispatchAfterExpressionAnalysis($event) === false) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-05-08 23:43:26 +02:00
|
|
|
|
2021-01-06 15:05:53 +01:00
|
|
|
$file_manipulations = $event->getFileReplacements();
|
2019-09-17 00:42:44 +02:00
|
|
|
|
2021-01-06 15:05:53 +01:00
|
|
|
if ($file_manipulations) {
|
|
|
|
FileManipulationBuffer::add($statements_analyzer->getFilePath(), $file_manipulations);
|
2016-10-22 19:23:18 +02:00
|
|
|
}
|
2016-11-01 19:14:35 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
2016-11-02 07:29:00 +01:00
|
|
|
}
|
2016-11-01 19:14:35 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
private static function handleExpression(
|
2019-11-08 13:01:34 +01:00
|
|
|
StatementsAnalyzer $statements_analyzer,
|
2020-05-18 21:13:27 +02:00
|
|
|
PhpParser\Node\Expr $stmt,
|
|
|
|
Context $context,
|
|
|
|
bool $array_assignment,
|
|
|
|
?Context $global_context,
|
|
|
|
bool $from_stmt
|
|
|
|
) : bool {
|
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Variable) {
|
|
|
|
return Expression\Fetch\VariableFetchAnalyzer::analyze(
|
|
|
|
$statements_analyzer,
|
|
|
|
$stmt,
|
|
|
|
$context,
|
|
|
|
false,
|
|
|
|
null,
|
|
|
|
$array_assignment
|
|
|
|
);
|
2019-11-08 13:01:34 +01:00
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Assign) {
|
|
|
|
$assignment_type = Expression\AssignmentAnalyzer::analyze(
|
2019-11-08 13:01:34 +01:00
|
|
|
$statements_analyzer,
|
2020-05-18 21:13:27 +02:00
|
|
|
$stmt->var,
|
2019-11-08 13:01:34 +01:00
|
|
|
$stmt->expr,
|
2020-03-17 22:34:45 +01:00
|
|
|
null,
|
2020-05-18 21:13:27 +02:00
|
|
|
$context,
|
|
|
|
$stmt->getDocComment()
|
|
|
|
);
|
|
|
|
|
|
|
|
if ($assignment_type === false) {
|
2019-11-08 13:01:34 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if (!$from_stmt) {
|
|
|
|
$statements_analyzer->node_data->setType($stmt, $assignment_type);
|
2019-11-08 13:01:34 +01:00
|
|
|
}
|
2020-05-18 21:13:27 +02:00
|
|
|
|
|
|
|
return true;
|
2019-11-08 13:01:34 +01:00
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\AssignOp) {
|
|
|
|
return Expression\AssignmentAnalyzer::analyzeAssignmentOperation($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2019-11-08 13:01:34 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\MethodCall) {
|
|
|
|
return MethodCallAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2019-11-08 13:01:34 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\StaticCall) {
|
|
|
|
return StaticCallAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2017-03-02 04:27:52 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\ConstFetch) {
|
|
|
|
Expression\Fetch\ConstFetchAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
2017-05-25 07:32:34 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
|
|
|
}
|
2018-11-06 03:57:36 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Scalar\String_) {
|
|
|
|
$statements_analyzer->node_data->setType($stmt, Type::getString($stmt->value));
|
2017-05-25 07:32:34 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
|
|
|
}
|
2019-08-21 17:25:08 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Scalar\EncapsedStringPart) {
|
|
|
|
return true;
|
|
|
|
}
|
2017-10-07 16:22:52 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Scalar\MagicConst) {
|
|
|
|
Expression\MagicConstAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
2019-09-26 21:08:05 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
|
|
|
}
|
2018-02-08 05:33:31 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Scalar\LNumber) {
|
|
|
|
$statements_analyzer->node_data->setType($stmt, Type::getInt(false, $stmt->value));
|
2019-09-19 17:59:43 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
2017-03-02 04:27:52 +01:00
|
|
|
}
|
2016-10-22 19:23:18 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Scalar\DNumber) {
|
|
|
|
$statements_analyzer->node_data->setType($stmt, Type::getFloat($stmt->value));
|
2016-10-22 19:23:18 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
2016-10-22 19:23:18 +02:00
|
|
|
}
|
2016-11-02 07:29:00 +01:00
|
|
|
|
2020-04-03 04:38:10 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\UnaryMinus || $stmt instanceof PhpParser\Node\Expr\UnaryPlus) {
|
|
|
|
return Expression\UnaryPlusMinusAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2020-04-03 04:38:10 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Isset_) {
|
|
|
|
Expression\IssetAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
$statements_analyzer->node_data->setType($stmt, Type::getBool());
|
2019-02-06 21:52:43 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
2019-02-06 21:52:43 +01:00
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\ClassConstFetch) {
|
|
|
|
return Expression\Fetch\ClassConstFetchAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2016-10-22 19:23:18 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\PropertyFetch) {
|
2020-06-18 17:53:24 +02:00
|
|
|
return Expression\Fetch\InstancePropertyFetchAnalyzer::analyze(
|
2020-05-18 21:13:27 +02:00
|
|
|
$statements_analyzer,
|
|
|
|
$stmt,
|
2020-06-25 06:24:37 +02:00
|
|
|
$context,
|
|
|
|
$array_assignment
|
2020-05-18 21:13:27 +02:00
|
|
|
);
|
|
|
|
}
|
2020-02-18 01:21:04 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\StaticPropertyFetch) {
|
2020-06-18 17:53:24 +02:00
|
|
|
return Expression\Fetch\StaticPropertyFetchAnalyzer::analyze(
|
2020-05-18 21:13:27 +02:00
|
|
|
$statements_analyzer,
|
|
|
|
$stmt,
|
|
|
|
$context
|
|
|
|
);
|
|
|
|
}
|
2020-02-18 01:21:04 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\BitwiseNot) {
|
|
|
|
return Expression\BitwiseNotAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2020-02-18 01:21:04 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\BinaryOp) {
|
|
|
|
return Expression\BinaryOpAnalyzer::analyze(
|
|
|
|
$statements_analyzer,
|
|
|
|
$stmt,
|
|
|
|
$context,
|
|
|
|
0,
|
|
|
|
$from_stmt
|
|
|
|
);
|
2016-10-22 19:23:18 +02:00
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\PostInc
|
|
|
|
|| $stmt instanceof PhpParser\Node\Expr\PostDec
|
|
|
|
|| $stmt instanceof PhpParser\Node\Expr\PreInc
|
|
|
|
|| $stmt instanceof PhpParser\Node\Expr\PreDec
|
|
|
|
) {
|
|
|
|
Expression\IncDecExpressionAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
2018-07-13 23:34:44 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
2016-10-22 19:23:18 +02:00
|
|
|
}
|
2016-11-02 07:29:00 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\New_) {
|
|
|
|
return NewAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2020-02-18 01:21:04 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Array_) {
|
|
|
|
return Expression\ArrayAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2016-10-22 19:23:18 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Scalar\Encapsed) {
|
|
|
|
return Expression\EncapsulatedStringAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2016-12-28 22:29:50 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\FuncCall) {
|
|
|
|
return FunctionCallAnalyzer::analyze(
|
|
|
|
$statements_analyzer,
|
|
|
|
$stmt,
|
|
|
|
$context
|
|
|
|
);
|
|
|
|
}
|
2019-03-16 02:50:16 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Ternary) {
|
|
|
|
return Expression\TernaryAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2019-02-26 07:03:33 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\BooleanNot) {
|
|
|
|
return Expression\BooleanNotAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
2016-12-28 22:29:50 +01:00
|
|
|
}
|
2019-03-16 02:50:16 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Empty_) {
|
|
|
|
Expression\EmptyAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
2016-10-22 19:23:18 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
2019-11-06 22:14:46 +01:00
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Closure
|
|
|
|
|| $stmt instanceof PhpParser\Node\Expr\ArrowFunction
|
|
|
|
) {
|
|
|
|
ClosureAnalyzer::analyzeExpression($statements_analyzer, $stmt, $context);
|
2017-09-03 01:48:59 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
2016-10-22 19:23:18 +02:00
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\ArrayDimFetch) {
|
|
|
|
return Expression\Fetch\ArrayFetchAnalyzer::analyze(
|
|
|
|
$statements_analyzer,
|
|
|
|
$stmt,
|
|
|
|
$context
|
|
|
|
);
|
|
|
|
}
|
2016-10-22 19:23:18 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Cast) {
|
|
|
|
return Expression\CastAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2020-01-30 04:28:40 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Clone_) {
|
|
|
|
return Expression\CloneAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
2019-03-17 21:31:56 +01:00
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Instanceof_) {
|
|
|
|
return Expression\InstanceofAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
2019-03-17 22:10:51 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Exit_) {
|
2020-06-25 23:17:08 +02:00
|
|
|
return Expression\ExitAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
2020-05-18 21:13:27 +02:00
|
|
|
}
|
2020-01-30 04:28:40 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Include_) {
|
|
|
|
return Expression\IncludeAnalyzer::analyze($statements_analyzer, $stmt, $context, $global_context);
|
|
|
|
}
|
2020-01-30 04:28:40 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Eval_) {
|
2020-05-23 06:03:29 +02:00
|
|
|
Expression\EvalAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
return true;
|
2020-05-18 21:13:27 +02:00
|
|
|
}
|
2020-01-30 04:28:40 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\AssignRef) {
|
|
|
|
return Expression\AssignmentAnalyzer::analyzeAssignmentRef($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\ErrorSuppress) {
|
|
|
|
$context->error_suppressing = true;
|
|
|
|
if (self::analyze($statements_analyzer, $stmt->expr, $context) === false) {
|
|
|
|
return false;
|
2020-01-30 04:28:40 +01:00
|
|
|
}
|
2020-05-18 21:13:27 +02:00
|
|
|
$context->error_suppressing = false;
|
2020-01-30 04:28:40 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
$expr_type = $statements_analyzer->node_data->getType($stmt->expr);
|
2020-02-21 21:17:35 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($expr_type) {
|
|
|
|
$statements_analyzer->node_data->setType($stmt, $expr_type);
|
2020-02-21 21:17:35 +01:00
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
2019-03-17 22:10:51 +01:00
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\ShellExec) {
|
2021-08-29 00:26:52 +02:00
|
|
|
if ($statements_analyzer->data_flow_graph instanceof VariableUseGraph) {
|
|
|
|
foreach ($stmt->parts as $part) {
|
|
|
|
if ($part instanceof PhpParser\Node\Expr\Variable) {
|
|
|
|
if (self::analyze($statements_analyzer, $part, $context) === false) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
$expr_type = $statements_analyzer->node_data->getType($part);
|
2021-08-29 00:39:36 +02:00
|
|
|
if ($expr_type === null) {
|
|
|
|
break;
|
|
|
|
}
|
2021-08-29 00:26:52 +02:00
|
|
|
|
|
|
|
foreach ($expr_type->parent_nodes as $parent_node) {
|
|
|
|
$statements_analyzer->data_flow_graph->addPath(
|
|
|
|
$parent_node,
|
|
|
|
new DataFlowNode('variable-use', 'variable use', null),
|
|
|
|
'variable-use'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if (IssueBuffer::accepts(
|
|
|
|
new ForbiddenCode(
|
|
|
|
'Use of shell_exec',
|
|
|
|
new CodeLocation($statements_analyzer->getSource(), $stmt)
|
|
|
|
),
|
|
|
|
$statements_analyzer->getSuppressedIssues()
|
|
|
|
)) {
|
|
|
|
// continue
|
2019-03-17 21:31:56 +01:00
|
|
|
}
|
2020-01-30 05:41:17 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
2020-01-30 05:41:17 +01:00
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Print_) {
|
|
|
|
$was_inside_call = $context->inside_call;
|
|
|
|
$context->inside_call = true;
|
|
|
|
if (Expression\PrintAnalyzer::analyze($statements_analyzer, $stmt, $context) === false) {
|
|
|
|
return false;
|
2017-01-15 19:58:20 +01:00
|
|
|
}
|
2020-05-18 21:13:27 +02:00
|
|
|
$context->inside_call = $was_inside_call;
|
2017-01-15 19:58:20 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
return true;
|
2017-01-15 19:58:20 +01:00
|
|
|
}
|
2018-04-09 16:20:13 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Yield_) {
|
|
|
|
return Expression\YieldAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
2017-01-15 19:58:20 +01:00
|
|
|
}
|
2018-01-10 01:33:39 +01:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\YieldFrom) {
|
|
|
|
return Expression\YieldFromAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
2017-01-16 18:59:09 +01:00
|
|
|
}
|
|
|
|
|
2021-02-22 19:15:34 +01:00
|
|
|
$php_major_version = $statements_analyzer->getCodebase()->php_major_version;
|
|
|
|
$php_minor_version = $statements_analyzer->getCodebase()->php_minor_version;
|
|
|
|
|
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Match_ && $php_major_version >= 8) {
|
2020-08-30 22:08:22 +02:00
|
|
|
return Expression\MatchAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
|
|
|
|
2021-02-22 19:15:34 +01:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Throw_ && $php_major_version >= 8) {
|
2020-08-30 22:08:22 +02:00
|
|
|
return ThrowAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
|
|
|
|
2020-10-14 23:09:56 +02:00
|
|
|
if (($stmt instanceof PhpParser\Node\Expr\NullsafePropertyFetch
|
|
|
|
|| $stmt instanceof PhpParser\Node\Expr\NullsafeMethodCall)
|
2021-02-22 19:15:34 +01:00
|
|
|
&& $php_major_version >= 8
|
2020-10-04 02:21:44 +02:00
|
|
|
) {
|
|
|
|
return Expression\NullsafeAnalyzer::analyze($statements_analyzer, $stmt, $context);
|
|
|
|
}
|
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if ($stmt instanceof PhpParser\Node\Expr\Error) {
|
|
|
|
// do nothing
|
|
|
|
return true;
|
|
|
|
}
|
2019-09-09 17:14:40 +02:00
|
|
|
|
2020-05-18 21:13:27 +02:00
|
|
|
if (IssueBuffer::accepts(
|
|
|
|
new UnrecognizedExpression(
|
2021-02-22 19:15:34 +01:00
|
|
|
'Psalm does not understand ' . get_class($stmt) . ' for PHP ' .
|
|
|
|
$php_major_version . ' ' . $php_minor_version,
|
2020-05-18 21:13:27 +02:00
|
|
|
new CodeLocation($statements_analyzer->getSource(), $stmt)
|
|
|
|
),
|
|
|
|
$statements_analyzer->getSuppressedIssues()
|
|
|
|
)) {
|
|
|
|
// fall through
|
2017-01-16 18:59:09 +01:00
|
|
|
}
|
2020-05-18 21:13:27 +02:00
|
|
|
|
|
|
|
return false;
|
2017-01-16 18:59:09 +01:00
|
|
|
}
|
|
|
|
|
2020-09-07 01:36:47 +02:00
|
|
|
public static function isMock(string $fq_class_name): bool
|
2016-10-22 19:23:18 +02:00
|
|
|
{
|
2018-12-18 05:29:27 +01:00
|
|
|
return in_array(strtolower($fq_class_name), Config::getInstance()->getMockClasses(), true);
|
2016-10-22 19:23:18 +02:00
|
|
|
}
|
|
|
|
}
|