1
0
mirror of https://github.com/danog/psalm.git synced 2024-12-14 10:17:33 +01:00
psalm/src/CodeInspector/EffectsAnalyser.php

87 lines
3.2 KiB
PHP
Raw Normal View History

<?php
namespace CodeInspector;
use PhpParser;
/**
* A class for analysing a given method call's effects in relation to
* $this/self and also looking at return types
*/
class EffectsAnalyser
{
/**
* Gets the return types from a list of statements
*
* @param array<PhpParser\Node\Stmt> $stmts
2016-06-16 02:16:40 +02:00
* @return array<AtomicType> a list of return types
*/
public static function getReturnTypes(array $stmts, $collapse_types = false)
{
$return_types = [];
2016-06-20 07:05:44 +02:00
$last_stmt = null;
foreach ($stmts as $stmt) {
2016-06-20 07:05:44 +02:00
if (!$stmt instanceof PhpParser\Node\Stmt\Nop) {
$last_stmt = $stmt;
}
if ($stmt instanceof PhpParser\Node\Stmt\Return_) {
2016-06-20 18:38:31 +02:00
if (isset($stmt->inferredType)) {
2016-06-17 22:05:28 +02:00
$return_types = array_merge(array_values($stmt->inferredType->types), $return_types);
}
else {
$return_types[] = Type::getMixed(false);
}
} elseif ($stmt instanceof PhpParser\Node\Stmt\If_) {
$return_types = array_merge($return_types, self::getReturnTypes($stmt->stmts));
foreach ($stmt->elseifs as $elseif) {
$return_types = array_merge($return_types, self::getReturnTypes($elseif->stmts));
}
if ($stmt->else) {
$return_types = array_merge($return_types, self::getReturnTypes($stmt->else->stmts));
}
} elseif ($stmt instanceof PhpParser\Node\Stmt\TryCatch) {
$return_types = array_merge($return_types, self::getReturnTypes($stmt->stmts));
foreach ($stmt->catches as $catch) {
$return_types = array_merge($return_types, self::getReturnTypes($catch->stmts));
}
if ($stmt->finallyStmts) {
$return_types = array_merge($return_types, self::getReturnTypes($stmt->finallyStmts));
}
} elseif ($stmt instanceof PhpParser\Node\Stmt\For_) {
$return_types = array_merge($return_types, self::getReturnTypes($stmt->stmts));
} elseif ($stmt instanceof PhpParser\Node\Stmt\Foreach_) {
$return_types = array_merge($return_types, self::getReturnTypes($stmt->stmts));
} elseif ($stmt instanceof PhpParser\Node\Stmt\While_) {
$return_types = array_merge($return_types, self::getReturnTypes($stmt->stmts));
} elseif ($stmt instanceof PhpParser\Node\Stmt\Do_) {
$return_types = array_merge($return_types, self::getReturnTypes($stmt->stmts));
} elseif ($stmt instanceof PhpParser\Node\Stmt\Switch_) {
foreach ($stmt->cases as $case) {
$return_types = array_merge($return_types, self::getReturnTypes($case->stmts));
}
}
}
2016-06-20 07:05:44 +02:00
// if we're at the top level and we're not ending in a return, make sure to add possible null
if ($collapse_types && !$last_stmt instanceof PhpParser\Node\Stmt\Return_ && !ScopeChecker::doesLeaveBlock($stmts, false, false)) {
$return_types[] = Type::getNull(false);
}
2016-06-16 02:16:40 +02:00
return $return_types;
}
}