diff --git a/InfinityloopCodingStandard/Sniffs/Classes/ConstructorPropertyPromotionSpacingSniff.php b/InfinityloopCodingStandard/Sniffs/Classes/ConstructorPropertyPromotionSpacingSniff.php
index 990d52e..ad1a1ca 100644
--- a/InfinityloopCodingStandard/Sniffs/Classes/ConstructorPropertyPromotionSpacingSniff.php
+++ b/InfinityloopCodingStandard/Sniffs/Classes/ConstructorPropertyPromotionSpacingSniff.php
@@ -4,6 +4,10 @@
namespace InfinityloopCodingStandard\Sniffs\Classes;
+use \SlevomatCodingStandard\Helpers\FunctionHelper;
+use \SlevomatCodingStandard\Helpers\SniffSettingsHelper;
+use \SlevomatCodingStandard\Helpers\TokenHelper;
+
class ConstructorPropertyPromotionSpacingSniff implements \PHP_CodeSniffer\Sniffs\Sniff
{
public const CONSTRUCTOR_PARAMETER_SAME_LINE = 'ConstructorParametersOnSameLine';
@@ -15,19 +19,19 @@ public function register() : array
public function process(\PHP_CodeSniffer\Files\File $phpcsFile, $functionPointer) : void
{
- if (!\SlevomatCodingStandard\Helpers\SniffSettingsHelper::isEnabledByPhpVersion(null, 80000)) {
+ if (!SniffSettingsHelper::isEnabledByPhpVersion(null, 80000)) {
return;
}
$tokens = $phpcsFile->getTokens();
- $namePointer = \SlevomatCodingStandard\Helpers\TokenHelper::findNextEffective($phpcsFile, $functionPointer + 1);
+ $namePointer = TokenHelper::findNextEffective($phpcsFile, $functionPointer + 1);
if (\strtolower($tokens[$namePointer]['content']) !== '__construct') {
return;
}
- if (\SlevomatCodingStandard\Helpers\FunctionHelper::isAbstract($phpcsFile, $functionPointer)) {
+ if (FunctionHelper::isAbstract($phpcsFile, $functionPointer)) {
return;
}
@@ -40,13 +44,13 @@ public function process(\PHP_CodeSniffer\Files\File $phpcsFile, $functionPointer
$containsPropertyPromotion = false;
foreach ($parameterPointers as $parameterPointer) {
- $pointerBefore = \SlevomatCodingStandard\Helpers\TokenHelper::findPrevious(
+ $pointerBefore = TokenHelper::findPrevious(
$phpcsFile,
[\T_COMMA, \T_OPEN_PARENTHESIS],
$parameterPointer - 1,
);
- $visibilityPointer = \SlevomatCodingStandard\Helpers\TokenHelper::findNextEffective($phpcsFile, $pointerBefore + 1);
+ $visibilityPointer = TokenHelper::findNextEffective($phpcsFile, $pointerBefore + 1);
if (\in_array($tokens[$visibilityPointer]['code'], \PHP_CodeSniffer\Util\Tokens::$scopeModifiers, true)) {
$containsPropertyPromotion = true;
@@ -58,7 +62,7 @@ public function process(\PHP_CodeSniffer\Files\File $phpcsFile, $functionPointer
}
if (\count($parameterPointers) === 1) {
- $pointerBefore = \SlevomatCodingStandard\Helpers\TokenHelper::findPrevious(
+ $pointerBefore = TokenHelper::findPrevious(
$phpcsFile,
[\T_COMMA, \T_OPEN_PARENTHESIS],
$parameterPointers[0],
@@ -110,7 +114,7 @@ public function process(\PHP_CodeSniffer\Files\File $phpcsFile, $functionPointer
$phpcsFile->fixer->beginChangeset();
- $pointerBefore = \SlevomatCodingStandard\Helpers\TokenHelper::findPrevious(
+ $pointerBefore = TokenHelper::findPrevious(
$phpcsFile,
[\T_COMMA, \T_OPEN_PARENTHESIS],
$parameterPointer - 1,
@@ -126,7 +130,7 @@ private function getParameterPointers(\PHP_CodeSniffer\Files\File $phpcsFile, in
{
$tokens = $phpcsFile->getTokens();
- return \SlevomatCodingStandard\Helpers\TokenHelper::findNextAll(
+ return TokenHelper::findNextAll(
$phpcsFile,
\T_VARIABLE,
$tokens[$functionPointer]['parenthesis_opener'] + 1,
diff --git a/InfinityloopCodingStandard/Sniffs/ControlStructures/RequireMultiLineNullCoalesceSniff.php b/InfinityloopCodingStandard/Sniffs/ControlStructures/RequireMultiLineNullCoalesceSniff.php
index 840f9b2..41c9ee5 100644
--- a/InfinityloopCodingStandard/Sniffs/ControlStructures/RequireMultiLineNullCoalesceSniff.php
+++ b/InfinityloopCodingStandard/Sniffs/ControlStructures/RequireMultiLineNullCoalesceSniff.php
@@ -4,6 +4,7 @@
namespace InfinityloopCodingStandard\Sniffs\ControlStructures;
+use \PHP_CodeSniffer\Files\File;
use \SlevomatCodingStandard\Helpers\TokenHelper;
class RequireMultiLineNullCoalesceSniff implements \PHP_CodeSniffer\Sniffs\Sniff
@@ -24,7 +25,7 @@ public function register() : array
}
//@phpcs:ignore Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
- public function process(\PHP_CodeSniffer\Files\File $phpcsFile, $coalescePointer) : void
+ public function process(File $phpcsFile, $coalescePointer) : void
{
$tokens = $phpcsFile->getTokens();
diff --git a/InfinityloopCodingStandard/Sniffs/ControlStructures/SwitchCommentSpacingSniff.php b/InfinityloopCodingStandard/Sniffs/ControlStructures/SwitchCommentSpacingSniff.php
index 8f79cc9..7a30b76 100644
--- a/InfinityloopCodingStandard/Sniffs/ControlStructures/SwitchCommentSpacingSniff.php
+++ b/InfinityloopCodingStandard/Sniffs/ControlStructures/SwitchCommentSpacingSniff.php
@@ -4,6 +4,7 @@
namespace InfinityloopCodingStandard\Sniffs\ControlStructures;
+use \PHP_CodeSniffer\Files\File;
use \SlevomatCodingStandard\Helpers\TokenHelper;
class SwitchCommentSpacingSniff implements \PHP_CodeSniffer\Sniffs\Sniff
@@ -21,7 +22,7 @@ public function register() : array
}
//@phpcs:ignore Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
- public function process(\PHP_CodeSniffer\Files\File $phpcsFile, $stackPtr) : void
+ public function process(File $phpcsFile, $stackPtr) : void
{
$tokens = $phpcsFile->getTokens();
@@ -127,7 +128,7 @@ public function process(\PHP_CodeSniffer\Files\File $phpcsFile, $stackPtr) : voi
}
}
- private function findNextCase(\PHP_CodeSniffer\Files\File $phpcsFile, int|bool|null $stackPtr, ?int $end = null) : bool|int
+ private function findNextCase(File $phpcsFile, int|bool|null $stackPtr, ?int $end = null) : bool|int
{
$tokens = $phpcsFile->getTokens();
@@ -145,7 +146,7 @@ private function findNextCase(\PHP_CodeSniffer\Files\File $phpcsFile, int|bool|n
return $stackPtr;
}
- private function getEndOfLineBefore(\PHP_CodeSniffer\Files\File $phpcsFile, int $pointer) : int
+ private function getEndOfLineBefore(File $phpcsFile, int $pointer) : int
{
$tokens = $phpcsFile->getTokens();
@@ -193,7 +194,7 @@ private function getEndOfLineBefore(\PHP_CodeSniffer\Files\File $phpcsFile, int
return $endOfLineBefore;
}
- private function getIndentation(\PHP_CodeSniffer\Files\File $phpcsFile, int $endOfLinePointer) : string
+ private function getIndentation(File $phpcsFile, int $endOfLinePointer) : string
{
$pointerAfterWhitespace = TokenHelper::findNextExcluding($phpcsFile, \T_WHITESPACE, $endOfLinePointer + 1);
$actualIndentation = TokenHelper::getContent($phpcsFile, $endOfLinePointer + 1, $pointerAfterWhitespace - 1);
diff --git a/InfinityloopCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesAfterUsageSniff.php b/InfinityloopCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesAfterUsageSniff.php
new file mode 100644
index 0000000..bb77768
--- /dev/null
+++ b/InfinityloopCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesAfterUsageSniff.php
@@ -0,0 +1,478 @@
+
+ */
+ public function register() : array
+ {
+ return [
+ \T_OPEN_TAG,
+ ];
+ }
+
+ //@phpcs:ignore Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
+ public function process(File $phpcsFile, $openTagPointer) : void
+ {
+ if (TokenHelper::findPrevious($phpcsFile, \T_OPEN_TAG, $openTagPointer - 1) !== null) {
+ return;
+ }
+
+ $tokens = $phpcsFile->getTokens();
+ $references = $this->getReferences($phpcsFile, $openTagPointer);
+ $definedClassesIndex = [];
+
+ foreach (ClassHelper::getAllNames($phpcsFile) as $definedClassPointer => $definedClassName) {
+ $definedClassesIndex[\strtolower($definedClassName)] = NamespaceHelper::resolveClassName(
+ $phpcsFile,
+ $definedClassName,
+ $definedClassPointer,
+ );
+ }
+
+ $classReferencesIndex = [];
+ $classReferences = \array_filter($references, static function (\stdClass $reference) : bool {
+ return $reference->source === self::SOURCE_CODE && $reference->isClass;
+ });
+
+ foreach ($classReferences as $classReference) {
+ $classReferencesIndex[\strtolower($classReference->name)] = NamespaceHelper::resolveName(
+ $phpcsFile,
+ $classReference->name,
+ $classReference->type,
+ $classReference->startPointer,
+ );
+ }
+
+ $namespacePointers = NamespaceHelper::getAllNamespacesPointers($phpcsFile);
+ $referenceErrors = [];
+ $referenced = [];
+
+ foreach ($references as $reference) {
+ $canonicalName = NamespaceHelper::normalizeToCanonicalName($reference->name);
+
+ if (isset($referenced[$canonicalName])) {
+ $referenced[$canonicalName]++;
+ } else {
+ $referenced[$canonicalName] = 1;
+ }
+ }
+
+ foreach ($references as $reference) {
+ $useStatements = UseStatementHelper::getUseStatementsForPointer($phpcsFile, $reference->startPointer);
+ $name = $reference->name;
+ $startPointer = $reference->startPointer;
+ $canonicalName = NamespaceHelper::normalizeToCanonicalName($name);
+ $isFullyQualified = NamespaceHelper::isFullyQualifiedName($name);
+
+ if ($reference->isClass === true && !NamespaceHelper::hasNamespace($name) && $isFullyQualified) {
+ continue;
+ }
+
+ if ($reference->isFunction === true && !NamespaceHelper::hasNamespace($name) && $isFullyQualified) {
+ continue;
+ }
+
+ if ($reference->isConstant === true && !NamespaceHelper::hasNamespace($name) && $isFullyQualified) {
+ continue;
+ }
+
+ if (
+ $isFullyQualified
+ && !NamespaceHelper::hasNamespace($name)
+ && $namespacePointers === []
+ ) {
+ $label = \sprintf('Class %s', $name);
+
+ $fix = $phpcsFile->addFixableError(\sprintf(
+ '%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,
+ ), $startPointer, self::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME_WITHOUT_NAMESPACE);
+
+ if ($fix) {
+ $phpcsFile->fixer->beginChangeset();
+
+ if ($reference->source === self::SOURCE_ANNOTATION) {
+ $fixedAnnotationContent = AnnotationHelper::fixAnnotationType(
+ $phpcsFile,
+ $reference->annotation,
+ $reference->nameNode,
+ new IdentifierTypeNode(\substr($reference->name, 1)),
+ );
+
+ $phpcsFile->fixer->replaceToken($startPointer, $fixedAnnotationContent);
+
+ for ($i = $startPointer + 1; $i <= $reference->endPointer; $i++) {
+ $phpcsFile->fixer->replaceToken($i, '');
+ }
+ } elseif ($reference->source === self::SOURCE_ANNOTATION_CONSTANT_FETCH) {
+ $fixedAnnotationContent = AnnotationHelper::fixAnnotationConstantFetchNode(
+ $phpcsFile,
+ $reference->annotation,
+ $reference->constantFetchNode,
+ new ConstFetchNode(\substr($reference->name, 1), $reference->constantFetchNode->name),
+ );
+
+ $phpcsFile->fixer->replaceToken($startPointer, $fixedAnnotationContent);
+
+ for ($i = $startPointer + 1; $i <= $reference->endPointer; $i++) {
+ $phpcsFile->fixer->replaceToken($i, '');
+ }
+ } else {
+ $phpcsFile->fixer->replaceToken($startPointer, \substr($tokens[$startPointer]['content'], 1));
+ }
+
+ $phpcsFile->fixer->endChangeset();
+ }
+ } else {
+ $shouldBeUsed = NamespaceHelper::hasNamespace($name);
+
+ if (!$shouldBeUsed) {
+ $shouldBeUsed = $isFullyQualified;
+ }
+
+ if (!$shouldBeUsed
+ || ($this->count !== null && $referenced[$canonicalName] < $this->count)
+ && ($this->length !== null && $this->length > \strlen($canonicalName))
+ ) {
+ continue;
+ }
+
+ $reason = '';
+
+ if ($referenced[$canonicalName] >= $this->count) {
+ $reason = 'because it\'s used more than ' . $this->count . ' times.';
+ }
+
+ if ($this->length !== null && $this->length < \strlen($canonicalName)) {
+ $reason = $reason === ''
+ ? 'because it\'s length is more than ' . $this->length . ' symbols.'
+ : 'because it\'s used more than ' . $this->count . ' times and it\'s length is more than '
+ . $this->length . ' symbols.';
+ }
+
+ $referenceErrors[] = (object) [
+ 'reference' => $reference,
+ 'canonicalName' => $canonicalName,
+ 'reason' => $reason,
+ ];
+ }
+ }
+
+ if (\count($referenceErrors) === 0) {
+ return;
+ }
+
+ $alreadyAddedUses = [
+ UseStatement::TYPE_CLASS => [],
+ UseStatement::TYPE_FUNCTION => [],
+ UseStatement::TYPE_CONSTANT => [],
+ ];
+
+ $phpcsFile->fixer->beginChangeset();
+
+ foreach ($referenceErrors as $referenceData) {
+ $reference = $referenceData->reference;
+ $startPointer = $reference->startPointer;
+ $canonicalName = $referenceData->canonicalName;
+ $useStatements = UseStatementHelper::getUseStatementsForPointer($phpcsFile, $reference->startPointer);
+ [$nameToReference, $isConflicting] = $this->getNormalizedClassName($reference->name, $useStatements);
+ $canonicalNameToReference = \strtolower($nameToReference);
+
+ $canBeFixed = \array_reduce(
+ $alreadyAddedUses[$reference->type],
+ static function (bool $carry, string $use) use ($canonicalName) : bool {
+ $useLastName = \strtolower(NamespaceHelper::getLastNamePart($use));
+ $canonicalLastName = \strtolower(NamespaceHelper::getLastNamePart($canonicalName));
+
+ return $useLastName === $canonicalLastName
+ ? false
+ : $carry;
+ },
+ true,
+ );
+
+ if (
+ (
+ $reference->isClass
+ && \array_key_exists($canonicalNameToReference, $definedClassesIndex)
+ && $canonicalName !== NamespaceHelper::normalizeToCanonicalName($definedClassesIndex[$canonicalNameToReference])
+ )
+ || (
+ $reference->isClass
+ && \array_key_exists($canonicalNameToReference, $classReferencesIndex)
+ && $canonicalName !== NamespaceHelper::normalizeToCanonicalName($classReferencesIndex[$canonicalNameToReference])
+ )
+ ) {
+ $canBeFixed = false;
+ }
+
+ foreach ($useStatements as $useStatement) {
+ if ($useStatement->getType() !== $reference->type) {
+ continue;
+ }
+
+ if ($useStatement->getFullyQualifiedTypeName() === $canonicalName) {
+ continue;
+ }
+
+ if ($useStatement->getCanonicalNameAsReferencedInFile() !== $canonicalNameToReference) {
+ continue;
+ }
+
+ $canBeFixed = false;
+
+ break;
+ }
+
+ $label = \sprintf('Class %s', $reference->name);
+ $errorCode = self::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME;
+ $errorMessage = \sprintf(
+ '%s should not be referenced via a fully qualified name, but via a use statement ' . $referenceData->reason,
+ $label,
+ );
+
+ if (!$canBeFixed) {
+ $phpcsFile->addError($errorMessage, $startPointer, $errorCode);
+
+ continue;
+ }
+
+ $fix = $phpcsFile->addFixableError($errorMessage, $startPointer, $errorCode);
+
+ if (!$fix) {
+ continue;
+ }
+
+ $addUse = !\in_array($canonicalName, $alreadyAddedUses[$reference->type], true);
+
+ if ($reference->isClass
+ && \array_key_exists($canonicalNameToReference, $definedClassesIndex)
+ ) {
+ $addUse = false;
+ }
+
+ foreach ($useStatements as $useStatement) {
+ if ($useStatement->getType() !== $reference->type
+ || $useStatement->getFullyQualifiedTypeName() !== $canonicalName
+ ) {
+ continue;
+ }
+
+ $nameToReference = $useStatement->getNameAsReferencedInFile();
+ $addUse = false;
+ }
+
+ if ($addUse) {
+ $useStatementPlacePointer = $this->getUseStatementPlacePointer($phpcsFile, $openTagPointer, $useStatements);
+ $useTypeName = UseStatement::getTypeName($reference->type);
+ $useTypeFormatted = $useTypeName !== null
+ ? \sprintf('%s ', $useTypeName)
+ : '';
+
+ $phpcsFile->fixer->addNewline($useStatementPlacePointer);
+
+ if ($isConflicting === true) {
+ $phpcsFile->fixer->addContent(
+ $useStatementPlacePointer,
+ \sprintf('use %s%s as %s;', $useTypeFormatted, $canonicalName, $nameToReference),
+ );
+ } else {
+ $phpcsFile->fixer->addContent($useStatementPlacePointer, \sprintf('use %s%s;', $useTypeFormatted, $canonicalName));
+ }
+
+ $alreadyAddedUses[$reference->type][] = $canonicalName;
+ }
+
+ if ($reference->source === self::SOURCE_ANNOTATION) {
+ $fixedAnnotationContent = AnnotationHelper::fixAnnotationType(
+ $phpcsFile,
+ $reference->annotation,
+ $reference->nameNode,
+ new IdentifierTypeNode($nameToReference),
+ );
+ $phpcsFile->fixer->replaceToken($startPointer, $fixedAnnotationContent);
+ } elseif ($reference->source === self::SOURCE_ANNOTATION_CONSTANT_FETCH) {
+ $fixedAnnotationContent = AnnotationHelper::fixAnnotationConstantFetchNode(
+ $phpcsFile,
+ $reference->annotation,
+ $reference->constantFetchNode,
+ new ConstFetchNode($nameToReference, $reference->constantFetchNode->name),
+ );
+ $phpcsFile->fixer->replaceToken($startPointer, $fixedAnnotationContent);
+ } elseif ($reference->source === self::SOURCE_ATTRIBUTE) {
+ $attributeContent = TokenHelper::getContent($phpcsFile, $startPointer, $reference->endPointer);
+ $fixedAttributeContent = \preg_replace(
+ '~(?<=\W)' . \preg_quote($reference->name, '~') . '(?=\W)~',
+ $nameToReference,
+ $attributeContent,
+ );
+ $phpcsFile->fixer->replaceToken($startPointer, $fixedAttributeContent);
+ } else {
+ $phpcsFile->fixer->replaceToken($startPointer, $nameToReference);
+ }
+
+ for ($i = $startPointer + 1; $i <= $reference->endPointer; $i++) {
+ $phpcsFile->fixer->replaceToken($i, '');
+ }
+ }
+
+ $phpcsFile->fixer->endChangeset();
+ }
+
+ private function getUseStatementPlacePointer(\PHP_CodeSniffer\Files\File $phpcsFile, int $openTagPointer, array $useStatements) : int
+ {
+ if (\count($useStatements) !== 0) {
+ $lastUseStatement = \array_values($useStatements)[\count($useStatements) - 1];
+
+ return TokenHelper::findNext($phpcsFile, \T_SEMICOLON, $lastUseStatement->getPointer() + 1);
+ }
+
+ $namespacePointer = TokenHelper::findNext($phpcsFile, \T_NAMESPACE, $openTagPointer + 1);
+
+ if ($namespacePointer !== null) {
+ return TokenHelper::findNext($phpcsFile, [\T_SEMICOLON, \T_OPEN_CURLY_BRACKET], $namespacePointer + 1);
+ }
+
+ $tokens = $phpcsFile->getTokens();
+
+ $useStatementPlacePointer = $openTagPointer;
+
+ $nonWhitespacePointerAfterOpenTag = TokenHelper::findNextExcluding($phpcsFile, \T_WHITESPACE, $openTagPointer + 1);
+
+ if (\in_array($tokens[$nonWhitespacePointerAfterOpenTag]['code'], \PHP_CodeSniffer\Util\Tokens::$commentTokens, true)) {
+ $commentEndPointer = CommentHelper::getCommentEndPointer($phpcsFile, $nonWhitespacePointerAfterOpenTag);
+
+ if (StringHelper::endsWith($tokens[$commentEndPointer]['content'], $phpcsFile->eolChar)) {
+ $useStatementPlacePointer = $commentEndPointer;
+ } else {
+ $newLineAfterComment = $commentEndPointer + 1;
+
+ if (\array_key_exists($newLineAfterComment, $tokens) && $tokens[$newLineAfterComment]['content'] === $phpcsFile->eolChar) {
+ $pointerAfterCommentEnd = TokenHelper::findNextExcluding($phpcsFile, \T_WHITESPACE, $newLineAfterComment + 1);
+
+ //@phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
+ if (TokenHelper::findNextContent($phpcsFile, \T_WHITESPACE, $phpcsFile->eolChar, $newLineAfterComment + 1, $pointerAfterCommentEnd) !== null) {
+ $useStatementPlacePointer = $commentEndPointer;
+ }
+ }
+ }
+ }
+
+ $pointerAfter = TokenHelper::findNextEffective($phpcsFile, $useStatementPlacePointer + 1);
+
+ if ($tokens[$pointerAfter]['code'] === \T_DECLARE) {
+ return TokenHelper::findNext($phpcsFile, \T_SEMICOLON, $pointerAfter + 1);
+ }
+
+ return $useStatementPlacePointer;
+ }
+
+ private function getReferences(\PHP_CodeSniffer\Files\File $phpcsFile, int $openTagPointer) : array
+ {
+ $references = [];
+
+ foreach (ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer) as $referencedName) {
+ $reference = new \stdClass();
+ $reference->source = self::SOURCE_CODE;
+ $reference->name = $referencedName->getNameAsReferencedInFile();
+ $reference->type = $referencedName->getType();
+ $reference->startPointer = $referencedName->getStartPointer();
+ $reference->endPointer = $referencedName->getEndPointer();
+ $reference->isClass = $referencedName->isClass();
+ $reference->isConstant = $referencedName->isConstant();
+ $reference->isFunction = $referencedName->isFunction();
+
+ $references[] = $reference;
+ }
+
+ foreach (ReferencedNameHelper::getAllReferencedNamesInAttributes($phpcsFile, $openTagPointer) as $referencedName) {
+ $reference = new \stdClass();
+ $reference->source = self::SOURCE_ATTRIBUTE;
+ $reference->name = $referencedName->getNameAsReferencedInFile();
+ $reference->type = $referencedName->getType();
+ $reference->startPointer = $referencedName->getStartPointer();
+ $reference->endPointer = $referencedName->getEndPointer();
+ $reference->isClass = $referencedName->isClass();
+ $reference->isConstant = $referencedName->isConstant();
+ $reference->isFunction = $referencedName->isFunction();
+
+ $references[] = $reference;
+ }
+
+ return $references;
+ }
+
+ private function getNormalizedClassName(string $name, array $useStatements) : array
+ {
+ $unqualifiedName = NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($name);
+
+ foreach ($useStatements as $useStatement) {
+ $useStatementUnqualified = NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($useStatement->getFullyQualifiedTypeName());
+
+ if ($unqualifiedName !== $useStatementUnqualified) {
+ continue;
+ }
+
+ $nameSplit = \explode('\\', \ltrim($name, '\\'));
+ $useStatementSplit = \explode('\\', \ltrim($useStatement->getFullyQualifiedTypeName(), '\\'));
+
+ $i = 0;
+ $toUse = null;
+
+ foreach ($nameSplit as $value) {
+ if (!isset($useStatementSplit[$i])) {
+ break;
+ }
+
+ if (\substr($value, 0, 1) !== \substr($useStatementSplit[$i], 0, 1)) {
+ $toUse = \substr($value, 0, 1);
+
+ break;
+ }
+
+ $i++;
+ }
+
+ return $toUse === null
+ ? [$unqualifiedName, false]
+ : [$toUse . $unqualifiedName, true];
+ }
+
+ return [$unqualifiedName, false];
+ }
+}
diff --git a/InfinityloopCodingStandard/Sniffs/TypeHints/UnionTypeHintFormatSniff.php b/InfinityloopCodingStandard/Sniffs/TypeHints/UnionTypeHintFormatSniff.php
index 3e28550..722eab6 100644
--- a/InfinityloopCodingStandard/Sniffs/TypeHints/UnionTypeHintFormatSniff.php
+++ b/InfinityloopCodingStandard/Sniffs/TypeHints/UnionTypeHintFormatSniff.php
@@ -4,6 +4,13 @@
namespace InfinityloopCodingStandard\Sniffs\TypeHints;
+use \PHP_CodeSniffer\Files\File;
+use \SlevomatCodingStandard\Helpers\FunctionHelper;
+use \SlevomatCodingStandard\Helpers\PropertyHelper;
+use \SlevomatCodingStandard\Helpers\SniffSettingsHelper;
+use \SlevomatCodingStandard\Helpers\TokenHelper;
+use \SlevomatCodingStandard\Helpers\TypeHint;
+
/**
* https://github.com/slevomat/coding-standard/blob/master/SlevomatCodingStandard/Sniffs/TypeHints/UnionTypeHintFormatSniff.php
*/
@@ -22,7 +29,7 @@ public function register() : array
{
return \array_merge(
[\T_VARIABLE],
- \SlevomatCodingStandard\Helpers\TokenHelper::$functionTokenCodes,
+ TokenHelper::$functionTokenCodes,
);
}
@@ -32,20 +39,20 @@ public function register() : array
* @param int $pointer
*/
//@phpcs:ignore Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
- public function process(\PHP_CodeSniffer\Files\File $phpcsFile, $pointer) : void
+ public function process(File $phpcsFile, $pointer) : void
{
- if (!\SlevomatCodingStandard\Helpers\SniffSettingsHelper::isEnabledByPhpVersion(null, 80000)) {
+ if (!SniffSettingsHelper::isEnabledByPhpVersion(null, 80000)) {
return;
}
$tokens = $phpcsFile->getTokens();
if ($tokens[$pointer]['code'] === \T_VARIABLE) {
- if (!\SlevomatCodingStandard\Helpers\PropertyHelper::isProperty($phpcsFile, $pointer)) {
+ if (!PropertyHelper::isProperty($phpcsFile, $pointer)) {
return;
}
- $propertyTypeHint = \SlevomatCodingStandard\Helpers\PropertyHelper::findTypeHint($phpcsFile, $pointer);
+ $propertyTypeHint = PropertyHelper::findTypeHint($phpcsFile, $pointer);
if ($propertyTypeHint !== null) {
$this->checkTypeHint($phpcsFile, $propertyTypeHint);
@@ -54,20 +61,20 @@ public function process(\PHP_CodeSniffer\Files\File $phpcsFile, $pointer) : void
return;
}
- $returnTypeHint = \SlevomatCodingStandard\Helpers\FunctionHelper::findReturnTypeHint($phpcsFile, $pointer);
+ $returnTypeHint = FunctionHelper::findReturnTypeHint($phpcsFile, $pointer);
if ($returnTypeHint !== null) {
$this->checkTypeHint($phpcsFile, $returnTypeHint);
}
- foreach (\SlevomatCodingStandard\Helpers\FunctionHelper::getParametersTypeHints($phpcsFile, $pointer) as $parameterTypeHint) {
+ foreach (FunctionHelper::getParametersTypeHints($phpcsFile, $pointer) as $parameterTypeHint) {
if ($parameterTypeHint !== null) {
$this->checkTypeHint($phpcsFile, $parameterTypeHint);
}
}
}
- private function checkTypeHint(\PHP_CodeSniffer\Files\File $phpcsFile, \SlevomatCodingStandard\Helpers\TypeHint $typeHint) : void
+ private function checkTypeHint(File $phpcsFile, TypeHint $typeHint) : void
{
$tokens = $phpcsFile->getTokens();
@@ -78,7 +85,7 @@ private function checkTypeHint(\PHP_CodeSniffer\Files\File $phpcsFile, \Slevomat
$isOneline = true;
foreach (
- \SlevomatCodingStandard\Helpers\TokenHelper::findNextAll(
+ TokenHelper::findNextAll(
$phpcsFile,
[\T_TYPE_UNION],
$typeHint->getStartPointer(),
@@ -93,7 +100,7 @@ private function checkTypeHint(\PHP_CodeSniffer\Files\File $phpcsFile, \Slevomat
);
}
- $nextUnionType = \SlevomatCodingStandard\Helpers\TokenHelper::findNextEffective($phpcsFile, $unionSeparator + 1);
+ $nextUnionType = TokenHelper::findNextEffective($phpcsFile, $unionSeparator + 1);
if ($tokens[$nextUnionType]['line'] === $firstUnionType['line']) {
continue;
@@ -132,7 +139,7 @@ private function checkTypeHint(\PHP_CodeSniffer\Files\File $phpcsFile, \Slevomat
}
for ($i = 0; $i < \abs($difference); $i++) {
- $token = \SlevomatCodingStandard\Helpers\TokenHelper::findPrevious(
+ $token = TokenHelper::findPrevious(
$phpcsFile,
[\T_WHITESPACE],
$nextUnionType - $i,
@@ -154,7 +161,7 @@ private function checkTypeHint(\PHP_CodeSniffer\Files\File $phpcsFile, \Slevomat
}
if ($isOneline) {
- $whitespacePointer = \SlevomatCodingStandard\Helpers\TokenHelper::findNext(
+ $whitespacePointer = TokenHelper::findNext(
$phpcsFile,
\T_WHITESPACE,
$typeHint->getStartPointer() + 1,
@@ -162,7 +169,7 @@ private function checkTypeHint(\PHP_CodeSniffer\Files\File $phpcsFile, \Slevomat
);
if ($whitespacePointer !== null) {
- $originalTypeHint = \SlevomatCodingStandard\Helpers\TokenHelper::getContent(
+ $originalTypeHint = TokenHelper::getContent(
$phpcsFile,
$typeHint->getStartPointer(),
$typeHint->getEndPointer(),
@@ -216,29 +223,29 @@ private function checkTypeHint(\PHP_CodeSniffer\Files\File $phpcsFile, \Slevomat
}
private function getTypeHintContentWithoutNull(
- \PHP_CodeSniffer\Files\File $phpcsFile,
+ File $phpcsFile,
\SlevomatCodingStandard\Helpers\TypeHint $typeHint,
) : string
{
$tokens = $phpcsFile->getTokens();
if (\strtolower($tokens[$typeHint->getEndPointer()]['content']) === 'null') {
- $previousTypeHintPointer = \SlevomatCodingStandard\Helpers\TokenHelper::findPrevious(
+ $previousTypeHintPointer = TokenHelper::findPrevious(
$phpcsFile,
- \SlevomatCodingStandard\Helpers\TokenHelper::getOnlyTypeHintTokenCodes(),
+ TokenHelper::getOnlyTypeHintTokenCodes(),
$typeHint->getEndPointer() - 1,
);
- return \SlevomatCodingStandard\Helpers\TokenHelper::getContent($phpcsFile, $typeHint->getStartPointer(), $previousTypeHintPointer);
+ return TokenHelper::getContent($phpcsFile, $typeHint->getStartPointer(), $previousTypeHintPointer);
}
$content = '';
for ($i = $typeHint->getStartPointer(); $i <= $typeHint->getEndPointer(); $i++) {
if (\strtolower($tokens[$i]['content']) === 'null') {
- $i = \SlevomatCodingStandard\Helpers\TokenHelper::findNext(
+ $i = TokenHelper::findNext(
$phpcsFile,
- \SlevomatCodingStandard\Helpers\TokenHelper::getOnlyTypeHintTokenCodes(),
+ TokenHelper::getOnlyTypeHintTokenCodes(),
$i + 1,
);
}
@@ -250,7 +257,7 @@ private function getTypeHintContentWithoutNull(
}
private function fixTypeHint(
- \PHP_CodeSniffer\Files\File $phpcsFile,
+ File $phpcsFile,
\SlevomatCodingStandard\Helpers\TypeHint $typeHint,
string $fixedTypeHint,
) : void
diff --git a/InfinityloopCodingStandard/Sniffs/WhiteSpace/MemberVarSpacingSniff.php b/InfinityloopCodingStandard/Sniffs/WhiteSpace/MemberVarSpacingSniff.php
index a3c9dfc..69590e7 100644
--- a/InfinityloopCodingStandard/Sniffs/WhiteSpace/MemberVarSpacingSniff.php
+++ b/InfinityloopCodingStandard/Sniffs/WhiteSpace/MemberVarSpacingSniff.php
@@ -4,6 +4,9 @@
namespace InfinityloopCodingStandard\Sniffs\WhiteSpace;
+use \PHP_CodeSniffer\Files\File;
+use \PHP_CodeSniffer\Util\Tokens;
+
class MemberVarSpacingSniff extends \PHP_CodeSniffer\Sniffs\AbstractVariableSniff
{
public int $spacing = 1;
@@ -11,11 +14,11 @@ class MemberVarSpacingSniff extends \PHP_CodeSniffer\Sniffs\AbstractVariableSnif
public bool $ignoreFirstMemberVar = false;
//@phpcs:ignore Squiz.Commenting.FunctionComment.ScalarTypeHintMissing
- protected function processMemberVar(\PHP_CodeSniffer\Files\File $phpcsFile, $stackPtr) : ?int
+ protected function processMemberVar(File $phpcsFile, $stackPtr) : ?int
{
$tokens = $phpcsFile->getTokens();
- $validPrefixes = \PHP_CodeSniffer\Util\Tokens::$methodPrefixes;
+ $validPrefixes = Tokens::$methodPrefixes;
$validPrefixes[] = \T_VAR;
$startOfStatement = $phpcsFile->findPrevious($validPrefixes, $stackPtr - 1, null, false, null, true);
@@ -32,9 +35,9 @@ protected function processMemberVar(\PHP_CodeSniffer\Files\File $phpcsFile, $sta
$start = $startOfStatement;
$prev = $phpcsFile->findPrevious($ignore, $startOfStatement - 1, null, true);
- if (isset(\PHP_CodeSniffer\Util\Tokens::$commentTokens[$tokens[$prev]['code']]) === true) {
+ if (isset(Tokens::$commentTokens[$tokens[$prev]['code']]) === true) {
// Assume the comment belongs to the member var if it is on a line by itself.
- $prevContent = $phpcsFile->findPrevious(\PHP_CodeSniffer\Util\Tokens::$emptyTokens, $prev - 1, null, true);
+ $prevContent = $phpcsFile->findPrevious(Tokens::$emptyTokens, $prev - 1, null, true);
if ($tokens[$prevContent]['line'] !== $tokens[$prev]['line']) {
// Check the spacing, but then skip it.
@@ -74,7 +77,7 @@ protected function processMemberVar(\PHP_CodeSniffer\Files\File $phpcsFile, $sta
// There needs to be n blank lines before the var, not counting comments.
if ($start === $startOfStatement) {
// No comment found.
- $first = $phpcsFile->findFirstOnLine(\PHP_CodeSniffer\Util\Tokens::$emptyTokens, $start, true);
+ $first = $phpcsFile->findFirstOnLine(Tokens::$emptyTokens, $start, true);
if ($first === false) {
$first = $start;
@@ -82,8 +85,8 @@ protected function processMemberVar(\PHP_CodeSniffer\Files\File $phpcsFile, $sta
} elseif ($tokens[$start]['code'] === \T_DOC_COMMENT_CLOSE_TAG) {
$first = $tokens[$start]['comment_opener'];
} else {
- $first = $phpcsFile->findPrevious(\PHP_CodeSniffer\Util\Tokens::$emptyTokens, $start - 1, null, true);
- $first = $phpcsFile->findNext(\PHP_CodeSniffer\Util\Tokens::$commentTokens, $first + 1);
+ $first = $phpcsFile->findPrevious(Tokens::$emptyTokens, $start - 1, null, true);
+ $first = $phpcsFile->findNext(Tokens::$commentTokens, $first + 1);
}
// Determine if this is the first member var.
@@ -103,7 +106,7 @@ protected function processMemberVar(\PHP_CodeSniffer\Files\File $phpcsFile, $sta
}
if ($tokens[$prev]['code'] === \T_OPEN_CURLY_BRACKET
- && isset(\PHP_CodeSniffer\Util\Tokens::$ooScopeTokens[$tokens[$tokens[$prev]['scope_condition']]['code']]) === true
+ && isset(Tokens::$ooScopeTokens[$tokens[$tokens[$prev]['scope_condition']]['code']]) === true
) {
$errorMsg = 'Expected %s blank line(s) before first member var; %s found';
$errorCode = 'FirstIncorrect';
diff --git a/InfinityloopCodingStandard/ruleset.xml b/InfinityloopCodingStandard/ruleset.xml
index a939741..14467e4 100644
--- a/InfinityloopCodingStandard/ruleset.xml
+++ b/InfinityloopCodingStandard/ruleset.xml
@@ -503,4 +503,10 @@
+
+
+
+
+
+
diff --git a/README.md b/README.md
index e89517e..e1beb7e 100644
--- a/README.md
+++ b/README.md
@@ -64,7 +64,7 @@ All other necessary sniffs to enforce remaining PSR12 rules are included.
#### InfinityloopCodingStandard.Classes.FinalClassVisibility :wrench:
-When class is final and doesnt extend any other class, it's safe to change visibility of all protected functions/properties to private.
+When class is final and doesn't extend any other class, it's safe to change visibility of all protected functions/properties to private.
#### InfinityloopCodingStandard.Namespaces.UseDoesStartWithBackslash :wrench:
@@ -86,9 +86,17 @@ Improved version of Slevomat UnionTypeHintFormat with added formatting of multil
Space constructor arguments one per line when Constructor Property Promotion is used
+#### InfinityloopCodingStandard.Namespaces.ReferenceUsedNamesAfterUsage :wrench:
+
+Specialized version of Slevomat ReferenceUsedNamesOnlySniff with added rules when the sniff should reference by FQN or Use statement.
+
+Sniff provides the following settings:
+- count - Minimum number of occurrences after which the class will get imported via Use statement.
+- length - The maximum length of the class up to which it will be used via FQN, if this length is exceeded it will be imported via Use statement.
+
### Slevomat sniffs
-Detailed list of Slevomat sniffs with configured settings. Some sniffs are not included, either because we dont find them helpful, the are too strict, or collide with their counter-sniff (require/disallow pairs).
+Detailed list of Slevomat sniffs with configured settings. Some sniffs are not included, either because we don't find them helpful, they are too strict, or collide with their counter-sniff (require/disallow pairs).
#### Functional
diff --git a/composer.json b/composer.json
index f5327f2..ae6d375 100644
--- a/composer.json
+++ b/composer.json
@@ -14,7 +14,8 @@
"bamarni/composer-bin-plugin": "^1.2"
},
"scripts": {
- "codestyle": "phpcs --standard=InfinityloopCodingStandard --extensions=php InfinityloopCodingStandard"
+ "codestyle": "phpcs --standard=InfinityloopCodingStandard --extensions=php InfinityloopCodingStandard",
+ "codestyle-fix": "phpcbf --standard=InfinityloopCodingStandard --extensions=php InfinityloopCodingStandard"
},
"autoload": {
"psr-4": {