Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

False report of unused use #9478

Closed
mimmi20 opened this issue Jun 21, 2023 · 3 comments
Closed

False report of unused use #9478

mimmi20 opened this issue Jun 21, 2023 · 3 comments

Comments

@mimmi20
Copy link

mimmi20 commented Jun 21, 2023

Bug report

I have this Unittest:

<?php
/**
 * This file is part of the mimmi20/laminasviewrenderer-flash-message package.
 *
 * Copyright (c) 2023, Thomas Mueller <mimmi20@live.de>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

declare(strict_types = 1);

namespace Mimmi20\LaminasView\FlashMessage\View\Helper;

use ArrayAccess;
use Laminas\Mvc\Plugin\FlashMessenger\FlashMessenger as LaminasFlashMessenger;
use Laminas\View\Exception\RuntimeException;
use Laminas\View\Model\ModelInterface;
use Laminas\View\Model\ViewModel;
use Laminas\View\Renderer\RendererInterface;
use PHPUnit\Framework\Exception;
use PHPUnit\Framework\TestCase;

use function str_repeat;

final class FlashMessenger2Test extends TestCase
{
    /**
     * @throws Exception
     * @throws RuntimeException
     *
     * @phpcs:disable Generic.Metrics.CyclomaticComplexity.TooHigh
     * @phpcs:disable SlevomatCodingStandard.Functions.FunctionLength.FunctionLength
     */
    public function testRender(): void
    {
        $flashMessenger = $this->createMock(LaminasFlashMessenger::class);
        $flashMessenger->expects(self::once())
            ->method('getErrorMessages')
            ->willReturn(['error-message']);
        $flashMessenger->expects(self::once())
            ->method('getCurrentErrorMessages')
            ->willReturn(['error-message', 'current-error-message']);
        $flashMessenger->expects(self::once())
            ->method('getSuccessMessages')
            ->willReturn(['success-message']);
        $flashMessenger->expects(self::once())
            ->method('getCurrentSuccessMessages')
            ->willReturn(['success-message', 'current-success-message']);
        $flashMessenger->expects(self::once())
            ->method('getWarningMessages')
            ->willReturn(['warning-message']);
        $flashMessenger->expects(self::once())
            ->method('getCurrentWarningMessages')
            ->willReturn(['warning-message', 'current-warning-message']);
        $flashMessenger->expects(self::once())
            ->method('getInfoMessages')
            ->willReturn(['info-message']);
        $flashMessenger->expects(self::once())
            ->method('getCurrentInfoMessages')
            ->willReturn(['info-message', 'current-info-message']);
        $flashMessenger->expects(self::once())
            ->method('getMessages')
            ->willReturn(['default-message']);
        $flashMessenger->expects(self::once())
            ->method('getCurrentMessages')
            ->willReturn(['default-message', 'current-default-message']);
        $flashMessenger->expects(self::once())
            ->method('clearMessagesFromContainer')
            ->willReturn(true);
        $flashMessenger->expects(self::once())
            ->method('clearCurrentMessagesFromContainer')
            ->willReturn(true);

        $object = new FlashMessenger($flashMessenger);

        $view    = $this->createMock(RendererInterface::class);
        $matcher = self::exactly(10);
        $view->expects($matcher)
            ->method('render')
            ->willReturnCallback(
                static function (ModelInterface | string $nameOrModel, array | ArrayAccess | null $values = null) use ($matcher): string {
                    self::assertInstanceOf(ViewModel::class, $nameOrModel);

                    match ($matcher->numberOfInvocations()) {
                        1, 2 => self::assertSame('danger', $nameOrModel->getVariable('alertLevel')),
                        3, 4 => self::assertSame('warning', $nameOrModel->getVariable('alertLevel')),
                        5, 6 => self::assertSame('info', $nameOrModel->getVariable('alertLevel')),
                        7, 8 => self::assertSame('success', $nameOrModel->getVariable('alertLevel')),
                        9, 10 => self::assertSame('primary', $nameOrModel->getVariable('alertLevel')),
                        default => self::assertSame('', $nameOrModel->getVariable('alertLevel')),
                    };

                    match ($matcher->numberOfInvocations()) {
                        1 => self::assertSame(
                            'error-message',
                            $nameOrModel->getVariable('alertMessage'),
                        ),
                        2 => self::assertSame(
                            'current-error-message',
                            $nameOrModel->getVariable('alertMessage'),
                        ),
                        3 => self::assertSame(
                            'warning-message',
                            $nameOrModel->getVariable('alertMessage'),
                        ),
                        4 => self::assertSame(
                            'current-warning-message',
                            $nameOrModel->getVariable('alertMessage'),
                        ),
                        5 => self::assertSame(
                            'info-message',
                            $nameOrModel->getVariable('alertMessage'),
                        ),
                        6 => self::assertSame(
                            'current-info-message',
                            $nameOrModel->getVariable('alertMessage'),
                        ),
                        7 => self::assertSame(
                            'success-message',
                            $nameOrModel->getVariable('alertMessage'),
                        ),
                        8 => self::assertSame(
                            'current-success-message',
                            $nameOrModel->getVariable('alertMessage'),
                        ),
                        9 => self::assertSame(
                            'default-message',
                            $nameOrModel->getVariable('alertMessage'),
                        ),
                        10 => self::assertSame(
                            'current-default-message',
                            $nameOrModel->getVariable('alertMessage'),
                        ),
                        default => self::assertSame('', $nameOrModel->getVariable('alertMessage')),
                    };

                    self::assertSame('widget/bootstrap-alert', $nameOrModel->getTemplate());
                    self::assertNull($values);

                    return 'test-render';
                },
            );

        $object->setView($view);

        self::assertSame(str_repeat('test-render', 10), $object->render());
    }
}

