<repo_name>oldy777/phpstan-src<file_sep>/tests/PHPStan/Rules/Exceptions/data/unthrown-exception.php
<?php

namespace UnthrownException;

class Foo
{

	public function doFoo(): void
	{
		try {
			$foo = 1;
		} catch (\Throwable $e) {
			// pass
		}
	}

	public function doBar(): void
	{
		try {
			$foo = 1;
		} catch (\Exception $e) {
			// pass
		}
	}

	/** @throws \InvalidArgumentException */
	public function throwIae(): void
	{

	}

	public function doBaz(): void
	{
		try {
			$this->throwIae();
		} catch (\InvalidArgumentException $e) {

		} catch (\Exception $e) {
			// dead
		} catch (\Throwable $e) {
			// not dead
		}
	}

	public function doLorem(): void
	{
		try {
			$this->throwIae();
		} catch (\RuntimeException $e) {
 			// dead
		} catch (\Throwable $e) {

		}
	}

	public function doIpsum(): void
	{
		try {
			$this->throwIae();
		} catch (\Throwable $e) {

		}
	}

	public function doDolor(): void
	{
		try {
			throw new \InvalidArgumentException();
		} catch (\InvalidArgumentException $e) {

		} catch (\Throwable $e) {

		}
	}

	public function doSit(): void
	{
		try {
			try {
				\ThrowPoints\Helpers\maybeThrows();
			} catch (\InvalidArgumentException $e) {

			}
		} catch (\InvalidArgumentException $e) {

		}
	}

	/**
	 * @throws \InvalidArgumentException
	 * @throws \DomainException
	 */
	public function doAmet()
	{

	}

	public function doAmet1()
	{
		try {
			$this->doAmet();
		} catch (\InvalidArgumentException $e) {

		} catch (\DomainException $e) {

		} catch (\Throwable $e) {
			// not dead
		}
	}

	public function doAmet2()
	{
		try {
			throw new \InvalidArgumentException();
		} catch (\InvalidArgumentException $e) {

		} catch (\DomainException $e) {
			// dead
		} catch (\Throwable $e) {
			// dead
		}
	}

	public function doConsecteur()
	{
		try {
			if (false) {

			} elseif ($this->doAmet()) {

			}
		} catch (\InvalidArgumentException $e) {

		}
	}

}

class InlineThrows
{

	public function doFoo()
	{
		try {
			/** @throws \InvalidArgumentException */
			echo 1;
		} catch (\InvalidArgumentException $e) {

		}
	}

	public function doBar()
	{
		try {
			/** @throws \InvalidArgumentException */
			$i = 1;
		} catch (\InvalidArgumentException $e) {

		}
	}

}

class TestDateTime
{

	public function doFoo(): void
	{
		try {
			new \DateTime();
		} catch (\Exception $e) {

		}
	}

	public function doBar(): void
	{
		try {
			new \DateTime('now');
		} catch (\Exception $e) {

		}
	}

	public function doBaz(string $s): void
	{
		try {
			new \DateTime($s);
		} catch (\Exception $e) {

		}
	}

	/**
	 * @phpstan-param 'now'|class-string $s
	 */
	public function doSuperBaz(string $s): void
	{
		try {
			new \DateTime($s);
		} catch (\Exception $e) {

		}
	}

}

class TestDateInterval
{

	public function doFoo(): void
	{
		try {
			new \DateInterval('invalid format');
		} catch (\Exception $e) {

		}
	}

	public function doBar(): void
	{
		try {
			new \DateInterval('P10D');
		} catch (\Exception $e) {

		}
	}

	public function doBaz(string $s): void
	{
		try {
			new \DateInterval($s);
		} catch (\Exception $e) {

		}
	}

	/**
	 * @phpstan-param 'P10D'|class-string $s
	 */
	public function doSuperBaz(string $s): void
	{
		try {
			new \DateInterval($s);
		} catch (\Exception $e) {

		}
	}

}

class TestIntdiv
{

