function UnusedUsesSniff::process
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint *
Parameters
int $openTagPointer:
Overrides Sniff::process
File
-
vendor/
slevomat/ coding-standard/ SlevomatCodingStandard/ Sniffs/ Namespaces/ UnusedUsesSniff.php, line 72
Class
Namespace
SlevomatCodingStandard\Sniffs\NamespacesCode
public function process(File $phpcsFile, $openTagPointer) : void {
if (TokenHelper::findPrevious($phpcsFile, T_OPEN_TAG, $openTagPointer - 1) !== null) {
return;
}
$startPointer = TokenHelper::findPrevious($phpcsFile, T_NAMESPACE, $openTagPointer - 1) ?? $openTagPointer;
$fileUnusedNames = UseStatementHelper::getFileUseStatements($phpcsFile);
$referencedNamesInCode = ReferencedNameHelper::getAllReferencedNames($phpcsFile, $startPointer);
$referencedNamesInAttributes = ReferencedNameHelper::getAllReferencedNamesInAttributes($phpcsFile, $startPointer);
$pointersBeforeUseStatements = array_reverse(NamespaceHelper::getAllNamespacesPointers($phpcsFile));
$allUsedNames = [];
foreach ([
$referencedNamesInCode,
$referencedNamesInAttributes,
] as $referencedNames) {
foreach ($referencedNames as $referencedName) {
$pointer = $referencedName->getStartPointer();
$pointerBeforeUseStatements = $this->firstPointerBefore($pointer, $pointersBeforeUseStatements, $startPointer);
$name = $referencedName->getNameAsReferencedInFile();
$nameParts = NamespaceHelper::getNameParts($name);
$nameAsReferencedInFile = $nameParts[0];
$nameReferencedWithoutSubNamespace = count($nameParts) === 1;
$uniqueId = $nameReferencedWithoutSubNamespace ? UseStatement::getUniqueId($referencedName->getType(), $nameAsReferencedInFile) : UseStatement::getUniqueId(ReferencedName::TYPE_CLASS, $nameAsReferencedInFile);
if (NamespaceHelper::isFullyQualifiedName($name) || !array_key_exists($pointerBeforeUseStatements, $fileUnusedNames) || !array_key_exists($uniqueId, $fileUnusedNames[$pointerBeforeUseStatements])) {
continue;
}
$allUsedNames[$pointerBeforeUseStatements][$uniqueId] = true;
}
}
if ($this->searchAnnotations) {
$tokens = $phpcsFile->getTokens();
$searchAnnotationsPointer = $startPointer + 1;
while (true) {
$docCommentOpenPointer = TokenHelper::findNext($phpcsFile, T_DOC_COMMENT_OPEN_TAG, $searchAnnotationsPointer);
if ($docCommentOpenPointer === null) {
break;
}
$annotations = AnnotationHelper::getAnnotations($phpcsFile, $docCommentOpenPointer);
if ($annotations === []) {
$searchAnnotationsPointer = $tokens[$docCommentOpenPointer]['comment_closer'] + 1;
continue;
}
$pointerBeforeUseStatements = $this->firstPointerBefore($docCommentOpenPointer - 1, $pointersBeforeUseStatements, $startPointer);
if (!array_key_exists($pointerBeforeUseStatements, $fileUnusedNames)) {
$searchAnnotationsPointer = $tokens[$docCommentOpenPointer]['comment_closer'] + 1;
continue;
}
foreach ($fileUnusedNames[$pointerBeforeUseStatements] as $useStatement) {
if (!$useStatement->isClass()) {
continue;
}
$nameAsReferencedInFile = $useStatement->getNameAsReferencedInFile();
$uniqueId = UseStatement::getUniqueId($useStatement->getType(), $nameAsReferencedInFile);
foreach ($annotations as $annotation) {
if (in_array($annotation->getName(), $this->getIgnoredAnnotations(), true)) {
continue;
}
if ($annotation->isInvalid()) {
continue;
}
$contentsToCheck = [];
if ($annotation->getValue() instanceof GenericTagValueNode) {
$contentsToCheck[] = $annotation->getName();
$contentsToCheck[] = $annotation->getValue()->value;
}
else {
/** @var list<IdentifierTypeNode> $identifierTypeNodes */
$identifierTypeNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), IdentifierTypeNode::class);
/** @var list<DoctrineAnnotation> $doctrineAnnotations */
$doctrineAnnotations = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), DoctrineAnnotation::class);
/** @var list<ConstFetchNode> $constFetchNodes */
$constFetchNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), ConstFetchNode::class);
$contentsToCheck = array_filter(array_merge($contentsToCheck, array_map(static function (IdentifierTypeNode $identifierTypeNode) : ?string {
if (TypeHintHelper::isSimpleTypeHint($identifierTypeNode->name) || TypeHintHelper::isSimpleUnofficialTypeHints($identifierTypeNode->name) || !TypeHelper::isTypeName($identifierTypeNode->name)) {
return null;
}
return $identifierTypeNode->name;
}, $identifierTypeNodes), array_map(function (DoctrineAnnotation $doctrineAnnotation) : ?string {
if (in_array($doctrineAnnotation->name, $this->getIgnoredAnnotationNames(), true)) {
return null;
}
return $doctrineAnnotation->name;
}, $doctrineAnnotations), array_map(static function (ConstFetchNode $constFetchNode) : string {
return $constFetchNode->className;
}, $constFetchNodes)));
}
foreach ($contentsToCheck as $contentToCheck) {
if (preg_match('~(?<=^|[^a-z\\\\])(' . preg_quote($nameAsReferencedInFile, '~') . ')(?=\\s|::|\\\\|\\||\\[|$)~im', $contentToCheck) === 0) {
continue;
}
$allUsedNames[$pointerBeforeUseStatements][$uniqueId] = true;
}
}
}
$searchAnnotationsPointer = $tokens[$docCommentOpenPointer]['comment_closer'] + 1;
}
}
foreach ($fileUnusedNames as $pointerBeforeUnusedNames => $unusedNames) {
$usedNames = $allUsedNames[$pointerBeforeUnusedNames] ?? [];
foreach (array_diff_key($unusedNames, $usedNames) as $unusedUse) {
$fullName = $unusedUse->getFullyQualifiedTypeName();
if ($unusedUse->getNameAsReferencedInFile() !== $fullName && $unusedUse->getNameAsReferencedInFile() !== NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($fullName)) {
$fullName .= sprintf(' (as %s)', $unusedUse->getNameAsReferencedInFile());
}
$fix = $phpcsFile->addFixableError(sprintf('Type %s is not used in this file.', $fullName), $unusedUse->getPointer(), self::CODE_UNUSED_USE);
if (!$fix) {
continue;
}
$endPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $unusedUse->getPointer()) + 1;
$phpcsFile->fixer
->beginChangeset();
FixerHelper::removeBetweenIncluding($phpcsFile, $unusedUse->getPointer(), $endPointer);
$phpcsFile->fixer
->endChangeset();
}
}
}