Skip to content

Commit

Permalink
Detect dependencies in catch blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobw authored Feb 21, 2024
1 parent 18a4b36 commit b6efadd
Show file tree
Hide file tree
Showing 8 changed files with 170 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Changelog
All notable changes to this project will be documented in this file.

## 0.10.14
* Add dependency detection for catch blocks.

## 0.10.13
* Fix namespace selector matching similar namespaces

Expand Down
8 changes: 8 additions & 0 deletions extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ services:
class: PHPat\Rule\Assertion\Relation\ShouldNotDepend\StaticMethodRule
tags:
- phpstan.rules.rule
-
class: PHPat\Rule\Assertion\Relation\ShouldNotDepend\CatchBlockRule
tags:
- phpstan.rules.rule

# CanOnlyDepend rules
-
Expand Down Expand Up @@ -217,6 +221,10 @@ services:
class: PHPat\Rule\Assertion\Relation\CanOnlyDepend\StaticMethodRule
tags:
- phpstan.rules.rule
-
class: PHPat\Rule\Assertion\Relation\CanOnlyDepend\CatchBlockRule
tags:
- phpstan.rules.rule

# ShouldNotConstruct rules
-
Expand Down
15 changes: 15 additions & 0 deletions src/Rule/Assertion/Relation/CanOnlyDepend/CatchBlockRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php declare(strict_types=1);

namespace PHPat\Rule\Assertion\Relation\CanOnlyDepend;

use PHPat\Rule\Extractor\Relation\CatchBlockExtractor;
use PhpParser\Node;
use PHPStan\Rules\Rule;

/**
* @implements Rule<Node\Stmt\Catch_>
*/
final class CatchBlockRule extends CanOnlyDepend implements Rule
{
use CatchBlockExtractor;
}
15 changes: 15 additions & 0 deletions src/Rule/Assertion/Relation/ShouldNotDepend/CatchBlockRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php declare(strict_types=1);

namespace PHPat\Rule\Assertion\Relation\ShouldNotDepend;

use PHPat\Rule\Extractor\Relation\CatchBlockExtractor;
use PhpParser\Node;
use PHPStan\Rules\Rule;

/**
* @implements Rule<Node\Stmt\Catch_>
*/
final class CatchBlockRule extends ShouldNotDepend implements Rule
{
use CatchBlockExtractor;
}
24 changes: 24 additions & 0 deletions src/Rule/Extractor/Relation/CatchBlockExtractor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types=1);

namespace PHPat\Rule\Extractor\Relation;

use PhpParser\Node;
use PhpParser\Node\Stmt\Catch_;
use PHPStan\Analyser\Scope;

trait CatchBlockExtractor
{
public function getNodeType(): string
{
return Catch_::class;
}

/**
* @param Catch_ $node
* @return array<class-string>
*/
protected function extractNodeClassNames(Node $node, Scope $scope): array
{
return namesToClassStrings($node->types);
}
}
7 changes: 7 additions & 0 deletions tests/fixtures/FixtureClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,11 @@ public function doSomething(string $modelClass)
{
return new $modelClass();
}

public function catchException(): void
{
try {
} catch (SimpleException $e) {
}
}
}
49 changes: 49 additions & 0 deletions tests/unit/rules/CanOnlyDepend/CatchBlockTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php declare(strict_types=1);

namespace Tests\PHPat\unit\rules\CanOnlyDepend;

use PHPat\Configuration;
use PHPat\Rule\Assertion\Relation\CanOnlyDepend\CanOnlyDepend;
use PHPat\Rule\Assertion\Relation\CanOnlyDepend\CatchBlockRule;
use PHPat\Selector\Classname;
use PHPat\Statement\Builder\StatementBuilderFactory;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use PHPStan\Type\FileTypeMapper;
use Tests\PHPat\fixtures\FixtureClass;
use Tests\PHPat\fixtures\Simple\SimpleException;
use Tests\PHPat\unit\FakeTestParser;

/**
* @extends RuleTestCase<CatchBlockRule>
* @internal
* @coversNothing
*/
class CatchBlockTest extends RuleTestCase
{
public const RULE_NAME = 'test_FixtureClassCanOnlyDependSimpleException';

public function testRule(): void
{
$this->analyse(['tests/fixtures/FixtureClass.php'], [
[sprintf('%s should not depend on %s', FixtureClass::class, SimpleException::class), 97],
]);
}

protected function getRule(): Rule
{
$testParser = FakeTestParser::create(
self::RULE_NAME,
CanOnlyDepend::class,
[new Classname(FixtureClass::class, false)],
[new Classname(\Exception::class, false)]
);

return new CatchBlockRule(
new StatementBuilderFactory($testParser),
new Configuration(false, true, false),
$this->createReflectionProvider(),
self::getContainer()->getByType(FileTypeMapper::class)
);
}
}
49 changes: 49 additions & 0 deletions tests/unit/rules/ShouldNotDepend/CatchBlockTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php declare(strict_types=1);

namespace Tests\PHPat\unit\rules\ShouldNotDepend;

use PHPat\Configuration;
use PHPat\Rule\Assertion\Relation\ShouldNotDepend\CatchBlockRule;
use PHPat\Rule\Assertion\Relation\ShouldNotDepend\ShouldNotDepend;
use PHPat\Selector\Classname;
use PHPat\Statement\Builder\StatementBuilderFactory;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;
use PHPStan\Type\FileTypeMapper;
use Tests\PHPat\fixtures\FixtureClass;
use Tests\PHPat\fixtures\Simple\SimpleException;
use Tests\PHPat\unit\FakeTestParser;

/**
* @extends RuleTestCase<CatchBlockRule>
* @internal
* @coversNothing
*/
class CatchBlockTest extends RuleTestCase
{
public const RULE_NAME = 'test_FixtureClassShouldNotDependSimpleException';

public function testRule(): void
{
$this->analyse(['tests/fixtures/FixtureClass.php'], [
[sprintf('%s should not depend on %s', FixtureClass::class, SimpleException::class), 97],
]);
}

protected function getRule(): Rule
{
$testParser = FakeTestParser::create(
self::RULE_NAME,
ShouldNotDepend::class,
[new Classname(FixtureClass::class, false)],
[new Classname(SimpleException::class, false)]
);

return new CatchBlockRule(
new StatementBuilderFactory($testParser),
new Configuration(false, true, false),
$this->createReflectionProvider(),
self::getContainer()->getByType(FileTypeMapper::class)
);
}
}

0 comments on commit b6efadd

Please sign in to comment.