diff --git a/README.md b/README.md
index 5288f6a95..da01b4c5a 100644
--- a/README.md
+++ b/README.md
@@ -335,9 +335,13 @@ new Foo\Bar();
* `namespacesRequiredToUse`: if not set, all namespaces are required to be used. When set, only mentioned namespaces are required to be used. Useful in tandem with UseOnlyWhitelistedNamespaces sniff.
* `allowFullyQualifiedNameForCollidingClasses`: allow fully qualified name for a class with a colliding use statement.
+* `allowFullyQualifiedNameForCollidingFunctions`: allow fully qualified name for a function with a colliding use statement.
+* `allowFullyQualifiedNameForCollidingConstants`: allow fully qualified name for a constant with a colliding use statement.
* `allowFullyQualifiedGlobalClasses`: allows using fully qualified classes from global space (i.e. `\DateTimeImmutable`).
* `allowFullyQualifiedGlobalFunctions`: allows using fully qualified functions from global space (i.e. `\phpversion()`).
* `allowFullyQualifiedGlobalConstants`: allows using fully qualified constants from global space (i.e. `\PHP_VERSION`).
+* `allowFallbackGlobalFunctions`: allows using global functions via fallback name without `use` (i.e. `phpversion()`).
+* `allowFallbackGlobalConstants`: allows using global constants via fallback name without `use` (i.e. `PHP_VERSION`).
#### SlevomatCodingStandard.Namespaces.UseOnlyWhitelistedNamespaces
diff --git a/SlevomatCodingStandard/Helpers/ConstantHelper.php b/SlevomatCodingStandard/Helpers/ConstantHelper.php
new file mode 100644
index 000000000..5b34dcb1f
--- /dev/null
+++ b/SlevomatCodingStandard/Helpers/ConstantHelper.php
@@ -0,0 +1,60 @@
+getTokens();
+ return $tokens[TokenHelper::findNext($codeSnifferFile, T_STRING, $constantPointer + 1)]['content'];
+ }
+
+ public static function getFullyQualifiedName(\PHP_CodeSniffer\Files\File $codeSnifferFile, int $constantPointer): string
+ {
+ $name = self::getName($codeSnifferFile, $constantPointer);
+ $namespace = NamespaceHelper::findCurrentNamespaceName($codeSnifferFile, $constantPointer);
+
+ return $namespace !== null ? sprintf('%s%s%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $namespace, NamespaceHelper::NAMESPACE_SEPARATOR, $name) : $name;
+ }
+
+ /**
+ * @param \PHP_CodeSniffer\Files\File $codeSnifferFile
+ * @return string[]
+ */
+ public static function getAllNames(\PHP_CodeSniffer\Files\File $codeSnifferFile): array
+ {
+ $previousConstantPointer = 0;
+
+ return array_map(
+ function (int $constantPointer) use ($codeSnifferFile): string {
+ return self::getName($codeSnifferFile, $constantPointer);
+ },
+ array_filter(
+ iterator_to_array(self::getAllConstantPointers($codeSnifferFile, $previousConstantPointer)),
+ function (int $constantPointer) use ($codeSnifferFile): bool {
+ foreach (array_reverse($codeSnifferFile->getTokens()[$constantPointer]['conditions']) as $conditionTokenCode) {
+ if (in_array($conditionTokenCode, [T_CLASS, T_INTERFACE, T_TRAIT, T_ANON_CLASS], true)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ )
+ );
+ }
+
+ private static function getAllConstantPointers(\PHP_CodeSniffer\Files\File $codeSnifferFile, int &$previousConstantPointer): \Generator
+ {
+ do {
+ $nextConstantPointer = TokenHelper::findNext($codeSnifferFile, T_CONST, $previousConstantPointer + 1);
+ if ($nextConstantPointer !== null) {
+ $previousConstantPointer = $nextConstantPointer;
+ yield $nextConstantPointer;
+ }
+ } while ($nextConstantPointer !== null);
+ }
+
+}
diff --git a/SlevomatCodingStandard/Helpers/FunctionHelper.php b/SlevomatCodingStandard/Helpers/FunctionHelper.php
index 976a0fc14..883d33601 100644
--- a/SlevomatCodingStandard/Helpers/FunctionHelper.php
+++ b/SlevomatCodingStandard/Helpers/FunctionHelper.php
@@ -218,4 +218,36 @@ public static function findReturnAnnotation(\PHP_CodeSniffer\Files\File $codeSni
return $returnAnnotations[0];
}
+ /**
+ * @param \PHP_CodeSniffer\Files\File $codeSnifferFile
+ * @return string[]
+ */
+ public static function getAllFunctionNames(\PHP_CodeSniffer\Files\File $codeSnifferFile): array
+ {
+ $previousFunctionPointer = 0;
+
+ return array_map(
+ function (int $functionPointer) use ($codeSnifferFile): string {
+ return self::getName($codeSnifferFile, $functionPointer);
+ },
+ array_filter(
+ iterator_to_array(self::getAllFunctionOrMethodPointers($codeSnifferFile, $previousFunctionPointer)),
+ function (int $functionOrMethodPointer) use ($codeSnifferFile): bool {
+ return !self::isMethod($codeSnifferFile, $functionOrMethodPointer);
+ }
+ )
+ );
+ }
+
+ private static function getAllFunctionOrMethodPointers(\PHP_CodeSniffer\Files\File $codeSnifferFile, int &$previousFunctionPointer): \Generator
+ {
+ do {
+ $nextFunctionPointer = TokenHelper::findNext($codeSnifferFile, T_FUNCTION, $previousFunctionPointer + 1);
+ if ($nextFunctionPointer !== null) {
+ $previousFunctionPointer = $nextFunctionPointer;
+ yield $nextFunctionPointer;
+ }
+ } while ($nextFunctionPointer !== null);
+ }
+
}
diff --git a/SlevomatCodingStandard/Helpers/ReferencedName.php b/SlevomatCodingStandard/Helpers/ReferencedName.php
index ce0595cc5..077030902 100644
--- a/SlevomatCodingStandard/Helpers/ReferencedName.php
+++ b/SlevomatCodingStandard/Helpers/ReferencedName.php
@@ -49,6 +49,11 @@ public function getEndPointer(): int
return $this->endPointer;
}
+ public function isClass(): bool
+ {
+ return $this->type === self::TYPE_DEFAULT;
+ }
+
public function isConstant(): bool
{
return $this->type === self::TYPE_CONSTANT;
diff --git a/SlevomatCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesOnlySniff.php b/SlevomatCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesOnlySniff.php
index 8d11811dd..dd6a85522 100644
--- a/SlevomatCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesOnlySniff.php
+++ b/SlevomatCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesOnlySniff.php
@@ -3,6 +3,8 @@
namespace SlevomatCodingStandard\Sniffs\Namespaces;
use SlevomatCodingStandard\Helpers\ClassHelper;
+use SlevomatCodingStandard\Helpers\ConstantHelper;
+use SlevomatCodingStandard\Helpers\FunctionHelper;
use SlevomatCodingStandard\Helpers\NamespaceHelper;
use SlevomatCodingStandard\Helpers\ReferencedName;
use SlevomatCodingStandard\Helpers\ReferencedNameHelper;
@@ -19,6 +21,8 @@ class ReferenceUsedNamesOnlySniff implements \PHP_CodeSniffer\Sniffs\Sniff
public const CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME_WITHOUT_NAMESPACE = 'ReferenceViaFullyQualifiedNameWithoutNamespace';
+ public const CODE_REFERENCE_VIA_FALLBACK_GLOBAL_NAME = 'ReferenceViaFallbackGlobalName';
+
public const CODE_PARTIAL_USE = 'PartialUse';
/** @var string[] */
@@ -36,9 +40,15 @@ class ReferenceUsedNamesOnlySniff implements \PHP_CodeSniffer\Sniffs\Sniff
/** @var bool */
public $allowFullyQualifiedGlobalFunctions = false;
+ /** @var bool */
+ public $allowFallbackGlobalFunctions = true;
+
/** @var bool */
public $allowFullyQualifiedGlobalConstants = false;
+ /** @var bool */
+ public $allowFallbackGlobalConstants = true;
+
/** @var string[] */
public $specialExceptionNames = [];
@@ -67,6 +77,12 @@ class ReferenceUsedNamesOnlySniff implements \PHP_CodeSniffer\Sniffs\Sniff
/** @var bool */
public $allowFullyQualifiedNameForCollidingClasses = false;
+ /** @var bool */
+ public $allowFullyQualifiedNameForCollidingFunctions = false;
+
+ /** @var bool */
+ public $allowFullyQualifiedNameForCollidingConstants = false;
+
/**
* @return mixed[]
*/
@@ -140,17 +156,51 @@ public function process(\PHP_CodeSniffer\Files\File $phpcsFile, $openTagPointer)
$tokens = $phpcsFile->getTokens();
$referencedNames = ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer);
+ $useStatements = UseStatementHelper::getUseStatements($phpcsFile, $openTagPointer);
+
$definedClassesIndex = array_flip(array_map(function (string $className): string {
return strtolower($className);
}, ClassHelper::getAllNames($phpcsFile)));
+ $definedFunctionsIndex = array_flip(array_map(function (string $functionName): string {
+ return strtolower($functionName);
+ }, FunctionHelper::getAllFunctionNames($phpcsFile)));
+ $definedConstantsIndex = array_flip(ConstantHelper::getAllNames($phpcsFile));
if ($this->allowFullyQualifiedNameForCollidingClasses) {
- $referencesIndex = array_flip(
+ $classReferencesIndex = array_flip(
+ array_map(
+ function (ReferencedName $referencedName): string {
+ return strtolower($referencedName->getNameAsReferencedInFile());
+ },
+ array_filter($referencedNames, function (ReferencedName $referencedName): bool {
+ return $referencedName->isClass();
+ })
+ )
+ );
+ }
+
+ if ($this->allowFullyQualifiedNameForCollidingFunctions) {
+ $functionReferencesIndex = array_flip(
array_map(
function (ReferencedName $referencedName): string {
return strtolower($referencedName->getNameAsReferencedInFile());
},
- $referencedNames
+ array_filter($referencedNames, function (ReferencedName $referencedName): bool {
+ return $referencedName->isFunction();
+ })
+ )
+ );
+ }
+
+ if ($this->allowFullyQualifiedNameForCollidingConstants) {
+ $constantReferencesIndex = array_flip(
+ array_map(
+ function (ReferencedName $referencedName): string {
+ return $referencedName->getNameAsReferencedInFile();
+ },
+ array_filter($referencedNames, function (ReferencedName $referencedName): bool {
+ return $referencedName->isConstant();
+ })
)
);
}
@@ -159,16 +209,33 @@ function (ReferencedName $referencedName): string {
$name = $referencedName->getNameAsReferencedInFile();
$nameStartPointer = $referencedName->getStartPointer();
$canonicalName = NamespaceHelper::normalizeToCanonicalName($name);
-
- if ($this->allowFullyQualifiedNameForCollidingClasses) {
- $unqualifiedClassName = strtolower(NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($name));
- if (isset($referencesIndex[$unqualifiedClassName]) || array_key_exists($unqualifiedClassName, $definedClassesIndex ?? [])) {
+ $unqualifiedName = NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($name);
+
+ $isFullyQualified = NamespaceHelper::isFullyQualifiedName($name);
+ $isGlobalFallback = !$isFullyQualified
+ && !NamespaceHelper::hasNamespace($name)
+ && !array_key_exists(UseStatement::getUniqueId($referencedName->getType(), $name), $useStatements);
+ $isGlobalFunctionFallback = $referencedName->isFunction() && $isGlobalFallback;
+ $isGlobalConstantFallback = $referencedName->isConstant() && $isGlobalFallback;
+
+ if ($referencedName->isClass() && $this->allowFullyQualifiedNameForCollidingClasses) {
+ $lowerCasedUnqualifiedClassName = strtolower($unqualifiedName);
+ if (isset($classReferencesIndex[$lowerCasedUnqualifiedClassName]) || array_key_exists($lowerCasedUnqualifiedClassName, $definedClassesIndex)) {
+ continue;
+ }
+ } elseif ($referencedName->isFunction() && $this->allowFullyQualifiedNameForCollidingFunctions) {
+ $lowerCasedUnqualifiedFunctionName = strtolower($unqualifiedName);
+ if (isset($functionReferencesIndex[$lowerCasedUnqualifiedFunctionName]) || array_key_exists($lowerCasedUnqualifiedFunctionName, $definedFunctionsIndex)) {
+ continue;
+ }
+ } elseif ($referencedName->isConstant() && $this->allowFullyQualifiedNameForCollidingConstants) {
+ if (isset($constantReferencesIndex[$unqualifiedName]) || array_key_exists($unqualifiedName, $definedConstantsIndex)) {
continue;
}
}
- if (NamespaceHelper::isFullyQualifiedName($name)) {
- if (!$this->isClassRequiredToBeUsed($name)) {
+ if ($isFullyQualified || $isGlobalFunctionFallback || $isGlobalConstantFallback) {
+ if ($isFullyQualified && !$this->isRequiredToBeUsed($name)) {
continue;
}
@@ -185,12 +252,15 @@ function (ReferencedName $referencedName): string {
$previousKeywordPointer = TokenHelper::findPreviousExcluding($phpcsFile, array_merge(TokenHelper::$nameTokenCodes, [T_WHITESPACE, T_COMMA]), $nameStartPointer - 1);
if (!in_array($tokens[$previousKeywordPointer]['code'], $this->getFullyQualifiedKeywords(), true)) {
if (
- !NamespaceHelper::hasNamespace($name)
+ $isFullyQualified
+ && !NamespaceHelper::hasNamespace($name)
&& NamespaceHelper::findCurrentNamespaceName($phpcsFile, $nameStartPointer) === null
) {
+ $label = sprintf($referencedName->isConstant() ? 'Constant %s' : ($referencedName->isFunction() ? 'Function %s()' : 'Class %s'), $name);
+
$fix = $phpcsFile->addFixableError(sprintf(
- 'Type %s should not be referenced via a fully qualified name, but via an unqualified name without the leading \\, because the file does not have a namespace and the type cannot be put in a use statement.',
- $name
+ '%s should not be referenced via a fully qualified name, but via an unqualified name without the leading \\, because the file does not have a namespace and the type cannot be put in a use statement.',
+ $label
), $nameStartPointer, self::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME_WITHOUT_NAMESPACE);
if ($fix) {
$phpcsFile->fixer->beginChangeset();
@@ -201,9 +271,9 @@ function (ReferencedName $referencedName): string {
$shouldBeUsed = NamespaceHelper::hasNamespace($name);
if (!$shouldBeUsed) {
if ($referencedName->isFunction()) {
- $shouldBeUsed = !$this->allowFullyQualifiedGlobalFunctions;
+ $shouldBeUsed = $isFullyQualified ? !$this->allowFullyQualifiedGlobalFunctions : !$this->allowFallbackGlobalFunctions;
} elseif ($referencedName->isConstant()) {
- $shouldBeUsed = !$this->allowFullyQualifiedGlobalConstants;
+ $shouldBeUsed = $isFullyQualified ? !$this->allowFullyQualifiedGlobalConstants : !$this->allowFallbackGlobalConstants;
} else {
$shouldBeUsed = !$this->allowFullyQualifiedGlobalClasses;
}
@@ -213,27 +283,41 @@ function (ReferencedName $referencedName): string {
continue;
}
- $useStatements = UseStatementHelper::getUseStatements($phpcsFile, $openTagPointer);
$nameToReference = NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($name);
- $canonicalNameToReference = strtolower($nameToReference);
+ $canonicalNameToReference = $referencedName->isConstant() ? $nameToReference : strtolower($nameToReference);
$canBeFixed = true;
foreach ($useStatements as $useStatement) {
+ if ($useStatement->getType() !== $referencedName->getType()) {
+ continue;
+ }
+
+ if ($useStatement->getFullyQualifiedTypeName() === $canonicalName) {
+ continue;
+ }
+
if (
- $useStatement->getType() === $referencedName->getType()
- && $useStatement->getFullyQualifiedTypeName() !== $canonicalName
- && ($useStatement->getCanonicalNameAsReferencedInFile() === $canonicalNameToReference || array_key_exists($canonicalNameToReference, $definedClassesIndex))
+ $useStatement->getCanonicalNameAsReferencedInFile() === $canonicalNameToReference
+ || ($referencedName->isClass() && array_key_exists($canonicalNameToReference, $definedClassesIndex))
+ || ($referencedName->isFunction() && array_key_exists($canonicalNameToReference, $definedFunctionsIndex))
+ || ($referencedName->isConstant() && array_key_exists($canonicalNameToReference, $definedConstantsIndex))
) {
$canBeFixed = false;
break;
}
}
- $errorMessage = sprintf('Type %s should not be referenced via a fully qualified name, but via a use statement.', $name);
+ $label = sprintf($referencedName->isConstant() ? 'Constant %s' : ($referencedName->isFunction() ? 'Function %s()' : 'Class %s'), $name);
+ $errorCode = $isGlobalConstantFallback || $isGlobalFunctionFallback
+ ? self::CODE_REFERENCE_VIA_FALLBACK_GLOBAL_NAME
+ : self::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME;
+ $errorMessage = $isGlobalConstantFallback || $isGlobalFunctionFallback
+ ? sprintf('%s should not be referenced via a fallback global name, but via a use statement.', $label)
+ : sprintf('%s should not be referenced via a fully qualified name, but via a use statement.', $label);
if ($canBeFixed) {
- $fix = $phpcsFile->addFixableError($errorMessage, $nameStartPointer, self::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME);
+ $fix = $phpcsFile->addFixableError($errorMessage, $nameStartPointer, $errorCode);
} else {
- $phpcsFile->addError($errorMessage, $nameStartPointer, self::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME);
+ $phpcsFile->addError($errorMessage, $nameStartPointer, $errorCode);
$fix = false;
}
@@ -286,7 +370,7 @@ function (ReferencedName $referencedName): string {
}
}
- private function isClassRequiredToBeUsed(string $name): bool
+ private function isRequiredToBeUsed(string $name): bool
{
if (count($this->namespacesRequiredToUse) === 0) {
return true;
diff --git a/build/phpcs.xml b/build/phpcs.xml
index f64c3acb8..addd5760a 100644
--- a/build/phpcs.xml
+++ b/build/phpcs.xml
@@ -49,6 +49,8 @@
+
+
diff --git a/tests/Helpers/ConstantHelperTest.php b/tests/Helpers/ConstantHelperTest.php
new file mode 100644
index 000000000..fe2011635
--- /dev/null
+++ b/tests/Helpers/ConstantHelperTest.php
@@ -0,0 +1,32 @@
+getCodeSnifferFile(__DIR__ . '/data/constantWithNamespace.php');
+
+ $constantPointer = $this->findConstantPointerByName($codeSnifferFile, 'FOO');
+ $this->assertSame('\FooNamespace\FOO', ConstantHelper::getFullyQualifiedName($codeSnifferFile, $constantPointer));
+ $this->assertSame('FOO', ConstantHelper::getName($codeSnifferFile, $constantPointer));
+ }
+
+ public function testNameWithoutNamespace(): void
+ {
+ $codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/constantWithoutNamespace.php');
+
+ $constantPointer = $this->findConstantPointerByName($codeSnifferFile, 'FOO');
+ $this->assertSame('FOO', ConstantHelper::getFullyQualifiedName($codeSnifferFile, $constantPointer));
+ $this->assertSame('FOO', ConstantHelper::getName($codeSnifferFile, $constantPointer));
+ }
+
+ public function testGetAllNames(): void
+ {
+ $codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/constantNames.php');
+ $this->assertSame(['FOO', 'BOO'], ConstantHelper::getAllNames($codeSnifferFile));
+ }
+
+}
diff --git a/tests/Helpers/FunctionHelperTest.php b/tests/Helpers/FunctionHelperTest.php
index 40a844691..ce547f94b 100644
--- a/tests/Helpers/FunctionHelperTest.php
+++ b/tests/Helpers/FunctionHelperTest.php
@@ -367,4 +367,10 @@ public function testAnnotations(): void
$this->assertNull(FunctionHelper::findReturnAnnotation($codeSnifferFile, $functionPointer));
}
+ public function testGetAllFunctionNames(): void
+ {
+ $codeSnifferFile = $this->getCodeSnifferFile(__DIR__ . '/data/functionNames.php');
+ $this->assertSame(['foo', 'boo'], FunctionHelper::getAllFunctionNames($codeSnifferFile));
+ }
+
}
diff --git a/tests/Helpers/data/constantNames.php b/tests/Helpers/data/constantNames.php
new file mode 100644
index 000000000..d629793ed
--- /dev/null
+++ b/tests/Helpers/data/constantNames.php
@@ -0,0 +1,14 @@
+checkFile(__DIR__ . '/data/shouldBeInUseStatement.php', [
+ 'allowFallbackGlobalFunctions' => false,
+ ]);
+ $this->assertSniffError(
+ $report,
+ 18,
+ ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FALLBACK_GLOBAL_NAME,
+ 'min'
+ );
+ }
+
+ public function testReferencingGlobalConstantViaFallback(): void
+ {
+ $report = $this->checkFile(__DIR__ . '/data/shouldBeInUseStatement.php', [
+ 'allowFallbackGlobalConstants' => false,
+ ]);
+ $this->assertSniffError(
+ $report,
+ 19,
+ ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FALLBACK_GLOBAL_NAME,
+ 'PHP_VERSION'
+ );
+ }
+
/**
* @dataProvider dataIgnoredNamesForIrrelevantTests
* @param string[] $ignoredNames
@@ -601,12 +627,14 @@ public function testAllowingFullyQualifiedGlobalConstants(): void
$this->assertNoSniffErrorInFile($report);
}
- public function testFixableReferenceViaFullyQualifiedName(): void
+ public function testFixableReferenceViaFullyQualifiedOrGlobalFallbackName(): void
{
$report = $this->checkFile(__DIR__ . '/data/fixableReferenceViaFullyQualifiedName.php', [
'fullyQualifiedKeywords' => ['T_EXTENDS'],
'allowFullyQualifiedExceptions' => true,
- ], [ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME]);
+ 'allowFallbackGlobalFunctions' => false,
+ 'allowFallbackGlobalConstants' => false,
+ ], [ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME, ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FALLBACK_GLOBAL_NAME]);
$this->assertAllFixedInFile($report);
}
@@ -707,4 +735,44 @@ public function testCollidingClassNameExtendsDisabled(): void
$this->assertSniffError($report, 5, ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME);
}
+ public function testCollidingFullyQualifiedFunctionNameAllowed(): void
+ {
+ $report = $this->checkFile(
+ __DIR__ . '/data/collidingFullyQualifiedFunctionNames.php',
+ ['allowFullyQualifiedNameForCollidingFunctions' => true]
+ );
+ $this->assertNoSniffErrorInFile($report);
+ }
+
+ public function testCollidingFullyQualifiedFunctionNameDisallowed(): void
+ {
+ $report = $this->checkFile(
+ __DIR__ . '/data/collidingFullyQualifiedFunctionNames.php',
+ ['allowFullyQualifiedNameForCollidingFunctions' => false]
+ );
+
+ $this->assertSame(1, $report->getErrorCount());
+ $this->assertSniffError($report, 15, ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME);
+ }
+
+ public function testCollidingFullyQualifiedConstantNameAllowed(): void
+ {
+ $report = $this->checkFile(
+ __DIR__ . '/data/collidingFullyQualifiedConstantNames.php',
+ ['allowFullyQualifiedNameForCollidingConstants' => true]
+ );
+ $this->assertNoSniffErrorInFile($report);
+ }
+
+ public function testCollidingFullyQualifiedConstantNameDisallowed(): void
+ {
+ $report = $this->checkFile(
+ __DIR__ . '/data/collidingFullyQualifiedConstantNames.php',
+ ['allowFullyQualifiedNameForCollidingConstants' => false]
+ );
+
+ $this->assertSame(1, $report->getErrorCount());
+ $this->assertSniffError($report, 12, ReferenceUsedNamesOnlySniff::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME);
+ }
+
}
diff --git a/tests/Sniffs/Namespaces/data/collidingFullyQualifiedConstantNames.php b/tests/Sniffs/Namespaces/data/collidingFullyQualifiedConstantNames.php
new file mode 100644
index 000000000..c002c15db
--- /dev/null
+++ b/tests/Sniffs/Namespaces/data/collidingFullyQualifiedConstantNames.php
@@ -0,0 +1,15 @@
+