PHPStan 1.10.20 reports this:

 ------ ------------------------------------------------
  Line   tests\View\Helper\FlashMessenger2Test.php
 ------ ------------------------------------------------
  82     Anonymous function has an unused use $matcher.
 ------ ------------------------------------------------

But the variable $matcher is used on lines 85 and 94.

This is my phpstan.neon file:

parameters:
  level: max

  parallel:
    maximumNumberOfProcesses: 1
    processTimeout: 200.0

  paths:
    - src
    - tests

  scanFiles:
    - %currentWorkingDirectory%/vendor/autoload.php
    - %currentWorkingDirectory%/vendor/squizlabs/php_codesniffer/autoload.php
    - %currentWorkingDirectory%/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php

  # reports occurrences of type-checking functions always evaluated to true
  checkAlwaysTrueCheckTypeFunctionCall: false

  # reports instanceof occurrences always evaluated to true
  checkAlwaysTrueInstanceof: true

  # reports === and !== occurrences always evaluated to true
  checkAlwaysTrueStrictComparison: true

  # enable stricter analysis of benevolent union types
  checkBenevolentUnionTypes: true

  # reports use of dynamic properties as undefined
  checkDynamicProperties: true

  # reports code paths with missing return statement in functions and methods with @return mixed PHPDoc
  checkExplicitMixedMissingReturn: true

  # reports function and method calls with incorrect name case
  checkFunctionNameCase: true

  # it requires type variables always be specified in typehints
  checkGenericClassInNonGenericObjectType: true

  # be strict about values with an unspecified (implicit mixed) type
  checkImplicitMixed: true

  # reports references to built-in classes with incorrect name case
  checkInternalClassCaseSensitivity: true

  # require that callable signatures are specified
  checkMissingCallableSignature: true

  # checks for missing typehints in iterables
  checkMissingIterableValueType: true

  # reports return typehints that could be narrowed down because some of the listed types are never returned
  checkTooWideReturnTypesInProtectedAndPublicMethods: true

  # reports properties with native types that weren’t initialized in the class constructor
  checkUninitializedProperties: true

  # doesn’t require typehints for properties if the types can be inferred from constructor injection
  inferPrivatePropertyTypeFromConstructor: false

  # prevents reading key and value variables set in foreach when iterating over a non-empty array
  polluteScopeWithAlwaysIterableForeach: false

  # prevents reading variables set in for loop initial statement and while loop condition after the loop
  polluteScopeWithLoopInitialAssignments: false

  # report always true last condition in a series of elseif branches and match expression arms
  reportAlwaysTrueInLastCondition: true

  # reports violations of parameter type contravariance and return type covariance
  reportMaybesInMethodSignatures: true

  # reports violations of property type invariance
  reportMaybesInPropertyPhpDocTypes: true

  # reports violations of parameter type contravariance and return type covariance in static methods
  reportStaticMethodSignatures: true

  #
  reportWrongPhpDocTypeInVarTag: true

  # differentiate between PHPDoc and native types (if false)
  treatPhpDocTypesAsCertain: false

  tipsOfTheDay: false

  exceptions:
    implicitThrows: false
    checkedExceptionRegexes:
      - '#Exception#'
      - '#Throwable#'
    check:
      missingCheckedExceptionInThrows: true
      tooWideThrowType: true

#  ignoreErrors:
#    - '~MockObject~'

The error is reported with PHPStan 1.10.20, but not with 1.10.19.

Code snippet that reproduces the problem

I was not able to reproduce the error with the playground, maybe because of the many dependencies to PHPUnit and the Laminas Framework.

Expected output

no error

Did PHPStan help you today? Did it make you happy in any way?

No response

@ondrejmirtes
Copy link
Member

Already fixed: phpstan/phpstan-src@a719486

Gonna release the fix shortly.

@mimmi20
Copy link
Author

mimmi20 commented Jun 21, 2023

Thanks

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 23, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants