private function inferenceTypeOfCalledObject(TES5ObjectCall $objectCall, TES5MultipleScriptsScope $multipleScriptsScope) { $inferencableType = $objectCall->getAccessedObject()->getType()->getNativeType(); /** * Check if we have something to inference inside the code, not some static class or method call return */ if ($objectCall->getAccessedObject()->getReferencesTo() !== null) { //this is not "exactly" nice solution, but its enough. For now. $inferenceType = TES5InheritanceGraphAnalyzer::findTypeByMethod($objectCall); if ($inferencableType === null) { throw new ConversionException("Cannot inference a null type"); } if ($inferencableType == $inferenceType) { return; //We already have the good type. } if ($this->inferenceType($objectCall->getAccessedObject()->getReferencesTo(), $inferenceType, $multipleScriptsScope)) { return; } } }
/** * @param TES5ObjectCall $objectCall * @return mixed|TES5Type * @throws \Ormin\OBSLexicalParser\TES5\Exception\ConversionException * */ public static function findTypeByMethod(TES5ObjectCall $objectCall) { $methodName = $objectCall->getFunctionName(); $possibleMatches = []; foreach (self::$callReturns as $type => $methods) { foreach ($methods as $method => $functionData) { if (strtolower($method) == strtolower($methodName)) { $possibleMatches[] = TES5TypeFactory::memberByValue($type); } } } $calledOn = $objectCall->getAccessedObject()->getReferencesTo(); $extendingMatches = []; $actualType = $calledOn->getPropertyType()->getNativeType(); /** * @var TES5Type[] $possibleMatches */ foreach ($possibleMatches as $possibleMatch) { if ($possibleMatch == $actualType) { return $possibleMatch; //if the possible match matches the actual basic type, it means that it surely IS one of those. } //Ok, so are those matches somehow connected at all? if (TES5InheritanceGraphAnalyzer::isExtending($possibleMatch, $actualType) || TES5InheritanceGraphAnalyzer::isExtending($actualType, $possibleMatch)) { $extendingMatches[] = $possibleMatch; } } switch (count($extendingMatches)) { case 0: $concatTypes = []; foreach ($possibleMatches as $possibleMatch) { $concatTypes[] = $possibleMatch->value(); } throw new ConversionException("Cannot find any possible type for method " . $methodName . ", trying to extend " . $actualType->value() . " with following types: " . implode(', ', $concatTypes)); case 1: return current($extendingMatches); default: //We analyze the property name and check inside the ESM analyzer. $formType = ESMAnalyzer::instance()->getFormTypeByEDID($calledOn->getReferenceEdid()); if (!in_array($formType, $extendingMatches)) { throw new ConversionException("ESM <-> Inheritance Graph conflict, ESM returned " . $formType->value() . ", which is not present in possible matches from inheritance graph"); } return $formType; } }