Repository: maglnet/ComposerRequireChecker (PHP)

Issue:
DefinedSymbolCollector - Breaks on anonymous classes
```
$ cd /var/www/my_project
$ php composer-require-checker check composer.json 
ComposerRequireChecker 0.1.4

                                                                                                                                                     
  [UnexpectedValueException]                                                                                                                         
  Given node of type "PhpParser\Node\Stmt\Class_" (defined at line 129)does not have an assigned "namespacedName" property: did you pass it through  
   a name resolver visitor?                                                                                                                          
                                                                                                                                                     

check [--config-file CONFIG-FILE] [--] [<composer-json>]
```

not sure how to proceed?

This seems to cause the exception; from `composer.json`
```
  "autoload": {
    "psr-4": {
      "ProjectName\\": "src"
    }
  },
```


Discussion:
What about the source version?

On 23 Jun 2017 2:24 PM, "SpacePossum" <notifications@github.com> wrote:

> $ cd /var/www/my_project
> $ php composer-require-checker check composer.json
> ComposerRequireChecker 0.1.4
>
>
>   [UnexpectedValueException]
>   Given node of type "PhpParser\Node\Stmt\Class_" (defined at line 129)does not have an assigned "namespacedName" property: did you pass it through
>    a name resolver visitor?
>
>
> check [--config-file CONFIG-FILE] [--] [<composer-json>]
>
> not sure how to proceed?
>
> —
> You are receiving this because you are subscribed to this thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/maglnet/ComposerRequireChecker/issues/23>, or mute
> the thread
> <https://github.com/notifications/unsubscribe-auth/AAJakPYLuWcDTcpUyk03cPqfBgfMqijrks5sG65fgaJpZM4ODgFI>
> .
>

Install through composer.

```
$ php -v
PHP 7.1.6-1~ubuntu16.04.1+deb.sury.org+1 (cli) (built: Jun  9 2017 08:26:34) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.1.6-1~ubuntu16.04.1+deb.sury.org+1, Copyright (c) 1999-2017, by Zend Technologies
    with Xdebug v2.5.1, Copyright (c) 2002-2017, by Derick Rethans
```

```
$ ./vendor/bin/composer-require-checker check  composer.json -vvv
ComposerRequireChecker 1.2.98-63-gd02a3a3-dev
```

```
  [UnexpectedValueException]                                                                                                                         
  Given node of type "PhpParser\Node\Stmt\Class_" (defined at line 129)does not have an assigned "namespacedName" property: did you pass it through  
   a name resolver visitor?                                                                                                                          
```
Could you run it with -vvv? I think we simply haven't considered files in
the root namespace

On 23 Jun 2017 3:47 PM, "SpacePossum" <notifications@github.com> wrote:

> Install through composer.
>
> $ php -v
> PHP 7.1.6-1~ubuntu16.04.1+deb.sury.org+1 (cli) (built: Jun  9 2017 08:26:34) ( NTS )
> Copyright (c) 1997-2017 The PHP Group
> Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
>     with Zend OPcache v7.1.6-1~ubuntu16.04.1+deb.sury.org+1, Copyright (c) 1999-2017, by Zend Technologies
>     with Xdebug v2.5.1, Copyright (c) 2002-2017, by Derick Rethans
>
> $ ./vendor/bin/composer-require-checker check  composer.json -vvv
> ComposerRequireChecker 1.2.98-63-gd02a3a3-dev
>
>   [UnexpectedValueException]
>   Given node of type "PhpParser\Node\Stmt\Class_" (defined at line 129)does not have an assigned "namespacedName" property: did you pass it through
>    a name resolver visitor?
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <https://github.com/maglnet/ComposerRequireChecker/issues/23#issuecomment-310669785>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAJakNbZxMVsKTGvbZd4bmtOUqlz8LLvks5sG8HagaJpZM4ODgFI>
> .
>

