private function parseParams(DivinerAtom $atom, AASTNode $func)
 {
     $params = $func->getChildByIndex(3, 'n_DECLARATAION_PARAMETER_LIST')->selectDescendantsOfType('n_DECLARATION_PARAMETER');
     $param_spec = array();
     if ($atom->getDocblockRaw()) {
         $metadata = $atom->getDocblockMeta();
     } else {
         $metadata = array();
     }
     $docs = idx($metadata, 'param');
     if ($docs) {
         $docs = (array) $docs;
         $docs = array_filter($docs);
     } else {
         $docs = array();
     }
     if (count($docs)) {
         if (count($docs) < count($params)) {
             $atom->addWarning(pht('This call takes %s parameter(s), but only %s are documented.', phutil_count($params), phutil_count($docs)));
         }
     }
     foreach ($params as $param) {
         $name = $param->getChildByIndex(1)->getConcreteString();
         $dict = array('type' => $param->getChildByIndex(0)->getConcreteString(), 'default' => $param->getChildByIndex(2)->getConcreteString());
         if ($docs) {
             $doc = array_shift($docs);
             if ($doc) {
                 $dict += $this->parseParamDoc($atom, $doc, $name);
             }
         }
         $param_spec[] = array('name' => $name) + $dict;
     }
     if ($docs) {
         foreach ($docs as $doc) {
             if ($doc) {
                 $param_spec[] = $this->parseParamDoc($atom, $doc, null);
             }
         }
     }
     // TODO: Find `assert_instances_of()` calls in the function body and
     // add their type information here. See T1089.
     $atom->setProperty('parameters', $param_spec);
 }
 /**
  * Determines whether the current node appears //before// a specified node in
  * the tree.
  *
  * @param  AASTNode
  * @return bool
  */
 public final function isBefore(AASTNode $node)
 {
     return last($this->getTokens())->getOffset() < head($node->getTokens())->getOffset();
 }