Exemplo n.º 1
0
 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
 }
Exemplo n.º 2
0
 /**
  * @param XRef_ParsedFile $pf
  * @param bool $is_library_file
  * @return * any data
  */
 public function createFileSlice(XRef_IParsedFile $pf, $is_library_file = false)
 {
     /** array of arrays with info about called functions and methods */
     $called_functions = array();
     /** map: (function call info => true), to report any call once only */
     $uniqs = array();
     /** map of function names, checked for existence by function_exists() */
     $checked_for_functions = array();
     $tokens = $pf->getTokens();
     for ($i = 0; $i < count($tokens); ++$i) {
         $t = $tokens[$i];
         // $this->foo();
         // Foo\Barr::foo();
         if ($t->text == '(') {
             $p = $t->prevNS();
             if ($p->kind != T_STRING) {
                 continue;
             }
             // array with parts of the name (T_NS_SEPARATOR && T_STRING)
             $function_name_parts = array($p->text);
             $class_name = '';
             $pp = $p->prevNS();
             if ($pp->kind == T_NS_SEPARATOR) {
                 // Foo\bar();
                 // \bar();
                 while ($pp->kind == T_NS_SEPARATOR || $pp->kind == T_STRING) {
                     array_unshift($function_name_parts, $pp->text);
                     $pp = $pp->prevNS();
                 }
             } elseif ($pp->kind == T_OBJECT_OPERATOR) {
                 // $var->bar()
                 // $this->bar();
                 $pp = $pp->prevNS();
                 if ($pp->kind == T_VARIABLE && $pp->text == '$this') {
                     $class_name = 'self';
                     // will be resolved later
                 } else {
                     // TODO
                     continue;
                 }
             } elseif ($pp->kind == T_DOUBLE_COLON) {
                 // Foo::bar();
                 // Foo\Bar::bar();
                 // self::foo();
                 // static::bar();
                 $pp = $pp->prevNS();
                 while ($pp->kind == T_NS_SEPARATOR || $pp->kind == T_STRING || $pp->kind == T_STATIC) {
                     $class_name = $pp->text . $class_name;
                     $pp = $pp->prevNS();
                 }
             }
             if ($pp->text == '&') {
                 $pp = $pp->prevNS();
             }
             if ($pp->kind == T_FUNCTION) {
                 // skip function declarations
                 continue;
             }
             $arguments = $pf->extractList($t->nextNS());
             $num_of_arguments = count($arguments);
             $from_class = $pf->getClassAt($t->index);
             $from_class_name = $from_class ? $from_class->name : '';
             if ($pp->kind == T_NEW) {
                 // new Something();
                 // new ns\Another\Something();
                 // new \Foo();
                 $class_name = implode('', $function_name_parts);
                 if ($class_name == 'static' || $class_name == 'self') {
                     $class_name = $from_class_name;
                 } elseif ($class_name == 'parent') {
                     $class_name = $from_class && $from_class->extends ? $from_class->extends[0] : null;
                 } else {
                     $class_name = $pf->qualifyName($class_name, $t->index);
                 }
                 if ($class_name) {
                     $uniq = "new##{$class_name}#{$num_of_arguments}";
                     if (!isset($uniqs[$uniq])) {
                         $uniqs[$uniq] = true;
                         $called_functions[] = array(self::F_CLASS_CONSTRUCTOR, null, $class_name, $t->lineNumber, $num_of_arguments);
                     }
                 }
             } elseif ($class_name) {
                 // method call:
                 //  $this->foo();
                 //  self::foo();
                 //  Foo::bar();
                 //  \bar\Baz::foo();
                 if ($class_name == 'static' || $class_name == 'self') {
                     $class_name = $from_class_name;
                 } elseif ($class_name == 'parent') {
                     $class_name = $from_class && $from_class->extends ? $from_class->extends[0] : null;
                 } else {
                     $class_name = $pf->qualifyName($class_name, $t->index);
                 }
                 if ($class_name) {
                     if (count($function_name_parts) > 1) {
                         throw new Exception("{$class_name}::" . implode('', $function_name_parts));
                     }
                     $function_name = $function_name_parts[0];
                     if ($function_name == '__construct') {
                         $uniq = "new##{$class_name}#{$num_of_arguments}";
                         if (!isset($uniqs[$uniq])) {
                             $uniqs[$uniq] = true;
                             $called_functions[] = array(self::F_CLASS_CONSTRUCTOR, null, $class_name, $t->lineNumber, $num_of_arguments);
                         }
                     } else {
                         $uniq = "{$function_name}##{$class_name}#{$num_of_arguments}";
                         if (!isset($uniqs[$uniq])) {
                             $uniqs[$uniq] = true;
                             $called_functions[] = array(self::F_CLASS_METHOD, $function_name, $class_name, $t->lineNumber, $num_of_arguments);
                         }
                     }
                 }
             } else {
                 // function call: qualified or unqualified
                 // foo();
                 // foo\bar();
                 // \foo\bar\baz();
                 if (count($function_name_parts) > 1) {
                     $function_name = $pf->qualifyName(implode('', $function_name_parts), $t->index);
                     $uniq = "{$function_name}##{$num_of_arguments}";
                     if (!isset($uniqs[$uniq])) {
                         $uniqs[$uniq] = true;
                         $called_functions[] = array(self::F_FULLY_QUALIFIED_FUNC, $function_name, null, $t->lineNumber, $num_of_arguments);
                     }
                 } else {
                     $function_name = $function_name_parts[0];
                     $namespace = $pf->getNamespaceAt($t->index);
                     $namespace_name = $namespace ? $namespace->name : '';
                     $uniq = "{$function_name}##{$namespace_name}#{$num_of_arguments}";
                     if (!isset($uniqs[$uniq])) {
                         $uniqs[$uniq] = true;
                         $called_functions[] = array(self::F_NOT_QUALIFIED_FUNC, $function_name, $namespace_name, $t->lineNumber, $num_of_arguments, $from_class_name);
                     }
                 }
                 if ($function_name == 'function_exists') {
                     $n = $t->nextNS();
                     if ($n->kind == T_CONSTANT_ENCAPSED_STRING) {
                         $checked_for_function_name = trim($n->text, '\'"');
                         $checked_for_functions[$checked_for_function_name] = true;
                     }
                 }
             }
         }
     }
     $file_slice = array("called" => $called_functions, "checked" => $checked_for_functions);
     return $file_slice;
 }
