Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .github/workflows/docblock_check.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Docblock Check

on:
pull_request: null

env:
COMPOSER_ROOT_VERSION: "dev-main"
DOCBLOCK_CHECK_LOG: "/tmp/docblock-check.log"

jobs:
docblock_check:
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- uses: actions/checkout@v5

-
uses: shivammathur/setup-php@v2
with:
php-version: 8.4
coverage: none
ini-values: zend.assertions=1

- uses: "ramsey/composer-install@v4"

-
uses: actions/setup-go@v5
with:
go-version: "1.26"

-
name: Install honestype docblock checker
run: |
GOPROXY=direct GOSUMDB=off go install github.com/rectorphp/honestype@main
echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"

-
name: Instrument sources
run: |
honestype instrument src
honestype instrument rules

# Load the helper for every PHP process, including any parallel test
# workers which do not inherit a -d auto_prepend_file flag.
-
name: Enable runtime helper globally
run: |
INI="$(php -i | grep '^Loaded Configuration File' | awk '{print $NF}')"
echo "auto_prepend_file=$GITHUB_WORKSPACE/src/docblock_check.php" | sudo tee -a "$INI"

-
name: Run tests to collect docblock type mismatches
run: vendor/bin/phpunit tests rules-tests utils/phpstan/tests || true

-
name: Restore sources
if: always()
run: |
git checkout -- src rules
rm -f src/docblock_check.php rules/docblock_check.php

-
name: List docblock type mismatches
run: honestype report "$DOCBLOCK_CHECK_LOG"
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public function refactor(Node $node): ClassConstFetch|null
}

/**
* @param array<string, mixed> $configuration
* @param string[] $configuration
*/
public function configure(array $configuration): void
{
Expand Down
11 changes: 8 additions & 3 deletions rules/TypeDeclaration/NodeAnalyzer/CallTypesResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function __construct(

/**
* @param MethodCall[]|StaticCall[] $calls
* @return array<int, Type>
* @return array<int|string, Type>
*/
public function resolveStrictTypesFromCalls(array $calls): array
{
Expand All @@ -47,6 +47,11 @@ public function resolveStrictTypesFromCalls(array $calls): array
return [];
}

// must be int
if (! is_int($position)) {
continue;
}

/** @var Arg $arg */
$staticTypesByArgumentPosition[$position][] = $this->resolveStrictArgValueType($arg);
}
Expand Down Expand Up @@ -110,8 +115,8 @@ private function correctSelfType(Type $argValueType): Type
}

/**
* @param array<int, Type[]> $staticTypesByArgumentPosition
* @return array<int, Type>
* @param array<int|string, Type[]> $staticTypesByArgumentPosition
* @return array<int|string, Type>
*/
private function unionToSingleType(array $staticTypesByArgumentPosition, bool $removeMixedArray = false): array
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public function __construct(
}

/**
* @param array<int, Type> $classParameterTypes
* @param array<int|string, Type> $classParameterTypes
*/
public function complete(ClassMethod $classMethod, array $classParameterTypes, int $maxUnionTypes): ?ClassMethod
{
Expand Down Expand Up @@ -73,7 +73,7 @@ public function complete(ClassMethod $classMethod, array $classParameterTypes, i
private function shouldSkipArgumentStaticType(
ClassMethod $classMethod,
Type $argumentStaticType,
int $position,
int|string $position,
int $maxUnionTypes
): bool {
if ($argumentStaticType instanceof MixedType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,8 @@ private function nodeScopeResolverProcessNodes(
MutatingScope $mutatingScope,
callable $nodeCallback
): void {
Assert::allIsInstanceOf($stmts, Stmt::class);

try {
$this->nodeScopeResolver->processNodes($stmts, $mutatingScope, $nodeCallback);
} catch (ParserErrorsException|ParserException|ShouldNotHappenException|UndefinedVariableException) {
Expand Down Expand Up @@ -629,7 +631,7 @@ private function processProperty(Property $property, MutatingScope $mutatingScop
/** @var Stmt[] $stmts */
$stmts = $hook->body instanceof Expr
? [new Expression($hook->body)]
: [$hook->body];
: $hook->body;
$this->nodeScopeResolverProcessNodes($stmts, $mutatingScope, $nodeCallback);
}
}
Expand Down
5 changes: 5 additions & 0 deletions tests/Config/RectorConfigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ protected function setUp(): void
// the registered-rule lists so the assertions hold whether this class
// runs alone or batched into one warm process by a parallel runner
RectorConfig::resetRecreated();

// the container is shared across tests, so its per-rule dedupe maps persist and would
// swallow a re-registration; reset them so REGISTERED_RECTOR_RULES fills regardless of order
self::getContainer()->resetRuleConfigurations();

SimpleParameterProvider::setParameter(Option::REGISTERED_RECTOR_RULES, []);
SimpleParameterProvider::setParameter(Option::ROOT_STANDALONE_REGISTERED_RULES, []);
}
Expand Down
7 changes: 7 additions & 0 deletions tests/Configuration/ConfigurationFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@

final class ConfigurationFactoryTest extends AbstractLazyTestCase
{
protected function tearDown(): void
{
SimpleParameterProvider::setParameter(Option::IS_RUN_NARROWED, false);
SimpleParameterProvider::setParameter(Option::SOURCE, []);
SimpleParameterProvider::setParameter(Option::PATHS, []);
}

public function test(): void
{
$configurationFactory = $this->make(ConfigurationFactory::class);
Expand Down
Loading