Psalm: Psalm-internal and direct usage of method from internal class

Created on 25 May 2020  路  8Comments  路  Source: vimeo/psalm

https://psalm.dev/r/17f080d422

<?php
namespace App\A {
    /**
     * @internal
     * @psalm-internal App\A
     */
    class Foo {
        public static function abc(): int { return 1; }
    }
}

namespace App\B {
    class Bat {

        /**
        * @var \App\A\Foo
        */
        public $a;

        public function __construct(\App\A\Foo $a)
        {
            $this->a = $a;
        }

        public function batBat() :void {
            $a = $this->a->abc();
            $b = \App\A\Foo::abc();
            $c = new \App\A\Foo();
        }
    }
}

Psalm returns

ERROR: InternalClass - 27:18 - App\A\Foo is marked internal to App\A
ERROR: InternalClass - 28:18 - App\A\Foo is marked internal to App\A

and this is fine, but what about the line $a = $this->a->abc();? Psalm did not find any issue. Why?

It works fine when I use @internal (but namespaces are not completely different)
https://psalm.dev/r/6add224dce

<?php
  namespace A {
    /**
     * @internal
     */
    class Foo {
        public static function abc(): int { return 1; }
    }
}

namespace B {
    class Bat {

        /**
        * @var \A\Foo
        */
        public $a;

        public function __construct(\A\Foo $a)
        {
            $this->a = $a;
        }

        public function batBat(): void
        {
            $a = $this->a->abc();
            $b = \A\Foo::abc();
            $c = new \A\Foo();
        }
    }
}

Output:

ERROR: InternalMethod - 25:28 - The method A\Foo::abc has been marked as internal
ERROR: InternalClass - 26:18 - A\Foo is marked internal to A
ERROR: InternalMethod - 26:18 - The method A\Foo::abc has been marked as internal
ERROR: InternalClass - 27:18 - A\Foo is marked internal to A
bug

Most helpful comment

This: https://psalm.dev/r/a4f18d346f should be marked as error. I think it doesn't matter where the error is generated, could as well be reported at @var \A\Foo line and/or constructor.

All 8 comments

I found these snippets:


https://psalm.dev/r/17f080d422

<?php
  namespace App\A {
    /**
     * @internal
     * @psalm-internal App\A
     */
    class Foo {
        public static function abc(): int { return 1; }
    }
}

namespace App\B {
    class Bat {

        /**
        * @var \App\A\Foo
        */
        public $a;

        public function __construct(\App\A\Foo $a)
        {
            $this->a = $a;
        }

        public function batBat() :void {
            $a = $this->a->abc();
            $b = \App\A\Foo::abc();
            $c = new \App\A\Foo();
        }
    }
}
Psalm output (using commit 2e6fc24):

ERROR: InternalClass - 27:18 - App\A\Foo is marked internal to App\A

ERROR: InternalClass - 28:18 - App\A\Foo is marked internal to App\A


https://psalm.dev/r/6add224dce

<?php
  namespace A {
    /**
     * @internal
     */
    class Foo {
        public static function abc(): int { return 1; }
    }
}

namespace B {
    class Bat {

        /**
        * @var \A\Foo
        */
        public $a;

        public function __construct(\A\Foo $a)
        {
            $this->a = $a;
        }

        public function batBat() :void {
            $a = $this->a->abc();
            $b = \A\Foo::abc();
            $c = new \A\Foo();
        }
    }
}
Psalm output (using commit 2e6fc24):

ERROR: InternalMethod - 25:28 - The method A\Foo::abc has been marked as internal

ERROR: InternalClass - 26:18 - A\Foo is marked internal

ERROR: InternalMethod - 26:18 - The method A\Foo::abc has been marked as internal

ERROR: InternalClass - 27:18 - A\Foo is marked internal

This: https://psalm.dev/r/a4f18d346f should be marked as error. I think it doesn't matter where the error is generated, could as well be reported at @var \A\Foo line and/or constructor.

I found these snippets:


https://psalm.dev/r/a4f18d346f

<?php
  namespace App\A {
    /**
     * @internal
     * @psalm-internal App\A
     */
    class Foo {
        public static function abc(): int { return 1; }
    }
}

namespace App\B {
    class Bat {

        /**
        * @var \App\A\Foo
        */
        public $a;

        public function __construct(\App\A\Foo $a)
        {
            $this->a = $a;
        }

        public function batBat() :void {
            $a = $this->a->abc();
        }
    }
}
Psalm output (using commit 7e7456c):

No issues!

Hi @skolman - I'll try and take a look at this soon. I'm the original author of the @psalm-internal feature. I didn't know until now whether anyone outside my company was using it. As @weirdan pointed out the type annotation at line 16 in the above snippet should also be an error, but as noted in the PR that introduced the feature that isn't currently checked.

As a workaround for now, if you're willing to do extra work in App\A to prevent possible mistakes in App\B you can change your code to https://psalm.dev/r/969d26e1ac

I found these snippets:


https://psalm.dev/r/969d26e1ac

<?php
  namespace App\A {
    /**
     * @internal
     * @psalm-internal App\A
     */
    class Foo {
        /**
         * @internal
         * @psalm-internal App\A
         */
        public static function abc(): int { return 1; }
    }
}

namespace App\B {
    class Bat {

        /**
        * @var \App\A\Foo
        */
        public $a;

        public function __construct(\App\A\Foo $a)
        {
            $this->a = $a;
        }

        public function batBat() :void {
            $a = $this->a->abc();
            $b = \App\A\Foo::abc();
            $c = new \App\A\Foo();
        }
    }
}
Psalm output (using commit 3a9c743):

ERROR: InternalMethod - 30:28 - The method App\A\Foo::abc has been marked as internal to App\A

ERROR: InternalClass - 31:18 - App\A\Foo is marked internal to App\A

ERROR: InternalMethod - 31:18 - The method App\A\Foo::abc has been marked as internal to App\A

ERROR: InternalClass - 32:18 - App\A\Foo is marked internal to App\A

I just reported several similar issues in report at #3706 .

@muglug I think this can be closed. The original snippet https://psalm.dev/r/17f080d422 now produces four errors.

I found these snippets:


https://psalm.dev/r/17f080d422

<?php
  namespace App\A {
    /**
     * @internal
     * @psalm-internal App\A
     */
    class Foo {
        public static function abc(): int { return 1; }
    }
}

namespace App\B {
    class Bat {

        /**
        * @var \App\A\Foo
        */
        public $a;

        public function __construct(\App\A\Foo $a)
        {
            $this->a = $a;
        }

        public function batBat() :void {
            $a = $this->a->abc();
            $b = \App\A\Foo::abc();
            $c = new \App\A\Foo();
        }
    }
}
Psalm output (using commit 5f5ce6e):

ERROR: InternalMethod - 26:28 - The method App\A\Foo::abc is internal to App\A but called from App\B\Bat

ERROR: InternalClass - 27:18 - App\A\Foo is internal to App\A but called from App\B\Bat

ERROR: InternalMethod - 27:18 - The method App\A\Foo::abc is internal to App\A but called from App\B\Bat

ERROR: InternalClass - 28:18 - App\A\Foo is internal to App\A but called from App\B\Bat

Was this page helpful?
0 / 5 - 0 ratings