	public function doFoo(): void
	{
		try {
			intdiv(1, 1);
			intdiv(1, -1);
		} catch (\ArithmeticError $e) {

		}
		try {
			intdiv(PHP_INT_MIN, -1);
		} catch (\ArithmeticError $e) {

		}
		try {
			intdiv(1, 0);
		} catch (\ArithmeticError $e) {

		}
	}

	public function doBar(int $int): void
	{
		try {
			intdiv($int, 1);
		} catch (\ArithmeticError $e) {

		}
		try {
			intdiv($int, -1);
		} catch (\ArithmeticError $e) {

		}
	}

	public function doBaz(int $int): void
	{
		try {
			intdiv(1, $int);
		} catch (\ArithmeticError $e) {

		}
		try {
			intdiv(PHP_INT_MIN, $int);
		} catch (\ArithmeticError $e) {

		}
	}

}

class TestSimpleXMLElement
{

	public function doFoo(): void
	{
		try {
			new \SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><root></root>');
		} catch (\Exception $e) {

		}
	}

	public function doBar(): void
	{
		try {
			new \SimpleXMLElement('foo');
		} catch (\Exception $e) {

		}
	}

	public function doBaz(string $string): void
	{
		try {
			new \SimpleXMLElement($string);
		} catch (\Exception $e) {

		}
	}

}
<file_sep>/tests/PHPStan/Rules/Api/ApiRuleHelperTest.php
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Api;

use PHPUnit\Framework\TestCase;

class ApiRuleHelperTest extends TestCase
{

	public function dataIsInPhpStanNamespace(): array
	{
		return [
			[
				null,
				false,
			],
			[
				'PHPStan',
				true,
			],
			[
				'PhpStan',
				true,
			],
			[
				'PHPStan\\Foo',
				true,
			],
			[
				'PhpStan\\Foo',
				true,
			],
			[
				'App\\Foo',
				false,
			],
			[
				'PHPStanWorkshop',
				false,
			],
			[
				'PHPStanWorkshop\\',
				false,
			],
			[
				'PHPStan\\PhpDocParser\\',
				false,
			],
		];
	}

	/**
	 * @dataProvider dataIsInPhpStanNamespace
	 * @param string|null $namespace
	 * @param bool $expected
	 */
	public function testIsInPhpStanNamespace(?string $namespace, bool $expected): void
	{
		$rule = new ApiRuleHelper();
		$this->assertSame($expected, $rule->isInPhpStanNamespace($namespace));
	}

}
<file_sep>/src/Rules/Api/ApiClassImplementsRule.php
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Api;

use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Analyser\Scope;
use PHPStan\Analyser\TypeSpecifierAwareExtension;
use PHPStan\Command\ErrorFormatter\ErrorFormatter;
use PHPStan\PhpDoc\TypeNodeResolverAwareExtension;
use PHPStan\PhpDoc\TypeNodeResolverExtension;
use PHPStan\Reflection\BrokerAwareExtension;
use PHPStan\Reflection\ClassMemberReflection;
use PHPStan\Reflection\MethodReflection;
use PHPStan\Reflection\MethodsClassReflectionExtension;
use PHPStan\Reflection\ParameterReflection;
use PHPStan\Reflection\ParametersAcceptor;
use PHPStan\Reflection\PropertiesClassReflectionExtension;
use PHPStan\Reflection\PropertyReflection;
use PHPStan\Reflection\ReflectionProvider;
use PHPStan\Rules\Constants\AlwaysUsedClassConstantsExtension;
use PHPStan\Rules\Exceptions\ExceptionTypeResolver;
use PHPStan\Rules\Properties\ReadWritePropertiesExtension;
use PHPStan\Rules\Rule;
use PHPStan\Rules\RuleError;
use PHPStan\Rules\RuleErrorBuilder;
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
use PHPStan\Type\DynamicFunctionThrowTypeExtension;
use PHPStan\Type\DynamicMethodReturnTypeExtension;
use PHPStan\Type\DynamicMethodThrowTypeExtension;
use PHPStan\Type\DynamicStaticMethodReturnTypeExtension;
use PHPStan\Type\DynamicStaticMethodThrowTypeExtension;
use PHPStan\Type\FunctionTypeSpecifyingExtension;
use PHPStan\Type\MethodTypeSpecifyingExtension;
use PHPStan\Type\OperatorTypeSpecifyingExtension;
use PHPStan\Type\StaticMethodTypeSpecifyingExtension;

