Repository: Roave/BetterReflection (php)

Issue:
`Roave\BetterReflection\Reflection\ReflectionFunctionAbstract#getStartColumn()` throws `RuntimeException` instead of `Roave\BetterReflection\Util\Exception\NoNodePosition`
https://github.com/Roave/BetterReflection/blob/55b947fe0b929ec6ec4d40d6b4a37b7e6bf2496b/src/Reflection/ReflectionFunctionAbstract.php#L349-L407

This API should probably throw `NoNodePosition`, to be more specific?

Would be a minor BC break, since `NoNodePosition extends InvalidArgumentException`

Pull request description:
`Reflection*::getStartLine()/getEndLine()/getStartColumn()/getEndColumn()` throws `\Roave\BetterReflection\Reflection\Exception\CodeLocationMissing` instead of `\RuntimeException`
Fixes #1276

Patch:
diff --git a/src/Reflection/Exception/CodeLocationMissing.php b/src/Reflection/Exception/CodeLocationMissing.php
new file mode 100644
index 00000000..6c302f9b
--- /dev/null
+++ b/src/Reflection/Exception/CodeLocationMissing.php
@@ -0,0 +1,15 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Roave\BetterReflection\Reflection\Exception;
+
+use RuntimeException;
+
+class CodeLocationMissing extends RuntimeException
+{
+    public static function create(): self
+    {
+        return new self('Code location is missing');
+    }
+}
diff --git a/src/Reflection/ReflectionFunctionAbstract.php b/src/Reflection/ReflectionFunctionAbstract.php
index c4f15395..bd94bac5 100644
--- a/src/Reflection/ReflectionFunctionAbstract.php
+++ b/src/Reflection/ReflectionFunctionAbstract.php
@@ -13,11 +13,11 @@ use PhpParser\NodeTraverser;
 use PhpParser\NodeVisitor\FindingVisitor;
 use Roave\BetterReflection\Reflection\Annotation\AnnotationHelper;
 use Roave\BetterReflection\Reflection\Attribute\ReflectionAttributeHelper;
+use Roave\BetterReflection\Reflection\Exception\CodeLocationMissing;
 use Roave\BetterReflection\SourceLocator\Located\LocatedSource;
 use Roave\BetterReflection\Util\CalculateReflectionColumn;
 use Roave\BetterReflection\Util\Exception\NoNodePosition;
 use Roave\BetterReflection\Util\GetLastDocComment;
-use RuntimeException;
 
 use function array_filter;
 use function array_values;
