/** * @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; } $namespaceName = NamespaceHelper::findCurrentNamespaceName($phpcsFile, $usePointer); if ($namespaceName === null) { $namespaceName = ''; } $usedTypeName = UseStatementHelper::getFullyQualifiedTypeNameFromUse($phpcsFile, $usePointer); if (!StringHelper::startsWith($usedTypeName, $namespaceName)) { return; } $asPointer = $this->findAsPointer($phpcsFile, $usePointer); if ($asPointer !== null) { return; } $usedTypeNameRest = substr($usedTypeName, strlen($namespaceName)); if (!NamespaceHelper::isFullyQualifiedName($usedTypeNameRest) && $namespaceName !== '') { return; } if (!NamespaceHelper::hasNamespace($usedTypeNameRest)) { $fix = $phpcsFile->addFixableError(sprintf('Use %s is from the same namespace – that is prohibited', $usedTypeName), $usePointer, self::CODE_USE_FROM_SAME_NAMESPACE); if ($fix) { $phpcsFile->fixer->beginChangeset(); $endPointer = $phpcsFile->findNext(T_SEMICOLON, $usePointer) + 1; for ($i = $usePointer; $i <= $endPointer; $i++) { $phpcsFile->fixer->replaceToken($i, ''); } $phpcsFile->fixer->endChangeset(); } } }
/** * @param string $path * @return string|null */ public function getTypeNameFromProjectPath($path) { if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') { return null; } $pathParts = explode(DIRECTORY_SEPARATOR, $path); $rootNamespace = null; while (count($pathParts) > 0) { array_shift($pathParts); foreach ($this->rootNamespaces as $directory => $namespace) { if (StringHelper::startsWith(implode('/', $pathParts) . '/', $directory . '/')) { for ($i = 0; $i < count(explode('/', $directory)); $i++) { array_shift($pathParts); } $rootNamespace = $namespace; break 2; } } } if ($rootNamespace === null) { return null; } if (count($pathParts) === 0) { return null; } array_unshift($pathParts, $rootNamespace); $typeName = implode('\\', array_filter($pathParts, function ($pathPart) { return !isset($this->skipDirs[$pathPart]); })); return substr($typeName, 0, -strlen('.php')); }
/** * @param \PHP_CodeSniffer_File $phpcsFile * @param integer $openTagPointer * @param boolean $searchAnnotations * @return \SlevomatCodingStandard\Helpers\ReferencedName[] referenced names */ private static function createAllReferencedNames(PHP_CodeSniffer_File $phpcsFile, $openTagPointer, $searchAnnotations) { $beginSearchAtPointer = $openTagPointer + 1; $tokens = $phpcsFile->getTokens(); $phpDocTypes = [T_DOC_COMMENT_STRING, T_DOC_COMMENT_TAG]; $searchTypes = array_merge([T_RETURN_TYPE], TokenHelper::$nameTokenCodes); if ($searchAnnotations) { $searchTypes = array_merge($phpDocTypes, $searchTypes); } $types = []; $matchTypesInAnnotation = function ($annotation, $nameStartPointer) use(&$types) { $annotation = trim($annotation, '@ '); if (preg_match('#([a-zA-Z0-9_|\\[\\]\\\\]+)#', $annotation, $matches) > 0) { $referencedNames = array_filter(array_map(function ($name) { return trim($name, '[]'); }, explode('|', $matches[1])), function ($match) { return !in_array($match, ['null', 'self', 'static', 'mixed', 'array', 'string', 'int', 'integer', 'bool', 'boolean'], true); }); foreach ($referencedNames as $name) { $types[] = new ReferencedName($name, $nameStartPointer); } } }; while (true) { $nameStartPointer = $phpcsFile->findNext($searchTypes, $beginSearchAtPointer); if ($nameStartPointer === false) { break; } $nameStartToken = $tokens[$nameStartPointer]; if (in_array($nameStartToken['code'], $phpDocTypes, true)) { if ($nameStartToken['code'] === T_DOC_COMMENT_TAG) { if (!StringHelper::startsWith($nameStartToken['content'], '@var') && !StringHelper::startsWith($nameStartToken['content'], '@param') && !StringHelper::startsWith($nameStartToken['content'], '@return') && !StringHelper::startsWith($nameStartToken['content'], '@throws') && !StringHelper::startsWith($nameStartToken['content'], '@see') && !StringHelper::startsWith($nameStartToken['content'], '@link') && !StringHelper::startsWith($nameStartToken['content'], '@inherit')) { $matchTypesInAnnotation($nameStartToken['content'], $nameStartPointer); } } elseif ($nameStartToken['code'] === T_DOC_COMMENT_STRING) { $matchTypesInAnnotation($nameStartToken['content'], $nameStartPointer); } $beginSearchAtPointer = $nameStartPointer + 1; continue; } $nameEndPointer = self::findReferencedNameEndPointer($phpcsFile, $nameStartPointer); if ($nameEndPointer === null) { $beginSearchAtPointer = TokenHelper::findNextExcluding($phpcsFile, array_merge([T_WHITESPACE, T_RETURN_TYPE], TokenHelper::$nameTokenCodes), $nameStartPointer); continue; } $types[] = new ReferencedName(TokenHelper::getContent($phpcsFile, $nameStartPointer, $nameEndPointer), $nameStartPointer); $beginSearchAtPointer = $nameEndPointer + 1; } return $types; }
/** * @param \PHP_CodeSniffer_File $phpcsFile * @param integer $stackPointer */ public function process(\PHP_CodeSniffer_File $phpcsFile, $stackPointer) { $tokens = $phpcsFile->getTokens(); $namePointer = $phpcsFile->findNext(T_STRING, $stackPointer + 1); $nameToken = $tokens[$namePointer]; $typeName = $nameToken['content']; $namespacePointer = $phpcsFile->findPrevious(T_NAMESPACE, $stackPointer - 1); if ($namespacePointer !== false) { $namespaceName = ''; while (true) { $namespaceNamePartPointer = $phpcsFile->findNext([T_STRING, T_NS_SEPARATOR, T_SEMICOLON], $namespacePointer + 1); if ($namespaceNamePartPointer === false) { break; } $namespaceNamePartToken = $tokens[$namespaceNamePartPointer]; if ($namespaceNamePartToken['code'] === T_SEMICOLON) { break; } $namespaceName .= $namespaceNamePartToken['content']; $namespacePointer = $namespaceNamePartPointer; } $typeName = $namespaceName . '\\' . $typeName; } else { // skip types without a namespace return; } foreach ($this->ignoredNamespaces as $ignoredNamespace) { if (StringHelper::startsWith($typeName, $ignoredNamespace . '\\')) { return; } } $expectedTypeName = $this->getNamespaceExtractor()->getTypeNameFromProjectPath($phpcsFile->getFilename()); if ($typeName !== $expectedTypeName) { $phpcsFile->addError(sprintf('%s name %s does not match filepath %s.', ucfirst($tokens[$stackPointer]['content']), $typeName, $phpcsFile->getFilename()), $namePointer); } }
/** * @param string $typeName * @param string $namespace * @return boolean */ public static function isTypeInNamespace($typeName, $namespace) { return StringHelper::startsWith(self::normalizeToCanonicalName($typeName) . '\\', $namespace . '\\'); }