public function visitFuncDecl(Decl $node) : Context
{
$function_name = (string) $node->name;
try {
$canonical_function = (new ContextNode($this->code_base, $this->context, $node))->getFunction($function_name, true);
} catch (CodeBaseException $exception) {
// This really ought not happen given that
// we already successfully parsed the code
// base
throw $exception;
return $this->context;
}
// Hunt for the alternate associated with the file we're
// looking at currently in this context.
$function = null;
foreach ($canonical_function->alternateGenerator($this->code_base) as $i => $alternate_function) {
if ($alternate_function->getFileRef()->getProjectRelativePath() === $this->context->getProjectRelativePath()) {
$function = $alternate_function;
break;
}
}
if (empty($function)) {
// No alternate was found
throw new CodeBaseException(null, "Can't find function {$function_name} in context {$this->context} - aborting");
}
$context = $this->context->withScope($function->getInternalScope());
// Parse the comment above the method to get
// extra meta information about the method.
$comment = Comment::fromStringInContext($node->docComment ?? '', $this->context);
// For any @var references in the method declaration,
// add them as variables to the method's scope
foreach ($comment->getVariableList() as $parameter) {
$context->addScopeVariable($parameter->asVariable($this->context));
}
// Add each method parameter to the scope. We clone it
// so that changes to the variable don't alter the
// parameter definition
foreach ($function->getParameterList() as $parameter) {
$context->addScopeVariable(clone $parameter);
}
if ($this->analyzeFunctionLikeIsGenerator($node)) {
$this->setReturnTypeOfGenerator($function, $node);
}
return $context;
}