/** * @param \PHP_CodeSniffer_File $phpcsFile * @param integer $anyPointer any pointer type where the search begins from (backwards) * @return string|null */ public static function findCurrentNamespaceName(PHP_CodeSniffer_File $phpcsFile, $anyPointer) { $namespacePointer = $phpcsFile->findPrevious(T_NAMESPACE, $anyPointer); if ($namespacePointer === false) { return null; } $namespaceNameStartPointer = TokenHelper::findNextNonWhitespace($phpcsFile, $namespacePointer + 1); $namespaceNameEndPointer = TokenHelper::findNextExcluding($phpcsFile, TokenHelper::$nameTokenCodes, $namespaceNameStartPointer + 1); return TokenHelper::getContent($phpcsFile, $namespaceNameStartPointer, $namespaceNameEndPointer); }
/** * @param \PHP_CodeSniffer_File $phpcsFile * @param integer $usePointer * @return string */ public static function getFullyQualifiedTypeNameFromUse(PHP_CodeSniffer_File $phpcsFile, $usePointer) { $nameEndPointer = $phpcsFile->findNext([T_SEMICOLON, T_AS, T_COMMA], $usePointer + 1); $tokens = $phpcsFile->getTokens(); if ($tokens[$nameEndPointer - 1]['code'] === T_WHITESPACE) { $nameEndPointer = TokenHelper::findPreviousExcluding($phpcsFile, [T_WHITESPACE], $nameEndPointer - 1) + 1; } $nameStartPointer = $phpcsFile->findNext(TokenHelper::$nameTokenCodes, $usePointer + 1, $nameEndPointer); $name = TokenHelper::getContent($phpcsFile, $nameStartPointer, $nameEndPointer); return NamespaceHelper::normalizeToCanonicalName($name); }
/** * @param \PHP_CodeSniffer_File $phpcsFile * @param integer $usePointer */ public function process(PHP_CodeSniffer_File $phpcsFile, $usePointer) { if (UseStatementHelper::isAnonymousFunctionUse($phpcsFile, $usePointer) || UseStatementHelper::isTraitUse($phpcsFile, $usePointer)) { return; } $tokens = $phpcsFile->getTokens(); $nextTokenPointer = TokenHelper::findNextEffective($phpcsFile, $usePointer + 1); $nextToken = $tokens[$nextTokenPointer]; if ($nextToken['code'] === T_NS_SEPARATOR) { $phpcsFile->addError('Use statement cannot start with a backslash', $nextTokenPointer, self::CODE_STARTS_WITH_BACKSLASH); } }
/** * @param \PHP_CodeSniffer_File $phpcsFile * @param integer $keywordPointer * @param integer $nameStartPointer * @return integer Referenced name end pointer (exclusive) */ private function checkReferencedName(PHP_CodeSniffer_File $phpcsFile, $keywordPointer, $nameStartPointer) { $tokens = $phpcsFile->getTokens(); $nameStartToken = $tokens[$nameStartPointer]; $endPointer = ReferencedNameHelper::findReferencedNameEndPointer($phpcsFile, $nameStartPointer); if ($nameStartToken['code'] !== T_NS_SEPARATOR) { $name = TokenHelper::getContent($phpcsFile, $nameStartPointer, $endPointer); $keyword = $tokens[$keywordPointer]['content']; $phpcsFile->addError(sprintf('Type %s in %s statement should be referenced via a fully qualified name', $name, $keyword), $keywordPointer, self::getErrorCode($keyword)); } return $endPointer; }
/** * @param \PHP_CodeSniffer_File $phpcsFile * @param integer $openTagPointer * @return \SlevomatCodingStandard\Helpers\UseStatement[] canonicalName(string) => useStatement(\SlevomatCodingStandard\Helpers\UseStatement) */ public static function getUseStatements(PHP_CodeSniffer_File $phpcsFile, $openTagPointer) { $names = []; $tokens = $phpcsFile->getTokens(); foreach (self::getUseStatementPointers($phpcsFile, $openTagPointer) as $usePointer) { $nextTokenFromUsePointer = TokenHelper::findNextEffective($phpcsFile, $usePointer + 1); $type = UseStatement::TYPE_DEFAULT; if ($tokens[$nextTokenFromUsePointer]['code'] === T_STRING) { if ($tokens[$nextTokenFromUsePointer]['content'] === 'const') { $type = UseStatement::TYPE_CONSTANT; } elseif ($tokens[$nextTokenFromUsePointer]['content'] === 'function') { $type = UseStatement::TYPE_FUNCTION; } } $name = self::getNameAsReferencedInClassFromUse($phpcsFile, $usePointer); $useStatement = new UseStatement($name, self::getFullyQualifiedTypeNameFromUse($phpcsFile, $usePointer), $usePointer, $type); $names[$useStatement->getCanonicalNameAsReferencedInFile()] = $useStatement; } return $names; }
/** * @param \PHP_CodeSniffer_File $phpcsFile * @param integer $stackPointer */ public function process(PHP_CodeSniffer_File $phpcsFile, $stackPointer) { $tokens = $phpcsFile->getTokens(); $arrayToken = $tokens[$stackPointer]; $closeParenthesisPointer = $arrayToken['bracket_closer']; $openParenthesisToken = $tokens[$arrayToken['bracket_opener']]; $closeParenthesisToken = $tokens[$closeParenthesisPointer]; if ($openParenthesisToken['line'] === $closeParenthesisToken['line']) { return; } $previousToCloseParenthesisPointer = TokenHelper::findPreviousEffective($phpcsFile, $closeParenthesisPointer - 1); $previousToCloseParenthesisToken = $tokens[$previousToCloseParenthesisPointer]; if ($previousToCloseParenthesisToken['code'] !== T_COMMA && $closeParenthesisToken['line'] !== $previousToCloseParenthesisToken['line']) { $fix = $phpcsFile->addFixableError('Multiline arrays must have a trailing comma after the last element', $previousToCloseParenthesisPointer, self::CODE_MISSING_TRAILING_COMMA); if ($fix) { $phpcsFile->fixer->beginChangeset(); $phpcsFile->fixer->addContent($previousToCloseParenthesisPointer, ','); $phpcsFile->fixer->endChangeset(); } } }
/** * @param \PHP_CodeSniffer_File $phpcsFile * @param integer $openTagPointer */ public function process(PHP_CodeSniffer_File $phpcsFile, $openTagPointer) { $tokens = $phpcsFile->getTokens(); $referencedNames = ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer); foreach ($referencedNames as $referencedName) { $name = $referencedName->getNameAsReferencedInFile(); $pointer = $referencedName->getPointer(); $canonicalName = NamespaceHelper::normalizeToCanonicalName($name); if (NamespaceHelper::isFullyQualifiedName($name)) { $isExceptionByName = StringHelper::endsWith($name, 'Exception') || $name === '\\Throwable' || StringHelper::endsWith($name, 'Error') && !NamespaceHelper::hasNamespace($name) || in_array($canonicalName, $this->getSpecialExceptionNames(), true); $inIgnoredNames = in_array($canonicalName, $this->getIgnoredNames(), true); if ($this->isClassRequiredToBeUsed($name) && (!$this->allowFullyQualifiedExceptions || !$isExceptionByName || $inIgnoredNames)) { $previousKeywordPointer = TokenHelper::findPreviousExcluding($phpcsFile, array_merge(TokenHelper::$nameTokenCodes, [T_WHITESPACE, T_COMMA]), $pointer - 1); if (!in_array($tokens[$previousKeywordPointer]['code'], $this->getFullyQualifiedKeywords(), true)) { if (!NamespaceHelper::hasNamespace($name) && NamespaceHelper::findCurrentNamespaceName($phpcsFile, $pointer) === null) { $phpcsFile->addError(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), $pointer, self::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME_WITHOUT_NAMESPACE); } else { $phpcsFile->addError(sprintf('Type %s should not be referenced via a fully qualified name, but via a use statement', $name), $pointer, self::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME); } } } } elseif (!$this->allowPartialUses) { if (NamespaceHelper::isQualifiedName($name)) { $phpcsFile->addError(sprintf('Partial use statements are not allowed, but referencing %s found', $name), $pointer, self::CODE_PARTIAL_USE); } } } }
/** * @param \PHP_CodeSniffer_File $phpcsFile * @param integer $startPointer * @return boolean */ private static function isReferencedName(PHP_CodeSniffer_File $phpcsFile, $startPointer) { $tokens = $phpcsFile->getTokens(); $previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $startPointer - 1); $previousToken = $tokens[$previousPointer]; $skipTokenCodes = [T_FUNCTION, T_AS, T_DOUBLE_COLON, T_OBJECT_OPERATOR, T_NAMESPACE, T_CONST]; if ($previousToken['code'] === T_USE) { $classPointer = $phpcsFile->findPrevious(T_CLASS, $startPointer - 1); if ($classPointer !== false) { $tokens = $phpcsFile->getTokens(); $classToken = $tokens[$classPointer]; return $startPointer > $classToken['scope_opener'] && $startPointer < $classToken['scope_closer']; } return false; } return !in_array($previousToken['code'], array_merge($skipTokenCodes, TokenHelper::$typeKeywordTokenCodes), true); }
/** * @param PHP_CodeSniffer_File $phpcsFile * @param mixed[] $tokens * @param integer $methodTokenPointer * @return integer|null */ private function findVisibilityModifier(PHP_CodeSniffer_File $phpcsFile, array $tokens, $methodTokenPointer) { $visibilityModifiedTokenPointer = TokenHelper::findPreviousNonWhitespace($phpcsFile, $methodTokenPointer - 1); $visibilityModifiedToken = $tokens[$visibilityModifiedTokenPointer]; if (in_array($visibilityModifiedToken['code'], [T_PUBLIC, T_PROTECTED, T_PRIVATE], true)) { return $visibilityModifiedToken['code']; } elseif (in_array($visibilityModifiedToken['code'], [T_ABSTRACT, T_STATIC], true)) { return $this->findVisibilityModifier($phpcsFile, $tokens, $visibilityModifiedTokenPointer); } return null; }