Skip to content

Commit 558aaae

Browse files
committed
Detect case only name changes for Classes
1 parent b9de798 commit 558aaae

File tree

5 files changed

+122
-13
lines changed

5 files changed

+122
-13
lines changed

docs/Ruleset.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ V097 | MAJOR | Class public method parameter default value changed
7171
V098 | MAJOR | Class protected method parameter default value changed
7272
V099 | PATCH | Class private method parameter default value changed
7373
V150 | PATCH | Class public/protected/private method renamed (case only)
74+
V154 | PATCH | Class renamed (case only)
7475
VXXX | MAJOR | *Final class public method parameter added*
7576
VXXX | MAJOR | *Final class protected method parameter added*
7677
VXXX | PATCH | *Final class private method parameter added*

src/PHPSemVerChecker/Analyzer/ClassAnalyzer.php

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use PHPSemVerChecker\Operation\ClassAdded;
66
use PHPSemVerChecker\Operation\ClassRemoved;
7+
use PHPSemVerChecker\Operation\ClassRenamedCaseOnly;
78
use PHPSemVerChecker\Registry\Registry;
89
use PHPSemVerChecker\Report\Report;
910

@@ -14,30 +15,58 @@ public function analyze(Registry $registryBefore, Registry $registryAfter)
1415
{
1516
$report = new Report();
1617

17-
$keysBefore = array_keys($registryBefore->data['class']);
18-
$keysAfter = array_keys($registryAfter->data['class']);
19-
$added = array_diff($keysAfter, $keysBefore);
20-
$removed = array_diff($keysBefore, $keysAfter);
21-
$toVerify = array_intersect($keysBefore, $keysAfter);
18+
$classesBefore = $registryBefore->data['class'];
19+
$classesAfter = $registryAfter->data['class'];
20+
21+
$classesBeforeKeyed = [];
22+
$mappingsBeforeKeyed = [];
23+
foreach($classesBefore as $key => $classBefore)
24+
{
25+
$classesBeforeKeyed[strtolower($classBefore->name)] = $classBefore;
26+
$mappingsBeforeKeyed[strtolower($classBefore->name)] = $registryBefore->mapping['class'][$key];
27+
}
28+
29+
$classesAfterKeyed = [];
30+
$mappingsAfterKeyed = [];
31+
foreach($classesAfter as $key => $classAfter)
32+
{
33+
$classesAfterKeyed[strtolower($classAfter->name)] = $classAfter;
34+
$mappingsAfterKeyed[strtolower($classAfter->name)] = $registryAfter->mapping['class'][$key];
35+
}
36+
37+
$classNamesBefore = array_keys($classesBeforeKeyed);
38+
$classNamesAfter = array_keys($classesAfterKeyed);
39+
$added = array_diff($classNamesAfter, $classNamesBefore);
40+
$removed = array_diff($classNamesBefore, $classNamesAfter);
41+
$toVerify = array_intersect($classNamesBefore, $classNamesAfter);
2242

2343
foreach ($removed as $key) {
24-
$fileBefore = $registryBefore->mapping['class'][$key];
25-
$classBefore = $registryBefore->data['class'][$key];
44+
$fileBefore = $mappingsBeforeKeyed[$key];
45+
$classBefore = $classesBeforeKeyed[$key];
2646

2747
$data = new ClassRemoved($fileBefore, $classBefore);
2848
$report->addClass($data);
2949
}
3050

3151
foreach ($toVerify as $key) {
32-
$fileBefore = $registryBefore->mapping['class'][$key];
52+
$fileBefore = $mappingsBeforeKeyed[$key];
3353
/** @var \PhpParser\Node\Stmt\Class_ $classBefore */
34-
$classBefore = $registryBefore->data['class'][$key];
35-
$fileAfter = $registryAfter->mapping['class'][$key];
54+
$classBefore = $classesBeforeKeyed[$key];
55+
$fileAfter = $mappingsAfterKeyed[$key];
3656
/** @var \PhpParser\Node\Stmt\Class_ $classBefore */
37-
$classAfter = $registryAfter->data['class'][$key];
57+
$classAfter = $classesAfterKeyed[$key];
3858

3959
// Leave non-strict comparison here
4060
if ($classBefore != $classAfter) {
61+
62+
// Check for case change of class name
63+
if(
64+
$classBefore->name !== $classAfter->name
65+
&& strtolower($classBefore->name) === strtolower($classAfter->name)
66+
) {
67+
$report->add($this->context, new ClassRenamedCaseOnly($fileAfter, $classAfter));
68+
}
69+
4170
$analyzers = [
4271
new ClassMethodAnalyzer('class', $fileBefore, $fileAfter),
4372
new PropertyAnalyzer('class', $fileBefore, $fileAfter),
@@ -51,8 +80,8 @@ public function analyze(Registry $registryBefore, Registry $registryAfter)
5180
}
5281

5382
foreach ($added as $key) {
54-
$fileAfter = $registryAfter->mapping['class'][$key];
55-
$classAfter = $registryAfter->data['class'][$key];
83+
$fileAfter = $mappingsAfterKeyed[$key];
84+
$classAfter = $classesAfterKeyed[$key];
5685

5786
$data = new ClassAdded($fileAfter, $classAfter);
5887
$report->addClass($data);

src/PHPSemVerChecker/Configuration/LevelMapping.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ class LevelMapping
125125
'V151' => Level::PATCH,
126126
'V152' => Level::PATCH,
127127
'V153' => Level::PATCH,
128+
'V154' => Level::PATCH,
128129
];
129130

130131
public static function getLevelForCode($code)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace PHPSemVerChecker\Operation;
4+
5+
use PhpParser\Node\Stmt\Class_;
6+
use PHPSemVerChecker\Node\Statement\Class_ as PClass;
7+
8+
class ClassRenamedCaseOnly extends Operation {
9+
/**
10+
* @var string
11+
*/
12+
protected $code = 'V154';
13+
/**
14+
* @var string
15+
*/
16+
protected $reason = 'Class was renamed (case only).';
17+
/**
18+
* @var string
19+
*/
20+
protected $fileAfter;
21+
/**
22+
* @var \PhpParser\Node\Stmt\Class_
23+
*/
24+
protected $classAfter;
25+
26+
/**
27+
* @param string $fileAfter
28+
* @param \PhpParser\Node\Stmt\Class_ $classAfter
29+
*/
30+
public function __construct($fileAfter, Class_ $classAfter)
31+
{
32+
$this->fileAfter = $fileAfter;
33+
$this->classAfter = $classAfter;
34+
}
35+
36+
/**
37+
* @return string
38+
*/
39+
public function getLocation()
40+
{
41+
return $this->fileAfter;
42+
}
43+
44+
/**
45+
* @return int
46+
*/
47+
public function getLine()
48+
{
49+
return $this->classAfter->getLine();
50+
}
51+
52+
/**
53+
* @return string
54+
*/
55+
public function getTarget()
56+
{
57+
return PClass::getFullyQualifiedName($this->classAfter);
58+
}
59+
}

tests/PHPSemVerChecker/Analyzer/ClassAnalyzerTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,23 @@ public function testClassRemoved()
6262
$this->assertSame('Class was removed.', $report[$context][$expectedLevel][0]->getReason());
6363
$this->assertSame('tmp', $report[$context][$expectedLevel][0]->getTarget());
6464
}
65+
66+
public function testClassRenamedCaseOnly()
67+
{
68+
$before = new Registry();
69+
$after = new Registry();
70+
71+
$before->addClass(new Class_('TestCLASS'));
72+
$after->addClass(new Class_('TestClass'));
73+
74+
$analyzer = new ClassAnalyzer();
75+
$report = $analyzer->analyze($before, $after);
76+
77+
$context = 'class';
78+
$expectedLevel = Level::PATCH;
79+
Assert::assertDifference($report, $context, $expectedLevel);
80+
$this->assertSame('V154', $report[$context][$expectedLevel][0]->getCode());
81+
$this->assertSame('Class was renamed (case only).', $report[$context][$expectedLevel][0]->getReason());
82+
$this->assertSame('TestClass', $report[$context][$expectedLevel][0]->getTarget());
83+
}
6584
}

0 commit comments

Comments
 (0)