@@ -351,12 +351,12 @@ trait ReflectionFunctionAbstract
      *
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getStartLine(): int
     {
         if ($this->startLine === null) {
-            throw new RuntimeException('Start line missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->startLine;
@@ -367,12 +367,12 @@ trait ReflectionFunctionAbstract
      *
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getEndLine(): int
     {
         if ($this->endLine === null) {
-            throw new RuntimeException('End line missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->endLine;
@@ -381,12 +381,12 @@ trait ReflectionFunctionAbstract
     /**
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getStartColumn(): int
     {
         if ($this->startColumn === null) {
-            throw new RuntimeException('Start column missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->startColumn;
@@ -395,12 +395,12 @@ trait ReflectionFunctionAbstract
     /**
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getEndColumn(): int
     {
         if ($this->endColumn === null) {
-            throw new RuntimeException('End column missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->endColumn;
diff --git a/src/Reflection/ReflectionParameter.php b/src/Reflection/ReflectionParameter.php
index b8237187..3a957c1f 100644
--- a/src/Reflection/ReflectionParameter.php
+++ b/src/Reflection/ReflectionParameter.php
@@ -16,11 +16,11 @@ use Roave\BetterReflection\NodeCompiler\CompileNodeToValue;
 use Roave\BetterReflection\NodeCompiler\CompilerContext;
 use Roave\BetterReflection\NodeCompiler\Exception\UnableToCompileNode;
 use Roave\BetterReflection\Reflection\Attribute\ReflectionAttributeHelper;
+use Roave\BetterReflection\Reflection\Exception\CodeLocationMissing;
 use Roave\BetterReflection\Reflection\StringCast\ReflectionParameterStringCast;
 use Roave\BetterReflection\Reflector\Reflector;
 use Roave\BetterReflection\Util\CalculateReflectionColumn;
 use Roave\BetterReflection\Util\Exception\NoNodePosition;
-use RuntimeException;
 
 use function array_map;
 use function assert;
@@ -483,12 +483,12 @@ class ReflectionParameter
     /**
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getStartLine(): int
     {
         if ($this->startLine === null) {
-            throw new RuntimeException('Start line missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->startLine;
@@ -497,12 +497,12 @@ class ReflectionParameter
     /**
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getEndLine(): int
     {
         if ($this->endLine === null) {
-            throw new RuntimeException('End line missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->endLine;
@@ -511,12 +511,12 @@ class ReflectionParameter
     /**
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getStartColumn(): int
     {
         if ($this->startColumn === null) {
-            throw new RuntimeException('Start column missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->startColumn;
@@ -525,12 +525,12 @@ class ReflectionParameter
     /**
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getEndColumn(): int
     {
         if ($this->endColumn === null) {
-            throw new RuntimeException('End column missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->endColumn;
diff --git a/src/Reflection/ReflectionProperty.php b/src/Reflection/ReflectionProperty.php
index 718f688a..6efe09a5 100644
--- a/src/Reflection/ReflectionProperty.php
+++ b/src/Reflection/ReflectionProperty.php
@@ -18,6 +18,7 @@ use Roave\BetterReflection\Reflection\Adapter\ReflectionProperty as ReflectionPr
 use Roave\BetterReflection\Reflection\Annotation\AnnotationHelper;
 use Roave\BetterReflection\Reflection\Attribute\ReflectionAttributeHelper;
 use Roave\BetterReflection\Reflection\Exception\ClassDoesNotExist;
+use Roave\BetterReflection\Reflection\Exception\CodeLocationMissing;
 use Roave\BetterReflection\Reflection\Exception\NoObjectProvided;
 use Roave\BetterReflection\Reflection\Exception\NotAnObject;
 use Roave\BetterReflection\Reflection\Exception\ObjectNotInstanceOfClass;
@@ -28,7 +29,6 @@ use Roave\BetterReflection\Util\CalculateReflectionColumn;
 use Roave\BetterReflection\Util\ClassExistenceChecker;
 use Roave\BetterReflection\Util\Exception\NoNodePosition;
 use Roave\BetterReflection\Util\GetLastDocComment;
-use RuntimeException;
 
 use function array_map;
 use function assert;
@@ -359,12 +359,12 @@ class ReflectionProperty
      *
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getStartLine(): int
     {
         if ($this->startLine === null) {
-            throw new RuntimeException('Start line missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->startLine;
@@ -375,12 +375,12 @@ class ReflectionProperty
      *
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getEndLine(): int
     {
         if ($this->endLine === null) {
-            throw new RuntimeException('End line missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->endLine;
@@ -389,12 +389,12 @@ class ReflectionProperty
     /**
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getStartColumn(): int
     {
         if ($this->startColumn === null) {
-            throw new RuntimeException('Start column missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->startColumn;
@@ -403,12 +403,12 @@ class ReflectionProperty
     /**
      * @return positive-int
      *
-     * @throws RuntimeException
+     * @throws CodeLocationMissing
      */
     public function getEndColumn(): int
     {
         if ($this->endColumn === null) {
-            throw new RuntimeException('End column missing');
+            throw CodeLocationMissing::create();
         }
 
         return $this->endColumn;


Test patch:
diff --git a/test/unit/Reflection/Exception/CodeLocationMissingTest.php b/test/unit/Reflection/Exception/CodeLocationMissingTest.php
new file mode 100644
index 00000000..d453791f
--- /dev/null
+++ b/test/unit/Reflection/Exception/CodeLocationMissingTest.php
@@ -0,0 +1,20 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Roave\BetterReflectionTest\Reflection\Exception;
+
+use PHPUnit\Framework\TestCase;
+use Roave\BetterReflection\Reflection\Exception\CodeLocationMissing;
+
+/** @covers \Roave\BetterReflection\Reflection\Exception\CodeLocationMissing */
+class CodeLocationMissingTest extends TestCase
+{
+    public function testCreate(): void
+    {
+        $exception = CodeLocationMissing::create();
+
+        self::assertInstanceOf(CodeLocationMissing::class, $exception);
+        self::assertSame('Code location is missing', $exception->getMessage());
+    }
+}
diff --git a/test/unit/Reflection/ReflectionFunctionAbstractTest.php b/test/unit/Reflection/ReflectionFunctionAbstractTest.php
index 2549adb2..c56221b1 100644
--- a/test/unit/Reflection/ReflectionFunctionAbstractTest.php
+++ b/test/unit/Reflection/ReflectionFunctionAbstractTest.php
@@ -8,6 +8,7 @@ use PhpParser\Node\Stmt\Function_;
 use PhpParser\Parser;
 use PHPUnit\Framework\TestCase;
 use ReflectionClass as CoreReflectionClass;
+use Roave\BetterReflection\Reflection\Exception\CodeLocationMissing;
 use Roave\BetterReflection\Reflection\ReflectionFunction;
 use Roave\BetterReflection\Reflection\ReflectionParameter;
 use Roave\BetterReflection\Reflection\ReflectionType;
@@ -23,7 +24,6 @@ use Roave\BetterReflection\SourceLocator\Type\StringSourceLocator;
 use Roave\BetterReflectionTest\BetterReflectionSingleton;
 use Roave\BetterReflectionTest\Fixture\Attr;
 use Roave\BetterReflectionTest\Fixture\StringEnum;
-use RuntimeException;
 use stdClass;
 
 use function sprintf;
@@ -296,7 +296,7 @@ class ReflectionFunctionAbstractTest extends TestCase
         $classReflection  = $reflector->reflectClass(StringEnum::class);
         $methodReflection = $classReflection->getMethod('tryFrom');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $methodReflection->getStartLine();
     }
 
@@ -310,7 +310,7 @@ class ReflectionFunctionAbstractTest extends TestCase
         $classReflection  = $reflector->reflectClass(StringEnum::class);
         $methodReflection = $classReflection->getMethod('tryFrom');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $methodReflection->getEndLine();
     }
 
@@ -324,7 +324,7 @@ class ReflectionFunctionAbstractTest extends TestCase
         $classReflection  = $reflector->reflectClass(StringEnum::class);
         $methodReflection = $classReflection->getMethod('tryFrom');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $methodReflection->getStartColumn();
     }
 
@@ -338,7 +338,7 @@ class ReflectionFunctionAbstractTest extends TestCase
         $classReflection  = $reflector->reflectClass(StringEnum::class);
         $methodReflection = $classReflection->getMethod('tryFrom');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $methodReflection->getEndColumn();
     }
 
diff --git a/test/unit/Reflection/ReflectionParameterTest.php b/test/unit/Reflection/ReflectionParameterTest.php
index bebf9972..0685586c 100644
--- a/test/unit/Reflection/ReflectionParameterTest.php
+++ b/test/unit/Reflection/ReflectionParameterTest.php
@@ -9,6 +9,7 @@ use LogicException;
 use OutOfBoundsException;
 use PhpParser\Node;
 use PHPUnit\Framework\TestCase;
+use Roave\BetterReflection\Reflection\Exception\CodeLocationMissing;
 use Roave\BetterReflection\Reflection\ReflectionFunction;
 use Roave\BetterReflection\Reflection\ReflectionMethod;
 use Roave\BetterReflection\Reflection\ReflectionParameter;
@@ -30,7 +31,6 @@ use Roave\BetterReflectionTest\Fixture\NullableParameterTypeDeclarations;
 use Roave\BetterReflectionTest\Fixture\PhpParameterTypeDeclarations;
 use Roave\BetterReflectionTest\Fixture\StringEnum;
 use Roave\BetterReflectionTest\FixtureOther\OtherClass;
-use RuntimeException;
 use SplDoublyLinkedList;
 use stdClass;
 use Throwable;
@@ -596,7 +596,7 @@ class ReflectionParameterTest extends TestCase
             false,
         );
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $parameterReflection->getStartLine();
     }
 
@@ -614,7 +614,7 @@ class ReflectionParameterTest extends TestCase
             false,
         );
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $parameterReflection->getEndLine();
     }
 
