示例#1
0
 /**
  * Processes a single file.
  *
  * @param string $filename
  * @param bool   $countTests
  */
 public function countFile($filename, $countTests)
 {
     if ($countTests) {
         $this->preProcessFile($filename);
     }
     $buffer = file_get_contents($filename);
     $this->collector->incrementLines(substr_count($buffer, "\n"));
     $tokens = token_get_all($buffer);
     $numTokens = count($tokens);
     unset($buffer);
     $this->collector->addFile($filename);
     $blocks = [];
     $currentBlock = false;
     $namespace = false;
     $className = null;
     $functionName = null;
     $testClass = false;
     $this->collector->currentClassReset();
     $isInMethod = false;
     for ($i = 0; $i < $numTokens; $i++) {
         if (is_string($tokens[$i])) {
             $token = trim($tokens[$i]);
             if ($token == ';') {
                 if ($className !== null && !$testClass) {
                     $this->collector->currentClassIncrementLines();
                     if ($functionName !== null) {
                         $this->collector->currentMethodIncrementLines();
                     }
                 } elseif ($functionName !== null) {
                     $this->collector->incrementFunctionLines();
                 }
                 $this->collector->incrementLogicalLines();
             } elseif ($token == '?' && !$testClass) {
                 if ($className !== null) {
                     $this->collector->currentClassIncrementComplexity();
                     $this->collector->currentMethodIncrementComplexity();
                 }
                 $this->collector->incrementComplexity();
             } elseif ($token == '{') {
                 if ($currentBlock == T_CLASS) {
                     $block = $className;
                 } elseif ($currentBlock == T_FUNCTION) {
                     $block = $functionName;
                 } else {
                     $block = false;
                 }
                 array_push($blocks, $block);
                 $currentBlock = false;
             } elseif ($token == '}') {
                 $block = array_pop($blocks);
                 if ($block !== false && $block !== null) {
                     if ($block == $functionName) {
                         $functionName = null;
                         if ($isInMethod) {
                             $this->collector->currentMethodStop();
                             $isInMethod = false;
                         }
                     } elseif ($block == $className) {
                         $className = null;
                         $testClass = false;
                         $this->collector->currentClassReset();
                     }
                 }
             }
             continue;
         }
         list($token, $value) = $tokens[$i];
         switch ($token) {
             case T_NAMESPACE:
                 $namespace = $this->getNamespaceName($tokens, $i);
                 $this->collector->addNamespace($namespace);
                 break;
             case T_CLASS:
             case T_INTERFACE:
             case T_TRAIT:
                 if (!$this->isClassDeclaration($tokens, $i)) {
                     continue;
                 }
                 $this->collector->currentClassReset();
                 $this->collector->currentClassIncrementComplexity();
                 $className = $this->getClassName($namespace, $tokens, $i);
                 $currentBlock = T_CLASS;
                 if ($token == T_TRAIT) {
                     $this->collector->incrementTraits();
                 } elseif ($token == T_INTERFACE) {
                     $this->collector->incrementInterfaces();
                 } else {
                     if ($countTests && $this->isTestClass($className)) {
                         $testClass = true;
                         $this->collector->incrementTestClasses();
                     } else {
                         if (isset($tokens[$i - 2]) && is_array($tokens[$i - 2]) && $tokens[$i - 2][0] == T_ABSTRACT) {
                             $this->collector->incrementAbstractClasses();
                         } else {
                             $this->collector->incrementConcreteClasses();
                         }
                     }
                 }
                 break;
             case T_FUNCTION:
                 $prev = $this->getPreviousNonWhitespaceTokenPos($tokens, $i);
                 if ($tokens[$prev][0] === T_USE) {
                     continue;
                 }
                 $currentBlock = T_FUNCTION;
                 $next = $this->getNextNonWhitespaceTokenPos($tokens, $i);
                 if (!is_array($tokens[$next]) && $tokens[$next] == '&') {
                     $next = $this->getNextNonWhitespaceTokenPos($tokens, $next);
                 }
                 if (is_array($tokens[$next]) && $tokens[$next][0] == T_STRING) {
                     $functionName = $tokens[$next][1];
                 } else {
                     $currentBlock = 'anonymous function';
                     $functionName = 'anonymous function';
                     $this->collector->incrementAnonymousFunctions();
                 }
                 if ($currentBlock == T_FUNCTION) {
                     if ($className === null && $functionName != 'anonymous function') {
                         $this->collector->incrementNamedFunctions();
                     } else {
                         $static = false;
                         $visibility = T_PUBLIC;
                         for ($j = $i; $j > 0; $j--) {
                             if (is_string($tokens[$j])) {
                                 if ($tokens[$j] == '{' || $tokens[$j] == '}' || $tokens[$j] == ';') {
                                     break;
                                 }
                                 continue;
                             }
                             if (isset($tokens[$j][0])) {
                                 switch ($tokens[$j][0]) {
                                     case T_PRIVATE:
                                         $visibility = T_PRIVATE;
                                         break;
                                     case T_PROTECTED:
                                         $visibility = T_PROTECTED;
                                         break;
                                     case T_STATIC:
                                         $static = true;
                                         break;
                                 }
                             }
                         }
                         if ($testClass && $this->isTestMethod($functionName, $visibility, $static, $tokens, $i)) {
                             $this->collector->incrementTestMethods();
                         } elseif (!$testClass) {
                             $isInMethod = true;
                             $this->collector->currentMethodStart();
                             if (!$static) {
                                 $this->collector->incrementNonStaticMethods();
                             } else {
                                 $this->collector->incrementStaticMethods();
                             }
                             if ($visibility == T_PUBLIC) {
                                 $this->collector->incrementPublicMethods();
                             } else {
                                 $this->collector->incrementNonPublicMethods();
                             }
                         }
                     }
                 }
                 break;
             case T_CURLY_OPEN:
                 $currentBlock = T_CURLY_OPEN;
                 array_push($blocks, $currentBlock);
                 break;
             case T_DOLLAR_OPEN_CURLY_BRACES:
                 $currentBlock = T_DOLLAR_OPEN_CURLY_BRACES;
                 array_push($blocks, $currentBlock);
                 break;
             case T_IF:
             case T_ELSEIF:
             case T_FOR:
             case T_FOREACH:
             case T_WHILE:
             case T_CASE:
             case T_CATCH:
             case T_BOOLEAN_AND:
             case T_LOGICAL_AND:
             case T_BOOLEAN_OR:
             case T_LOGICAL_OR:
                 if (!$testClass) {
                     if ($isInMethod) {
                         $this->collector->currentClassIncrementComplexity();
                         $this->collector->currentMethodIncrementComplexity();
                     }
                     $this->collector->incrementComplexity();
                 }
                 break;
             case T_COMMENT:
             case T_DOC_COMMENT:
                 // We want to count all intermediate lines before the token ends
                 // But sometimes a new token starts after a newline, we don't want to count that.
                 // That happend with /* */ and /**  */, but not with // since it'll end at the end
                 $this->collector->incrementCommentLines(substr_count(rtrim($value, "\n"), "\n") + 1);
                 break;
             case T_CONST:
                 $this->collector->incrementClassConstants();
                 break;
             case T_STRING:
                 if ($value == 'define') {
                     $this->collector->incrementGlobalConstants();
                     $j = $i + 1;
                     while (isset($tokens[$j]) && $tokens[$j] != ';') {
                         if (is_array($tokens[$j]) && $tokens[$j][0] == T_CONSTANT_ENCAPSED_STRING) {
                             $this->collector->addConstant(str_replace('\'', '', $tokens[$j][1]));
                             break;
                         }
                         $j++;
                     }
                 } else {
                     $this->collector->addPossibleConstantAccesses($value);
                 }
                 break;
             case T_DOUBLE_COLON:
             case T_OBJECT_OPERATOR:
                 $n = $this->getNextNonWhitespaceTokenPos($tokens, $i);
                 $nn = $this->getNextNonWhitespaceTokenPos($tokens, $n);
                 if ($n && $nn && isset($tokens[$n][0]) && ($tokens[$n][0] == T_STRING || $tokens[$n][0] == T_VARIABLE) && $tokens[$nn] == '(') {
                     if ($token == T_DOUBLE_COLON) {
                         $this->collector->incrementStaticMethodCalls();
                     } else {
                         $this->collector->incrementNonStaticMethodCalls();
                     }
                 } else {
                     if ($token == T_DOUBLE_COLON && $tokens[$n][0] == T_VARIABLE) {
                         $this->collector->incrementStaticAttributeAccesses();
                     } elseif ($token == T_OBJECT_OPERATOR) {
                         $this->collector->incrementNonStaticAttributeAccesses();
                     }
                 }
                 break;
             case T_GLOBAL:
                 $this->collector->incrementGlobalVariableAccesses();
                 break;
             case T_VARIABLE:
                 if ($value == '$GLOBALS') {
                     $this->collector->incrementGlobalVariableAccesses();
                 } elseif (isset($this->superGlobals[$value])) {
                     $this->collector->incrementSuperGlobalVariableAccesses();
                 }
                 break;
         }
     }
 }