public function visit(NodeTraversal $t, \PHPParser_Node $n, \PHPParser_Node $parent = null)
 {
     if ($n instanceof \PHPParser_Node_Stmt_Property) {
         $containerNode = NodeUtil::getContainer($n)->get();
         $class = $this->typeRegistry->getClassByNode($containerNode);
         if ($class->isInterface()) {
             $this->phpFile->addComment($n->getLine(), Comment::error('basic_semantics.property_on_interface', 'In PHP, declaring a method on an interface is not yet allowed.'));
         }
     }
     if (NodeUtil::isMethodContainer($n)) {
         $class = $this->typeRegistry->getClassByNode($n);
         if ($class instanceof Clazz && !$class->isAbstract()) {
             $abstractMethods = array();
             foreach ($class->getMethods() as $method) {
                 assert($method instanceof ClassMethod);
                 /** @var $method ClassMethod */
                 if ($method->isAbstract()) {
                     $abstractMethods[] = $method->getMethod()->getName();
                 }
             }
             if (!empty($abstractMethods)) {
                 switch (count($abstractMethods)) {
                     case 1:
                         $this->phpFile->addComment($n->getLine(), Comment::error('basic_semantics.abstract_method_on_non_abstract_class', 'There is one abstract method ``%method%`` in this class; you could implement it, or declare this class as abstract.', array('method' => reset($abstractMethods))));
                         break;
                     default:
                         $this->phpFile->addComment($n->getLine(), Comment::error('basic_semantics.abstract_methods_on_non_abstract_class', 'There is at least one abstract method in this class. Maybe declare it as abstract, or implement the remaining methods: %methods%', array('methods' => implode(', ', $abstractMethods))));
                 }
             }
         }
     }
 }
 private function getThisType(\PHPParser_Node $node, Scope $parentScope = null)
 {
     $parent = $node;
     while (null !== $parent) {
         // As of PHP 5.4, closures inherit the this type of their parent scope. Since there is currently no way to
         // configure the PHP version that we build against, we will simply always infer the ThisType. Other passes,
         // can then perform checks whether ``$this`` may be accessed, allowing us to produce better error messages.
         if ($parent instanceof \PHPParser_Node_Expr_Closure) {
             if (null === $parentScope) {
                 return null;
             }
             return $parentScope->getTypeOfThis();
         }
         if (NodeUtil::isMethodContainer($parent)) {
             $name = implode("\\", $parent->namespacedName->parts);
             return $this->typeRegistry->getClassOrCreate($name);
         }
         $parent = $parent->getAttribute('parent');
     }
     return null;
 }
 /**
  * This method will stop traversal depending on the parent node.
  *
  * Principally, we are only interested in adding edges between nodes that change control flow. Notable ones are
  * loops (WHILE, FOR, etc.) and IF-ELSE statements; other statements typically transfer control to their next sibling.
  *
  * With regard to expression trees, we currently do not perform any sort of control flow within them, even if there
  * are short circuiting operators or conditionals. Instead, we synthesize lattices up when performing data flow
  * analysis by finding the meet at each expression node.
  *
  * @param NodeTraversal $t
  * @param \PHPParser_Node $node
  * @param \PHPParser_Node $parent
  *
  * @return boolean
  */
 public function shouldTraverse(NodeTraversal $t, \PHPParser_Node $node, \PHPParser_Node $parent = null)
 {
     $node->setAttribute('position', $this->astPositionCounter++);
     if ($node instanceof \PHPParser_Node_Stmt_TryCatch) {
         $this->exceptionHandlers->push($node);
         return true;
     }
     if (null !== $parent) {
         // Do not traverse into classes, interfaces, or traits as control flow never gets passed in.
         if (NodeUtil::isMethodContainer($parent)) {
             return false;
         }
         // Generally, the above also applies to closures except when they are the scope's root.
         if (NodeUtil::isScopeCreator($parent) && $parent !== $this->root) {
             return false;
         }
         // Skip conditions.
         if ($parent instanceof \PHPParser_Node_Stmt_For || $parent instanceof \PHPParser_Node_Stmt_Foreach) {
             return $parent->stmts === $node;
         }
         // Skip conditions.
         if ($parent instanceof \PHPParser_Node_Stmt_If || $parent instanceof \PHPParser_Node_Stmt_ElseIf || $parent instanceof \PHPParser_Node_Stmt_While || $parent instanceof \PHPParser_Node_Stmt_Do || $parent instanceof \PHPParser_Node_Stmt_Switch || $parent instanceof \PHPParser_Node_Stmt_Case) {
             return $parent->cond !== $node;
         }
         // Skip exception type.
         if ($parent instanceof \PHPParser_Node_Stmt_Catch) {
             return $parent->stmts === $node;
         }
         // Skip expressions, see above.
         if ($parent instanceof \PHPParser_Node_Expr && !$parent instanceof \PHPParser_Node_Expr_Closure) {
             return false;
         }
         if ($parent instanceof \PHPParser_Node_Stmt_Continue || $parent instanceof \PHPParser_Node_Stmt_Break || $parent instanceof \PHPParser_Node_Stmt_Return || $parent instanceof \PHPParser_Node_Stmt_Echo || $parent instanceof \PHPParser_Node_Stmt_Use || $parent instanceof \PHPParser_Node_Stmt_Unset || $parent instanceof \PHPParser_Node_Stmt_Declare || $parent instanceof \PHPParser_Node_Stmt_Global || $parent instanceof \PHPParser_Node_Stmt_Static || $parent instanceof \PHPParser_Node_Stmt_StaticVar || $parent instanceof \PHPParser_Node_Stmt_Throw) {
             return false;
         }
         // Skip parameters.
         if (NodeUtil::isScopeCreator($parent) && $node !== $parent->stmts) {
             return false;
         }
         // If we are reaching the CATCH, or FINALLY node, they current exception handler cannot catch anymore
         // exceptions, and we therefore can remove it.
         // TODO: Add Support for FINALLY (PHP 5.5)
         if ($parent instanceof \PHPParser_Node_Stmt_TryCatch && $parent->catches[0] === $node && $parent === $this->exceptionHandlers->top()) {
             $this->exceptionHandlers->pop();
         }
     }
     return true;
 }
 public function visit(NodeTraversal $t, \PHPParser_Node $node, \PHPParser_Node $parent = null)
 {
     switch (true) {
         case $node instanceof \PHPParser_Node_Expr_Variable:
             if (NodeUtil::isSuperGlobal($node)) {
                 return;
             }
             if (is_string($node->name)) {
                 $this->checkNaming($node->getLine(), '$' . $node->name, $node->name, 'local_variable');
             }
             break;
         case $node instanceof \PHPParser_Node_Stmt_PropertyProperty:
             $this->checkNaming($node->getLine(), '$' . $node->name, $node->name, 'property_name');
             break;
         case $node instanceof \PHPParser_Node_Stmt_Function:
         case $node instanceof \PHPParser_Node_Stmt_ClassMethod:
             $function = $this->typeRegistry->getFunctionByNode($node);
             // If a class method is constrained by a contract of an interface, or an abstract
             // class, then there is no point in adding warnings for them.
             if ($function instanceof ClassMethod && $function->isConstrainedByContract()) {
                 break;
             }
             $this->checkNaming($node->getLine(), 'function ' . $node->name . '()', $node->name, 'method_name');
             if (null !== $function && null !== ($returnType = $function->getReturnType()) && $returnType->isBooleanType()) {
                 $this->checkNaming($node->getLine(), 'function ' . $node->name . '()', $node->name, 'isser_method_name');
             }
             $this->checkParameters($node->params);
             break;
         case $node instanceof \PHPParser_Node_Expr_Closure:
             $this->checkParameters($node->params);
             break;
         case NodeUtil::isMethodContainer($node):
             $class = $this->typeRegistry->getClassByNode($node)->toMaybeObjectType();
             if ($class) {
                 $this->checkNaming($node->getLine(), $class->getShortName(), $class->getShortName(), 'type_name');
                 if ($class->isInterface()) {
                     $this->checkNaming($node->getLine(), $class->getShortName(), $class->getShortName(), 'interface_name');
                 } elseif ($class instanceof Clazz) {
                     if ($class->isUtilityClass()) {
                         $this->checkNaming($node->getLine(), $class->getShortName(), $class->getShortName(), 'utility_class_name');
                     } elseif ($class->isAbstract()) {
                         $this->checkNaming($node->getLine(), $class->getShortName(), $class->getShortName(), 'abstract_class_name');
                     }
                     // No Else-If here as there might be an abstract exception.
                     // TODO: isSubtype needs to return a TernaryValue so that we
                     //       can decide here what to do in the unknown case.
                     //                        if ($class->isSubTypeOf($this->typeRegistry->getClassOrCreate('Exception'))) {
                     //                            $this->checkNaming($node->getLine(), $class->getShortName(), $class->getShortName(), 'exception_name');
                     //                        }
                 }
                 // The original check only allows final classes to have a private
                 // constructor. We also allow the constructor to be private if it
                 // is declared final, and the class is declared abstract. This is
                 // for example a common practice for utility classes.
                 $method = $class->getMethod('__construct');
                 if (null !== $method && $method->isPrivate() && !$class->isFinal() && (!$method->isFinal() || !$class->isAbstract())) {
                     if (($method = $class->getMethod('__construct')) && $method->isPrivate() && !$class->isFinal() && (!$method->isFinal() || !$class->isAbstract())) {
                         if ($method->isFinal()) {
                             if ($class->isUtilityClass()) {
                                 $this->phpFile->addComment($node->getLine(), Comment::warning('coding_style.non_abstract_util_class', 'Since you have declared the constructor as final, and this seems like a utility class, maybe you should also declare the class as abstract.'));
                             } else {
                                 if (null === $method->getAstNode()) {
                                     break;
                                 }
                                 $this->phpFile->addComment($method->getAstNode()->getLine(), Comment::warning('coding_style.non_util_class_with_final_private_constructor', 'Instead of declaring the constructor as final, maybe you should declare the entire class as final.'));
                             }
                         } elseif ($class->isAbstract()) {
                             if ($class->isUtilityClass()) {
                                 $this->phpFile->addComment($method->getAstNode()->getLine(), Comment::warning('coding_style.util_class_with_non_final_constructor', 'Since you have declared this class abstract, and the constructor is private, maybe you should also declare the constructor as final.'));
                             } else {
                                 $this->phpFile->addComment($method->getAstNode()->getLine(), Comment::warning('coding_style.abstract_non_util_class_with_private_constructor', 'Something seems to be off here. Are you sure you want to declare the constructor as private, and the class as abstract?'));
                             }
                         } else {
                             $this->phpFile->addComment($node->getLine(), Comment::warning('coding_style.non_final_class_with_private_constructor', 'Since you have declared the constructor as private, maybe you should also declare the class as final.'));
                         }
                     }
                 }
             }
             break;
     }
 }
 private function enterNode(\PHPParser_Node $node)
 {
     if (NodeUtil::isMethodContainer($node)) {
         $this->commentParser->setCurrentClassName(implode("\\", $node->namespacedName->parts));
         $this->commentParser->setImportedNamespaces($this->importedNamespaces);
         $this->classParser->setImportedNamespaces($this->importedNamespaces);
         $class = $this->classParser->parse($node);
         $this->classFiles[$class] = $this->phpFile;
         if ($this->typeRegistry->hasClass($class->getName(), TypeRegistry::LOOKUP_NO_CACHE)) {
             $this->analyzer->logger->warning(sprintf('The class "%s" has been defined more than once (maybe as a fixture for code generation). Ignoring the second definition.', $class->getName()));
             return;
         }
         $this->typeRegistry->registerClass($class);
     } else {
         if ($node instanceof \PHPParser_Node_Stmt_Function) {
             $this->functionParser->setImportedNamespaces($this->importedNamespaces);
             $function = $this->functionParser->parse($node);
             if ($this->typeRegistry->hasFunction($functionName = $function->getName(), false)) {
                 $this->analyzer->logger->warning(sprintf('The function "%s" has been defined more than once (probably conditionally). Ignoring the second definition.', $functionName));
                 return;
             }
             $this->typeRegistry->registerFunction($function);
         } else {
             if (NodeUtil::isConstantDefinition($node)) {
                 assert($node instanceof \PHPParser_Node_Expr_FuncCall);
                 if (!$node->args[0]->value instanceof \PHPParser_Node_Scalar_String) {
                     return;
                 }
                 $constant = new GlobalConstant($node->args[0]->value->value);
                 $constant->setAstNode($node);
                 $constant->setPhpType($this->typeRegistry->getNativeType('unknown'));
                 if (null !== ($type = $node->args[1]->value->getAttribute('type'))) {
                     $constant->setPhpType($type);
                 }
                 if ($this->typeRegistry->hasConstant($constant->getName(), false)) {
                     $this->analyzer->logger->warning(sprintf('The constant "%s" was defined more than once. Ignoring all but first definition.', $constant->getName()));
                     return;
                 }
                 $this->typeRegistry->registerConstant($constant);
             }
         }
     }
 }