public function testCachedCallSitesAreRemoved() { $cachedFooFunc = new GlobalFunction('foo'); $cachedBarFunc = new GlobalFunction('bar'); $cachedBarClass = new Clazz('Bar'); $cachedBarClass->addMethod($cachedBarMethod = new Method('bar')); $cachedFooClass = new Clazz('Foo'); $cachedFooClass->addMethod($cachedFooMethod = new Method('foo')); CallSite::create($cachedFooFunc, $cachedBarFunc); CallSite::create($cachedFooMethod, $cachedBarFunc); CallSite::create($cachedFooMethod, $cachedBarMethod); CallSite::create($cachedBarFunc, $cachedFooFunc); CallSite::create($cachedBarMethod, $cachedFooFunc); $this->provider->addFunction($cachedFooFunc); $this->provider->addFunction($cachedBarFunc); $this->provider->addClass($cachedBarClass); $this->provider->addClass($cachedFooClass); $this->analyzeAst('CallGraph/cache.php'); $fooFunc = $this->registry->getFunction('foo'); $fooMethod = $this->registry->getClass('Foo')->getMethod('foo')->getMethod(); $this->assertInCallSites($fooFunc, array($cachedBarMethod), array($cachedBarFunc)); $this->assertOutCallSites($fooFunc, array(), array()); $this->assertInCallSites($fooMethod, array(), array()); $this->assertOutCallSites($fooMethod, array($cachedBarMethod), array($cachedBarFunc)); $this->assertInCallSites($cachedBarMethod, array($fooMethod), array()); $this->assertOutCallSites($cachedBarMethod, array(), array($fooFunc)); $this->assertInCallSites($cachedBarFunc, array($fooMethod), array()); $this->assertOutCallSites($cachedBarFunc, array(), array($fooFunc)); $this->assertInCallSites($cachedFooFunc, array($cachedBarMethod), array($cachedBarFunc)); $this->assertOutCallSites($cachedFooFunc, array(), array($cachedBarFunc)); $this->assertInCallSites($cachedFooMethod, array(), array()); $this->assertOutCallSites($cachedFooMethod, array($cachedBarMethod), array($cachedBarFunc)); }
public function testPersist() { $this->packageVersion->addContainer($foo = new Clazz('Foo')); $foo->addImplementedInterface('Iterator'); $foo->addMethod($fooMethod = new Method('foo')); $this->packageVersion->addFunction($count_foo = new GlobalFunction('count_foo')); CallSite::create($fooMethod, $count_foo); $this->persister->persist($this->packageVersion); $reloadedFoo = $this->em->createQuery('SELECT c FROM Scrutinizer\\PhpAnalyzer\\Model\\Clazz c WHERE c.name = :name')->setParameter('name', 'Foo')->getSingleResult(); assert($reloadedFoo instanceof Clazz); $this->assertEquals(array('Iterator'), $reloadedFoo->getImplementedInterfaces()); $this->assertTrue($reloadedFoo->hasMethod('foo')); $reloadedCountFoo = $this->em->createQuery('SELECT f FROM Scrutinizer\\PhpAnalyzer\\Model\\GlobalFunction f WHERE f.name = :name')->setParameter('name', 'count_foo')->getSingleResult(); $this->assertCount(1, $inSites = $reloadedCountFoo->getInCallSites()); $this->assertSame($reloadedFoo->getMethod('foo')->getMethod(), $inSites[0]->getSource()); }
public function persist(CallSite $callSite) { // In this case, the call site has already been persisted. if (null !== $callSite->getId()) { return; } $sourceFunctionId = $targetFunctionId = $sourceMethodId = $targetMethodId = null; switch (true) { case $callSite instanceof FunctionToFunctionCallSite: $type = 'f2f'; $sourceFunctionId = $sourceId = $callSite->getSource()->getId(); $targetFunctionId = $targetId = $callSite->getTarget()->getId(); break; case $callSite instanceof FunctionToMethodCallSite: $type = 'f2m'; $sourceFunctionId = $sourceId = $callSite->getSource()->getId(); $targetMethodId = $targetId = $callSite->getTarget()->getId(); break; case $callSite instanceof MethodToFunctionCallSite: $type = 'm2f'; $sourceMethodId = $sourceId = $callSite->getSource()->getId(); $targetFunctionId = $targetId = $callSite->getTarget()->getId(); break; case $callSite instanceof MethodToMethodCallSite: $type = 'm2m'; $sourceMethodId = $sourceId = $callSite->getSource()->getId(); $targetMethodId = $targetId = $callSite->getTarget()->getId(); break; default: throw new \InvalidArgumentException('Unknown call site ' . get_class($callSite)); } // If either target, or source have not yet been persisted, we // simply ignore this call as there will be a second call when // both are complete. if (null === $sourceId || null === $targetId) { return; } $this->insertStmt->bindValue(1, $type); $this->insertStmt->bindValue(2, $sourceFunctionId, $sourceFunctionId ? \PDO::PARAM_INT : \PDO::PARAM_NULL); $this->insertStmt->bindValue(3, $targetFunctionId, $targetFunctionId ? \PDO::PARAM_INT : \PDO::PARAM_NULL); $this->insertStmt->bindValue(4, $targetMethodId, $targetMethodId ? \PDO::PARAM_INT : \PDO::PARAM_NULL); $this->insertStmt->bindValue(5, $sourceMethodId, $sourceMethodId ? \PDO::PARAM_INT : \PDO::PARAM_NULL); $this->insertStmt->execute(); $callSiteId = $this->con->lastInsertId(); $this->idRef->setValue($callSite, $callSiteId); if ("0" == $callSiteId) { throw new \LogicException(sprintf('Could not retrieve id of call-site: ' . json_encode(array('type' => $type, 'source_function_id' => $sourceFunctionId, 'target_function_id' => $targetFunctionId, 'target_method_id' => $targetMethodId, 'source_method_id' => $sourceMethodId)))); } foreach ($callSite->getArgs() as $arg) { $this->argPersister->persist($arg, $callSiteId); } }
private function copyInCallSites(AbstractFunction $function, AbstractFunction $nonCachedFunction) { foreach ($function->getInCallSites() as $site) { $source = $site->getSource(); $args = $site->getArgs()->getValues(); $args = array_map(function ($arg) { return clone $arg; }, $args); $source->removeCallSite($site); CallSite::create($source, $nonCachedFunction, $args); } }
public function removeCallSite(CallSite $site) { if ($site->getSource() === $this) { $target = $site->getTarget(); if ($target instanceof Method) { return $this->getOutMethodCallSites()->removeElement($site); } else { if ($target instanceof GlobalFunction) { return $this->getOutFunctionCallSites()->removeElement($site); } } throw new \LogicException('Previous ifs were exhaustive.'); } else { if ($site->getTarget() === $this) { $source = $site->getSource(); if ($source instanceof Method) { return $this->getInMethodCallSites()->removeElement($site); } else { if ($source instanceof GlobalFunction) { return $this->getInFunctionCallSites()->removeElement($site); } } throw new \LogicException('Previous ifs were exhaustive.'); } } throw new \InvalidArgumentException('$site is neither originating, nor targeting this function.'); }