@@ -632,7 +632,7 @@ class ReflectionParameterTest extends TestCase
             false,
         );
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $parameterReflection->getStartColumn();
     }
 
@@ -650,7 +650,7 @@ class ReflectionParameterTest extends TestCase
             false,
         );
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $parameterReflection->getEndColumn();
     }
 
@@ -665,7 +665,7 @@ class ReflectionParameterTest extends TestCase
         $methodReflection    = $classReflection->getMethod('tryFrom');
         $parameterReflection = $methodReflection->getParameter('value');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $parameterReflection->getStartLine();
     }
 
@@ -680,7 +680,7 @@ class ReflectionParameterTest extends TestCase
         $methodReflection    = $classReflection->getMethod('tryFrom');
         $parameterReflection = $methodReflection->getParameter('value');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $parameterReflection->getEndLine();
     }
 
@@ -695,7 +695,7 @@ class ReflectionParameterTest extends TestCase
         $methodReflection    = $classReflection->getMethod('tryFrom');
         $parameterReflection = $methodReflection->getParameter('value');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $parameterReflection->getStartColumn();
     }
 
@@ -710,7 +710,7 @@ class ReflectionParameterTest extends TestCase
         $methodReflection    = $classReflection->getMethod('tryFrom');
         $parameterReflection = $methodReflection->getParameter('value');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $parameterReflection->getEndColumn();
     }
 
