public function advance($parser) { if ($this->pos >= 0) { $type = $this->tokens[$this->pos][0]; switch ($type) { case T_FOR: case T_FOREACH: $this->start_loop(); break; case T_DO: $this->ignoreNextWhile = true; $this->start_loop(); break; case T_WHILE: if (!$this->ignoreNextWhile) { $this->start_loop(); } $this->ignoreNextWhile = false; break; case T_SWITCH: case T_TRY: $this->start_cond(); break; case T_IF: if (!$this->lastWasElse) { $this->start_cond(); } else { // count the number of "T_ELSE T_IF" because for each of those we get another call // to end_cond() $this->vars->set_elseif(); } break; case T_ELSEIF: $this->start_cond(true, false); break; case T_ELSE: $this->start_cond(true, true); break; } $this->lastWasElse = $type == T_ELSE; } $res = parent::advance($parser); if ($this->lastComment && $this->lastComment != $this->lastCheckComment) { // it was a comment, so lets see if it contains a "@var $<name> <type>" that gives us a // hint what type a variable has. $matches = array(); if (preg_match('/\\@var\\s+\\$([a-z0-9_]+)\\s+(\\S+)/i', $this->lastComment, $matches)) { // do we know that variable? $scopename = $this->scope->get_name(); if ($this->vars->exists($scopename, $matches[1])) { // ok, determine type and set it $type = PC_Obj_MultiType::get_type_by_name($matches[2]); $var = $this->vars->get($scopename, $matches[1]); $var->set_type($type); } } $this->lastCheckComment = $this->lastComment; } return $res; }
/** * Finds variables that have not been read in the given scope. * * @param PC_Engine_VarContainer $vars the variables * @param string $scope the scope */ public function analyze($vars, $scope) { if (!$this->env->get_options()->get_report_unused()) { return; } $accesses = $vars->get_accesses(); if (isset($accesses[$scope])) { // determine the parameters to handle them special $params = array(); if ($scope != PC_Obj_Variable::SCOPE_GLOBAL) { if (strstr($scope, '::')) { list($cname, $fname) = explode('::', $scope); $func = $this->env->get_types()->get_method($cname, $fname); } else { $func = $this->env->get_types()->get_function($scope); } if ($func) { // don't report anything for abstract methods if ($func->is_abstract()) { return; } $params = $func->get_params(); } } foreach ($accesses[$scope] as $vname => $count) { if ($count == 0) { if (isset($params[$vname])) { // if it's a method and this method exists in a superclass, too, don't report the error // because it happens quite often that you don't use a parameter in subclasses, but you // are still forced to specify it. if (strstr($scope, '::')) { list($cname, $fname) = explode('::', $scope); $class = $this->env->get_types()->get_class($cname); if ($class) { $super = $class->get_super_class(); if ($this->env->get_types()->get_method_of_super($super, $fname) !== null) { return; } foreach ($class->get_interfaces() as $if) { if ($this->env->get_types()->get_method_of_super($if, $fname)) { return; } } } } // for references, write-only is ok if ($params[$vname]->is_reference()) { return; } $name = 'parameter'; $error = PC_Obj_Error::E_S_PARAM_UNUSED; } else { $name = 'variable'; $error = PC_Obj_Error::E_S_VAR_UNUSED; } $var = $vars->get($scope, $vname); $this->report($var, 'The ' . $name . ' $' . $vname . ' in #' . $scope . '# is unused', $error); } } } }