Esempio n. 1
0
 /**
  * Calculate cyclomatic complexity number
  *
  * We can calculate ccn in two ways (we choose the second):
  *
  *  1.  Cyclomatic complexity (CC) = E - N + 2P
  *      Where:
  *      P = number of disconnected parts of the flow graph (e.g. a calling program and a subroutine)
  *      E = number of edges (transfers of control)
  *      N = number of nodes (sequential group of statements containing only one transfer of control)
  *
  * 2. CC = Number of each decision point
  *
  * @param string $filename
  * @return Result
  */
 public function calculate($filename)
 {
     $info = new Result();
     $tokens = $this->tokenizer->tokenize($filename);
     $ccn = 0;
     foreach ($tokens as $token) {
         switch ($token->getType()) {
             case T_IF:
             case T_ELSEIF:
             case T_FOREACH:
             case T_FOR:
             case T_WHILE:
             case T_DO:
             case T_BOOLEAN_AND:
             case T_LOGICAL_AND:
             case T_BOOLEAN_OR:
             case T_LOGICAL_OR:
             case T_CASE:
             case T_DEFAULT:
             case T_CATCH:
             case T_CONTINUE:
                 $ccn++;
                 break;
         }
     }
     $info->setCyclomaticComplexityNumber(max(1, $ccn));
     return $info;
 }
Esempio n. 2
0
 /**
  * Extract infos from file
  *
  * @param $filename
  * @return Result
  */
 public function extract($filename)
 {
     $result = new Result();
     $tokens = $this->tokenizer->tokenize($filename);
     $nameResolver = new NameResolver();
     // default current values
     $class = $interface = $function = $method = null;
     //        $mapOfAliases = array();
     $len = sizeof($tokens, COUNT_NORMAL);
     for ($n = 0; $n < $len; $n++) {
         $token = $tokens[$n];
         switch ($token->getType()) {
             case T_USE:
                 $alias = $this->extractors->alias->extract($n, $tokens);
                 if (null !== $alias->name && null !== $alias->alias) {
                     $nameResolver->pushAlias($alias);
                 }
                 break;
             case T_NAMESPACE:
                 $namespace = '\\' . $this->searcher->getFollowingName($n, $tokens);
                 $this->extractors->class->setNamespace($namespace);
                 $this->extractors->interface->setNamespace($namespace);
                 break;
             case T_INTERFACE:
                 $class = $this->extractors->interface->extract($n, $tokens);
                 $class->setNameResolver($nameResolver);
                 // push class AND in global AND in local class map
                 $this->result->pushClass($class);
                 $result->pushClass($class);
                 break;
             case T_EXTENDS:
                 $i = $n;
                 $parent = $this->searcher->getFollowingName($i, $tokens);
                 $class->setParent(trim($parent));
                 break;
             case T_CLASS:
                 $class = $this->extractors->class->extract($n, $tokens);
                 $class->setNameResolver($nameResolver);
                 // push class AND in global AND in local class map
                 $this->result->pushClass($class);
                 $result->pushClass($class);
                 break;
             case T_FUNCTION:
                 if ($class) {
                     // avoid closure
                     $next = $tokens[$n + 1];
                     if (T_WHITESPACE != $next->getType()) {
                         continue;
                     }
                     $method = $this->extractors->method->extract($n, $tokens);
                     $method->setNameResolver($nameResolver);
                     $class->pushMethod($method);
                 }
                 break;
         }
     }
     return $result;
 }
 public function onParseTestedFilesEnd(UnitsResultEvent $event)
 {
     $tokenizer = new Tokenizer();
     $units = $event->getUnits();
     foreach ($units->all() as $unit) {
         $testedFiles = $unit->getTestedFiles();
         foreach ($testedFiles as $filename) {
             $tokens = new \Hal\MutaTesting\Token\TokenCollection($tokenizer->tokenize($filename));
             array_push($this->allTokens, $tokens);
         }
     }
 }