/**
 * @implements Rule<Class_>
 */
class ApiClassImplementsRule implements Rule
{

	public const INTERFACES = [
		PropertiesClassReflectionExtension::class,
		PropertyReflection::class,
		MethodsClassReflectionExtension::class,
		MethodReflection::class,
		ParametersAcceptor::class,
		ParameterReflection::class,
		ClassMemberReflection::class,
		DynamicMethodReturnTypeExtension::class,
		DynamicFunctionReturnTypeExtension::class,
		DynamicStaticMethodReturnTypeExtension::class,
		DynamicMethodThrowTypeExtension::class,
		DynamicFunctionThrowTypeExtension::class,
		DynamicStaticMethodThrowTypeExtension::class,
		OperatorTypeSpecifyingExtension::class,
		MethodTypeSpecifyingExtension::class,
		FunctionTypeSpecifyingExtension::class,
		StaticMethodTypeSpecifyingExtension::class,
		ErrorFormatter::class,
		Rule::class,
		TypeSpecifierAwareExtension::class,
		BrokerAwareExtension::class,
		AlwaysUsedClassConstantsExtension::class,
		ReadWritePropertiesExtension::class,
		ExceptionTypeResolver::class,
		TypeNodeResolverExtension::class,
		TypeNodeResolverAwareExtension::class,
	];

	private ApiRuleHelper $apiRuleHelper;

	private ReflectionProvider $reflectionProvider;

	public function __construct(
		ApiRuleHelper $apiRuleHelper,
		ReflectionProvider $reflectionProvider
	)
	{
		$this->apiRuleHelper = $apiRuleHelper;
		$this->reflectionProvider = $reflectionProvider;
	}

	public function getNodeType(): string
	{
		return Class_::class;
	}

	public function processNode(Node $node, Scope $scope): array
	{
		if ($this->apiRuleHelper->isInPhpStanNamespace($scope->getNamespace())) {
			return [];
		}

		$errors = [];
		foreach ($node->implements as $implements) {
			$errors = array_merge($errors, $this->checkName($implements));
		}

		return $errors;
	}

	/**
	 * @param Node\Name $name
	 * @return RuleError[]
	 */
	private function checkName(Node\Name $name): array
	{
		$implementedClassName = (string) $name;
		if (!$this->reflectionProvider->hasClass($implementedClassName)) {
			return [];
		}

		$implementedClassReflection = $this->reflectionProvider->getClass($implementedClassName);
		if (!$this->apiRuleHelper->isInPhpStanNamespace($implementedClassReflection->getName())) {
			return [];
		}

		if (in_array($implementedClassReflection->getName(), self::INTERFACES, true)) {
			return [];
		}

		$ruleError = RuleErrorBuilder::message(sprintf(
			'Implementing %s is not covered by backward compatibility promise. The interface might change in a minor PHPStan version.',
			$implementedClassReflection->getDisplayName()
		))->tip(sprintf(
			"If you think it should be covered by backward compatibility promise, open a discussion:\n   %s\n\n   See also:\n   https://phpstan.org/developing-extensions/backward-compatibility-promise",
			'https://github.com/phpstan/phpstan/discussions'
		))->build();

		return [$ruleError];
	}

}
<file_sep>/src/Rules/Api/ApiRuleHelper.php
<?php declare(strict_types = 1);

namespace PHPStan\Rules\Api;

class ApiRuleHelper
{

	public function isInPhpStanNamespace(?string $namespace): bool
	{
		if ($namespace === null) {
			return false;
		}

		if (strtolower($namespace) === 'phpstan') {
			return true;
		}

		if (strpos($namespace, 'PHPStan\\PhpDocParser\\') === 0) {
			return false;
		}

		return stripos($namespace, 'PHPStan\\') === 0;
	}

}
