1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Transition to more flexible error handling

This commit is contained in:
Matthew Brown 2016-06-05 20:25:16 -04:00
parent 281751d85c
commit d8854fd4ef
7 changed files with 692 additions and 285 deletions

View File

@ -5,6 +5,7 @@ namespace CodeInspector;
use CodeInspector\Exception\InvalidClassException;
use CodeInspector\Exception\UndefinedClassException;
use CodeInspector\Exception\UndefinedTraitException;
use CodeInspector\ExceptionHandler;
use PhpParser;
use PhpParser\Error;
use PhpParser\ParserFactory;
@ -95,7 +96,11 @@ class ClassChecker implements StatementsSource
foreach ($stmt->traits as $trait) {
$trait_name = self::getAbsoluteClassFromName($trait, $this->_namespace, $this->_aliased_classes);
if (!trait_exists($trait_name)) {
throw new UndefinedTraitException('Trait ' . $trait_name . ' does not exist', $this->_file_name, $trait->getLine());
if (ExceptionHandler::accepts(
new UndefinedTraitException('Trait ' . $trait_name . ' does not exist', $this->_file_name, $trait->getLine())
)) {
return false;
}
}
$this->_registerInheritedMethods($trait_name, $method_map);
}
@ -198,14 +203,22 @@ class ClassChecker implements StatementsSource
}
if (!class_exists($absolute_class, true) && !interface_exists($absolute_class, true)) {
throw new UndefinedClassException('Class ' . $absolute_class . ' does not exist', $file_name, $stmt->getLine());
if (ExceptionHandler::accepts(
new UndefinedClassException('Class ' . $absolute_class . ' does not exist', $file_name, $stmt->getLine())
)) {
return false;
}
}
if (class_exists($absolute_class, true) && strpos($absolute_class, '\\') === false) {
$reflection_class = new ReflectionClass($absolute_class);
if ($reflection_class->getName() !== $absolute_class) {
throw new InvalidClassException('Class ' . $absolute_class . ' has wrong casing', $file_name, $stmt->getLine());
if (ExceptionHandler::accepts(
new InvalidClassException('Class ' . $absolute_class . ' has wrong casing', $file_name, $stmt->getLine())
)) {
return false;
}
}
}

View File

