Skip to content

Commit

Permalink
Add support for closure checks
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Dec 7, 2016
1 parent 7aac998 commit 55a060b
Show file tree
Hide file tree
Showing 20 changed files with 677 additions and 319 deletions.
18 changes: 15 additions & 3 deletions src/Psalm/Checker/ClassLikeChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,19 @@ public function check($check_methods = true, Context $class_context = null, $upd
$method_checker->check(clone $class_context);

if (!$config->excludeIssueInFile('InvalidReturnType', $this->file_name)) {
$method_checker->checkReturnTypes($update_docblocks);
/** @var string */
$method_id = $method_checker->getMethodId();
$return_type_location = MethodChecker::getMethodReturnTypeLocation(
$method_id,
$secondary_return_type_location
);

$method_checker->checkReturnTypes(
$update_docblocks,
MethodChecker::getMethodReturnType($method_id),
$return_type_location,
$secondary_return_type_location
);
}
}
}
Expand Down Expand Up @@ -531,9 +543,9 @@ protected function visitClassMethod(
$class_context->self . '::' . $this->getMappedMethodName(strtolower($stmt->name)),
$method_id
);

self::$class_methods[$class_context->self][strtolower($stmt->name)] = true;
}

self::$class_methods[$class_context->self][strtolower($stmt->name)] = true;
}

/**
Expand Down
44 changes: 36 additions & 8 deletions src/Psalm/Checker/FileChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -228,15 +228,33 @@ public function check(
);

$this->namespace_aliased_classes[$namespace_name] = $namespace_checker->getAliasedClasses();
$this->namespace_aliased_classes_flipped[$namespace_name] = $namespace_checker->getAliasedClassesFlipped();
$this->namespace_aliased_classes_flipped[$namespace_name] =
$namespace_checker->getAliasedClassesFlipped();

$this->declared_classes = array_merge($namespace_checker->getDeclaredClasses());
} elseif ($stmt instanceof PhpParser\Node\Stmt\Function_ && $check_functions) {
$function_context = new Context($this->file_name, $file_context->self);
$function_checkers[$stmt->name]->check($function_context, $file_context);

if (!$config->excludeIssueInFile('InvalidReturnType', $this->file_name)) {
$function_checkers[$stmt->name]->checkReturnTypes();
/** @var string */
$method_id = $function_checkers[$stmt->name]->getMethodId();

$return_type = FunctionChecker::getFunctionReturnType(
$method_id,
$this->file_name
);

$return_type_location = FunctionChecker::getFunctionReturnTypeLocation(
$method_id,
$this->file_name
);

$function_checkers[$stmt->name]->checkReturnTypes(
false,
$return_type,
$return_type_location
);
}
}
} else {
Expand Down Expand Up @@ -333,7 +351,9 @@ public static function getStatementsForFile($file_name)
$stmts = [];

$root_cache_directory = Config::getInstance()->getCacheDirectory();
$parser_cache_directory = $root_cache_directory ? $root_cache_directory . '/' . self::PARSER_CACHE_DIRECTORY : null;
$parser_cache_directory = $root_cache_directory
? $root_cache_directory . '/' . self::PARSER_CACHE_DIRECTORY
: null;
$from_cache = false;

$cache_location = null;
Expand All @@ -347,9 +367,10 @@ public static function getStatementsForFile($file_name)

if (self::$file_content_hashes === null) {
/** @var array<string, string> */
self::$file_content_hashes = $root_cache_directory && is_readable($root_cache_directory . '/' . self::FILE_HASHES)
? unserialize((string)file_get_contents($root_cache_directory . '/' . self::FILE_HASHES))
: [];
self::$file_content_hashes = $root_cache_directory &&
is_readable($root_cache_directory . '/' . self::FILE_HASHES)
? unserialize((string)file_get_contents($root_cache_directory . '/' . self::FILE_HASHES))
: [];
}

if ($parser_cache_directory) {
Expand Down Expand Up @@ -390,7 +411,10 @@ public static function getStatementsForFile($file_name)

self::$file_content_hashes[$name_cache_key] = $file_content_hash;

file_put_contents($root_cache_directory . '/' . self::FILE_HASHES, serialize(self::$file_content_hashes));
file_put_contents(
$root_cache_directory . '/' . self::FILE_HASHES,
serialize(self::$file_content_hashes)
);
}
}

Expand Down Expand Up @@ -660,8 +684,12 @@ public static function getDeletedReferencedFiles()
if (self::$deleted_files === null) {
self::$deleted_files = array_filter(
array_keys(self::$file_references),
/**
* @param string $file_name
* @return bool
*/
function ($file_name) {
return !file_exists((string)$file_name);
return !file_exists($file_name);
}
);
}
Expand Down
18 changes: 8 additions & 10 deletions src/Psalm/Checker/FunctionChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ protected function registerFunction(PhpParser\Node\Stmt\Function_ $function, $fi
}
}

self::$function_return_type_locations[$file_name][$function_id] =
self::$function_return_type_locations[$file_name][$function_id] = $return_type_location ?: false;

self::$function_return_types[$file_name][$function_id] = $return_type ?: false;
return null;
Expand Down Expand Up @@ -619,15 +619,13 @@ protected static function getArrayMapReturnType(
if (isset($call_args[$function_index])) {
$function_call_arg = $call_args[$function_index];

if ($function_call_arg->value instanceof PhpParser\Node\Expr\Closure) {
$closure_yield_types = [];
$closure_return_types = EffectsAnalyser::getReturnTypes(
$function_call_arg->value->stmts,
$closure_yield_types,
true
);
if ($function_call_arg->value instanceof PhpParser\Node\Expr\Closure &&
isset($function_call_arg->value->inferredType) &&
$function_call_arg->value->inferredType->types['Closure'] instanceof Type\Fn
) {
$closure_return_type = $function_call_arg->value->inferredType->types['Closure']->return_type;

if (!$closure_return_types) {
if ($closure_return_type->isVoid()) {
IssueBuffer::accepts(
new InvalidReturnType(
'No return type could be found in the closure passed to ' . $call_map_key,
Expand All @@ -640,7 +638,7 @@ protected static function getArrayMapReturnType(
}

if ($call_map_key === 'array_map') {
$inner_type = new Type\Union($closure_return_types);
$inner_type = clone $closure_return_type;
return new Type\Union([new Type\Generic('array', [Type::getInt(), $inner_type])]);
}

Expand Down
Loading

0 comments on commit 55a060b

Please sign in to comment.