Esempio n. 4
0
 /**
  * Inventories tokens
  *
  * @param string $filename
  * @return $this
  */
 private function inventory($filename)
 {
     $this->operators = $this->operands = array();
     $tokens = $this->tokenizer->tokenize($filename);
     foreach ($tokens as $token) {
         if ($this->tokenType->isOperator($token)) {
             $this->operators[] = $token;
         } else {
             if ($this->tokenType->isOperand($token)) {
                 $this->operands[] = $token;
             }
         }
     }
     return $this;
 }
Esempio n. 5
0
 public function testWorkingWithShortOpenTagsIsEquivalentToLongTags()
 {
     $content1 = '<?php echo "ok";';
     $content2 = '<? echo "ok";';
     $filename1 = tempnam(sys_get_temp_dir(), 'phpmetrics-unit');
     $filename2 = tempnam(sys_get_temp_dir(), 'phpmetrics-unit');
     file_put_contents($filename1, $content1);
     file_put_contents($filename2, $content2);
     $tokenizer = new Tokenizer();
     $r1 = $tokenizer->tokenize($filename1);
     $r2 = $tokenizer->tokenize($filename2);
     $this->assertEquals($r1, $r2);
     unlink($filename1);
     unlink($filename2);
 }
Esempio n. 6
0
 public function factory($fileOrigin, $testFile)
 {
     $mutation = new Mutation();
     $tokenizer = new Tokenizer();
     $mutation->setTokens($tokenizer->tokenize($fileOrigin))->setSourceFile($fileOrigin)->setTestFile($testFile);
     foreach ($mutation->getTokens() as $index => $token) {
         if ($this->mutaterFactory->isMutable($token)) {
             $mutater = $this->mutaterFactory->factory($token);
             $mutated = $mutater->mutate($mutation, $index);
             if ($this->specification->isSatisfedBy($mutated, $index)) {
                 $mutation->addMutation($mutated);
             }
         }
     }
     return $mutation;
 }
Esempio n. 7
0
 /**
  * Calculates Myer's interval
  *
  *      Cyclomatic complexity : Cyclomatic complexity + L
  *      where L is the number of logical operators
  *
  * @param string $filename
  * @return Result
  */
 public function calculate($filename)
 {
     $mcCabe = new McCabe($this->tokenizer);
     $result = new Result();
     $tokens = $this->tokenizer->tokenize($filename);
     // Cyclomatic complexity
     $cc = $mcCabe->calculate($filename);
     // Number of operator
     $L = 0;
     $logicalOperators = array(T_BOOLEAN_AND => T_BOOLEAN_AND, T_LOGICAL_AND => T_LOGICAL_AND, T_BOOLEAN_OR => T_BOOLEAN_OR, T_LOGICAL_OR => T_LOGICAL_OR);
     foreach ($tokens as $token) {
         if (isset($logicalOperators[$token->getType()])) {
             $L++;
         }
     }
     $result->setNumberOfOperators($L)->setMcCabe($cc);
     return $result;
 }
Esempio n. 8
0
 /**
  * Calculate cyclomatic complexity number
  *
  * We can calculate ccn in two ways (we choose the second):
  *
  *  1.  Cyclomatic complexity (CC) = E - N + 2P
  *      Where:
  *      P = number of disconnected parts of the flow graph (e.g. a calling program and a subroutine)
  *      E = number of edges (transfers of control)
  *      N = number of nodes (sequential group of statements containing only one transfer of control)
  *
  * 2. CC = Number of each decision point
  *
  * @param string $filename
  * @return Result
  */
 public function calculate($filename)
 {
     $info = new Result();
     $tokens = $this->tokenizer->tokenize($filename);
     $ccn = 1;
     // default path
     foreach ($tokens as $token) {
         switch ($token->getType()) {
             case T_IF:
             case T_ELSEIF:
             case T_FOREACH:
             case T_FOR:
             case T_WHILE:
             case T_DO:
             case T_BOOLEAN_AND:
             case T_LOGICAL_AND:
             case T_BOOLEAN_OR:
             case T_LOGICAL_OR:
             case T_SPACESHIP:
             case T_CASE:
             case T_DEFAULT:
             case T_CATCH:
             case T_CONTINUE:
                 $ccn++;
                 break;
             case T_STRING:
                 if ('?' == $token->getValue()) {
                     $ccn = $ccn + 2;
                 }
                 break;
             case T_COALESCE:
                 $ccn = $ccn + 2;
                 break;
         }
     }
     $info->setCyclomaticComplexityNumber(max(1, $ccn));
     return $info;
 }
