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 getIsSubtypeTests() { $tests = array(); try { $registry = new TypeRegistry(); $foo = new Clazz('Foo'); $foo->setSuperClass('Bar'); $foo->setSuperClasses(array('Bar')); $foo->setImplementedInterfaces(array('Baz', 'FooBar')); $foo->setNormalized(true); $tests[] = array($foo, new InterfaceC('FooBar'), true); $tests[] = array($foo, new InterfaceC('Foo'), false); $tests[] = array($foo, $foo, true); $tests[] = array($foo, new Clazz('Bar'), true); $tests[] = array($foo, new Clazz('FooBar'), false); $tests[] = array($foo, NamedType::createResolved($registry, new InterfaceC('Baz')), true); $tests[] = array($foo, NamedType::createResolved($registry, new InterfaceC('Moo')), false); $tests[] = array($foo, NamedType::createResolved($registry, new Clazz('Foo')), true); $tests[] = array($foo, NamedType::createResolved($registry, new Clazz('FoooFooo')), false); $tests[] = array($foo, new UnknownType($registry, false), true); $tests[] = array($foo, new NoObjectType($registry), true); $tests[] = array($foo, new BooleanType($registry), false); $tests[] = array($foo, new IntegerType($registry), false); $tests[] = array($foo, new DoubleType($registry), false); $tests[] = array($foo, new StringType($registry), false); $tests[] = array($foo, $registry->createUnionType(array('string', new InterfaceC('Baz'))), true); $tests[] = array($foo, $registry->createUnionType(array('string', 'boolean')), false); } catch (\Exception $ex) { echo sprintf("Could not get tests for isSubtypeTests(): %s\n", $ex->getMessage() . ' on line ' . $ex->getLine() . ' in file ' . $ex->getFile()); } return $tests; }
public function __construct(Clazz $class, Property $property, $declaringClass = null) { $this->class = $class; $this->property = $property; $this->name = $property->getName(); if ($class->getName() === $declaringClass) { $declaringClass = null; } $this->declaringClass = $declaringClass; }
public function testObjectTypes() { $class = new \Scrutinizer\PhpAnalyzer\Model\Clazz('Foo'); $class->setNormalized(true); $this->registry->registerClass($class); $this->assertUnion('object<Foo>', new NamedType($this->registry, 'Foo'), $class); $named = new NamedType($this->registry, 'Foo'); $named->setReferencedType($class); $this->assertUnion('object<Foo>', $named, $class); }
public function __construct(Clazz $class, Method $method, $declaringClass = null) { $this->class = $class; $this->method = $method; $this->name = strtolower($method->getName()); if ($class->getName() === $declaringClass) { $declaringClass = null; } $this->declaringClass = $declaringClass; }
public function __construct(Clazz $class, Constant $constant, $declaringClass = null) { $this->class = $class; $this->constant = $constant; $this->name = $constant->getName(); if ($class->getName() === $declaringClass) { $declaringClass = null; } $this->declaringClass = $declaringClass; }
public function testDocTypesOfMethods() { $this->packageVersion->addContainer($foo = new Clazz('Foo')); $foo->addMethod($method = new Method('foo')); $method->setReturnDocType('self'); $method->setParamDocType(0, 'string'); $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(); $reloadedMethod = $reloadedFoo->getMethod('foo'); $this->assertEquals(array('param_0' => 'string', 'return' => 'self'), $reloadedMethod->getDocTypes()); }
public function testNullableThisType() { $class = new Clazz('Foo'); $class->setNormalized(true); $this->registry->registerClass($class); $builder = new UnionTypeBuilder($this->registry); $this->assertCount(0, $builder->getAlternates()); $builder->addAlternate($this->registry->getNativeType('null')); $this->assertCount(1, $builder->getAlternates()); $builder->addAlternate(new ThisType($this->registry, $class)); $this->assertCount(2, $builder->getAlternates()); $type = $builder->build(); $this->assertInstanceOf('Scrutinizer\\PhpAnalyzer\\PhpParser\\Type\\UnionType', $type); }
/** * @group packageDependencies */ public function testDeletePackageVersionWhenInheritingBetweenPackages() { $this->packageVersion->addContainer($foo = new Clazz('Foo')); $foo->addProperty($fooProperty = new Property('foo')); $fooProperty->setPhpType($this->typeRegistry->getNativeType('string')); $this->em->persist($this->packageVersion); $this->otherPackageVersion->addDependency($this->packageVersion); $this->otherPackageVersion->addContainer($bar = new Clazz('bar')); $bar->addProperty($fooProperty, 'Foo'); $this->em->persist($this->otherPackageVersion); $this->em->flush(); $this->assertVersionsCount(2); $this->repo->deletePackageVersion($this->packageVersion); $this->em->clear(); $this->assertVersionsCount(0); }
private function findOverriddenMethodsForDocInheritance($methodName, Clazz $clazz) { $methods = array(); foreach ($clazz->getImplementedInterfaces() as $interfaceName) { if (null !== ($interface = $this->registry->getClass($interfaceName))) { if ($interface->hasMethod($methodName)) { $methods[] = $interface->getMethod($methodName); } } } $superClass = $clazz; while (null !== ($superClass = $superClass->getSuperClassType())) { if ($superClass->hasMethod($methodName) && ($parentMethod = $superClass->getMethod($methodName)) && $parentMethod->isAbstract()) { $methods[] = $parentMethod; } } return $methods; }
private function setUpClass($class, array $extends) { $class = new Clazz($class); if (isset($extends[$class->getName()])) { $parentClass = $this->setUpClass($extends[$class->getName()], $extends); $class->setSuperClasses(array_merge(array($parentClass->getName()), $parentClass->getSuperClasses())); $class->setSuperClass($parentClass->getName()); } $class->setNormalized(true); $this->registry->registerClass($class); return $class; }
private function createClass($class) { $n = new \PHPParser_Node_Name_FullyQualified(explode("\\", $class)); if (is_string($class)) { $class = new \Scrutinizer\PhpAnalyzer\Model\Clazz($class); $class->setNormalized(true); $this->registry->registerClass($class); } $n->setAttribute('type', $class); return $n; }
public function parse(\PHPParser_Node $node) { if ($node instanceof \PHPParser_Node_Stmt_Class) { $class = new Clazz(implode("\\", $node->namespacedName->parts)); // convert PHPParser modifier to our modifier $modifier = 0; if (\PHPParser_Node_Stmt_Class::MODIFIER_FINAL === ($node->type & \PHPParser_Node_Stmt_Class::MODIFIER_FINAL)) { $modifier |= Clazz::MODIFIER_FINAL; } if (\PHPParser_Node_Stmt_Class::MODIFIER_ABSTRACT === ($node->type & \PHPParser_Node_Stmt_Class::MODIFIER_ABSTRACT)) { $modifier |= Clazz::MODIFIER_ABSTRACT; } $class->setModifier($modifier); if (null !== $node->extends) { $class->setSuperClass(implode("\\", $node->extends->parts)); } foreach ($node->implements as $iface) { $class->addImplementedInterface(implode("\\", $iface->parts)); } } else { if ($node instanceof \PHPParser_Node_Stmt_Interface) { $class = new InterfaceC(implode("\\", $node->namespacedName->parts)); foreach ($node->extends as $interface) { $class->addExtendedInterface(implode("\\", $interface->parts)); } } else { if ($node instanceof \PHPParser_Node_Stmt_Trait) { $class = new TraitC(implode("\\", $node->namespacedName->parts)); } else { throw new \LogicException(sprintf('The other statements were exhaustive. The node "%s" is not supported.', get_class($node))); } } } $class->setImportedNamespaces($this->importedNamespaces); $class->setAstNode($node); // add methods, properties, and constants foreach ($node->stmts as $stmt) { if ($stmt instanceof \PHPParser_Node_Stmt_ClassMethod) { $this->scanMethod($stmt, $class); } else { if ($stmt instanceof \PHPParser_Node_Stmt_Property) { $visibility = \PHPParser_Node_Stmt_Class::MODIFIER_PUBLIC === ($stmt->type & \PHPParser_Node_Stmt_Class::MODIFIER_PUBLIC) ? Property::VISIBILITY_PUBLIC : (\PHPParser_Node_Stmt_Class::MODIFIER_PROTECTED === ($stmt->type & \PHPParser_Node_Stmt_Class::MODIFIER_PROTECTED) ? Property::VISIBILITY_PROTECTED : Property::VISIBILITY_PRIVATE); foreach ($stmt->props as $propNode) { assert($propNode instanceof \PHPParser_Node_Stmt_PropertyProperty); // This is a PHP error which we flag in a later pass. Here, we can just ignore the property definition. if ($class->isInterface()) { continue; } assert($class instanceof Clazz || $class instanceof TraitC); $property = new Property($propNode->name); $property->setAstNode($propNode); $property->setVisibility($visibility); $class->addProperty($property); } } else { if ($stmt instanceof \PHPParser_Node_Stmt_ClassConst) { foreach ($stmt->consts as $constNode) { assert($constNode instanceof \PHPParser_Node_Const); $constant = new Constant($constNode->name); $constant->setAstNode($constNode); if (null !== ($type = $constNode->value->getAttribute('type'))) { $constant->setPhpType($type); } $class->addConstant($constant); } } } } } // Add magic properties denoted by @property, @property-read, @property-write. if ($node instanceof \PHPParser_Node_Stmt_Class && preg_match_all('#@(?:property|property-read|property-write)\\s+[^\\s]+\\s+\\$?([^\\s]+)#', $node->getDocComment(), $matches)) { for ($i = 0, $c = count($matches[0]); $i < $c; $i++) { // If there is already an explicitly declared property of the same // name, it has precedence for us. if ($class->hasProperty($matches[1][$i])) { $this->logger->warning(sprintf('The property "%s" is already defined in code; ignoring @property tag.', $matches[1][$i])); continue; } $property = new Property($matches[1][$i]); $property->setAstNode($node); $class->addProperty($property); } } // Add magic methods denoted by @method. if ($node instanceof \PHPParser_Node_Stmt_Class && preg_match_all('#@method\\s+([^@]+)#s', $node->getDocComment(), $matches)) { foreach ($matches[1] as $methodDef) { if (null !== ($method = $this->parseCommentMethodDef($methodDef))) { // An explicitly defined method has precedence. if ($class->hasMethod($method->getName())) { $this->logger->warning(sprintf('The method "%s" is already defined in code; ignoring @method tag.', $method->getName())); continue; } $class->addMethod($method); } } } return $class; }
/** * @group equals */ public function testEqualsWithResolvedNamedAndResolvedType() { $a = new NamedType($this->registry, 'Foo'); $b = new \Scrutinizer\PhpAnalyzer\Model\Clazz('Foo'); $b->setNormalized(true); $a->setReferencedType($b); $this->assertTrue($a->equals($b)); $this->assertTrue($b->equals($a)); $a = new NamedType($this->registry, 'Foo'); $c = new \Scrutinizer\PhpAnalyzer\Model\Clazz('Foo'); $c->setNormalized(true); $a->setReferencedType($c); $this->assertTrue($c->equals($a)); $this->assertTrue($a->equals($c)); }