Support reference in method tag

This commit is contained in:
Fabien Villepinte
2022-03-31 13:22:11 +00:00
parent 6baa6f8bd7
commit 29ed9ae60d
2 changed files with 75 additions and 12 deletions
+28 -7
View File
@@ -57,6 +57,9 @@ final class Method extends BaseTag implements Factory\StaticMethod
/** @var Type */ /** @var Type */
private $returnType; private $returnType;
/** @var bool */
private $returnsReference;
/** /**
* @param array<int, array<string, Type|string>> $arguments * @param array<int, array<string, Type|string>> $arguments
* @phpstan-param array<int, array{name: string, type: Type}|string> $arguments * @phpstan-param array<int, array{name: string, type: Type}|string> $arguments
@@ -66,7 +69,8 @@ final class Method extends BaseTag implements Factory\StaticMethod
array $arguments = [], array $arguments = [],
?Type $returnType = null, ?Type $returnType = null,
bool $static = false, bool $static = false,
?Description $description = null ?Description $description = null,
bool $returnsReference = false
) { ) {
Assert::stringNotEmpty($methodName); Assert::stringNotEmpty($methodName);
@@ -79,6 +83,7 @@ final class Method extends BaseTag implements Factory\StaticMethod
$this->returnType = $returnType; $this->returnType = $returnType;
$this->isStatic = $static; $this->isStatic = $static;
$this->description = $description; $this->description = $description;
$this->returnsReference = $returnsReference;
} }
public static function create( public static function create(
@@ -95,11 +100,13 @@ final class Method extends BaseTag implements Factory\StaticMethod
// 2. optionally the keyword "static" followed by whitespace // 2. optionally the keyword "static" followed by whitespace
// 3. optionally a word with underscores followed by whitespace : as // 3. optionally a word with underscores followed by whitespace : as
// type for the return value // type for the return value
// 4. then optionally a word with underscores followed by () and // 4. optionally an ampersand followed or not by whitespace : as
// a reference
// 5. then optionally a word with underscores followed by () and
// whitespace : as method name as used by phpDocumentor // whitespace : as method name as used by phpDocumentor
// 5. then a word with underscores, followed by ( and any character // 6. then a word with underscores, followed by ( and any character
// until a ) and whitespace : as method name with signature // until a ) and whitespace : as method name with signature
// 6. any remaining text : as description // 7. any remaining text : as description
if ( if (
!preg_match( !preg_match(
'/^ '/^
@@ -122,6 +129,11 @@ final class Method extends BaseTag implements Factory\StaticMethod
) )
\s+ \s+
)? )?
# Returns reference
(?:
(&)
\s*
)?
# Method name # Method name
([\w_]+) ([\w_]+)
# Arguments # Arguments
@@ -139,7 +151,7 @@ final class Method extends BaseTag implements Factory\StaticMethod
return null; return null;
} }
[, $static, $returnType, $methodName, $argumentLines, $description] = $matches; [, $static, $returnType, $returnsReference, $methodName, $argumentLines, $description] = $matches;
$static = $static === 'static'; $static = $static === 'static';
@@ -147,6 +159,8 @@ final class Method extends BaseTag implements Factory\StaticMethod
$returnType = 'void'; $returnType = 'void';
} }
$returnsReference = $returnsReference === '&';
$returnType = $typeResolver->resolve($returnType, $context); $returnType = $typeResolver->resolve($returnType, $context);
$description = $descriptionFactory->create($description, $context); $description = $descriptionFactory->create($description, $context);
@@ -172,7 +186,7 @@ final class Method extends BaseTag implements Factory\StaticMethod
} }
} }
return new static($methodName, $arguments, $returnType, $static, $description); return new static($methodName, $arguments, $returnType, $static, $description, $returnsReference);
} }
/** /**
@@ -207,6 +221,11 @@ final class Method extends BaseTag implements Factory\StaticMethod
return $this->returnType; return $this->returnType;
} }
public function returnsReference(): bool
{
return $this->returnsReference;
}
public function __toString(): string public function __toString(): string
{ {
$arguments = []; $arguments = [];
@@ -228,9 +247,11 @@ final class Method extends BaseTag implements Factory\StaticMethod
$methodName = $this->methodName; $methodName = $this->methodName;
$reference = $this->returnsReference ? '&' : '';
return $static return $static
. ($returnType !== '' ? ($static !== '' ? ' ' : '') . $returnType : '') . ($returnType !== '' ? ($static !== '' ? ' ' : '') . $returnType : '')
. ($methodName !== '' ? ($static !== '' || $returnType !== '' ? ' ' : '') . $methodName : '') . ($methodName !== '' ? ($static !== '' || $returnType !== '' ? ' ' : '') . $reference . $methodName : '')
. $argumentStr . $argumentStr
. ($description !== '' ? ' ' . $description : ''); . ($description !== '' ? ' ' . $description : '');
} }
+42
View File
@@ -339,6 +339,7 @@ class MethodTest extends TestCase
$this->assertEquals($expectedArguments, $fixture->getArguments()); $this->assertEquals($expectedArguments, $fixture->getArguments());
$this->assertInstanceOf(Void_::class, $fixture->getReturnType()); $this->assertInstanceOf(Void_::class, $fixture->getReturnType());
$this->assertSame($description, $fixture->getDescription()); $this->assertSame($description, $fixture->getDescription());
$this->assertFalse($fixture->returnsReference());
} }
/** /**
@@ -370,6 +371,7 @@ class MethodTest extends TestCase
$this->assertSame('static $this myMethod()', (string) $fixture); $this->assertSame('static $this myMethod()', (string) $fixture);
$this->assertSame('myMethod', $fixture->getMethodName()); $this->assertSame('myMethod', $fixture->getMethodName());
$this->assertInstanceOf(This::class, $fixture->getReturnType()); $this->assertInstanceOf(This::class, $fixture->getReturnType());
$this->assertFalse($fixture->returnsReference());
} }
/** /**
@@ -401,6 +403,7 @@ class MethodTest extends TestCase
$this->assertSame('void myVeryLongMethodName(mixed $node)', (string) $fixture); $this->assertSame('void myVeryLongMethodName(mixed $node)', (string) $fixture);
$this->assertSame('myVeryLongMethodName', $fixture->getMethodName()); $this->assertSame('myVeryLongMethodName', $fixture->getMethodName());
$this->assertInstanceOf(Void_::class, $fixture->getReturnType()); $this->assertInstanceOf(Void_::class, $fixture->getReturnType());
$this->assertFalse($fixture->returnsReference());
} }
/** /**
@@ -542,6 +545,7 @@ class MethodTest extends TestCase
$this->assertEquals([], $fixture->getArguments()); $this->assertEquals([], $fixture->getArguments());
$this->assertInstanceOf(Void_::class, $fixture->getReturnType()); $this->assertInstanceOf(Void_::class, $fixture->getReturnType());
$this->assertSame($description, $fixture->getDescription()); $this->assertSame($description, $fixture->getDescription());
$this->assertFalse($fixture->returnsReference());
} }
/** /**
@@ -578,6 +582,7 @@ class MethodTest extends TestCase
$this->assertEquals([], $fixture->getArguments()); $this->assertEquals([], $fixture->getArguments());
$this->assertInstanceOf(Void_::class, $fixture->getReturnType()); $this->assertInstanceOf(Void_::class, $fixture->getReturnType());
$this->assertSame($description, $fixture->getDescription()); $this->assertSame($description, $fixture->getDescription());
$this->assertFalse($fixture->returnsReference());
} }
/** /**
@@ -613,6 +618,7 @@ class MethodTest extends TestCase
$this->assertEquals([], $fixture->getArguments()); $this->assertEquals([], $fixture->getArguments());
$this->assertInstanceOf(Void_::class, $fixture->getReturnType()); $this->assertInstanceOf(Void_::class, $fixture->getReturnType());
$this->assertSame($description, $fixture->getDescription()); $this->assertSame($description, $fixture->getDescription());
$this->assertFalse($fixture->returnsReference());
} }
/** /**
@@ -656,4 +662,40 @@ class MethodTest extends TestCase
$fixture->getReturnType() $fixture->getReturnType()
); );
} }
/**
* @uses \phpDocumentor\Reflection\DocBlock\Tags\Method::<public>
* @uses \phpDocumentor\Reflection\DocBlock\DescriptionFactory
* @uses \phpDocumentor\Reflection\TypeResolver
* @uses \phpDocumentor\Reflection\DocBlock\Description
* @uses \phpDocumentor\Reflection\Fqsen
* @uses \phpDocumentor\Reflection\Types\Context
* @uses \phpDocumentor\Reflection\Types\String_
*
* @covers ::create
*/
public function testCreateWithReference(): void
{
$descriptionFactory = m::mock(DescriptionFactory::class);
$resolver = new TypeResolver();
$context = new Context('');
$description = new Description('');
$descriptionFactory->shouldReceive('create')->with('', $context)->andReturn($description);
$fixture = Method::create(
'string &myMethod()',
$resolver,
$descriptionFactory,
$context
);
$this->assertSame('string &myMethod()', (string) $fixture);
$this->assertSame('myMethod', $fixture->getMethodName());
$this->assertEquals([], $fixture->getArguments());
$this->assertInstanceOf(String_::class, $fixture->getReturnType());
$this->assertSame($description, $fixture->getDescription());
$this->assertTrue($fixture->returnsReference());
}
} }