mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Make CodeExceptions all self-contained
This commit is contained in:
parent
b9b639e968
commit
92a05355aa
@ -2,6 +2,8 @@
|
||||
|
||||
namespace CodeInspector;
|
||||
|
||||
use CodeInspector\Exception\InvalidClassException;
|
||||
use CodeInspector\Exception\UndefinedClassException;
|
||||
use PhpParser;
|
||||
use PhpParser\Error;
|
||||
use PhpParser\ParserFactory;
|
||||
@ -109,14 +111,14 @@ class ClassChecker implements StatementsSource
|
||||
}
|
||||
|
||||
if (!class_exists($absolute_class, true) && !interface_exists($absolute_class, true)) {
|
||||
throw new CodeException('Class ' . $absolute_class . ' does not exist', $file_name, $stmt->getLine());
|
||||
throw new UndefinedClassException('Class ' . $absolute_class . ' does not exist', $file_name, $stmt->getLine());
|
||||
}
|
||||
|
||||
if (class_exists($absolute_class, true) && strpos($absolute_class, '\\') === false) {
|
||||
$reflection_class = new ReflectionClass($absolute_class);
|
||||
|
||||
if ($reflection_class->getName() !== $absolute_class) {
|
||||
throw new CodeException('Class ' . $absolute_class . ' has wrong casing', $file_name, $stmt->getLine());
|
||||
throw new InvalidClassException('Class ' . $absolute_class . ' has wrong casing', $file_name, $stmt->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace CodeInspector;
|
||||
|
||||
use CodeInspector\Exception\UndefinedMethodException;
|
||||
use PhpParser;
|
||||
|
||||
class ClassMethodChecker extends FunctionChecker
|
||||
@ -338,7 +339,7 @@ class ClassMethodChecker extends FunctionChecker
|
||||
return;
|
||||
|
||||
} catch (\ReflectionException $e) {
|
||||
throw new CodeException('Method ' . $method_id . ' does not exist', $file_name, $stmt->getLine());
|
||||
throw new UndefinedMethodException('Method ' . $method_id . ' does not exist', $file_name, $stmt->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector;
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class CodeException extends \Exception
|
||||
abstract class CodeException extends \Exception
|
||||
{
|
||||
const CODE_EXCEPTION = 1;
|
||||
public $line_number;
|
7
src/CodeInspector/Exception/ForbiddenCodeException.php
Normal file
7
src/CodeInspector/Exception/ForbiddenCodeException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class ForbiddenCodeException extends CodeException
|
||||
{
|
||||
}
|
7
src/CodeInspector/Exception/InvalidArgumentException.php
Normal file
7
src/CodeInspector/Exception/InvalidArgumentException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class InvalidArgumentException extends CodeException
|
||||
{
|
||||
}
|
7
src/CodeInspector/Exception/InvalidClassException.php
Normal file
7
src/CodeInspector/Exception/InvalidClassException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class InvalidClassException extends CodeException
|
||||
{
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class InvalidNamespaceException extends CodeException
|
||||
{
|
||||
}
|
7
src/CodeInspector/Exception/IteratorException.php
Normal file
7
src/CodeInspector/Exception/IteratorException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class IteratorException extends CodeException
|
||||
{
|
||||
}
|
7
src/CodeInspector/Exception/ParentNotFoundException.php
Normal file
7
src/CodeInspector/Exception/ParentNotFoundException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class ParentNotFoundException extends CodeException
|
||||
{
|
||||
}
|
7
src/CodeInspector/Exception/ScopeException.php
Normal file
7
src/CodeInspector/Exception/ScopeException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class ScopeException extends CodeException
|
||||
{
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class StaticInvocationException extends CodeException
|
||||
{
|
||||
}
|
7
src/CodeInspector/Exception/StaticVariableException.php
Normal file
7
src/CodeInspector/Exception/StaticVariableException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class StaticVariableException extends CodeException
|
||||
{
|
||||
}
|
7
src/CodeInspector/Exception/TypeException.php
Normal file
7
src/CodeInspector/Exception/TypeException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class TypeResolutionException extends CodeException
|
||||
{
|
||||
}
|
7
src/CodeInspector/Exception/UndefinedClassException.php
Normal file
7
src/CodeInspector/Exception/UndefinedClassException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class UndefinedClassException extends CodeException
|
||||
{
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class UndefinedConstantException extends CodeException
|
||||
{
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class UndefinedFunctionException extends CodeException
|
||||
{
|
||||
}
|
7
src/CodeInspector/Exception/UndefinedMethodException.php
Normal file
7
src/CodeInspector/Exception/UndefinedMethodException.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class UndefinedMethodException extends CodeException
|
||||
{
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class UndefinedPropertyException extends CodeException
|
||||
{
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace CodeInspector\Exception;
|
||||
|
||||
class UndefinedVariableException extends CodeException
|
||||
{
|
||||
}
|
@ -4,6 +4,19 @@ namespace CodeInspector;
|
||||
|
||||
use PhpParser;
|
||||
|
||||
use CodeInspector\Exception\ForbiddenCodeException;
|
||||
use CodeInspector\Exception\InvalidArgumentException;
|
||||
use CodeInspector\Exception\InvalidNamespaceException;
|
||||
use CodeInspector\Exception\IteratorException;
|
||||
use CodeInspector\Exception\ParentNotFoundException;
|
||||
use CodeInspector\Exception\ScopeException;
|
||||
use CodeInspector\Exception\StaticInvocationException;
|
||||
use CodeInspector\Exception\StaticVariableException;
|
||||
use CodeInspector\Exception\UndefinedConstantException;
|
||||
use CodeInspector\Exception\UndefinedFunctionException;
|
||||
use CodeInspector\Exception\UndefinedPropertyException;
|
||||
use CodeInspector\Exception\UndefinedVariableException;
|
||||
|
||||
class StatementsChecker
|
||||
{
|
||||
protected $_stmts;
|
||||
@ -177,7 +190,7 @@ class StatementsChecker
|
||||
|
||||
} elseif ($stmt instanceof PhpParser\Node\Stmt\Namespace_) {
|
||||
if ($this->_namespace) {
|
||||
throw new CodeException('Cannot redeclare namespace', $this->_require_file_name, $stmt->getLine());
|
||||
throw new InvalidNamespaceException('Cannot redeclare namespace', $this->_require_file_name, $stmt->getLine());
|
||||
}
|
||||
|
||||
$namespace_checker = new NamespaceChecker($stmt, $this->_source);
|
||||
@ -671,7 +684,7 @@ class StatementsChecker
|
||||
// do nothing
|
||||
|
||||
} elseif ($stmt instanceof PhpParser\Node\Expr\ShellExec) {
|
||||
throw new CodeException('Use of shell_exec', $this->_file_name, $stmt->getLine());
|
||||
throw new ForbiddenCodeException('Use of shell_exec', $this->_file_name, $stmt->getLine());
|
||||
|
||||
} elseif ($stmt instanceof PhpParser\Node\Expr\Print_) {
|
||||
$this->_checkExpression($stmt->expr, $vars_in_scope, $vars_possibly_in_scope);
|
||||
@ -685,7 +698,7 @@ class StatementsChecker
|
||||
protected function _checkVariable(PhpParser\Node\Expr\Variable $stmt, array &$vars_in_scope, array &$vars_possibly_in_scope, $method_id = null, $argument_offset = -1)
|
||||
{
|
||||
if ($stmt->name === 'this' && $this->_is_static) {
|
||||
throw new CodeException('Invalid reference to $this in a static context', $this->_file_name, $stmt->getLine());
|
||||
throw new StaticVariableException('Invalid reference to $this in a static context', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
|
||||
if (!$this->_check_variables) {
|
||||
@ -712,7 +725,7 @@ class StatementsChecker
|
||||
}
|
||||
|
||||
if (!isset($vars_possibly_in_scope[$stmt->name])) {
|
||||
throw new CodeException('Cannot find referenced variable $' . $stmt->name, $this->_file_name, $stmt->getLine());
|
||||
throw new UndefinedVariableException('Cannot find referenced variable $' . $stmt->name, $this->_file_name, $stmt->getLine());
|
||||
|
||||
} elseif (isset($this->_all_vars[$stmt->name])) {
|
||||
if (!isset($this->_warn_vars[$stmt->name])) {
|
||||
@ -724,7 +737,7 @@ class StatementsChecker
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new CodeException('Cannot find referenced variable $' . $stmt->name, $this->_file_name, $stmt->getLine());
|
||||
throw new UndefinedVariableException('Cannot find referenced variable $' . $stmt->name, $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -747,12 +760,12 @@ class StatementsChecker
|
||||
|
||||
if (!in_array($stmt->name, $property_names)) {
|
||||
if (!self::_propertyExists($this->_absolute_class . '::' . $stmt->name)) {
|
||||
throw new CodeException('$this->' . $stmt->name . ' is not defined', $this->_file_name, $stmt->getLine());
|
||||
throw new UndefinedPropertyException('$this->' . $stmt->name . ' is not defined', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new CodeException('Cannot use $this when not inside class', $this->_file_name, $stmt->getLine());
|
||||
throw new ScopeException('Cannot use $this when not inside class', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
} else {
|
||||
$this->_checkVariable($stmt->var, $vars_in_scope, $vars_possibly_in_scope);
|
||||
@ -869,10 +882,10 @@ class StatementsChecker
|
||||
// do nothing
|
||||
}
|
||||
elseif (in_array($return_type, ['string', 'void', 'int'])) {
|
||||
throw new CodeException('Cannot iterate over ' . $return_type, $this->_file_name, $stmt->getLine());
|
||||
throw new IteratorException('Cannot iterate over ' . $return_type, $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
elseif ($return_type === 'null') {
|
||||
throw new CodeException('Cannot iterate over null', $this->_file_name, $stmt->getLine());
|
||||
throw new IteratorException('Cannot iterate over null', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
else {
|
||||
if (strpos($return_type, '<') !== false && strpos($return_type, '>') !== false) {
|
||||
@ -884,7 +897,7 @@ class StatementsChecker
|
||||
ClassChecker::checkAbsoluteClass($return_type, $stmt, $this->_file_name);
|
||||
|
||||
if (!ClassChecker::classImplements($return_type, 'Traversable')) {
|
||||
throw new CodeException('Class ' . $return_type . ' does not implement the Traversable interface', $this->_file_name, $stmt->getLine());
|
||||
throw new IteratorException('Class ' . $return_type . ' does not implement the Traversable interface', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1079,7 +1092,7 @@ class StatementsChecker
|
||||
$this->_checkExpression($stmt->var->name, $vars_in_scope, $vars_possibly_in_scope);
|
||||
}
|
||||
else if ($stmt->var->name === 'this' && !$this->_class_name) {
|
||||
throw new CodeException('Use of $this in non-class context', $this->_file_name, $stmt->getLine());
|
||||
throw new ScopeException('Use of $this in non-class context', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
} elseif ($stmt->var instanceof PhpParser\Node\Expr) {
|
||||
$this->_checkExpression($stmt->var, $vars_in_scope, $vars_possibly_in_scope);
|
||||
@ -1100,11 +1113,11 @@ class StatementsChecker
|
||||
$absolute_class = preg_replace('/\<[A-Za-z0-9' . '\\\\' . ']+\>/', '', $absolute_class);
|
||||
|
||||
if ($absolute_class === 'null') {
|
||||
throw new CodeException('Cannot call method ' . $stmt->name . ' on nullable variable ' . $class_type, $this->_file_name, $stmt->getLine());
|
||||
throw new InvalidArgumentException('Cannot call method ' . $stmt->name . ' on nullable variable ' . $class_type, $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
|
||||
if (in_array($absolute_class, ['int', 'bool', 'array'])) {
|
||||
throw new CodeException('Cannot call method ' . $stmt->name . ' on ' . $class_type . ' variable', $this->_file_name, $stmt->getLine());
|
||||
throw new InvalidArgumentException('Cannot call method ' . $stmt->name . ' on ' . $class_type . ' variable', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
|
||||
if ($absolute_class && $absolute_class[0] === strtoupper($absolute_class[0]) && !method_exists($absolute_class, '__call') && !self::isMock($absolute_class)) {
|
||||
@ -1149,7 +1162,7 @@ class StatementsChecker
|
||||
$this->registerVariable($use->var, $use->getLine());
|
||||
|
||||
} elseif (!isset($vars_possibly_in_scope[$use->var])) {
|
||||
throw new CodeException('Cannot find referenced variable $' . $use->var, $this->_file_name, $use->getLine());
|
||||
throw new UndefinedVariableException('Cannot find referenced variable $' . $use->var, $this->_file_name, $use->getLine());
|
||||
|
||||
} elseif (isset($this->_all_vars[$use->var])) {
|
||||
if (!isset($this->_warn_vars[$use->var])) {
|
||||
@ -1161,7 +1174,7 @@ class StatementsChecker
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new CodeException('Cannot find referenced variable $' . $use->var, $this->_file_name, $use->getLine());
|
||||
throw new UndefinedVariableException('Cannot find referenced variable $' . $use->var, $this->_file_name, $use->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1181,7 +1194,7 @@ class StatementsChecker
|
||||
if (count($stmt->class->parts) === 1 && in_array($stmt->class->parts[0], ['self', 'static', 'parent'])) {
|
||||
if ($stmt->class->parts[0] === 'parent') {
|
||||
if ($this->_class_extends === null) {
|
||||
throw new CodeException('Cannot call method on parent as this class does not extend another', $this->_file_name, $stmt->getLine());
|
||||
throw new ParentNotFoundException('Cannot call method on parent as this class does not extend another', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
|
||||
$absolute_class = $this->_class_extends;
|
||||
@ -1212,13 +1225,13 @@ class StatementsChecker
|
||||
|
||||
if ($this->_is_static) {
|
||||
if (!ClassMethodChecker::isGivenMethodStatic($method_id)) {
|
||||
throw new CodeException('Method ' . $method_id . ' is not static', $this->_file_name, $stmt->getLine());
|
||||
throw new StaticInvocationException('Method ' . $method_id . ' is not static', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($stmt->class->parts[0] === 'self' && $stmt->name !== '__construct') {
|
||||
if (!ClassMethodChecker::isGivenMethodStatic($method_id)) {
|
||||
throw new CodeException('Cannot call non-static method ' . $method_id . ' as if it were static', $this->_file_name, $stmt->getLine());
|
||||
throw new StaticInvocationException('Cannot call non-static method ' . $method_id . ' as if it were static', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1341,7 +1354,7 @@ class StatementsChecker
|
||||
$const_id = $absolute_class . '::' . $stmt->name;
|
||||
|
||||
if (!defined($const_id)) {
|
||||
throw new CodeException('Const ' . $const_id . ' is not defined', $this->_file_name, $stmt->getLine());
|
||||
throw new UndefinedConstantException('Const ' . $const_id . ' is not defined', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
} elseif ($stmt->class instanceof PhpParser\Node\Expr) {
|
||||
$this->_checkExpression($stmt->class, $vars_in_scope, $vars_possibly_in_scope);
|
||||
@ -1374,7 +1387,7 @@ class StatementsChecker
|
||||
$var_id = $absolute_class . '::$' . $stmt->name;
|
||||
|
||||
if (!self::_staticVarExists($var_id)) {
|
||||
throw new CodeException('Static variable ' . $var_id . ' does not exist', $this->_file_name, $stmt->getLine());
|
||||
throw new UndefinedVariableException('Static variable ' . $var_id . ' does not exist', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1553,7 +1566,7 @@ class StatementsChecker
|
||||
|
||||
} elseif ($method->parts === ['var_dump'] || $method->parts === ['die'] || $method->parts === ['exit']) {
|
||||
if (FileChecker::shouldCheckVarDumps($this->_file_name)) {
|
||||
throw new CodeException('Unsafe ' . implode('', $method->parts), $this->_file_name, $stmt->getLine());
|
||||
throw new ForbiddenCodeException('Unsafe ' . implode('', $method->parts), $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1662,7 +1675,7 @@ class StatementsChecker
|
||||
(new \ReflectionFunction($method_id));
|
||||
}
|
||||
catch (\ReflectionException $e) {
|
||||
throw new CodeException('Function ' . $method_id . ' does not exist', $this->_file_name, $stmt->getLine());
|
||||
throw new UndefinedFunctionException('Function ' . $method_id . ' does not exist', $this->_file_name, $stmt->getLine());
|
||||
}
|
||||
|
||||
self::$_existing_functions[$method_id] = 1;
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace CodeInspector;
|
||||
|
||||
use CodeInspector\Exception\InvalidArgumentException;
|
||||
use CodeInspector\Exception\TypeResolutionException;
|
||||
use PhpParser;
|
||||
|
||||
class TypeChecker
|
||||
@ -43,7 +45,7 @@ class TypeChecker
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new CodeException('Argument ' . ($arg_offset + 1) . ' of ' . $method_id . ' cannot be null, but possibly null value was supplied', $file_name, $line_number);
|
||||
throw new InvalidArgumentException('Argument ' . ($arg_offset + 1) . ' of ' . $method_id . ' cannot be null, but possibly null value was supplied', $file_name, $line_number);
|
||||
}
|
||||
|
||||
// Remove generic type
|
||||
@ -63,7 +65,7 @@ class TypeChecker
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new CodeException('Argument ' . ($arg_offset + 1) . ' of ' . $method_id . ' has incorrect type of ' . $return_type . ', expecting ' . $expected_type, $file_name, $line_number);
|
||||
throw new InvalidArgumentException('Argument ' . ($arg_offset + 1) . ' of ' . $method_id . ' has incorrect type of ' . $return_type . ', expecting ' . $expected_type, $file_name, $line_number);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -407,7 +409,7 @@ class TypeChecker
|
||||
|
||||
if (empty($existing_type)) {
|
||||
if ($strict) {
|
||||
throw new CodeException('Cannot resolve types for ' . $key, $file_name, $line_number);
|
||||
throw new TypeResolutionException('Cannot resolve types for ' . $key, $file_name, $line_number);
|
||||
}
|
||||
|
||||
$result_types[$key] = $existing_types[$key];
|
||||
|
Loading…
Reference in New Issue
Block a user