Exemplo n.º 3
0
 public function createFileSlice(XRef_IParsedFile $pf, $is_library_file = false)
 {
     $this->slice = array();
     $this->already_seen = array();
     $tokens = $pf->getTokens();
     for ($i = 0; $i < count($tokens); ++$i) {
         $t = $tokens[$i];
         // new Foo();
         // new \Bar\Baz();
         // new $class
         // new self()
         if ($t->kind == T_NEW) {
             $n = $t->nextNS();
             $class_name = '';
             while ($n->kind == T_NS_SEPARATOR || $n->kind == T_STRING) {
                 $class_name = $class_name . $n->text;
                 $n = $n->nextNS();
             }
             if ($class_name) {
                 $class_name = $pf->qualifyName($class_name, $t->index);
                 if ($class_name == 'self' || $class_name == 'parent' || $class_name == 'static') {
                     $class = $pf->getClassAt($t->index);
                     if (!$class) {
                         continue;
                     }
                     $class_name = $class->name;
                 }
                 $this->addUsedConstruct($class_name, 'method', '__construct', $t->lineNumber, $class_name, false, false);
             }
             continue;
         }
         // $this->foo();
         // $this->bar;
         if ($t->kind == T_VARIABLE && $t->text == '$this') {
             $n = $t->nextNS();
             if ($n->text == '->') {
                 $n = $n->nextNS();
                 if ($n->kind == T_STRING) {
                     $name = $n->text;
                     $n = $n->nextNS();
                     $class = $pf->getClassAt($t->index);
                     if (!$class) {
                         continue;
                     }
                     $class_name = $class->name;
                     $key = $n->text == '(' ? 'method' : 'property';
                     $this->addUsedConstruct($class_name, $key, $name, $t->lineNumber, $class_name, false, false);
                 }
             }
             continue;
         }
         // Foo::bar();
         // \Foo::bar();
         // Foo\Bar::BAZ
         if ($t->kind == T_DOUBLE_COLON) {
             $class_name = '';
             $p = $t->prevNS();
             while ($p->kind == T_NS_SEPARATOR || $p->kind == T_STRING) {
                 $class_name = $p->text . $class_name;
                 $p = $p->prevNS();
             }
             if ($class_name) {
                 $class_name = $pf->qualifyName($class_name, $t->index);
                 $check_parent_only = $class_name == 'parent';
                 $from_class = $pf->getClassAt($t->index);
                 $from_class_name = $from_class ? $from_class->name : '';
                 if ($class_name == 'self' || $class_name == 'static' || $class_name == 'parent') {
                     $check_parent_only = $class_name == 'parent';
                     $class_name = $from_class_name;
                     $from_method = $pf->getMethodAt($t->index);
                     $is_static_context = !$from_class || !$from_method || XRef::isStatic($from_method->attributes);
                 } else {
                     $is_static_context = true;
                 }
                 $n = $t->nextNS();
                 if ($n->kind == T_STRING) {
                     $nn = $n->nextNS();
                     if ($nn->text == '(') {
                         // Foo::bar()
                         // self::bar() - this can be either static or instance access, depends on context
                         $this->addUsedConstruct($class_name, 'method', $n->text, $t->lineNumber, $from_class_name, $is_static_context, $check_parent_only);
                     } else {
                         // Foo::BAR - constant
                         $const_name = $n->text;
                         $this->addUsedConstruct($class_name, 'constant', $n->text, $t->lineNumber, $from_class_name, true, $check_parent_only);
                     }
                 } elseif ($n->kind == T_VARIABLE) {
                     // Foo::$bar
                     $property_name = substr($n->text, 1);
                     // skip '$' sign
                     $this->addUsedConstruct($class_name, 'property', $property_name, $t->lineNumber, $from_class_name, true, $check_parent_only);
                 } else {
                     // e.g. self::$$keyName
                     //error_log($n);
                 }
                 continue;
             }
         }
     }
     return $this->slice;
 }