public function getFormattedText(XRef_IParsedFile $pf, $root) { $filename = $pf->getFileName(); $links = $this->xref->getSourceFileLinks($filename); $tokens = $pf->getTokens(); $lineNumber = 1; $ret = ''; $ret .= sprintf(self::LINE_NUMBER_FORMAT, $lineNumber, $lineNumber); for ($i = 0; $i < count($tokens); ++$i) { $token = $tokens[$i]; if ($links && array_key_exists($i, $links)) { // TODO: ugly, redo if (is_array($links[$i])) { list($reportName, $objectId) = $links[$i]; $link = $this->xref->getHtmlLinkFor($reportName, $objectId, $root); $ret .= "<a href='{$link}'>"; } else { $ret .= "</a>"; } } $text = htmlspecialchars($token->text); if ($token->kind == XRef::T_ONE_CHAR) { $ret .= $text; } else { $span_class = array_key_exists($token->kind, XRef::$tokenNames) ? XRef::$tokenNames[$token->kind] : token_name($token->kind); if ($span_class == 'UNKNOWN') { $span_class = $token->kind; } // special classes for php predefined constants if ($token->kind == T_STRING) { $str_upper = strtoupper($token->text); switch (strtoupper($token->text)) { case "NULL": $span_class == 'T_NULL'; break; case "TRUE": $span_class == 'T_TRUE'; break; case "FALSE": $span_class == 'T_FALSE'; break; } } if (strpos($text, "\n") === false) { // no new lines, simple $ret .= "<span class='{$span_class}'>{$text}</span>"; } else { // ugly code that does the following: // input: // some \n multiline text \n startig at line 10 // output: // <span class="text">some</span> // 11 <span class="text">multiline text </span> // 12 <span class="text"> starting at line 10 </span> $parts = explode("\n", $text); for ($j = 0; $j < count($parts); $j++) { if ($j != 0) { $lineNumber++; $ret .= sprintf(self::LINE_NUMBER_FORMAT, $lineNumber, $lineNumber); } $ret .= "<span class='{$span_class}'>{$parts[$j]}</span>"; if ($j != count($parts) - 1) { $ret .= "\n"; } } } } } return $ret; }
/** methods to use when parsed files are already available */ public function addParsedFile(XRef_IParsedFile $pf) { $this->report[$pf->getFileName()] = $this->getFileReport($pf); }
public function __construct(XRef_IParsedFile $pf, $startIndex, $endIndex = 0) { $this->fileName = $pf->getFileName(); $this->lineNumber = $pf->getLineNumberAt($startIndex); $this->startIndex = $startIndex; $this->endIndex = $endIndex ? $endIndex : $startIndex; $class = $pf->getClassAt($startIndex); $method = $pf->getMethodAt($startIndex); $this->inClass = $class ? $class->name : null; $this->inMethod = $method ? $method->name : null; }
public function generateFileReport(XRef_IParsedFile $pf) { if ($pf->getFileType() != $this->supportedFileType) { return; } $tokens = $pf->getTokens(); for ($i = 0; $i < count($tokens); ++$i) { $t = $tokens[$i]; // Const declared: // const FOO = 10; if ($t->kind == T_CONST) { $n = $t->nextNS(); $class = $pf->getClassAt($n->index); if ($class) { $name = $class->name . "::" . $n->text; } else { $name = $n->text; } $c = $this->getOrCreate($name); $filePos = new XRef_FilePosition($pf, $n->index); $c->declaredAt[] = $filePos; // link from source file HTML page to report page "reportId/objectId" $this->xref->addSourceFileLink($filePos, $this->reportId, $c->id); } // Const used: // foo::bar, but not foo::bar() or foo::$bar\ if ($t->kind == T_DOUBLE_COLON) { $p = $t->prevNS(); if ($p->kind == T_STRING) { $n = $t->nextNS(); if ($n->kind == T_VARIABLE) { // static field continue; } elseif ($n->kind == T_STRING) { $nn = $n->nextNS(); if ($nn->kind == XRef::T_ONE_CHAR && $nn->text == '(') { // method call continue; } } elseif ($n->text == '$') { // rare case: Class::$$static_field_name continue; } else { error_log("What's this: {$n->text}"); continue; } $className = $p->text; if ($className == 'self') { $class = $pf->getClassAt($p->index); if (!$class) { error_log("Reference to self:: class not inside a class method at " . $pf->getFileName() . ":{$p->lineNumber}"); continue; } $className = $class->name; } $name = $className . "::" . $n->text; $c = $this->getOrCreate($name); $filePos = new XRef_FilePosition($pf, $n->index); $c->usedAt[] = $filePos; // link from source file HTML page to report page "reportId/objectId" $this->xref->addSourceFileLink($filePos, $this->reportId, $c->id); } } } // foreach token }
public function generateFileReport(XRef_IParsedFile $pf) { if ($pf->getFileType() != $this->supportedFileType) { return; } // collect all declared classes foreach ($pf->getClasses() as $pfc) { $c = $this->getOrCreate($pfc->name); $c->isInterface = $pfc->kind == T_INTERFACE; $definedAt = new XRef_FilePosition($pf, $pfc->nameIndex); $c->definedAt[] = $definedAt; // link from source file HTML page to report page "reportId/objectId" $this->xref->addSourceFileLink($definedAt, $this->reportId, $c->id); // extended classes/interfaces foreach ($pfc->extends as $ext_name) { $c->extends[] = $ext_name; $ext_class = $this->getOrCreate($ext_name); $ext_class->inheritedBy[] = $pfc->name; $extendsIndex = $pfc->extendsIndex[$ext_name]; $filePos = new XRef_FilePosition($pf, $extendsIndex[0], $extendsIndex[1]); $ext_class->usedAt[] = $filePos; // link from source file HTML page to report page "reportId/objectId" $this->xref->addSourceFileLink($filePos, $this->reportId, $ext_class->id); } // extended classes/interfaces foreach ($pfc->implements as $imp_name) { $c->implements[] = $imp_name; $imp_class = $this->getOrCreate($imp_name); $imp_class->inheritedBy[] = $pfc->name; $extendsIndex = $pfc->implementsIndex[$imp_name]; $filePos = new XRef_FilePosition($pf, $extendsIndex[0], $extendsIndex[1]); $imp_class->usedAt[] = $filePos; // link from source file HTML page to report page "reportId/objectId" $this->xref->addSourceFileLink($filePos, $this->reportId, $imp_class->id); } } // foreach declared class // collect all places where this class is instantiated or mentioned: $tokens = $pf->getTokens(); $tokens_count = count($tokens); for ($i = 0; $i < $tokens_count; ++$i) { $t = $tokens[$i]; // "new" <name> // "new" $className // "new" "(" <callable-name> ")" // AS3 // "new" "<" <int> ">" // AS3 if ($t->kind == T_NEW) { $t = $t->nextNS(); if ($t->kind != T_STRING) { continue; } // TODO: scan for namespaced name, e.g. new \Foo\Bar() $name = $pf->qualifyName($t->text, $t->index); $new = $this->getOrCreate($name); $filePos = new XRef_FilePosition($pf, $t->index); $new->instantiatedAt[] = $filePos; // link from source file HTML page to report page "reportId/objectId" $this->xref->addSourceFileLink($filePos, $this->reportId, $new->id); continue; } // T_NEW // // Class :: $foo // Class :: foo() // but not Class :: CONST if ($t->kind == T_DOUBLE_COLON) { $p = $t->prevNS(); if ($p->kind == T_STRING) { $n = $t->nextNS(); if ($n->kind == T_VARIABLE) { // ok, static field } elseif ($n->kind == T_STRING) { // method or constant $nn = $n->nextNS(); if ($nn->text != '(') { continue; } } elseif ($n->text == '$') { // rare case: Class::$$static_field_name continue; } else { throw new XRef_ParseException($n); } $className = $pf->qualifyName($p->text, $p->index); if ($pf->getFileType() == XRef::FILETYPE_PHP) { if ($className == 'self') { $class = $pf->getClassAt($p->index); if (!$class) { error_log("Reference to self:: class not inside a class method at " . $pf->getFileName() . ":{$t->lineNumber}"); continue; } $className = $class->name; } // TODO: super:: class resolution needs 2-pass parser } $c = $this->getOrCreate($className); $filePos = new XRef_FilePosition($pf, $p->index); $c->usedAt[] = $filePos; $this->xref->addSourceFileLink($filePos, $this->reportId, $c->id); } else { error_log("Unexpected token {$t->text} at " . $pf->getFileName() . ":{$t->lineNumber}"); } } // $foo isinstanceof Bar // $foo isinstanceof $bar if ($t->kind == T_INSTANCEOF) { $n = $t->nextNS(); if ($n->kind == T_STRING) { $className = $pf->qualifyName($n->text, $n->index); $c = $this->getOrCreate($className); $filePos = new XRef_FilePosition($pf, $n->index); $c->usedAt[] = $filePos; $this->xref->addSourceFileLink($filePos, $this->reportId, $c->id); } } // is_a($foo, "Bar") if ($t->kind == T_STRING && $t->text == "is_a") { $n = $t->nextNS(); if ($n->text != '(') { continue; } // TODO: add more checks below $n = $n->nextNS(); // var name. Actually, should skip any expression, e.g.: is_a($user->world, "World") $n = $n->nextNS(); // comma $n = $n->nextNS(); // class name literal? $className = $pf->qualifyName(preg_replace("#[\\'\"]#", '', $n->text), $n->index); $c = $this->getOrCreate($className); $filePos = new XRef_FilePosition($pf, $n->index); $c->usedAt[] = $filePos; $this->xref->addSourceFileLink($filePos, $this->reportId, $c->id); } } // foreach $token }