public function testEmptyDocBlock()
 {
     $doc = '/**
          *
          */';
     $this->assertEquals([], $this->parser->parseString($doc));
 }
 /**
  * Called when entering a node.
  *
  * Return value semantics:
  *  * null:      $node stays as-is
  *  * otherwise: $node is set to the return value
  *
  * @param Node $node
  *
  * @return null|Node
  */
 public function enterNode(Node $node)
 {
     if ($node instanceof Namespace_) {
         $this->namespace = '\\' . $node->name;
         $this->namespaceLine = $node->getLine();
     } elseif ($node instanceof Use_) {
         $use_count = 0;
         foreach ($node->uses as $use) {
             if ($use instanceof UseUse) {
                 if (!$this->resolver->isValid("\\{$use->name}")) {
                     $this->result->error(ErrorType::UNABLE_TO_RESOLVE_USE, $use->getLine(), "Use '\\{$use->name}' could not be resolved");
                 }
                 if (isset($this->aliases[$use->alias])) {
                     $line = $this->aliases[$use->alias]->getNode()->getLine();
                     $this->result->error(ErrorType::DUPLICATE_ALIAS, $use->getLine(), "Alias '{$use->alias}' is already in use on line {$line}");
                 }
                 $this->aliases[$use->alias] = new UseTracker($use->alias, (string) $use->name, $use);
                 $this->useStatements[] = $use;
             } else {
                 // I don't know if this error can ever be generated, as it should be a parse error...
                 $this->result->error(ErrorType::MALFORMED_USE, $use->getLine(), "Malformed use statement");
                 return;
             }
             $use_count++;
         }
         if ($use_count > 1) {
             $this->result->error(ErrorType::MULTI_STATEMENT_USE, $node->getLine(), "Multiple uses in one statement is discouraged");
         }
     } else {
         if ($node instanceof New_) {
             $this->validateMethodAccess($node->getLine(), $node->class, '__construct');
         }
         if ($node instanceof StaticCall) {
             if ($node->name !== '__construct') {
                 $this->validateMethodExists($node->getLine(), $node->class, $node->name);
             }
             $this->validateMethodAccess($node->getLine(), $node->class, $node->name);
         }
         if (isset($node->class) && $node->class instanceof Name) {
             $this->resolveType($node->getLine(), $node->class);
         }
         if (isset($node->traits)) {
             foreach ($node->traits as $trait) {
                 $this->resolveType($node->getLine(), $trait);
             }
         }
         if (isset($node->implements)) {
             foreach ($node->implements as $implements) {
                 $this->resolveType($node->getLine(), $implements);
             }
         }
         if (isset($node->extends)) {
             if ($node->extends instanceof Name) {
                 $this->resolveType($node->getLine(), $node->extends);
             } else {
                 foreach ($node->extends as $extends) {
                     $this->resolveType($node->getLine(), $extends);
                 }
             }
         }
         if (isset($node->type) && $node->type instanceof Name) {
             $this->resolveType($node->getLine(), $node->type);
         }
         if ($node instanceof ClassMethod && $node->getReturnType() instanceof Name) {
             $this->resolveType($node->getLine(), $node->getReturnType());
         }
         if ($node instanceof ClassMethod or $node instanceof Function_ or $node instanceof Property or $node instanceof Class_ or $node instanceof Variable) {
             /** @var $docblock Doc */
             if ($docblock = $node->getDocComment()) {
                 $annotations = $this->annotationParser->parseString($docblock->getText());
                 foreach ($annotations as $annotation) {
                     if ($annotation instanceof DoctrineAnnotation) {
                         $this->resolveDoctrineComment($docblock->getLine() - 1, $annotation);
                     } elseif ($annotation instanceof NonDoctrineAnnotation) {
                         $this->resolveNonDoctrineComment($docblock->getLine() - 1, $annotation);
                     }
                 }
             }
         }
         if ($node instanceof Catch_) {
             foreach ($node->types as $type) {
                 $this->resolveType($node->getLine(), $type);
             }
         }
         // eclipse can only handle inline type hints in a normal comment block
         if ($node instanceof Variable) {
             $comments = $node->getAttribute('comments');
             if (is_array($comments)) {
                 $phpVariableRegex = '[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*';
                 // regex for matching /* @var $variable Class */
                 $eclipseInlineTypeHintRegex = '~^/\\* @var \\$' . $phpVariableRegex . ' (\\\\?' . $phpVariableRegex . '(\\\\' . $phpVariableRegex . ')*) \\*/$~';
                 foreach ($comments as $comment) {
                     /* @var $comment Comment */
                     $matches = [];
                     $match = preg_match($eclipseInlineTypeHintRegex, $comment->getText(), $matches);
                     if ($match === 1) {
                         $className = $matches[1];
                         $this->resolveAnnotatedType($comment->getLine(), $className);
                     }
                 }
             }
         }
     }
     $this->nodeStack[] = $node;
 }