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

Break out large chunk

This commit is contained in:
Matthew Brown 2021-01-05 17:47:15 -05:00 committed by Daniil Gentili
parent 0e1ef2e096
commit f00a53efd5
Signed by: danog
GPG Key ID: 8C1BE3B34B230CA7

View File

@ -126,201 +126,26 @@ class FunctionLikeNodeScanner
$this->codebase->scanner->queueClassLikeForScanning('Closure'); $this->codebase->scanner->queueClassLikeForScanning('Closure');
} }
$classlike_storage = null; $functionlike_info = $this->createStorageForFunctionLike($stmt, $fake_method);
$fq_classlike_name = null;
$is_functionlike_override = false;
$function_id = null; if ($functionlike_info === false) {
$method_name_lc = null; return false;
$method_id = null; }
if ($fake_method && $stmt instanceof PhpParser\Node\Stmt\ClassMethod) { [
$cased_function_id = '@method ' . $stmt->name->name; $cased_function_id,
$storage,
$function_id,
$fq_classlike_name,
$method_name_lc,
$classlike_storage,
$is_functionlike_override,
$method_id,
$is_dupe
] = $functionlike_info;
$storage = $this->storage = new MethodStorage(); if ($is_dupe) {
$storage->defining_fqcln = ''; return $storage;
$storage->is_static = $stmt->isStatic();
$storage->final = $this->classlike_storage && $this->classlike_storage->final;
$storage->final_from_docblock = $this->classlike_storage && $this->classlike_storage->final_from_docblock;
} elseif ($stmt instanceof PhpParser\Node\Stmt\Function_) {
$cased_function_id =
($this->aliases->namespace ? $this->aliases->namespace . '\\' : '') . $stmt->name->name;
$function_id = strtolower($cased_function_id);
$storage = $this->storage = new FunctionStorage();
if ($this->codebase->register_stub_files || $this->codebase->register_autoload_files) {
if (isset($this->file_storage->functions[$function_id])
&& ($this->codebase->register_stub_files
|| !$this->codebase->functions->hasStubbedFunction($function_id))
) {
$this->codebase->functions->addGlobalFunction(
$function_id,
$this->file_storage->functions[$function_id]
);
$storage = $this->storage = $this->file_storage->functions[$function_id];
return $storage;
}
} else {
if (isset($this->file_storage->functions[$function_id])) {
$duplicate_function_storage = $this->file_storage->functions[$function_id];
if ($duplicate_function_storage->location
&& $duplicate_function_storage->location->getLineNumber() === $stmt->getLine()
) {
$storage = $this->storage = $this->file_storage->functions[$function_id];
return $storage;
}
if (IssueBuffer::accepts(
new DuplicateFunction(
'Method ' . $function_id . ' has already been defined'
. ($duplicate_function_storage->location
? ' in ' . $duplicate_function_storage->location->file_path
: ''),
new CodeLocation($this->file_scanner, $stmt, null, true)
)
)) {
// fall through
}
$this->file_storage->has_visitor_issues = true;
$duplicate_function_storage->has_visitor_issues = true;
$storage = $this->storage = $this->file_storage->functions[$function_id];
return $storage;
}
if (isset($this->config->getPredefinedFunctions()[$function_id])) {
/** @psalm-suppress ArgumentTypeCoercion */
$reflection_function = new \ReflectionFunction($function_id);
if ($reflection_function->getFileName() !== $this->file_path) {
if (IssueBuffer::accepts(
new DuplicateFunction(
'Method ' . $function_id . ' has already been defined as a core function',
new CodeLocation($this->file_scanner, $stmt, null, true)
)
)) {
// fall through
}
}
}
}
} elseif ($stmt instanceof PhpParser\Node\Stmt\ClassMethod) {
if (!$this->classlike_storage) {
throw new \LogicException('$this->classlike_storage should not be null');
}
$fq_classlike_name = $this->classlike_storage->name;
$method_name_lc = strtolower($stmt->name->name);
$function_id = $fq_classlike_name . '::' . $method_name_lc;
$cased_function_id = $fq_classlike_name . '::' . $stmt->name->name;
$classlike_storage = $this->classlike_storage;
$storage = null;
if (isset($classlike_storage->methods[$method_name_lc])) {
if (!$this->codebase->register_stub_files) {
$duplicate_method_storage = $classlike_storage->methods[$method_name_lc];
if (IssueBuffer::accepts(
new DuplicateMethod(
'Method ' . $function_id . ' has already been defined'
. ($duplicate_method_storage->location
? ' in ' . $duplicate_method_storage->location->file_path
: ''),
new CodeLocation($this->file_scanner, $stmt, null, true)
)
)) {
// fall through
}
$this->file_storage->has_visitor_issues = true;
$duplicate_method_storage->has_visitor_issues = true;
return false;
}
$is_functionlike_override = true;
$storage = $this->storage = $classlike_storage->methods[$method_name_lc];
}
if (!$storage) {
$storage = $this->storage = new MethodStorage();
}
$storage->stubbed = $this->codebase->register_stub_files;
$storage->defining_fqcln = $fq_classlike_name;
$class_name_parts = explode('\\', $fq_classlike_name);
$class_name = array_pop($class_name_parts);
if ($method_name_lc === strtolower($class_name)
&& !isset($classlike_storage->methods['__construct'])
&& strpos($fq_classlike_name, '\\') === false
&& $this->codebase->php_major_version < 8
) {
$this->codebase->methods->setDeclaringMethodId(
$fq_classlike_name,
'__construct',
$fq_classlike_name,
$method_name_lc
);
$this->codebase->methods->setAppearingMethodId(
$fq_classlike_name,
'__construct',
$fq_classlike_name,
$method_name_lc
);
}
$method_id = new \Psalm\Internal\MethodIdentifier(
$fq_classlike_name,
$method_name_lc
);
$storage->is_static = $stmt->isStatic();
$storage->abstract = $stmt->isAbstract();
$storage->final = $classlike_storage->final || $stmt->isFinal();
$storage->final_from_docblock = $classlike_storage->final_from_docblock;
if ($stmt->isPrivate()) {
$storage->visibility = ClassLikeAnalyzer::VISIBILITY_PRIVATE;
} elseif ($stmt->isProtected()) {
$storage->visibility = ClassLikeAnalyzer::VISIBILITY_PROTECTED;
} else {
$storage->visibility = ClassLikeAnalyzer::VISIBILITY_PUBLIC;
}
} elseif ($stmt instanceof PhpParser\Node\Expr\Closure
|| $stmt instanceof PhpParser\Node\Expr\ArrowFunction
) {
$function_id = $cased_function_id = strtolower($this->file_path)
. ':' . $stmt->getLine()
. ':' . (int) $stmt->getAttribute('startFilePos') . ':-:closure';
$storage = $this->storage = $this->file_storage->functions[$function_id] = new FunctionStorage();
if ($stmt instanceof PhpParser\Node\Expr\Closure) {
foreach ($stmt->uses as $closure_use) {
if ($closure_use->byRef && \is_string($closure_use->var->name)) {
$storage->byref_uses[$closure_use->var->name] = true;
}
}
}
} else {
throw new \UnexpectedValueException('Unrecognized functionlike');
} }
if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod) { if ($stmt instanceof PhpParser\Node\Stmt\ClassMethod) {
@ -959,4 +784,231 @@ class FunctionLikeNodeScanner
: null : null
); );
} }
/**
* @return array{
* string,
* FunctionStorage|MethodStorage,
* null|string,
* null|string,
* null|lowercase-string,
* ClassLikeStorage|null,
* bool,
* \Psalm\Internal\MethodIdentifier|null,
* bool
* }|false
*/
private function createStorageForFunctionLike(
PhpParser\Node\FunctionLike $stmt,
bool $fake_method
) {
$classlike_storage = null;
$fq_classlike_name = null;
$is_functionlike_override = false;
$function_id = null;
$method_name_lc = null;
$method_id = null;
if ($fake_method && $stmt instanceof PhpParser\Node\Stmt\ClassMethod) {
$cased_function_id = '@method ' . $stmt->name->name;
$storage = $this->storage = new MethodStorage();
$storage->defining_fqcln = '';
$storage->is_static = $stmt->isStatic();
$storage->final = $this->classlike_storage && $this->classlike_storage->final;
$storage->final_from_docblock = $this->classlike_storage && $this->classlike_storage->final_from_docblock;
} elseif ($stmt instanceof PhpParser\Node\Stmt\Function_) {
$cased_function_id =
($this->aliases->namespace ? $this->aliases->namespace . '\\' : '') . $stmt->name->name;
$function_id = strtolower($cased_function_id);
$storage = $this->storage = new FunctionStorage();
if ($this->codebase->register_stub_files || $this->codebase->register_autoload_files) {
if (isset($this->file_storage->functions[$function_id])
&& ($this->codebase->register_stub_files
|| !$this->codebase->functions->hasStubbedFunction($function_id))
) {
$this->codebase->functions->addGlobalFunction(
$function_id,
$this->file_storage->functions[$function_id]
);
$storage = $this->storage = $this->file_storage->functions[$function_id];
return [$function_id, $storage, null, null, null, null, false, null, true];
}
} else {
if (isset($this->file_storage->functions[$function_id])) {
$duplicate_function_storage = $this->file_storage->functions[$function_id];
if ($duplicate_function_storage->location
&& $duplicate_function_storage->location->getLineNumber() === $stmt->getLine()
) {
$storage = $this->storage = $this->file_storage->functions[$function_id];
return [$function_id, $storage, null, null, null, null, false, null, true];
}
if (IssueBuffer::accepts(
new DuplicateFunction(
'Method ' . $function_id . ' has already been defined'
. ($duplicate_function_storage->location
? ' in ' . $duplicate_function_storage->location->file_path
: ''),
new CodeLocation($this->file_scanner, $stmt, null, true)
)
)) {
// fall through
}
$this->file_storage->has_visitor_issues = true;
$duplicate_function_storage->has_visitor_issues = true;
$storage = $this->storage = $this->file_storage->functions[$function_id];
return [$function_id, $storage, null, null, null, null, false, null, true];
}
if (isset($this->config->getPredefinedFunctions()[$function_id])) {
/** @psalm-suppress ArgumentTypeCoercion */
$reflection_function = new \ReflectionFunction($function_id);
if ($reflection_function->getFileName() !== $this->file_path) {
if (IssueBuffer::accepts(
new DuplicateFunction(
'Method ' . $function_id . ' has already been defined as a core function',
new CodeLocation($this->file_scanner, $stmt, null, true)
)
)) {
// fall through
}
}
}
}
} elseif ($stmt instanceof PhpParser\Node\Stmt\ClassMethod) {
if (!$this->classlike_storage) {
throw new \LogicException('$this->classlike_storage should not be null');
}
$fq_classlike_name = $this->classlike_storage->name;
$method_name_lc = strtolower($stmt->name->name);
$function_id = $fq_classlike_name . '::' . $method_name_lc;
$cased_function_id = $fq_classlike_name . '::' . $stmt->name->name;
$classlike_storage = $this->classlike_storage;
$storage = null;
if (isset($classlike_storage->methods[$method_name_lc])) {
if (!$this->codebase->register_stub_files) {
$duplicate_method_storage = $classlike_storage->methods[$method_name_lc];
if (IssueBuffer::accepts(
new DuplicateMethod(
'Method ' . $function_id . ' has already been defined'
. ($duplicate_method_storage->location
? ' in ' . $duplicate_method_storage->location->file_path
: ''),
new CodeLocation($this->file_scanner, $stmt, null, true)
)
)) {
// fall through
}
$this->file_storage->has_visitor_issues = true;
$duplicate_method_storage->has_visitor_issues = true;
return false;
}
$is_functionlike_override = true;
$storage = $this->storage = $classlike_storage->methods[$method_name_lc];
}
if (!$storage) {
$storage = $this->storage = new MethodStorage();
}
$storage->stubbed = $this->codebase->register_stub_files;
$storage->defining_fqcln = $fq_classlike_name;
$class_name_parts = explode('\\', $fq_classlike_name);
$class_name = array_pop($class_name_parts);
if ($method_name_lc === strtolower($class_name)
&& !isset($classlike_storage->methods['__construct'])
&& strpos($fq_classlike_name, '\\') === false
&& $this->codebase->php_major_version < 8
) {
$this->codebase->methods->setDeclaringMethodId(
$fq_classlike_name,
'__construct',
$fq_classlike_name,
$method_name_lc
);
$this->codebase->methods->setAppearingMethodId(
$fq_classlike_name,
'__construct',
$fq_classlike_name,
$method_name_lc
);
}
$method_id = new \Psalm\Internal\MethodIdentifier(
$fq_classlike_name,
$method_name_lc
);
$storage->is_static = $stmt->isStatic();
$storage->abstract = $stmt->isAbstract();
$storage->final = $classlike_storage->final || $stmt->isFinal();
$storage->final_from_docblock = $classlike_storage->final_from_docblock;
if ($stmt->isPrivate()) {
$storage->visibility = ClassLikeAnalyzer::VISIBILITY_PRIVATE;
} elseif ($stmt->isProtected()) {
$storage->visibility = ClassLikeAnalyzer::VISIBILITY_PROTECTED;
} else {
$storage->visibility = ClassLikeAnalyzer::VISIBILITY_PUBLIC;
}
} elseif ($stmt instanceof PhpParser\Node\Expr\Closure
|| $stmt instanceof PhpParser\Node\Expr\ArrowFunction
) {
$function_id = $cased_function_id = strtolower($this->file_path)
. ':' . $stmt->getLine()
. ':' . (int)$stmt->getAttribute('startFilePos') . ':-:closure';
$storage = $this->storage = $this->file_storage->functions[$function_id] = new FunctionStorage();
if ($stmt instanceof PhpParser\Node\Expr\Closure) {
foreach ($stmt->uses as $closure_use) {
if ($closure_use->byRef && \is_string($closure_use->var->name)) {
$storage->byref_uses[$closure_use->var->name] = true;
}
}
}
} else {
throw new \UnexpectedValueException('Unrecognized functionlike');
}
return [
$cased_function_id,
$storage,
$function_id,
$fq_classlike_name,
$method_name_lc,
$classlike_storage,
$is_functionlike_override,
$method_id,
false
];
}
} }