getDocComment(); $var_comments = []; $var_comment_type = null; $codebase = $statements_analyzer->getCodebase(); if ($doc_comment) { try { $var_comments = CommentAnalyzer::getTypeFromComment( $doc_comment, $statements_analyzer, $statements_analyzer->getAliases(), ); } catch (DocblockParseException $e) { IssueBuffer::maybeAdd( new InvalidDocblock( $e->getMessage(), new CodeLocation($statements_analyzer->getSource(), $stmt), ), ); } foreach ($var_comments as $var_comment) { if (!$var_comment->type) { continue; } $comment_type = TypeExpander::expandUnion( $codebase, $var_comment->type, $context->self, $context->self ? new TNamedObject($context->self) : null, $statements_analyzer->getParentFQCLN(), ); $type_location = null; if ($var_comment->type_start && $var_comment->type_end && $var_comment->line_number ) { $type_location = new DocblockTypeLocation( $statements_analyzer, $var_comment->type_start, $var_comment->type_end, $var_comment->line_number, ); } if (!$var_comment->var_id) { $var_comment_type = $comment_type; continue; } if ($codebase->find_unused_variables && $type_location && isset($context->vars_in_scope[$var_comment->var_id]) && $context->vars_in_scope[$var_comment->var_id]->getId() === $comment_type->getId() ) { $project_analyzer = $statements_analyzer->getProjectAnalyzer(); if ($codebase->alter_code && isset($project_analyzer->getIssuesToFix()['UnnecessaryVarAnnotation']) ) { FileManipulationBuffer::addVarAnnotationToRemove($type_location); } else { IssueBuffer::maybeAdd( new UnnecessaryVarAnnotation( 'The @var annotation for ' . $var_comment->var_id . ' is unnecessary', $type_location, ), $statements_analyzer->getSuppressedIssues(), true, ); } } if (isset($context->vars_in_scope[$var_comment->var_id])) { $comment_type = $comment_type->setParentNodes( $context->vars_in_scope[$var_comment->var_id]->parent_nodes, ); } $context->vars_in_scope[$var_comment->var_id] = $comment_type; } } if ($stmt->key) { $context->inside_call = true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->key, $context) === false) { return false; } $context->inside_call = false; } if ($stmt->value) { $context->inside_call = true; if (ExpressionAnalyzer::analyze($statements_analyzer, $stmt->value, $context) === false) { return false; } $context->inside_call = false; if ($var_comment_type) { $expression_type = $var_comment_type; } elseif ($stmt_var_type = $statements_analyzer->node_data->getType($stmt->value)) { $expression_type = $stmt_var_type; } else { $expression_type = Type::getMixed(); } } else { $expression_type = Type::getNever(); } $yield_type = null; foreach ($expression_type->getAtomicTypes() as $expression_atomic_type) { if (!$expression_atomic_type instanceof TNamedObject) { continue; } if (!$codebase->classlikes->classOrInterfaceExists($expression_atomic_type->value)) { continue; } $classlike_storage = $codebase->classlike_storage_provider->get($expression_atomic_type->value); if (!$classlike_storage->yield) { continue; } $declaring_classlike_storage = $classlike_storage->declaring_yield_fqcn ? $codebase->classlike_storage_provider->get($classlike_storage->declaring_yield_fqcn) : $classlike_storage; $yield_candidate_type = $classlike_storage->yield; $yield_candidate_type = !$yield_candidate_type->isMixed() ? TypeExpander::expandUnion( $codebase, $yield_candidate_type, $expression_atomic_type->value, $expression_atomic_type->value, null, true, false, ) : $yield_candidate_type; $class_template_params = ClassTemplateParamCollector::collect( $codebase, $declaring_classlike_storage, $classlike_storage, null, $expression_atomic_type, true, ); if ($class_template_params) { if (!$expression_atomic_type instanceof TGenericObject) { $type_params = []; foreach ($class_template_params as $type_map) { $type_params[] = array_values($type_map)[0]; } $expression_atomic_type = new TGenericObject($expression_atomic_type->value, $type_params); } $yield_candidate_type = AtomicPropertyFetchAnalyzer::localizePropertyType( $codebase, $yield_candidate_type, $expression_atomic_type, $classlike_storage, $declaring_classlike_storage, ); } $yield_type = Type::combineUnionTypes( $yield_type, $yield_candidate_type, $codebase, ); } if ($yield_type) { $expression_type = $expression_type->getBuilder()->substitute($expression_type, $yield_type)->freeze(); } $statements_analyzer->node_data->setType($stmt, $expression_type); $source = $statements_analyzer->getSource(); if ($source instanceof FunctionLikeAnalyzer && !($source->getSource() instanceof TraitAnalyzer) ) { $source->examineParamTypes($statements_analyzer, $context, $codebase, $stmt); $storage = $source->getFunctionLikeStorage($statements_analyzer); if ($storage->return_type && !$yield_type) { foreach ($storage->return_type->getAtomicTypes() as $atomic_return_type) { if ($atomic_return_type instanceof TNamedObject && $atomic_return_type->value === 'Generator' ) { if ($atomic_return_type instanceof TGenericObject) { if (!$atomic_return_type->type_params[2]->isVoid()) { $statements_analyzer->node_data->setType( $stmt, $atomic_return_type->type_params[2], ); } } else { $statements_analyzer->node_data->setType( $stmt, Type::combineUnionTypes( Type::getMixed(), $expression_type, ), ); } } } } } return true; } }