/** * Tokenizes the content of the source file with {@link token_get_all()} and * filters this token stream. * * @return void */ private function tokenize() { if ($this->tokens) { return; } $this->tokens = array(); $this->index = 0; $this->count = 0; // Replace short open tags, short open tags will produce invalid results // in all environments with disabled short open tags. $source = $this->sourceFile->getSource(); $source = preg_replace(array('(<\\?=)', '(<\\?(\\s))'), array('<?php echo ', '<?php\\1'), $source); if (version_compare(phpversion(), '5.3.0alpha3') < 0) { $tokens = PHPTokenizerHelperVersion52::tokenize($source); } else { $tokens = token_get_all($source); } $tokens = $this->substituteTokens($tokens); // Is the current token between an opening and a closing php tag? $inTag = false; // The current line number $startLine = 1; $startColumn = 1; $endColumn = 1; $literalMap = self::$literalMap; $tokenMap = self::$tokenMap; // Previous found type $previousType = null; while ($token = current($tokens)) { $type = null; $image = null; if (is_string($token)) { $token = array(null, $token); } if ($token[0] === T_OPEN_TAG) { $type = $tokenMap[$token[0]]; $image = $token[1]; $inTag = true; } elseif ($token[0] === T_CLOSE_TAG) { $type = $tokenMap[$token[0]]; $image = $token[1]; $inTag = false; } elseif ($inTag === false) { $type = Tokens::T_NO_PHP; $image = $this->consumeNonePhpTokens($tokens); } elseif ($token[0] === T_WHITESPACE) { // Count newlines in token $lines = substr_count($token[1], "\n"); if ($lines === 0) { $startColumn += strlen($token[1]); } else { $startColumn = strlen(substr($token[1], strrpos($token[1], "\n") + 1)) + 1; } $startLine += $lines; } else { $value = strtolower($token[1]); if (isset($literalMap[$value])) { // Fetch literal type $type = $literalMap[$value]; $image = $token[1]; // Check for a context sensitive alternative if (isset(self::$alternativeMap[$type][$previousType])) { $type = self::$alternativeMap[$type][$previousType]; } if (isset(self::$reductionMap[$type][$previousType])) { $image = self::$reductionMap[$type][$previousType]['image']; $type = self::$reductionMap[$type][$previousType]['type']; array_pop($this->tokens); } } elseif (isset($tokenMap[$token[0]])) { $type = $tokenMap[$token[0]]; // Check for a context sensitive alternative if (isset(self::$alternativeMap[$type][$previousType])) { $type = self::$alternativeMap[$type][$previousType]; } $image = $token[1]; } else { // This should never happen // @codeCoverageIgnoreStart list($type, $image) = $this->generateUnknownToken($token[1]); // @codeCoverageIgnoreEnd } } if ($type) { $rtrim = rtrim($image); $lines = substr_count($rtrim, "\n"); if ($lines === 0) { $endColumn = $startColumn + strlen($rtrim) - 1; } else { $endColumn = strlen(substr($rtrim, strrpos($rtrim, "\n") + 1)); } $endLine = $startLine + $lines; $token = new Token($type, $rtrim, $startLine, $endLine, $startColumn, $endColumn); // Store token in internal list $this->tokens[] = $token; // Count newlines in token $lines = substr_count($image, "\n"); if ($lines === 0) { $startColumn += strlen($image); } else { $startColumn = strlen(substr($image, strrpos($image, "\n") + 1)) + 1; } $startLine += $lines; // Store current type if ($type !== Tokens::T_COMMENT && $type !== Tokens::T_DOC_COMMENT) { $previousType = $type; } } next($tokens); } $this->count = count($this->tokens); }
/** * Generates an identifier for the given file instance. * * @param \PDepend\Source\AST\ASTCompilationUnit $compilationUnit * @return string */ public function forFile(ASTCompilationUnit $compilationUnit) { return $this->hash($compilationUnit->getFileName()); }
/** * Extracts the @package information from the given comment. * * @param string $comment A doc comment block. * * @return string */ private function parsePackageAnnotation($comment) { $package = Builder::DEFAULT_NAMESPACE; if (preg_match('#\\*\\s*@package\\s+(\\S+)#', $comment, $match)) { $package = trim($match[1]); if (preg_match('#\\*\\s*@subpackage\\s+(\\S+)#', $comment, $match)) { $package .= '\\' . trim($match[1]); } } // Check for doc level comment if ($this->globalPackageName === Builder::DEFAULT_NAMESPACE && $this->isFileComment() === true) { $this->globalPackageName = $package; $this->compilationUnit->setDocComment($comment); } return $package; }
/** * Visits a file node. * * @param \PDepend\Source\AST\ASTCompilationUnit $compilationUnit * @return void */ public function visitCompilationUnit(ASTCompilationUnit $compilationUnit) { // Skip for dummy files if ($compilationUnit->getFileName() === null) { return; } // Check for initial file $id = $compilationUnit->getId(); if (isset($this->metrics[$id])) { return; } $this->fireStartFile($compilationUnit); if ($this->restoreFromCache($compilationUnit)) { $this->updateProjectMetrics($id); return $this->fireEndFile($compilationUnit); } list($cloc, $eloc, $lloc) = $this->linesOfCode($compilationUnit->getTokens()); $loc = $compilationUnit->getEndLine(); $ncloc = $loc - $cloc; $this->metrics[$id] = array(self::M_LINES_OF_CODE => $loc, self::M_COMMENT_LINES_OF_CODE => $cloc, self::M_EXECUTABLE_LINES_OF_CODE => $eloc, self::M_LOGICAL_LINES_OF_CODE => $lloc, self::M_NON_COMMENT_LINES_OF_CODE => $ncloc); $this->updateProjectMetrics($id); $this->fireEndFile($compilationUnit); }
/** * Sets the source file for this item. * * @param \PDepend\Source\AST\ASTCompilationUnit $compilationUnit * @return void */ public function setCompilationUnit(ASTCompilationUnit $compilationUnit) { if ($this->compilationUnit === null || $this->compilationUnit->getName() === null) { $this->compilationUnit = $compilationUnit; } }
/** * Tests the {@link \PDepend\Source\AST\ASTCompilationUnit#getSource()} method. * * @return void */ public function testGetSourceReturnsOriginalFileContents() { $file = new ASTCompilationUnit(self::createCodeResourceUriForTest()); $actual = $file->getSource(); $expected = file_get_contents(self::createCodeResourceUriForTest()); $this->assertEquals($expected, $actual); }
/** * testBuilderCreatesCaseInSensitiveMethodIdentifiers * * @return void */ public function testBuilderCreatesCaseInSensitiveMethodIdentifiers() { $compilationUnit = new ASTCompilationUnit(__FILE__); $compilationUnit->setId(__FUNCTION__); $class = new ASTClass(__FUNCTION__); $class->setCompilationUnit($compilationUnit); $method0 = new ASTMethod(__FUNCTION__); $method0->setParent($class); $method1 = new ASTMethod(strtolower(__FUNCTION__)); $method1->setParent($class); $builder0 = new IdBuilder(); $builder1 = new IdBuilder(); $this->assertEquals($builder0->forMethod($method0), $builder1->forMethod($method1)); }
/** * testAnalyzerIgnoresFilesWithoutFileName * * @return void */ public function testAnalyzerIgnoresFilesWithoutFileName() { $compilationUnit = new ASTCompilationUnit(null); $compilationUnit->setId(42); $analyzer = $this->_createAnalyzer(); $analyzer->visitCompilationUnit($compilationUnit); $metrics = $analyzer->getNodeMetrics($compilationUnit); $this->assertEquals(array(), $metrics); }