getCodebase(); $source = $statements_analyzer->getSource(); $config = $codebase->config; if ($stmt->class instanceof PhpParser\Node\Name) { $fq_class_name = null; if (count($stmt->class->parts) === 1 && in_array(strtolower($stmt->class->parts[0]), ['self', 'static', 'parent'], true) ) { if ($stmt->class->parts[0] === 'parent') { $child_fq_class_name = $context->self; $class_storage = $child_fq_class_name ? $codebase->classlike_storage_provider->get($child_fq_class_name) : null; if (!$class_storage || !$class_storage->parent_class) { if (IssueBuffer::accepts( new ParentNotFound( 'Cannot call method on parent as this class does not extend another', new CodeLocation($statements_analyzer->getSource(), $stmt) ), $statements_analyzer->getSuppressedIssues() )) { return false; } return true; } $fq_class_name = $class_storage->parent_class; $fq_class_name = $codebase->classlikes->getUnAliasedName($fq_class_name); $class_storage = $codebase->classlike_storage_provider->get($fq_class_name); $fq_class_name = $class_storage->name; } elseif ($context->self) { if ($stmt->class->parts[0] === 'static' && isset($context->vars_in_scope['$this'])) { $fq_class_name = (string) $context->vars_in_scope['$this']; $lhs_type = clone $context->vars_in_scope['$this']; } else { $fq_class_name = $context->self; } } else { if (IssueBuffer::accepts( new NonStaticSelfCall( 'Cannot use ' . $stmt->class->parts[0] . ' outside class context', new CodeLocation($statements_analyzer->getSource(), $stmt) ), $statements_analyzer->getSuppressedIssues() )) { return false; } return true; } if ($context->isPhantomClass($fq_class_name)) { return true; } } elseif ($context->check_classes) { $aliases = $statements_analyzer->getAliases(); if ($context->calling_method_id && !$stmt->class instanceof PhpParser\Node\Name\FullyQualified ) { $codebase->file_reference_provider->addMethodReferenceToClassMember( $context->calling_method_id, 'use:' . $stmt->class->parts[0] . ':' . \md5($statements_analyzer->getFilePath()) ); } $fq_class_name = ClassLikeAnalyzer::getFQCLNFromNameObject( $stmt->class, $aliases ); if ($context->isPhantomClass($fq_class_name)) { return true; } $does_class_exist = false; if ($context->self) { $self_storage = $codebase->classlike_storage_provider->get($context->self); if (isset($self_storage->used_traits[strtolower($fq_class_name)])) { $fq_class_name = $context->self; $does_class_exist = true; } } if (!isset($context->phantom_classes[strtolower($fq_class_name)]) && !$does_class_exist ) { $does_class_exist = ClassLikeAnalyzer::checkFullyQualifiedClassLikeName( $statements_analyzer, $fq_class_name, new CodeLocation($source, $stmt->class), !$context->collect_initializations && !$context->collect_mutations ? $context->self : null, !$context->collect_initializations && !$context->collect_mutations ? $context->calling_method_id : null, $statements_analyzer->getSuppressedIssues(), false, false, false ); } if (!$does_class_exist) { return $does_class_exist !== false; } } if ($codebase->store_node_types && $fq_class_name && !$context->collect_initializations && !$context->collect_mutations ) { $codebase->analyzer->addNodeReference( $statements_analyzer->getFilePath(), $stmt->class, $fq_class_name ); } if ($fq_class_name && !$lhs_type) { $lhs_type = new Type\Union([new TNamedObject($fq_class_name)]); } } else { $was_inside_use = $context->inside_use; $context->inside_use = true; ExpressionAnalyzer::analyze($statements_analyzer, $stmt->class, $context); $context->inside_use = $was_inside_use; $lhs_type = $statements_analyzer->node_data->getType($stmt->class) ?: Type::getMixed(); } if (!$lhs_type) { if (ArgumentsAnalyzer::analyze( $statements_analyzer, $stmt->args, null, null, true, $context ) === false) { return false; } return true; } $has_mock = false; $moved_call = false; $has_existing_method = false; foreach ($lhs_type->getAtomicTypes() as $lhs_type_part) { StaticMethod\AtomicStaticCallAnalyzer::analyze( $statements_analyzer, $stmt, $context, $lhs_type_part, $lhs_type->ignore_nullable_issues, $moved_call, $has_mock, $has_existing_method ); } if (!$has_existing_method) { return self::checkMethodArgs( $method_id, $stmt->args, null, $context, new CodeLocation($statements_analyzer->getSource(), $stmt), $statements_analyzer ); } if (!$config->remember_property_assignments_after_call && !$context->collect_initializations) { $context->removeAllObjectVars(); } if (!$statements_analyzer->node_data->getType($stmt)) { $statements_analyzer->node_data->setType($stmt, Type::getMixed()); } return true; } public static function taintReturnType( StatementsAnalyzer $statements_analyzer, PhpParser\Node\Expr\StaticCall $stmt, MethodIdentifier $method_id, string $cased_method_id, Type\Union $return_type_candidate, ?\Psalm\Storage\MethodStorage $method_storage ) : void { if (!$statements_analyzer->data_flow_graph instanceof TaintFlowGraph || \in_array('TaintedInput', $statements_analyzer->getSuppressedIssues()) ) { return; } $code_location = new CodeLocation($statements_analyzer->getSource(), $stmt); $method_location = $method_storage ? ($method_storage->signature_return_type_location ?: $method_storage->location) : null; if ($method_storage && $method_storage->specialize_call) { $method_source = DataFlowNode::getForMethodReturn( (string) $method_id, $cased_method_id, $method_location, $code_location ); } else { $method_source = DataFlowNode::getForMethodReturn( (string) $method_id, $cased_method_id, $method_location ); } $statements_analyzer->data_flow_graph->addNode($method_source); $return_type_candidate->parent_nodes = [$method_source->id => $method_source]; if ($method_storage && $method_storage->taint_source_types) { $method_node = TaintSource::getForMethodReturn( (string) $method_id, $cased_method_id, $method_storage->signature_return_type_location ?: $method_storage->location ); $method_node->taints = $method_storage->taint_source_types; $statements_analyzer->data_flow_graph->addSource($method_node); } } }