@ -74,18 +74,26 @@ class ClassMethodChecker extends FunctionChecker
$doc_comment = $this->_function->getDocComment();
$this->_registerNewDocComment($return_types, $doc_comment);
return;
}
else {
throw new ReturnTypeException(
if (ExceptionHandler::accepts(
new ReturnTypeException(
'The given return type for ' . $method_id . ' is incorrect, expecting ' . implode('|', $return_types),
$this->_file_name,
$this->_function->getLine()
);
)
)) {
return false;
}
}
}
return;
}
else if ($update_doc_comment) {
if ($update_doc_comment) {
$return_types = EffectsAnalyser::getReturnTypes($this->_function->stmts, true);
if ($return_types && $return_types !== ['mixed']) {
@ -460,7 +468,11 @@ class ClassMethodChecker extends FunctionChecker
return;
}
throw new UndefinedMethodException('Method ' . $method_id . ' does not exist', $file_name, $stmt->getLine());
if (ExceptionHandler::accepts(
new UndefinedMethodException('Method ' . $method_id . ' does not exist', $file_name, $stmt->getLine())
)) {
return false;
}
}
protected static function _populateData($method_id)
@ -486,7 +498,11 @@ class ClassMethodChecker extends FunctionChecker
$method_name = explode('::', $method_id)[1];
if (!isset(self::$_method_visibility[$method_id])) {
throw new InaccessibleMethodException('Cannot access method ' . $method_id, $file_name, $line_number);
if (ExceptionHandler::accepts(
new InaccessibleMethodException('Cannot access method ' . $method_id, $file_name, $line_number)
)) {
return false;
}
}
switch (self::$_method_visibility[$method_id]) {
@ -495,7 +511,11 @@ class ClassMethodChecker extends FunctionChecker
case self::VISIBILITY_PRIVATE:
if (!$calling_context || $method_class !== $calling_context) {
throw new InaccessibleMethodException('Cannot access private method ' . $method_id . ' from context ' . $calling_context, $file_name, $line_number);
if (ExceptionHandler::accepts(
new InaccessibleMethodException('Cannot access private method ' . $method_id . ' from context ' . $calling_context, $file_name, $line_number)
)) {
return false;
}
}
return;
@ -505,7 +525,11 @@ class ClassMethodChecker extends FunctionChecker
}
if (!$calling_context) {
throw new InaccessibleMethodException('Cannot access protected method ' . $method_id, $file_name, $line_number);
if (ExceptionHandler::accepts(
new InaccessibleMethodException('Cannot access protected method ' . $method_id, $file_name, $line_number)
)) {
return false;
}
}
if (is_subclass_of($method_class, $calling_context) && method_exists($calling_context, $method_name)) {
@ -513,7 +537,11 @@ class ClassMethodChecker extends FunctionChecker
}
if (!is_subclass_of($calling_context, $method_class)) {
throw new InaccessibleMethodException('Cannot access protected method ' . $method_id . ' from context ' . $calling_context, $file_name, $line_number);
if (ExceptionHandler::accepts(
new InaccessibleMethodException('Cannot access protected method ' . $method_id . ' from context ' . $calling_context, $file_name, $line_number)
)) {
return false;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?php
namespace CodeInspector\Exception;
class PossiblyUndefinedVariableException extends CodeException
{
}

View File

@ -0,0 +1,12 @@
<?php
namespace CodeInspector;
class ExceptionHandler
{
public static function accepts(Exception\CodeException $e)
{
throw $e;
//return true;
}
}

View File

@ -41,7 +41,7 @@ class FunctionChecker implements StatementsSource
if (ClassChecker::getThisClass() && $this instanceof ClassMethodChecker) {
$hash = $this->getMethodId() . json_encode([$vars_in_scope, $vars_possibly_in_scope]);
// if we know that the function has no effects on vars, we don't bother checking
// if we know that the function has no effects on vars, we don't bother rechecking
if (isset(self::$_no_effects_hashes[$hash])) {
list($vars_in_scope, $vars_possibly_in_scope) = self::$_no_effects_hashes[$hash];
@ -66,10 +66,9 @@ class FunctionChecker implements StatementsSource
$param->default->name->parts = ['null'];
if ($param->type && is_object($param->type)) {
$vars_in_scope[$param->name] =
$param->type->parts === ['self'] ?
$this->_absolute_class :
ClassChecker::getAbsoluteClassFromName($param->type, $this->_namespace, $this->_aliased_classes);
$vars_in_scope[$param->name] = $param->type->parts === ['self'] ?
$this->_absolute_class :
ClassChecker::getAbsoluteClassFromName($param->type, $this->_namespace, $this->_aliased_classes);
if ($is_nullable) {
$vars_in_scope[$param->name] .= '|null';
@ -78,6 +77,9 @@ class FunctionChecker implements StatementsSource
elseif (is_string($param->type)) {
$vars_in_scope[$param->name] = $param->type;
}
else {
$vars_in_scope[$param->name] = 'mixed';
}
$vars_possibly_in_scope[$param->name] = true;
$statements_checker->registerVariable($param->name, $param->getLine());

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@ namespace CodeInspector;
use CodeInspector\Exception\InvalidArgumentException;
use CodeInspector\Exception\TypeResolutionException;
use CodeInspector\ExceptionHandler;
use PhpParser;
class TypeChecker
@ -33,7 +34,15 @@ class TypeChecker
}
if ($return_type === 'void') {
throw new TypeResolutionException('Argument ' . ($arg_offset + 1) . ' of ' . $method_id . ' cannot be void, but possibly void value was supplied', $file_name, $line_number);
if (ExceptionHandler::accepts(
new TypeResolutionException(
'Argument ' . ($arg_offset + 1) . ' of ' . $method_id . ' cannot be void, but possibly void value was supplied',
$file_name,
$line_number
)
)) {
return false;
}
}
$method_params = ClassMethodChecker::getMethodParams($method_id);
@ -53,12 +62,14 @@ class TypeChecker
return true;
}
if ($check_nulls) {
throw new InvalidArgumentException(
if (ExceptionHandler::accepts(
new InvalidArgumentException(
'Argument ' . ($arg_offset + 1) . ' of ' . $method_id . ' cannot be null, but possibly null value was supplied',
$file_name,
$line_number
);
)
)) {
return false;
}
return true;
@ -81,7 +92,15 @@ class TypeChecker
return true;
}
throw new InvalidArgumentException('Argument ' . ($arg_offset + 1) . ' of ' . $method_id . ' has incorrect type of ' . $return_type . ', expecting ' . $expected_type, $file_name, $line_number);
if (ExceptionHandler::accepts(
new InvalidArgumentException(
'Argument ' . ($arg_offset + 1) . ' of ' . $method_id . ' has incorrect type of ' . $return_type . ', expecting ' . $expected_type,
$file_name,
$line_number
)
)) {
return false;
}
}
return true;
@ -480,7 +499,11 @@ class TypeChecker
if (empty($existing_var_types)) {
if ($strict) {
throw new TypeResolutionException('Cannot resolve types for ' . $key, $file_name, $line_number);
if (ExceptionHandler::accepts(
new TypeResolutionException('Cannot resolve types for ' . $key, $file_name, $line_number)
)) {
return false;
}
}
}
}