Skip to content

Commit

Permalink
Merge pull request #653 from PHPCSStandards/feature/generic-duplicate…
Browse files Browse the repository at this point in the history
…classname-fix-bugs-performance

Generic/DuplicateClassName: 4 bug fixes + performance improvement
  • Loading branch information
jrfnl authored Nov 2, 2024
2 parents a22a1cb + 060338f commit f145bb4
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 44 deletions.
96 changes: 52 additions & 44 deletions src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Util\Tokens;

class DuplicateClassNameSniff implements Sniff
{
Expand Down Expand Up @@ -55,63 +56,70 @@ public function process(File $phpcsFile, $stackPtr)
T_TRAIT,
T_ENUM,
T_NAMESPACE,
T_CLOSE_TAG,
];

$stackPtr = $phpcsFile->findNext($findTokens, ($stackPtr + 1));
while ($stackPtr !== false) {
if ($tokens[$stackPtr]['code'] === T_CLOSE_TAG) {
// We can stop here. The sniff will continue from the next open
// tag when PHPCS reaches that token, if there is one.
return;
}

// Keep track of what namespace we are in.
if ($tokens[$stackPtr]['code'] === T_NAMESPACE) {
$nsEnd = $phpcsFile->findNext(
[
T_NS_SEPARATOR,
T_STRING,
T_WHITESPACE,
],
($stackPtr + 1),
null,
true
);

$namespace = trim($phpcsFile->getTokensAsString(($stackPtr + 1), ($nsEnd - $stackPtr - 1)));
$stackPtr = $nsEnd;
} else {
$nameToken = $phpcsFile->findNext(T_STRING, $stackPtr);
$name = $tokens[$nameToken]['content'];
if ($namespace !== '') {
$name = $namespace.'\\'.$name;
$nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true);
if ($nextNonEmpty !== false
// Ignore namespace keyword used as operator.
&& $tokens[$nextNonEmpty]['code'] !== T_NS_SEPARATOR
) {
$namespace = '';
for ($i = $nextNonEmpty; $i < $phpcsFile->numTokens; $i++) {
if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) {
continue;
}

if ($tokens[$i]['code'] !== T_STRING && $tokens[$i]['code'] !== T_NS_SEPARATOR) {
break;
}

$namespace .= $tokens[$i]['content'];
}

$stackPtr = $i;
}

$compareName = strtolower($name);
if (isset($this->foundClasses[$compareName]) === true) {
$type = strtolower($tokens[$stackPtr]['content']);
$file = $this->foundClasses[$compareName]['file'];
$line = $this->foundClasses[$compareName]['line'];
$error = 'Duplicate %s name "%s" found; first defined in %s on line %s';
$data = [
$type,
$name,
$file,
$line,
];
$phpcsFile->addWarning($error, $stackPtr, 'Found', $data);
} else {
$this->foundClasses[$compareName] = [
'file' => $phpcsFile->getFilename(),
'line' => $tokens[$stackPtr]['line'],
];
} else {
$name = $phpcsFile->getDeclarationName($stackPtr);
if (empty($name) === false) {
if ($namespace !== '') {
$name = $namespace.'\\'.$name;
}

$compareName = strtolower($name);
if (isset($this->foundClasses[$compareName]) === true) {
$type = strtolower($tokens[$stackPtr]['content']);
$file = $this->foundClasses[$compareName]['file'];
$line = $this->foundClasses[$compareName]['line'];
$error = 'Duplicate %s name "%s" found; first defined in %s on line %s';
$data = [
$type,
$name,
$file,
$line,
];
$phpcsFile->addWarning($error, $stackPtr, 'Found', $data);
} else {
$this->foundClasses[$compareName] = [
'file' => $phpcsFile->getFilename(),
'line' => $tokens[$stackPtr]['line'],
];
}
}//end if

if (isset($tokens[$stackPtr]['scope_closer']) === true) {
$stackPtr = $tokens[$stackPtr]['scope_closer'];
}
}//end if

$stackPtr = $phpcsFile->findNext($findTokens, ($stackPtr + 1));
}//end while

return $phpcsFile->numTokens;

}//end process()


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
namespace Code\IsNamespaced ?>

<?php
class MyClass {}
interface MyInterface {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
namespace Code\IsNamespaced;
class FooBar {}

namespace Code\AnotherNamespace;

namespace Code\IsNamespaced ?>

<?php
echo '123';
?>
<?php
class FooBar {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
namespace E;
namespace\functionCall();
class MyClass {}
interface YourInterface {}

namespace F;
namespace\functionCall();
class MyClass {}

namespace /*comment*/ G;
namespace\functionCall();
class MyClass {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php
namespace Foo\Bar;
class MyClass {}
interface YourInterface {}

namespace Foo /*comment*/ \ /*comment*/ Bar;
class MyClass {}
interface YourInterface {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php
namespace {
class MyClass {}
trait YourTrait {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

// Intentional parse error/live coding.
// This should be the only test in this file.
// This is a two-file test: test case file 97 and 98 belong together.
// Testing against false positives during live coding and invalid class names being stored in the cache.

class
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

// Intentional parse error/live coding.
// This should be the only test in this file.
// This is a two-file test: test case file 97 and 98 belong together.
// Testing against false positives during live coding and invalid class names being stored in the cache.

class
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

// Intentional parse error/live coding.
// This should be the only test in this file.
// Testing that the sniff is *not* triggered.

namespace
15 changes: 15 additions & 0 deletions src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ public function getWarningList($testFile='')
case 'DuplicateClassNameUnitTest.6.inc':
return [10 => 1];

case 'DuplicateClassNameUnitTest.8.inc':
return [
7 => 1,
8 => 1,
];

case 'DuplicateClassNameUnitTest.9.inc':
return [
3 => 1,
4 => 1,
];

case 'DuplicateClassNameUnitTest.11.inc':
return [13 => 1];

default:
return [];
}//end switch
Expand Down

0 comments on commit f145bb4

Please sign in to comment.