```
$ cd /var/www/my_project
$ ./vendor/bin/composer-require-checker check composer.json  -vvv
ComposerRequireChecker 1.2.98-63-gd02a3a3-dev


  [UnexpectedValueException]
  Given node of type "PhpParser\Node\Stmt\Class_" (defined at line 129)does not have an assigned "namespacedName" property: did you pass it through
   a name resolver visitor?


Exception trace:
 () at /var/www/my_project/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/NodeVisitor/DefinedSymbolCollector.php:94
 ComposerRequireChecker\NodeVisitor\DefinedSymbolCollector->recordDefinitionOf() at /var/www/my_project/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/NodeVisitor/DefinedSymbolCollector.php:52
 ComposerRequireChecker\NodeVisitor\DefinedSymbolCollector->recordClassDefinition() at /var/www/my_project/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/NodeVisitor/DefinedSymbolCollector.php:42
 ComposerRequireChecker\NodeVisitor\DefinedSymbolCollector->enterNode() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:108
 PhpParser\NodeTraverser->traverseNode() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:120
 PhpParser\NodeTraverser->traverseNode() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:171
 PhpParser\NodeTraverser->traverseArray() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:101
 PhpParser\NodeTraverser->traverseNode() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:171
 PhpParser\NodeTraverser->traverseArray() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:101
 PhpParser\NodeTraverser->traverseNode() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:171
 PhpParser\NodeTraverser->traverseArray() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:101
 PhpParser\NodeTraverser->traverseNode() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:171
 PhpParser\NodeTraverser->traverseArray() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:101
 PhpParser\NodeTraverser->traverseNode() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:171
 PhpParser\NodeTraverser->traverseArray() at /var/www/my_project/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php:85
 PhpParser\NodeTraverser->traverse() at /var/www/my_project/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRoots.php:29
 ComposerRequireChecker\DefinedSymbolsLocator\LocateDefinedSymbolsFromASTRoots->__invoke() at /var/www/my_project/vendor/maglnet/composer-require-checker/src/ComposerRequireChecker/Cli/CheckCommand.php:72
 ComposerRequireChecker\Cli\CheckCommand->execute() at /var/www/my_project/vendor/symfony/console/Command/Command.php:264
 Symfony\Component\Console\Command\Command->run() at /var/www/my_project/vendor/symfony/console/Application.php:835
 Symfony\Component\Console\Application->doRunCommand() at /var/www/my_project/vendor/symfony/console/Application.php:200
 Symfony\Component\Console\Application->doRun() at /var/www/my_project/vendor/symfony/console/Application.php:124
 Symfony\Component\Console\Application->run() at /var/www/my_project/vendor/maglnet/composer-require-checker/bin/composer-require-checker.php:32
 include() at /var/www/my_project/vendor/maglnet/composer-require-checker/bin/composer-require-checker:3

check [--config-file CONFIG-FILE] [--] [<composer-json>]



```

maybe I can have a look into this later on, let me know if I can provide more useful data :)
@SpacePossum I think we'd need to know the offending file here: was hoping to see such information in the trace :-\
I pinned it down to anonymous class, for example;

```php
namespace MyProject\CLI\Commands;

abstract class AbstractCommand extends Command
{
    public function execute(InputInterface $input, OutputInterface $output)
    {
//        $ended = new class() {
//            public $controlledEnd = false;
//        };

         // ...
    }
```

I'll try to come up with utest and fix PR when I find the time :)
Aha, that's a nasty one indeed :-)

Thanks for pinning it down - wouldn't be able to do so otherwise.

I guess it's something around https://github.com/maglnet/ComposerRequireChecker/blob/7768b06093922677601af16bbce7f9f1adda31ce/test/ComposerRequireCheckerTest/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRootsTest.php#L32-L44
thanks for the pointer @Ocramius , is a good help :+1: 
Would love to see this released. 



Patch:
diff --git a/.travis.yml b/.travis.yml
index a07d6b5f..1d41aa9e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,29 +1,34 @@
 language: php
 
-php:
-  - '7.0'
-  - '7.1'
-  - nightly
+sudo: false
+
+git:
+    depth: 1
 
 matrix:
