Skip to content

Commit

Permalink
Exclude assertion checks and add Psalm types
Browse files Browse the repository at this point in the history
Exclude the Slevomat assertion check from code analysis. Added multiple @psalm-type annotations for better static analysis and removed extensive debug code from namespace parsing and token handling functions.
  • Loading branch information
koriym committed Nov 4, 2024
1 parent 518c07f commit 88eb150
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 53 deletions.
1 change: 1 addition & 0 deletions phpcs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ com
<exclude name="SlevomatCodingStandard.TypeHints.PropertyTypeHint.MissingNativeTypeHint"/>
<exclude name="SlevomatCodingStandard.TypeHints.ReturnTypeHint.MissingNativeTypeHint"/>
<exclude name="SlevomatCodingStandard.Classes.SuperfluousTraitNaming.SuperfluousSuffix"/>
<exclude name="SlevomatCodingStandard.PHP.RequireExplicitAssertion.RequiredExplicitAssertion"/>
<!-- /Base -->
<!-- Option -->
<exclude name="SlevomatCodingStandard.Functions.RequireTrailingCommaInCall.MissingTrailingComma"/>
Expand Down
102 changes: 49 additions & 53 deletions src/ClassName.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,33 +18,34 @@
use const T_DOC_COMMENT;
use const T_FINAL;
use const T_NAMESPACE;
use const T_NS_SEPARATOR;
use const T_STRING;
use const T_WHITESPACE;

/**
* @psalm-type Position = int
* @psalm-type TokenType = int
* @psalm-type TokenValue = array{0: TokenType, 1: string, 2: int}
* @psalm-type Token = TokenValue|string
* @psalm-type Tokens = array<Position, Token>
* @psalm-type TokenResult = array{Token, Position}
* @psalm-immutable
*/
final class ClassName
{
private const T_NAME_QUALIFIED = 316;

/**
* Extract fully qualified class name from file
*/
public static function from(string $filePath): ?string
{
if (! file_exists($filePath)) {
return null;
}

$tokens = token_get_all(file_get_contents($filePath));
$tokens = token_get_all(file_get_contents($filePath)); // @phpstan-ignore-line
$count = count($tokens);
$position = 0;
$namespace = '';
$debug = true; // デバッグモード用フラグ

if ($debug) {
// トークンの内容をデバッグ出力
foreach ($tokens as $token) {
if (is_array($token)) {
echo "Token: " . token_name($token[0]) . " => " . $token[1] . "\n";
}
}
}

while ($position < $count) {
[$token, $position] = self::nextToken($tokens, $position);
Expand All @@ -55,25 +56,24 @@ public static function from(string $filePath): ?string
switch ($token[0]) {
case T_NAMESPACE:
[$namespace, $position] = self::parseNamespace($tokens, $position + 1, $count);
if ($debug) {
echo "Parsed namespace: " . $namespace . "\n";
}
continue 2;
case T_CLASS:
$className = self::parseClassName($tokens, $position + 1, $count);
if ($className !== null) {
$fullyQualifiedName = $namespace !== '' ? $namespace . '\\' . $className : $className;
if ($debug) {
echo "Final class name: " . $fullyQualifiedName . "\n";
}
return $fullyQualifiedName;
return $namespace !== '' ? $namespace . '\\' . $className : $className;
}
}
}

return null;
}

/**
* @param Tokens $tokens
* @param Position $position
*
* @return TokenResult
*/
private static function nextToken(array $tokens, int $position): array
{
if (is_array($tokens[$position]) && in_array($tokens[$position][0], [T_ABSTRACT, T_FINAL], true)) {
Expand All @@ -83,6 +83,10 @@ private static function nextToken(array $tokens, int $position): array
return [$tokens[$position], $position + 1];
}

/**
* @param Tokens $tokens
* @param Position $position
*/
private static function parseClassName(array $tokens, int $position, int $count): ?string
{
$position = self::skipWhitespace($tokens, $position, $count);
Expand All @@ -93,6 +97,12 @@ private static function parseClassName(array $tokens, int $position, int $count)
return $tokens[$position][1];
}

/**
* @param Tokens $tokens
* @param Position $position
*
* @return Position
*/
private static function skipWhitespace(array $tokens, int $position, int $count): int
{
while (
Expand All @@ -106,57 +116,43 @@ private static function skipWhitespace(array $tokens, int $position, int $count)
return $position;
}

/**
* @param Tokens $tokens
* @param Position $position
*
* @return array{string, Position}
*/
private static function parseNamespace(array $tokens, int $position, int $count): array
{
$position = self::skipWhitespace($tokens, $position, $count);
if (! is_array($tokens[$position])) {
return ['', $position];
}

// PHP 8.0以降のT_NAME_QUALIFIEDトークンのサポート
if (defined('T_NAME_QUALIFIED') && $tokens[$position][0] === T_NAME_QUALIFIED) {
return [$tokens[$position][1], $position + 1];
}

// 従来の方式(バックアップとして保持)
return $tokens[$position][0] === T_STRING
? self::parseNamespacePartsImproved($tokens, $position, $count)
: ['', $position];
}

private static function parseNamespacePartsImproved(array $tokens, int $position, int $count): array
{
/** @var list<string> $namespaceParts */
$namespaceParts = [];
$expectingNamespacePart = true;

while ($position < $count) {
$token = $tokens[$position];
/** @var Token $token */

if (! is_array($token)) {
if ($token === ';' || $token === '{') {
break;
}
if ($token === '\\') {
$namespaceParts[] = '\\';
$expectingNamespacePart = true;
}

$position++;
continue;

Check warning on line 141 in src/ClassName.php

View check run for this annotation

Codecov / codecov/patch

src/ClassName.php#L140-L141

Added lines #L140 - L141 were not covered by tests
}

if ($token[0] === T_STRING && $expectingNamespacePart) {
if ($token[0] === T_STRING || $token[0] === T_NS_SEPARATOR) {
$namespaceParts[] = $token[1];
$expectingNamespacePart = false;
} elseif ($token[0] === T_WHITESPACE) {
// スペースは無視
} else {
// 予期しないトークンの場合はデバッグ情報を出力
if (defined('DEBUG') && DEBUG) {
echo "Unexpected token: " . token_name($token[0]) . " => " . $token[1] . "\n";
}
$position++;
continue;
}

$position++;
if ($token[0] === T_WHITESPACE) {
$position++;
continue;
}

break;

Check warning on line 155 in src/ClassName.php

View check run for this annotation

Codecov / codecov/patch

src/ClassName.php#L155

Added line #L155 was not covered by tests
}

return [implode('', $namespaceParts), $position];
Expand Down

0 comments on commit 88eb150

Please sign in to comment.