diff --git a/test/unit/Reflection/ReflectionPropertyTest.php b/test/unit/Reflection/ReflectionPropertyTest.php
index f5463dcd..20ad0636 100644
--- a/test/unit/Reflection/ReflectionPropertyTest.php
+++ b/test/unit/Reflection/ReflectionPropertyTest.php
@@ -16,6 +16,7 @@ use PHPUnit\Framework\TestCase;
 use ReflectionProperty as CoreReflectionProperty;
 use Roave\BetterReflection\Reflection\Adapter\ReflectionProperty as ReflectionPropertyAdapter;
 use Roave\BetterReflection\Reflection\Exception\ClassDoesNotExist;
+use Roave\BetterReflection\Reflection\Exception\CodeLocationMissing;
 use Roave\BetterReflection\Reflection\Exception\NoObjectProvided;
 use Roave\BetterReflection\Reflection\Exception\NotAnObject;
 use Roave\BetterReflection\Reflection\Exception\ObjectNotInstanceOfClass;
@@ -41,7 +42,6 @@ use Roave\BetterReflectionTest\Fixture\PropertyGetSet;
 use Roave\BetterReflectionTest\Fixture\StaticPropertyGetSet;
 use Roave\BetterReflectionTest\Fixture\StringEnum;
 use Roave\BetterReflectionTest\Fixture\TraitStaticPropertyGetSet;
-use RuntimeException;
 use stdClass;
 use TraitWithProperty;
 
@@ -388,7 +388,7 @@ class ReflectionPropertyTest extends TestCase
         $classReflection    = $reflector->reflectClass(StringEnum::class);
         $propertyReflection = $classReflection->getProperty('name');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $propertyReflection->getStartLine();
     }
 
@@ -402,7 +402,7 @@ class ReflectionPropertyTest extends TestCase
         $classReflection    = $reflector->reflectClass(StringEnum::class);
         $propertyReflection = $classReflection->getProperty('name');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $propertyReflection->getEndLine();
     }
 
@@ -416,7 +416,7 @@ class ReflectionPropertyTest extends TestCase
         $classReflection    = $reflector->reflectClass(StringEnum::class);
         $propertyReflection = $classReflection->getProperty('name');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $propertyReflection->getStartColumn();
     }
 
@@ -430,7 +430,7 @@ class ReflectionPropertyTest extends TestCase
         $classReflection    = $reflector->reflectClass(StringEnum::class);
         $propertyReflection = $classReflection->getProperty('name');
 
-        self::expectException(RuntimeException::class);
+        self::expectException(CodeLocationMissing::class);
         $propertyReflection->getEndColumn();
     }