-  fast_finish: true
-  allow_failures:
-    - php: nightly
+    fast_finish: true
+    include:
+        - php: 7.0
+          env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest"
+        - php: 7.1
+        - php: nightly
+    allow_failures:
+        - php: nightly
 
 before_install:
-  - composer self-update
-  - sed s\@TRAVIS_BUILD_DIR@$TRAVIS_BUILD_DIR@g test/travis-composer.json > ~/.composer/composer.json
+    - composer self-update
+    - sed s\@TRAVIS_BUILD_DIR@$TRAVIS_BUILD_DIR@g test/travis-composer.json > ~/.composer/composer.json
 
 install:
-  - composer install -vvv
-
-  - composer global require maglnet/composer-require-checker:@dev
-  - export PATH=$PATH:~/.composer/vendor/bin
+    - composer update $COMPOSER_FLAGS --no-interaction --no-progress -vvv
+    - composer global require maglnet/composer-require-checker:@dev
+    - export PATH=$PATH:~/.composer/vendor/bin
+    - composer info -D | sort
 
 script:
-  - vendor/bin/phpunit --coverage-clover=clover.xml
-  - composer-require-checker
+    - vendor/bin/phpunit --coverage-clover=clover.xml
+    - composer-require-checker
 
 after_script:
-  - wget https://scrutinizer-ci.com/ocular.phar
-  - php ocular.phar code-coverage:upload --format=php-clover clover.xml
+    - wget https://scrutinizer-ci.com/ocular.phar
+    - php ocular.phar code-coverage:upload --format=php-clover clover.xml
diff --git a/composer.json b/composer.json
index cb19ff3e..a8c69f35 100644
--- a/composer.json
+++ b/composer.json
@@ -37,6 +37,9 @@
         "phpunit/phpunit":    "~6.0",
         "mikey179/vfsStream": "^1.6"
     },
+    "config": {
+        "optimize-autoloader": true
+    },
     "bin": [
         "bin/composer-require-checker"
     ],
diff --git a/src/ComposerRequireChecker/NodeVisitor/DefinedSymbolCollector.php b/src/ComposerRequireChecker/NodeVisitor/DefinedSymbolCollector.php
index 5e300c36..894011b5 100644
--- a/src/ComposerRequireChecker/NodeVisitor/DefinedSymbolCollector.php
+++ b/src/ComposerRequireChecker/NodeVisitor/DefinedSymbolCollector.php
@@ -48,7 +48,7 @@ public function enterNode(Node $node)
 
     private function recordClassDefinition(Node $node)
     {
-        if ($node instanceof Node\Stmt\Class_) {
+        if ($node instanceof Node\Stmt\Class_ && !$node->isAnonymous()) {
             $this->recordDefinitionOf($node);
         }
     }


Test patch:
diff --git a/test/ComposerRequireCheckerTest/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRootsTest.php b/test/ComposerRequireCheckerTest/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRootsTest.php
index 7bbfbd93..29f344df 100644
--- a/test/ComposerRequireCheckerTest/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRootsTest.php
+++ b/test/ComposerRequireCheckerTest/DefinedSymbolsLocator/LocateDefinedSymbolsFromASTRootsTest.php
@@ -38,11 +38,26 @@ public function testBasicLocate()
 
         $symbols = $this->locate([$roots]);
 
+        $this->assertInternalType('array', $symbols);
+        $this->assertCount(3, $symbols);
+
         $this->assertContains('MyClassA', $symbols);
         $this->assertContains('MyClassB', $symbols);
         $this->assertContains('MyClassC', $symbols);
     }
 
+    public function testBasicLocateAnonymous()
+    {
+        $roots = [
+            [new Class_(null)],
+        ];
+
+        $symbols = $this->locate([$roots]);
+
+        $this->assertInternalType('array', $symbols);
+        $this->assertCount(0, $symbols);
+    }
+
     private function locate(array $roots): array
     {
         return ($this->locator)(new ArrayObject($roots));