GiacoCorsiglia / php-stubs-generator

Generate stubs from any PHP code for IDE completion and static analysis.
MIT License
26 stars 3 forks source link

Inverted operation #2

Open szepeviktor opened 6 years ago

szepeviktor commented 6 years ago

Hello!

@GiacoCorsiglia Is it possible to output only parts which have side-effects?

GiacoCorsiglia commented 6 years ago

Definitely doable with PHP-Parser, but I'd say this is probably too different from generating stubs to belong in this tool. The implementation would have different considerations. For example, you'd have to recursively inspect every branch of every function starting with those called from the global scope (see below code sample). The NodeVisitor for generating stubs currently avoids doing that.

I'm open to ideas if you feel otherwise.

function a() {
    // Never called, should be discarded.
}

function b() {
    // called by c(), must be included in "side effect stubs".
}

function c() {
    return b();
}

$var = c();
szepeviktor commented 6 years ago

Thank you for your guidance.

Would it be simpler if I want only non-classes? I would check huge codebases with this, looking for everything except classes thus making sure the code is clean.

GiacoCorsiglia commented 6 years ago

Ah, I assumed you'd want the generated code to still function. If you want to output everything but declarations, a NodeVisitor with this method would probably do the trick (ignoring constant declarations):

public function leaveNode(Node $node)
{
    if ($node instanceof Function_
        || $node instanceof Class_
        || $node instanceof Interface_
        || $node instanceof Trait_
    ) {
        return NodeTraverser::REMOVE_NODE;
    }
}

So yes, that seems simpler. I imagine such a tool would be more useful if it also output file names and line numbers indicating where the code with side effects lives.

szepeviktor commented 6 years ago

Thank you!

Adding this to NodeVisitor::leaveNode() generated the code below.

        // Inverted operation: only OOP code should remain
        if ($node instanceof Class_
            || $node instanceof Interface_
            || $node instanceof Trait_
        ) {
            return NodeTraverser::REMOVE_NODE;
        }
<?php

/**
 * index.php - A frontend program belépőpontja.
 */
namespace app\frontend\web {
    /** @var \app\frontend\core\FrontendMain $main */
    $main = \app\frontend\core\FrontendMain::getInstance();
}
/**
 * index.php - Az API program belépőpontja.
 */
namespace app\api\web {
    /** @var \app\api\core\ApiMain $main */
    $main = \app\api\core\ApiMain::getInstance();
}
/**
 * index.php - A backend program belépőpontja.
 */
namespace app\backend\web {
    /** @var \app\backend\core\BackendMain $main */
    $main = \app\backend\core\BackendMain::getInstance();
}
namespace {
    // Cron program betöltése
    /** @var \core\Cron $cron */
    $cron = \core\Cron::getInstance();
}

So our code is clean!! These are the 3 entry points.

Would you add a command line option to do this?

szepeviktor commented 6 years ago

Here it is

diff --git a/src/NodeVisitor.php b/src/NodeVisitor.php
index e299e6b..76b4a77 100644
--- a/src/NodeVisitor.php
+++ b/src/NodeVisitor.php
@@ -19,6 +19,7 @@ use PhpParser\Node\Stmt\Trait_;
 use PhpParser\NodeTraverser;
 use PhpParser\NodeVisitorAbstract;
 use PhpParser\Node\Expr\ConstFetch;
+use PhpParser\Node\Stmt\Use_;

 /**
  * On node traversal, this visitor converts any AST to one just containing stub
@@ -174,6 +175,15 @@ class NodeVisitor extends NodeVisitorAbstract
         }
         $parent = $this->stack[count($this->stack) - 1] ?? null;

+        // Inverted operation: only OOP code should remain
+        if ($node instanceof Class_
+            || $node instanceof Interface_
+            || $node instanceof Trait_
+            || $node instanceof Use_
+        ) {
+            return NodeTraverser::REMOVE_NODE;
+        }
+
         if ($node instanceof Assign
             || $node instanceof Function_
             || $node instanceof Class_
@@ -244,6 +254,7 @@ class NodeVisitor extends NodeVisitorAbstract
         }

         // Any other top level junk we are happy to remove.
+return;
         return NodeTraverser::REMOVE_NODE;
     }

This removes all but OOP. Would it be possible to add a command line option? like --non-oop