Skip to content

Commit df826b0

Browse files
committed
Updated Rector to commit 367edb50d168d753eb00ad56d0681ac5e8a73a16
rectorphp/rector-src@367edb5 [TypeDeclaration] Skip with include on SafeDeclareStrictTypesRector (#7862)
1 parent d7ad85e commit df826b0

8 files changed

Lines changed: 254 additions & 6 deletions

File tree

vendor/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,6 +2042,7 @@
20422042
'Rector\\PHPUnit\\PHPUnit100\\Rector\\StmtsAwareInterface\\WithConsecutiveRector' => $vendorDir . '/rector/rector-phpunit/rules/PHPUnit100/Rector/StmtsAwareInterface/WithConsecutiveRector.php',
20432043
'Rector\\PHPUnit\\PHPUnit110\\Rector\\Class_\\NamedArgumentForDataProviderRector' => $vendorDir . '/rector/rector-phpunit/rules/PHPUnit110/Rector/Class_/NamedArgumentForDataProviderRector.php',
20442044
'Rector\\PHPUnit\\PHPUnit120\\Rector\\CallLike\\CreateStubOverCreateMockArgRector' => $vendorDir . '/rector/rector-phpunit/rules/PHPUnit120/Rector/CallLike/CreateStubOverCreateMockArgRector.php',
2045+
'Rector\\PHPUnit\\PHPUnit120\\Rector\\Class_\\AllowMockObjectsWithoutExpectationsAttributeRector' => $vendorDir . '/rector/rector-phpunit/rules/PHPUnit120/Rector/Class_/AllowMockObjectsWithoutExpectationsAttributeRector.php',
20452046
'Rector\\PHPUnit\\PHPUnit120\\Rector\\Class_\\AssertIsTypeMethodCallRector' => $vendorDir . '/rector/rector-phpunit/rules/PHPUnit120/Rector/Class_/AssertIsTypeMethodCallRector.php',
20462047
'Rector\\PHPUnit\\PHPUnit120\\Rector\\Class_\\RemoveOverrideFinalConstructTestCaseRector' => $vendorDir . '/rector/rector-phpunit/rules/PHPUnit120/Rector/Class_/RemoveOverrideFinalConstructTestCaseRector.php',
20472048
'Rector\\PHPUnit\\PHPUnit50\\Rector\\StaticCall\\GetMockRector' => $vendorDir . '/rector/rector-phpunit/rules/PHPUnit50/Rector/StaticCall/GetMockRector.php',

vendor/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,6 +2302,7 @@ class ComposerStaticInit26b401162da3a43f2d077daa053b5bf6
23022302
'Rector\\PHPUnit\\PHPUnit100\\Rector\\StmtsAwareInterface\\WithConsecutiveRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/PHPUnit100/Rector/StmtsAwareInterface/WithConsecutiveRector.php',
23032303
'Rector\\PHPUnit\\PHPUnit110\\Rector\\Class_\\NamedArgumentForDataProviderRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/PHPUnit110/Rector/Class_/NamedArgumentForDataProviderRector.php',
23042304
'Rector\\PHPUnit\\PHPUnit120\\Rector\\CallLike\\CreateStubOverCreateMockArgRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/PHPUnit120/Rector/CallLike/CreateStubOverCreateMockArgRector.php',
2305+
'Rector\\PHPUnit\\PHPUnit120\\Rector\\Class_\\AllowMockObjectsWithoutExpectationsAttributeRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/PHPUnit120/Rector/Class_/AllowMockObjectsWithoutExpectationsAttributeRector.php',
23052306
'Rector\\PHPUnit\\PHPUnit120\\Rector\\Class_\\AssertIsTypeMethodCallRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/PHPUnit120/Rector/Class_/AssertIsTypeMethodCallRector.php',
23062307
'Rector\\PHPUnit\\PHPUnit120\\Rector\\Class_\\RemoveOverrideFinalConstructTestCaseRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/PHPUnit120/Rector/Class_/RemoveOverrideFinalConstructTestCaseRector.php',
23072308
'Rector\\PHPUnit\\PHPUnit50\\Rector\\StaticCall\\GetMockRector' => __DIR__ . '/..' . '/rector/rector-phpunit/rules/PHPUnit50/Rector/StaticCall/GetMockRector.php',

vendor/composer/installed.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,12 +1818,12 @@
18181818
"source": {
18191819
"type": "git",
18201820
"url": "https:\/\/github.com\/rectorphp\/rector-phpunit.git",
1821-
"reference": "b2a2a0439bdd9356ca420c7a824fbf823019c80e"
1821+
"reference": "db0d1d5cf8500543523eb61f87975d67bbc13c9b"
18221822
},
18231823
"dist": {
18241824
"type": "zip",
1825-
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-phpunit\/zipball\/b2a2a0439bdd9356ca420c7a824fbf823019c80e",
1826-
"reference": "b2a2a0439bdd9356ca420c7a824fbf823019c80e",
1825+
"url": "https:\/\/api.github.com\/repos\/rectorphp\/rector-phpunit\/zipball\/db0d1d5cf8500543523eb61f87975d67bbc13c9b",
1826+
"reference": "db0d1d5cf8500543523eb61f87975d67bbc13c9b",
18271827
"shasum": ""
18281828
},
18291829
"require": {
@@ -1850,7 +1850,7 @@
18501850
"tomasvotruba\/unused-public": "^2.2",
18511851
"tracy\/tracy": "^2.11"
18521852
},
1853-
"time": "2026-01-28T13:28:14+00:00",
1853+
"time": "2026-01-28T16:35:39+00:00",
18541854
"default-branch": true,
18551855
"type": "rector-extension",
18561856
"extra": {

vendor/composer/installed.php

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

vendor/rector/extension-installer/src/GeneratedConfig.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010
final class GeneratedConfig
1111
{
12-
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main 46e4f77'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main a110e2f'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main b2a2a04'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main 582fc7c'));
12+
public const EXTENSIONS = array('rector/rector-doctrine' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-doctrine', 'relative_install_path' => '../../rector-doctrine', 'extra' => NULL, 'version' => 'dev-main 46e4f77'), 'rector/rector-downgrade-php' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-downgrade-php', 'relative_install_path' => '../../rector-downgrade-php', 'extra' => NULL, 'version' => 'dev-main a110e2f'), 'rector/rector-phpunit' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-phpunit', 'relative_install_path' => '../../rector-phpunit', 'extra' => NULL, 'version' => 'dev-main db0d1d5'), 'rector/rector-symfony' => array('install_path' => '/home/runner/work/rector-src/rector-src/rector-build/vendor/rector/rector-symfony', 'relative_install_path' => '../../rector-symfony', 'extra' => NULL, 'version' => 'dev-main 582fc7c'));
1313
private function __construct()
1414
{
1515
}
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
<?php
2+
3+
declare (strict_types=1);
4+
namespace Rector\PHPUnit\PHPUnit120\Rector\Class_;
5+
6+
use PhpParser\Node;
7+
use PhpParser\Node\Attribute;
8+
use PhpParser\Node\AttributeGroup;
9+
use PhpParser\Node\Expr\MethodCall;
10+
use PhpParser\Node\Expr\PropertyFetch;
11+
use PhpParser\Node\Name;
12+
use PhpParser\Node\Name\FullyQualified;
13+
use PhpParser\Node\Stmt\Class_;
14+
use PhpParser\Node\Stmt\ClassMethod;
15+
use PHPStan\Reflection\ReflectionProvider;
16+
use Rector\Doctrine\NodeAnalyzer\AttributeFinder;
17+
use Rector\PhpParser\Node\BetterNodeFinder;
18+
use Rector\PHPUnit\Enum\PHPUnitAttribute;
19+
use Rector\PHPUnit\Enum\PHPUnitClassName;
20+
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
21+
use Rector\Rector\AbstractRector;
22+
use Rector\ValueObject\MethodName;
23+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
24+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
25+
/**
26+
* @see \Rector\PHPUnit\Tests\PHPUnit120\Rector\Class_\AllowMockObjectsWithoutExpectationsAttributeRector\AllowMockObjectsWithoutExpectationsAttributeRectorTest
27+
*
28+
* @see https://github.com/sebastianbergmann/phpunit/commit/24c208d6a340c3071f28a9b5cce02b9377adfd43
29+
*/
30+
final class AllowMockObjectsWithoutExpectationsAttributeRector extends AbstractRector
31+
{
32+
/**
33+
* @readonly
34+
*/
35+
private TestsNodeAnalyzer $testsNodeAnalyzer;
36+
/**
37+
* @readonly
38+
*/
39+
private AttributeFinder $attributeFinder;
40+
/**
41+
* @readonly
42+
*/
43+
private ReflectionProvider $reflectionProvider;
44+
/**
45+
* @readonly
46+
*/
47+
private BetterNodeFinder $betterNodeFinder;
48+
public function __construct(TestsNodeAnalyzer $testsNodeAnalyzer, AttributeFinder $attributeFinder, ReflectionProvider $reflectionProvider, BetterNodeFinder $betterNodeFinder)
49+
{
50+
$this->testsNodeAnalyzer = $testsNodeAnalyzer;
51+
$this->attributeFinder = $attributeFinder;
52+
$this->reflectionProvider = $reflectionProvider;
53+
$this->betterNodeFinder = $betterNodeFinder;
54+
}
55+
public function getNodeTypes(): array
56+
{
57+
return [Class_::class];
58+
}
59+
/**
60+
* @param Class_ $node
61+
*/
62+
public function refactor(Node $node): ?Class_
63+
{
64+
if ($this->shouldSkipClass($node)) {
65+
return null;
66+
}
67+
$mockObjectPropertyNames = $this->matchMockObjectPropertyNames($node);
68+
// there are no mock object properties
69+
if ($mockObjectPropertyNames === []) {
70+
return null;
71+
}
72+
$missedTestMethodsByMockPropertyName = [];
73+
$usingTestMethodsByMockPropertyName = [];
74+
$testMethodCount = 0;
75+
foreach ($mockObjectPropertyNames as $mockObjectPropertyName) {
76+
$missedTestMethodsByMockPropertyName[$mockObjectPropertyName] = [];
77+
$usingTestMethodsByMockPropertyName[$mockObjectPropertyName] = [];
78+
foreach ($node->getMethods() as $classMethod) {
79+
if (!$this->testsNodeAnalyzer->isTestClassMethod($classMethod)) {
80+
continue;
81+
}
82+
++$testMethodCount;
83+
// is a mock property used in the class method, as part of some method call? guessing mock expectation is set
84+
// skip if so
85+
if ($this->isClassMethodUsingMethodCallOnPropertyNamed($classMethod, $mockObjectPropertyName)) {
86+
$usingTestMethodsByMockPropertyName[$mockObjectPropertyName][] = $this->getName($classMethod);
87+
continue;
88+
}
89+
$missedTestMethodsByMockPropertyName[$mockObjectPropertyName][] = $this->getName($classMethod);
90+
}
91+
}
92+
if (!$this->shouldAddAttribute($missedTestMethodsByMockPropertyName)) {
93+
return null;
94+
}
95+
// skip sole test method, as those are expected to use all mocks
96+
if ($testMethodCount < 2) {
97+
return null;
98+
}
99+
if (!$this->isAtLeastOneMockPropertyMockedOnce($usingTestMethodsByMockPropertyName)) {
100+
return null;
101+
}
102+
// add attribute
103+
$node->attrGroups[] = new AttributeGroup([new Attribute(new FullyQualified(PHPUnitAttribute::ALLOW_MOCK_OBJECTS_WITHOUT_EXPECTATIONS))]);
104+
return $node;
105+
}
106+
public function getRuleDefinition(): RuleDefinition
107+
{
108+
return new RuleDefinition('Add #[AllowMockObjectsWithoutExpectations] attribute to PHPUnit test classes with mock properties used in multiple methods but one, to avoid irrelevant notices in tests run', [new CodeSample(<<<'CODE_SAMPLE'
109+
use PHPUnit\Framework\TestCase;
110+
final class SomeTest extends TestCase
111+
{
112+
private \PHPUnit\Framework\MockObject\MockObject $someServiceMock;
113+
114+
protected function setUp(): void
115+
{
116+
$this->someServiceMock = $this->createMock(SomeService::class);
117+
}
118+
119+
public function testOne(): void
120+
{
121+
// use $this->someServiceMock
122+
}
123+
124+
public function testTwo(): void
125+
{
126+
// use $this->someServiceMock
127+
}
128+
}
129+
CODE_SAMPLE
130+
, <<<'CODE_SAMPLE'
131+
use PHPUnit\Framework\TestCase;
132+
use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations;
133+
134+
#[AllowMockObjectsWithoutExpectations]
135+
final class SomeTest extends TestCase
136+
{
137+
private \PHPUnit\Framework\MockObject\MockObject $someServiceMock;
138+
139+
protected function setUp(): void
140+
{
141+
$this->someServiceMock = $this->createMock(SomeService::class);
142+
}
143+
144+
public function testOne(): void
145+
{
146+
$this->someServiceMock->expects($this->once())
147+
->method('someMethod')
148+
->willReturn('someValue');
149+
}
150+
151+
public function testTwo(): void
152+
{
153+
$this->someServiceMock->expects($this->once())
154+
->method('someMethod')
155+
->willReturn('anotherValue');
156+
}
157+
}
158+
CODE_SAMPLE
159+
)]);
160+
}
161+
/**
162+
* @return string[]
163+
*/
164+
private function matchMockObjectPropertyNames(Class_ $class): array
165+
{
166+
$propertyNames = [];
167+
foreach ($class->getProperties() as $property) {
168+
if (!$property->type instanceof Name) {
169+
continue;
170+
}
171+
if (!$this->isName($property->type, PHPUnitClassName::MOCK_OBJECT)) {
172+
continue;
173+
}
174+
$propertyNames[] = $this->getName($property->props[0]);
175+
}
176+
return $propertyNames;
177+
}
178+
private function shouldSkipClass(Class_ $class): bool
179+
{
180+
if (!$this->testsNodeAnalyzer->isInTestClass($class)) {
181+
return \true;
182+
}
183+
// attribute must exist for the rule to work
184+
if (!$this->reflectionProvider->hasClass(PHPUnitAttribute::ALLOW_MOCK_OBJECTS_WITHOUT_EXPECTATIONS)) {
185+
return \true;
186+
}
187+
// already filled
188+
if ($this->attributeFinder->hasAttributeByClasses($class, [PHPUnitAttribute::ALLOW_MOCK_OBJECTS_WITHOUT_EXPECTATIONS])) {
189+
return \true;
190+
}
191+
// has mock objects properties and setUp() method?
192+
$setupClassMethod = $class->getMethod(MethodName::SET_UP);
193+
return !$setupClassMethod instanceof ClassMethod;
194+
}
195+
private function isClassMethodUsingMethodCallOnPropertyNamed(ClassMethod $classMethod, string $mockObjectPropertyName): bool
196+
{
197+
/** @var MethodCall[] $methodCalls */
198+
$methodCalls = $this->betterNodeFinder->findInstancesOfScoped([$classMethod], [MethodCall::class]);
199+
foreach ($methodCalls as $methodCall) {
200+
if (!$methodCall->var instanceof PropertyFetch) {
201+
continue;
202+
}
203+
$propertyFetch = $methodCall->var;
204+
// we found a method call on a property fetch named
205+
if ($this->isName($propertyFetch, $mockObjectPropertyName)) {
206+
return \true;
207+
}
208+
}
209+
return \false;
210+
}
211+
/**
212+
* @param array<string, string[]> $missedTestMethodsByMockPropertyName
213+
*/
214+
private function shouldAddAttribute(array $missedTestMethodsByMockPropertyName): bool
215+
{
216+
foreach ($missedTestMethodsByMockPropertyName as $missedTestMethods) {
217+
// all test methods are using method calls on the mock property, so skip
218+
if (count($missedTestMethods) === 0) {
219+
continue;
220+
}
221+
return \true;
222+
}
223+
return \false;
224+
}
225+
/**
226+
* @param array<string, string[]> $usingTestMethodsByMockPropertyName
227+
*/
228+
private function isAtLeastOneMockPropertyMockedOnce(array $usingTestMethodsByMockPropertyName): bool
229+
{
230+
foreach ($usingTestMethodsByMockPropertyName as $usingTestMethods) {
231+
if (count($usingTestMethods) !== 0) {
232+
return \true;
233+
}
234+
}
235+
return \false;
236+
}
237+
}

vendor/rector/rector-phpunit/src/Enum/PHPUnitAttribute.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,9 @@ final class PHPUnitAttribute
4141
* @var string
4242
*/
4343
public const TEST = 'PHPUnit\Framework\Attributes\Test';
44+
/**
45+
* @see https://github.com/sebastianbergmann/phpunit/commit/24c208d6a340c3071f28a9b5cce02b9377adfd43
46+
* @var string
47+
*/
48+
public const ALLOW_MOCK_OBJECTS_WITHOUT_EXPECTATIONS = 'PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations';
4449
}

vendor/rector/rector-phpunit/src/Enum/PHPUnitClassName.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ final class PHPUnitClassName
3434
* @var string
3535
*/
3636
public const TEST_LISTENER = 'PHPUnit\Framework\TestListener';
37+
/**
38+
* @var string
39+
*/
40+
public const MOCK_OBJECT = 'PHPUnit\Framework\MockObject\MockObject';
3741
/**
3842
* @var string[]
3943
*/

0 commit comments

Comments
 (0)