Esempio n. 9
0
 /**
  * Calculates Lines of code
  *
  * @param string $filename
  * @return Result
  */
 public function calculate($filename)
 {
     $info = new Result();
     $tokens = $this->tokenizer->tokenize($filename);
     $content = file_get_contents($filename);
     $cloc = $lloc = 0;
     foreach ($tokens as $token) {
         switch ($token->getType()) {
             case T_STRING:
                 if (';' == $token->getValue()) {
                     $lloc++;
                 }
                 break;
             case T_COMMENT:
                 $cloc++;
                 break;
             case T_DOC_COMMENT:
                 $cloc += count(preg_split('/\\r\\n|\\r|\\n/', $token->getValue()));
                 break;
         }
     }
     $info->setLoc(count(preg_split('/\\r\\n|\\r|\\n/', $content)) - 1)->setCommentLoc($cloc)->setLogicalLoc($lloc);
     return $info;
 }
Esempio n. 10
0
 /**
  * Extract infos from file
  *
  * @param $filename
  * @return Result
  */
 public function extract($filename)
 {
     $result = new Result();
     $tokens = $this->tokenizer->tokenize($filename);
     $nameResolver = new NameResolver();
     // default current values
     $class = $interface = $function = $namespace = $method = null;
     $len = sizeof($tokens, COUNT_NORMAL);
     $endAnonymous = 0;
     $mainContextClass = null;
     // class containing a anonymous class
     for ($n = 0; $n < $len; $n++) {
         if ($mainContextClass && $n > $endAnonymous) {
             // anonymous class is finished. We back to parent class
             // methods will be added to the main class now
             $class = $mainContextClass;
             $mainContextClass = null;
         }
         $token = $tokens[$n];
         switch ($token->getType()) {
             case T_USE:
                 $alias = $this->extractors->alias->extract($n, $tokens);
                 if (null !== $alias->name && null !== $alias->alias) {
                     $nameResolver->pushAlias($alias);
                 }
                 break;
             case T_NAMESPACE:
                 $namespace = '\\' . $this->searcher->getFollowingName($n, $tokens);
                 $this->extractors->class->setNamespace($namespace);
                 $this->extractors->interface->setNamespace($namespace);
                 break;
             case T_INTERFACE:
                 $class = $this->extractors->interface->extract($n, $tokens);
                 $class->setNameResolver($nameResolver);
                 // push class AND in global AND in local class map
                 $this->result->pushClass($class);
                 $result->pushClass($class);
                 break;
             case T_EXTENDS:
                 $i = $n;
                 $parent = $this->searcher->getFollowingName($i, $tokens);
                 $class->setParent(trim($parent));
                 break;
             case T_IMPLEMENTS:
                 $i = $n + 1;
                 $contracts = $this->searcher->getUnder(array('{'), $i, $tokens);
                 $contracts = explode(',', $contracts);
                 $contracts = array_map('trim', $contracts);
                 $class->setInterfaces($contracts);
                 break;
             case T_CLASS:
                 $c = $this->extractors->class->extract($n, $tokens);
                 $c->setNameResolver($nameResolver);
                 // push class AND in global AND in local class map
                 $this->result->pushClass($c);
                 $result->pushClass($c);
                 // PHP 7 and inner classes
                 if ($c instanceof ReflectedAnonymousClass) {
                     // avoid to consider anonymous class as main class
                     $p = $n;
                     $endAnonymous = $this->searcher->getPositionOfClosingBrace($p, $tokens);
                     $mainContextClass = $class;
                     // add anonymous class in method
                     if ($method) {
                         $method->pushAnonymousClass($c);
                     }
                 }
                 $class = $c;
                 break;
             case T_FUNCTION:
                 if ($class) {
                     // avoid closure
                     $next = $tokens[$n + 1];
                     if (T_WHITESPACE != $next->getType()) {
                         continue;
                     }
                     $method = $this->extractors->method->extract($n, $tokens, $class);
                     $method->setNamespace($namespace);
                     $class->pushMethod($method);
                 }
                 break;
         }
     }
     return $result;
 }
Esempio n. 11
0
 /**
  * @inheritdoc
  */
 public function execute(ResultCollection $collection, ResultCollection $aggregatedResults)
 {
     $files = $this->finder->find($this->path);
     if (0 == sizeof($files, COUNT_NORMAL)) {
         throw new \LogicException('No file found');
     }
     $progress = new ProgressBar($this->output);
     $progress->start(sizeof($files, COUNT_NORMAL));
     // tools
     $classMap = new ClassMap();
     $tokenizer = new Tokenizer();
     $syntaxChecker = new SyntaxChecker();
     $fileAnalyzer = new FileAnalyzer($this->output, $this->withOOP, new Extractor(), new \Hal\Metrics\Complexity\Text\Halstead\Halstead(new \Hal\Component\Token\TokenType()), new \Hal\Metrics\Complexity\Text\Length\Loc(), new \Hal\Metrics\Design\Component\MaintainabilityIndex\MaintainabilityIndex(), new \Hal\Metrics\Complexity\Component\McCabe\McCabe(), new \Hal\Metrics\Complexity\Component\Myer\Myer(), $classMap);
     foreach ($files as $k => $filename) {
         $progress->advance();
         // Integrity
         if (!$this->ignoreErrors && !$syntaxChecker->isCorrect($filename)) {
             $this->output->writeln(sprintf('<error>file %s is not valid and has been skipped</error>', $filename));
             unset($files[$k]);
             continue;
         }
         // Analyze
         try {
             $tokens = $tokenizer->tokenize($filename);
             $resultSet = $fileAnalyzer->execute($filename, $tokens);
         } catch (NoTokenizableException $e) {
             $this->output->writeln(sprintf("<error>file %s has been skipped: \n%s</error>", $filename, $e->getMessage()));
             unset($files[$k]);
             continue;
         } catch (\Exception $e) {
             throw new \Exception(sprintf("a '%s' exception occured analyzing file %s\nMessage: %s", get_class($e), $filename, $e->getMessage()) . sprintf("\n------------\nStack:\n%s", $e->getTraceAsString()) . sprintf("\n------------\nDo not hesitate to report a bug: https://github.com/PhpMetrics/PhpMetrics/issues"), 0, $e->getPrevious());
         }
         $collection->push($resultSet);
     }
     $progress->clear();
     $progress->finish();
     if ($this->withOOP) {
         // COUPLING (should be done after parsing files)
         $this->output->write(str_pad("\rAnalyzing coupling. This will take few minutes...", 80, " "));
         $couplingAnalyzer = new CouplingAnalyzer($classMap, $collection);
         $couplingAnalyzer->execute($files);
         // LCOM (should be done after parsing files)
         $this->output->write(str_pad("\rLack of cohesion of method (lcom). This will take few minutes...", 80, " "));
         $lcomAnalyzer = new LcomAnalyzer($classMap, $collection);
         $lcomAnalyzer->execute($files);
         // Card and Agresti (should be done after parsing files)
         $this->output->write(str_pad("\rAnalyzing System complexity. This will take few minutes...", 80, " "));
         $lcomAnalyzer = new CardAndAgrestiAnalyzer($classMap, $collection);
         $lcomAnalyzer->execute($files);
     }
 }