Пример #1
0
    public function isNotLocalClass()
    {
        $linksUp = Token::linksAsList();
        $this->addMethod(<<<GREMLIN
sideEffect{ inside = it.get().value("fullnspath"); }
.where(  __.repeat( __.in({$linksUp}) ).until( hasLabel("Class") ).filter{ it.get().value("fullnspath") == inside; }.count().is(eq(0)) )

GREMLIN
);
        return $this;
    }
Пример #2
0
    public function run()
    {
        $linksIn = Token::linksAsList();
        // processing '\parent' fullnspath
        $query = <<<GREMLIN
g.V().hasLabel("Identifier").filter{ it.get().value("fullnspath").toLowerCase() == "\\\\parent"}
.where( __.until( and( hasLabel("Class"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("EXTENDS") )
.property('fullnspath', __.until( and( hasLabel("Class"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("EXTENDS").values("fullnspath") )
.where( __.until( and( hasLabel("Class"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("EXTENDS").in("DEFINITION") )
.addE('DEFINITION').from( __.until( and( hasLabel("Class"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("EXTENDS").in("DEFINITION") )

GREMLIN;
        $this->gremlin->query($query);
        display("\\parent to fullnspath\n");
        // processing '\self' fullnspath
        $query = <<<GREMLIN
g.V().hasLabel("Identifier").filter{ it.get().value("fullnspath").toLowerCase() == "\\\\self"}
.where( __.until( and( hasLabel("Class", "Interface", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})) )
.property('fullnspath', __.until( and( hasLabel("Class", "Interface", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("NAME").values("fullnspath") )
.addE('DEFINITION').from( __.until( and( hasLabel("Class", "Interface", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})) )

GREMLIN;
        $this->gremlin->query($query);
        display('\\self to fullnspath');
        // processing '\static' fullnspath
        $query = <<<GREMLIN
g.V().hasLabel("Identifier").filter{ it.get().value("fullnspath").toLowerCase() == "\\\\static"}
.where( __.until( and( hasLabel("Class", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})) )
.property('fullnspath', __.until( and( hasLabel("Class", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})).out("NAME").values("fullnspath") )
.addE('DEFINITION').from( __.until( and( hasLabel("Class", "Trait"), __.out("NAME").not(has("atom", "Void")) ) ).repeat(__.in({$linksIn})) )

GREMLIN;
        $this->gremlin->query($query);
        display('\\static to fullnspath');
        // Create link between Class constant and definition
        $query = <<<'GREMLIN'
        g.V().hasLabel('Staticconstant').as('first')
.out('CONSTANT').sideEffect{name = it.get().value("code");}.select('first')
.out('CLASS').hasLabel("Identifier", "Nsname").sideEffect{classe = it.get().value("fullnspath");}.in('DEFINITION')
.where( __.sideEffect{classes = [];}
          .emit(hasLabel("Class")).repeat( out("EXTENDS").in("DEFINITION") ).times(15)
          .out("BLOCK").out("ELEMENT").hasLabel("Const").out("CONST").as('const')
          .out("NAME").filter{ it.get().value("code") == name; }.select('const')
          .sideEffect{classes.add(it.get()); }
          .fold()
)
.map{classes[0]}.as('theClass')
.addE('DEFINITION').from( 'first' )
GREMLIN;
        $this->gremlin->query($query);
        display('Create link between Class constant and definition');
        // Create propertyname for Property Definitions
        $query = <<<GREMLIN
g.V().hasLabel("Ppp", "Var").out("PPP").as("ppp")
.coalesce( out("LEFT"), __.filter{ true } )
.sideEffect{ propertyname = it.get().value('code').toString().substring(1, it.get().value('code').size()); }
.select("ppp")
.sideEffect{ it.get().property('propertyname', propertyname); }

GREMLIN;
        $this->gremlin->query($query);
        display('set propertyname');
        // update fullnspath with fallback for functions
        $query = <<<GREMLIN
g.V().hasLabel("Functioncall").as("a")
                              .has("fullnspath", without(''))
                              .has('token', within('T_STRING', 'T_NS_SEPARATOR'))
                              .where( __.in("NEW", "METHOD").count().is(eq(0)))
                              .sideEffect{ fullnspath = it.get().value("fullnspath")}
                              .in('DEFINITION')
                              .filter{ it.get().value("fullnspath") != fullnspath}
                              .sideEffect{ fullnspath = it.get().value("fullnspath")}
                              .select("a")
                              .sideEffect{ 
                                   it.get().property("fullnspath", fullnspath ); 
                               }

GREMLIN;
        $this->gremlin->query($query);
        display('fallback for global functioncall');
        // update fullnspath with fallback for functions
        $query = <<<GREMLIN
g.V().hasLabel("Functioncall").has("fullnspath", without(''))
                              .has('token', within('T_STRING', 'T_NS_SEPARATOR'))
                              .where( __.in("NEW", "METHOD", "DEFINITION").count().is(eq(0)))

.sideEffect{ 
    fullnspath = it.get().vertices(OUT, 'NAME').next().value("fullnspath").toString().toLowerCase();
    it.get().property("fullnspath", fullnspath ); 
}

GREMLIN;
        $this->gremlin->query($query);
        display('refine functioncall fullnspath');
        // update fullnspath with fallback for functions
        $query = <<<GREMLIN
g.V().hasLabel("Identifier", "Nsname").as("a")
                              .has("fullnspath", without(''))
                              .has('token', within('T_STRING', 'T_NS_SEPARATOR'))
                              .where( __.in("NEW", "METHOD", "NAME", "SUBNAME").count().is(eq(0)))
                              .sideEffect{ fullnspath = it.get().value("fullnspath")}
                              .in('DEFINITION').out("NAME")
                              .filter{ it.get().value("fullnspath") != fullnspath}
                              .sideEffect{ fullnspath = it.get().value("fullnspath")}
                              .select("a")
                              .sideEffect{ 
                                   it.get().property("fullnspath", fullnspath ); 
                               }

GREMLIN;
        $this->gremlin->query($query);
        display('fallback for global constants');
        // fallback for PHP and ext, class, function, constant
        // update fullnspath with fallback for functions
        $pathDocs = $this->config->dir_root . '/data/analyzers.sqlite';
        $docs = new Docs($pathDocs);
        $exts = $docs->listAllAnalyzer('Extensions');
        $exts[] = 'php_constants';
        $c = array();
        $f = array();
        foreach ($exts as $ext) {
            $inifile = str_replace('Extensions\\Ext', '', $ext) . '.ini';
            $fullpath = $this->config->dir_root . '/data/' . $inifile;
            $iniFile = parse_ini_file($fullpath);
            if (!empty($iniFile['constants'][0])) {
                $c[] = $iniFile['constants'];
            }
            if (!empty($iniFile['functions'][0])) {
                $f[] = $iniFile['functions'];
            }
        }
        $constants = call_user_func_array('array_merge', $c);
        $constants = array_filter($constants, function ($x) {
            return strpos($x, '\\') === false;
        });
        $constants = array_map('strtolower', $constants);
        $query = <<<GREMLIN
g.V().hasLabel("Identifier").where( __.in("DEFINITION", "NEW", "USE", "NAME", "EXTENDS", "IMPLEMENTS", "CLASS", "CONST", "CONSTANT", "TYPEHINT", "FUNCTION", "GROUPUSE", "SUBNAME").count().is(eq(0)) )  
                            .filter{ it.get().value("code").toLowerCase() in arg1 }
.sideEffect{ 
    fullnspath = "\\\\" + it.get().value("code").toLowerCase();
    it.get().property("fullnspath", fullnspath); 
}

GREMLIN;
        $this->gremlin->query($query, array('arg1' => $constants));
        display('spot PHP / ext constants');
        $query = 'g.V().hasLabel("Const").out("CONST").out("NAME").filter{ (it.get().value("fullnspath") =~ "^\\\\\\\\[^\\\\\\\\]+\\$" ).getCount() > 0 }.values("code")';
        $constants = $this->gremlin->query($query);
        $constantsGlobal = $constants->results;
        $query = 'g.V().hasLabel("Const").out("CONST").out("NAME").filter{ (it.get().value("fullnspath") =~ "^\\\\\\\\[^\\\\\\\\]+\\$" ).getCount() == 0 }.values("fullnspath")';
        $constants = $this->gremlin->query($query);
        $constantsDefinitions = $constants->results;
        $query = <<<GREMLIN
g.V().hasLabel("Identifier").where( __.in("DEFINITION", "NEW", "USE", "NAME", "EXTENDS", "IMPLEMENTS", "CLASS", "CONST", "CONSTANT", "TYPEHINT", "FUNCTION", "GROUPUSE", "SUBNAME").count().is(eq(0)) )  
                            .filter{ it.get().value("code") in arg1 }
                            .filter{ !(it.get().value("fullnspath").toLowerCase() in arg2) }
                            .sideEffect{ name = it.get().value("code"); }
.sideEffect{ 
    fullnspath = "\\\\" + it.get().value("code").toLowerCase();
    it.get().property("fullnspath", fullnspath); 
}.addE("DEFINITION").from( g.V().hasLabel("Const").out("CONST").out("NAME").filter{ it.get().value("code") == name} )

GREMLIN;
        $this->gremlin->query($query, array('arg1' => $constantsGlobal, 'arg2' => $constantsDefinitions));
        display('spot constants that falls back on global constants');
        $functions = call_user_func_array('array_merge', $f);
        $functions = array_filter($functions, function ($x) {
            return strpos($x, '\\') === false;
        });
        $functions = array_map('strtolower', $functions);
        $query = <<<GREMLIN
g.V().hasLabel("Functioncall").not(has("token", "T_OPEN_TAG_WITH_ECHO"))
                              .filter{ it.get().value("code").toLowerCase() in arg1 }
                              .where( __.in("DEFINITION").count().is(eq(0)) )
.sideEffect{
    fullnspath = "\\\\" + it.get().value("code").toLowerCase();
    it.get().property("fullnspath", fullnspath); 
}

GREMLIN;
        $this->gremlin->query($query, array('arg1' => $functions));
        display('mark PHP native functions call');
        // Define-style constant definitions
        $query = <<<GREMLIN
g.V().hasLabel("Functioncall").has("fullnspath", "\\\\define")
     .out("ARGUMENTS").out("ARGUMENT").has("rank", 0)
     .hasLabel("String").has("noDelimiter")
     .map{ s = it.get().value("noDelimiter").toString().toLowerCase();
           if ( s.substring(0,1) != "\\\\") {
               s = "\\\\" + s;
           }
           it.get().property("fullnspath", s);
           s;
         }.unique();
GREMLIN;
        $constants = $this->gremlin->query($query);
        $constants = $constants->results;
        if (!empty($constants)) {
            // First round, with full ns path
            $query = <<<GREMLIN
g.V().hasLabel("Identifier", "Nsname")
     .where( __.in("NAME", "SUBNAME").count().is(eq(0)) )
     .filter{ it.get().value("fullnspath") in arg1 }.sideEffect{name = it.get().value("fullnspath"); }
     .addE('DEFINITION')
     .from( 
        g.V().hasLabel("Functioncall").has("fullnspath", "\\\\define")
             .out("ARGUMENTS").as("a").out("ARGUMENT").has("rank", 0).hasLabel("String")
             .filter{ it.get().value("fullnspath") == name}.select('a')
         )

GREMLIN;
            $res = $this->gremlin->query($query, array('arg1' => $constants));
            // Second round, with fallback to global constants
            $query = <<<GREMLIN
g.V().hasLabel("Identifier", "Nsname")
     .where( __.in("NAME", "SUBNAME").count().is(eq(0)) )
     .where( __.in("DEFINITION").count().is(eq(0)) )
     .filter{ name = "\\\\" + it.get().value("fullcode").toString().toLowerCase(); name in arg1 }
     .addE('DEFINITION')
     .from( 
        g.V().hasLabel("Functioncall").has("fullnspath", "\\\\define")
             .out("ARGUMENTS").as("a").out("ARGUMENT").has("rank", 0).hasLabel("String")
             .filter{ it.get().value("fullnspath") == name}.select('a')
         )

GREMLIN;
            $res = $this->gremlin->query($query, array('arg1' => $constants));
            // TODO : handle case-insensitive
            display('Link constant definitions');
        } else {
            display('Link constant definitions : skipping.');
        }
        display('Mark literal expressions as constants');
        $query = <<<GREMLIN
g.V().hasLabel("Integer", "Boolean", "Real", "Null", "Void", "InlineHtml", "Magicconstant", "Staticconstant", "Void")
     .sideEffect{ it.get().property("constant", true); }

GREMLIN;
        $this->gremlin->query($query);
        $query = <<<GREMLIN
g.V().hasLabel("String").where( __.out("CONCAT").count().is(eq(0)))
     .sideEffect{ it.get().property("constant", true); }

GREMLIN;
        $this->gremlin->query($query);
        $query = <<<GREMLIN
g.V().hasLabel("Identifier",  "Nsname").not(hasLabel("Functioncall"))
     .sideEffect{ it.get().property("constant", true); }

GREMLIN;
        $this->gremlin->query($query);
        $data = new Methods();
        $deterministFunctions = $data->getDeterministFunctions();
        $deterministFunctions = array_map(function ($x) {
            return '\\' . $x;
        }, $deterministFunctions);
        for ($i = 0; $i < 3; ++$i) {
            // Cases for Structures (all sub element are constante => structure is constante)
            $structures = array('Addition' => array('LEFT', 'RIGHT'), 'Multiplication' => array('LEFT', 'RIGHT'), 'Bitshift' => array('LEFT', 'RIGHT'), 'Logical' => array('LEFT', 'RIGHT'), 'Power' => array('LEFT', 'RIGHT'), 'Keyvalue' => array('KEY', 'VALUE'), 'Arguments' => array('ARGUMENT'), 'Sequence' => array('ELEMENT'), 'Break' => array('BREAK'), 'Continue' => array('CONTINUE'), 'Return' => array('RETURN'), 'Ternary' => array('CONDITION', 'THEN', 'ELSE'), 'Comparison' => array('LEFT', 'RIGHT'), 'Noscream' => array('AT'), 'Not' => array('NOT'), 'Parenthesis' => array('CODE'), 'Concatenation' => array('CONCAT'), 'String' => array('CONCAT'));
            foreach ($structures as $atom => $links) {
                $linksList = "'" . implode("', '", $links) . "'";
                $query = <<<GREMLIN
g.V().hasLabel("{$atom}").where( __.out({$linksList}).not(has("constant", true)).count().is(eq(0)) )
    .sideEffect{ it.get().property("constant", true);}
GREMLIN;
                $this->gremlin->query($query);
            }
            $query = <<<GREMLIN
g.V().hasLabel("Functioncall").filter{ it.get().value("fullnspath") in arg1}
     .where( __.out("ARGUMENTS").out("ARGUMENT").not(has("constant", true)).count().is(eq(0)) )
    .sideEffect{ it.get().property("constant", true);}
GREMLIN;
            $this->gremlin->query($query, array('arg1' => $deterministFunctions));
        }
        display('Mark constants expressions');
        $query = <<<GREMLIN
g.V().hasLabel("Variable").has("code", "\\\$GLOBALS").in("VARIABLE").hasLabel("Array").as("var")
     .out("INDEX").hasLabel("String")
     .sideEffect{ varname = '\$' + it.get().value('noDelimiter');
                  it.get().property("globalvar", varname);}


GREMLIN;
        $this->gremlin->query($query);
        display('Mark constants expressions');
    }
Пример #3
0
    public function run()
    {
        $analyzer = $this->config->program;
        if (empty($analyzer)) {
            die('Provide the analyzer with the option -P X/Y. Aborting' . "\n");
        }
        $analyzerClass = Analyzer::getClass($analyzer);
        if ($analyzerClass === false) {
            $die = "'{$analyzer}' doesn't exist. Aborting\n";
            $r = Analyzer::getSuggestionClass($analyzer);
            if (count($r) > 0) {
                $die .= 'Did you mean : ' . implode(', ', str_replace('_', '/', $r)) . "\n";
            }
            die($die);
        }
        $analyzer = Analyzer::getName($analyzerClass);
        $query = <<<GREMLIN
g.V().hasLabel("Analysis").has("analyzer", "{$analyzer}").out().count();
GREMLIN;
        $vertices = $this->gremlin->query($query)->results;
        if (isset($vertices[0]->notCompatibleWithPhpVersion)) {
            die($this->config->program . " is not compatible with the running version of PHP. No result available.\n");
        }
        if (isset($vertices[0]->notCompatibleWithPhpConfiguration)) {
            die($this->config->program . " is not compatible with the compilation of the running version of PHP. No result available.\n");
        }
        $return = array();
        if ($this->config->style == 'BOOLEAN') {
            $queryTemplate = 'g.V().hasLabel("Analysis").has("analyzer", "' . $analyzer . '").out().count().is(gt(0))';
            $vertices = $this->gremlin->query($queryTemplate);
            $return[] = $vertices[0];
        } elseif ($this->config->style == 'COUNTED_ALL') {
            $queryTemplate = 'g.V().hasLabel("Analysis").has("analyzer", "' . $analyzer . '").out().count()';
            $vertices = $this->gremlin->query($queryTemplate)->results;
            $return[] = $vertices[0];
        } elseif ($this->config->style == 'ALL') {
            $linksDown = Token::linksAsList();
            $query = <<<GREMLIN
g.V().hasLabel("Analysis").has("analyzer", "{$analyzer}").out('ANALYZED')
.sideEffect{ line = it.get().value('line');
             fullcode = it.get().value('fullcode');
             file='None'; 
             theFunction = 'None'; 
             theClass='None'; 
             theNamespace='None'; 
             }
.sideEffect{ line = it.get().value('line'); }
.until( hasLabel('Project') ).repeat( 
    __.in({$linksDown})
      .sideEffect{ if (it.get().label() == 'Function') { theFunction = it.get().value('code')} }
      .sideEffect{ if (it.get().label() == 'Class') { theClass = it.get().value('fullcode')} }
      .sideEffect{ if (it.get().label() == 'File') { file = it.get().value('fullcode')} }
       )

.map{ ['line':line, 'file':file, 'fullcode':fullcode, 'function':theFunction, 'class':theClass, 'namespace':theNamespace]; }
GREMLIN;
            $vertices = $this->gremlin->query($query)->results;
            $return = array();
            foreach ($vertices as $k => $v) {
                $row = array($v->fullcode, $v->file, $v->line, $v->namespace, $v->class, $v->function);
                $return[] = $row;
            }
        } elseif ($this->config->style == 'DISTINCT') {
            $queryTemplate = 'g.V().hasLabel("Analysis").has("analyzer", "' . $analyzer . '").out("ANALYZED").values("code").unique()';
            $vertices = $this->gremlin->query($queryTemplate)->results;
            $return = array();
            foreach ($vertices as $k => $v) {
                $return[] = array($v);
            }
        } elseif ($this->config->style == 'COUNTED') {
            $queryTemplate = 'g.V().hasLabel("Analysis").has("analyzer", "' . $analyzer . '").out("ANALYZED").groupCount("m")by("code").cap("m")';
            $vertices = $this->gremlin->query($queryTemplate)->results;
            $return = array();
            foreach ($vertices[0] as $k => $v) {
                $return[$k] = $v;
            }
        }
        if ($this->config->json === true) {
            $text = json_encode($return);
        } elseif ($this->config->csv === true) {
            $text = array(array('Code', 'File', 'Namespace', 'Class', 'Function'));
            foreach ($return as $k => $v) {
                if (is_array($v)) {
                    $text[] = $v;
                } else {
                    $text[] = array($k, $v);
                }
            }
        } elseif ($this->config->html === true || $this->config->odt === true) {
            $text = '';
            foreach ($return as $k => $r) {
                if ($this->config->style == 'COUNTED') {
                    $text .= "+ {$k} => {$r}\n";
                } else {
                    $text .= "+ {$k}\n";
                    if (is_array($r)) {
                        $text .= '  + ' . implode("\n  + ", $r) . "\n";
                    } else {
                        $text .= "+ {$r}\n";
                    }
                }
            }
        } else {
            // count also for $this->config->text == 1
            $text = '';
            foreach ($return as $k => $v) {
                if ($this->config->style == 'COUNTED') {
                    $text .= "{$k} => {$v}\n";
                } else {
                    $text .= implode(', ', $v) . "\n";
                }
            }
        }
        if ($this->config->output) {
            echo $text;
        }
        switch (1) {
            case $this->config->json:
                $extension = 'json';
                break 1;
            case $this->config->odt:
                $extension = 'odt';
                break 1;
            case $this->config->html:
                $extension = 'html';
                break 1;
            case $this->config->csv:
                $extension = 'csv';
                break 1;
            case $this->config->text:
            default:
                $extension = 'txt';
                break 1;
        }
        if ($this->config->file != 'stdout') {
            $name = $this->config->file . '.' . $extension;
            if (file_exists($name)) {
                die("{$name} already exists. Aborting\n");
            }
            if ($this->config->format == 'ODT') {
                $name1 = FILE . '.html';
                file_put_contents($name1, $text);
                $name = FILE . '.' . $extension;
                shell_exec('pandoc -o ' . $name . ' ' . $name1);
                unlink($name1);
            } elseif ($this->config->format == 'CSV') {
                $csvFile = fopen($name, 'w');
                foreach ($text as $t) {
                    fputcsv($csvFile, $t);
                }
                fclose($csvFile);
            } else {
                file_put_contents($name, $text);
            }
        }
    }