Refactoring modified type behaviors

This commit is contained in:
Felix Siebeneicker 2020-08-10 16:20:57 +02:00
Родитель b4f5f2c9c2
Коммит 6b07addab5
8 изменённых файлов: 164 добавлений и 94 удалений

Просмотреть файл

@ -0,0 +1,16 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
/**
* Use the ModifiedTypeTrait for convenience in order to implement this interface.
*/
interface ModifiedTypeInterface {
public function hasModifier(int $targetModifier): bool;
public function isPublic(): bool;
public function isStatic(): bool;
}

46
src/ModifiedTypeTrait.php Normal file
Просмотреть файл

@ -0,0 +1,46 @@
<?php
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
namespace Microsoft\PhpParser;
trait ModifiedTypeTrait {
/** @var Token[] */
public $modifiers;
public function hasModifier(int $targetModifier): bool {
if ($this->modifiers === null) {
return false;
}
foreach ($this->modifiers as $modifier) {
if ($modifier->kind === $targetModifier) {
return true;
}
}
return false;
}
/**
* Convenience method to check for the existence of the "public" modifier.
* Does not necessarily need to be defined for that type.
*
* @return bool
*/
public function isPublic(): bool {
return $this->hasModifier(TokenKind::PublicKeyword);
}
/**
* Convenience method to check for the existence of the "static" modifier.
* Does not necessarily need to be defined for that type.
*
* @return bool
*/
public function isStatic(): bool {
return $this->hasModifier(TokenKind::StaticKeyword);
}
}

Просмотреть файл

@ -6,13 +6,13 @@
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\ModifiedTypeInterface;
use Microsoft\PhpParser\ModifiedTypeTrait;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class ClassConstDeclaration extends Node {
/** @var Token[] */
public $modifiers;
class ClassConstDeclaration extends Node implements ModifiedTypeInterface {
use ModifiedTypeTrait;
/** @var Token */
public $constKeyword;

Просмотреть файл

@ -10,15 +10,14 @@ use Microsoft\PhpParser\Diagnostic;
use Microsoft\PhpParser\DiagnosticKind;
use Microsoft\PhpParser\DiagnosticsProvider;
use Microsoft\PhpParser\FunctionLike;
use Microsoft\PhpParser\ModifiedTypeInterface;
use Microsoft\PhpParser\ModifiedTypeTrait;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
use Microsoft\PhpParser\TokenKind;
class MethodDeclaration extends Node implements FunctionLike {
/** @var Token[] */
public $modifiers;
use FunctionHeader, FunctionReturnType, FunctionBody;
class MethodDeclaration extends Node implements FunctionLike, ModifiedTypeInterface {
use FunctionHeader, FunctionReturnType, FunctionBody, ModifiedTypeTrait;
const CHILD_NAMES = [
'modifiers',
@ -41,23 +40,12 @@ class MethodDeclaration extends Node implements FunctionLike {
'compoundStatementOrSemicolon'
];
public function hasModifier(int $targetModifier) : bool {
if ($this->modifiers === null) {
return false;
}
foreach ($this->modifiers as $modifier) {
if ($modifier->kind === $targetModifier) {
return true;
}
}
return false;
}
public function isStatic() : bool {
return $this->hasModifier(TokenKind::StaticKeyword);
}
public function getName() {
/**
* Returns the name of the method.
*
* @return string
*/
public function getName(): string {
return $this->name->getText($this->getFileContents());
}
@ -79,4 +67,64 @@ class MethodDeclaration extends Node implements FunctionLike {
}
return null;
}
/**
* Returns the signature parts as an array. Use $this::getSignatureFormatted for a user-friendly string version.
*
* @return array
*/
private function getSignatureParts(): array {
$parts = [];
foreach ($this->getChildNodesAndTokens() as $i => $child) {
if ($i === "compoundStatementOrSemicolon") {
return $parts;
}
$parts[] = $child instanceof Token
? $child->getText($this->getFileContents())
: $child->getText();
};
return $parts;
}
/**
* Returns the signature of the method as a formatted string.
*
* @return string
*/
public function getSignatureFormatted(): string {
$signature = implode(" ", $this->getSignatureParts());
return $signature;
}
/**
* Returns the description part of the doc string.
*
* @return string
*/
public function getDescriptionFormatted(): string {
$comment = trim($this->getLeadingCommentAndWhitespaceText(), "\r\n");
$commentParts = explode("\n", $comment);
$description = [];
foreach ($commentParts as $i => $part) {
$part = trim($part, "*\r\t /");
if (strlen($part) <= 0) {
continue;
}
if ($part[0] === "@") {
break;
}
$description[] = $part;
}
$descriptionFormatted = implode(" ", $description);
return $descriptionFormatted;
}
}

Просмотреть файл

@ -6,13 +6,13 @@
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\ModifiedTypeInterface;
use Microsoft\PhpParser\ModifiedTypeTrait;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class MissingMemberDeclaration extends Node {
/** @var Token[] */
public $modifiers;
class MissingMemberDeclaration extends Node implements ModifiedTypeInterface {
use ModifiedTypeTrait;
/** @var Token|null needed along with typeDeclaration for what looked like typed property declarations but was missing VariableName */
public $questionToken;

Просмотреть файл

@ -6,14 +6,13 @@
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\ModifiedTypeInterface;
use Microsoft\PhpParser\ModifiedTypeTrait;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
use Microsoft\PhpParser\TokenKind;
class PropertyDeclaration extends Node {
/** @var Token[] */
public $modifiers;
class PropertyDeclaration extends Node implements ModifiedTypeInterface {
use ModifiedTypeTrait;
/** @var Token|null question token for PHP 7.4 type declaration */
public $questionToken;
@ -41,16 +40,4 @@ class PropertyDeclaration extends Node {
'propertyElements',
'semicolon'
];
public function isStatic() : bool {
if ($this->modifiers === null) {
return false;
}
foreach ($this->modifiers as $modifier) {
if ($modifier->kind === TokenKind::StaticKeyword) {
return true;
}
}
return false;
}
}

Просмотреть файл

@ -6,19 +6,20 @@
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\ModifiedTypeInterface;
use Microsoft\PhpParser\ModifiedTypeTrait;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Token;
class TraitSelectOrAliasClause extends Node {
class TraitSelectOrAliasClause extends Node implements ModifiedTypeInterface {
use ModifiedTypeTrait;
/** @var QualifiedName|Node\Expression\ScopedPropertyAccessExpression */
public $name;
/** @var Token */
public $asOrInsteadOfKeyword;
/** @var Token[] */
public $modifiers;
/** @var QualifiedName|Node\Expression\ScopedPropertyAccessExpression */
public $targetName;

Просмотреть файл

@ -5,11 +5,8 @@
*--------------------------------------------------------------------------------------------*/
use Microsoft\PhpParser\Node\MethodDeclaration;
use Microsoft\PhpParser\Node\PropertyDeclaration;
use Microsoft\PhpParser\Node\Statement\ClassDeclaration;
use Microsoft\PhpParser\Parser;
use Microsoft\PhpParser\Token;
use Microsoft\PhpParser\TokenKind;
require_once __DIR__ . "/../src/bootstrap.php";
@ -32,6 +29,7 @@ echo "> Note: This documentation was auto-generated using this parser to help do
foreach ($files as $file) {
$ast = $parser->parseSourceFile(file_get_contents($file));
foreach ($ast->getDescendantNodes() as $descendant) {
if ($descendant instanceof ClassDeclaration) {
$className = $descendant->name->getText($descendant->getFileContents());
@ -39,34 +37,22 @@ foreach ($files as $file) {
// TODO consider not having a separate classMemberDeclarations node
foreach ($descendant->classMembers->classMemberDeclarations as $member) {
// TODO: Maybe ask a class directly for all its method declarations
if ($member instanceof MethodDeclaration) {
// TODO this should be a helper function on any modified types
foreach ($member->modifiers as $modifier) {
if ($modifier->kind === TokenKind::PublicKeyword) {
$fileContents = $member->getFileContents();
$signature = implode(" ", getSignatureParts($member));
$comment = trim($member->getLeadingCommentAndWhitespaceText(), "\r\n");
$commentParts = explode("\n", $comment);
$description = [];
foreach ($commentParts as $i=>$part) {
$part = trim($part, "*\r\t /");
if (isset($part[0])) {
if ($part[0] === "@") {
break;
}
$description[] = $part;
}
}
$comment = implode(" ", $description);
if (strlen(trim($comment, " \t")) === 0) {
$comment = "> TODO: add doc comment\n";
}
echo "### " . $className . "::" . $member->name->getText($member->getFileContents()) . PHP_EOL;
echo $comment . PHP_EOL;
echo "```php\n$signature\n```" . PHP_EOL;
}
if (!$member->isPublic()) {
continue;
}
$signature = $member->getSignatureFormatted();
$description = $member->getDescriptionFormatted();
if (strlen($description) <= 0) {
$description = "> TODO: add doc comment\n";
}
echo "### " . $className . "::" . $member->getName() . PHP_EOL;
echo $description . PHP_EOL;
echo "```php\n$signature\n```" . PHP_EOL;
}
}
}
@ -76,17 +62,3 @@ foreach ($files as $file) {
echo "## Node types
> TODO: complete documentation - in addition to the helper methods on the Node base class,
every Node object has properties specific to the Node type. Browse `src/Node/` to explore these properties.";
function getSignatureParts(MethodDeclaration $methodDeclaration) : array {
// TODO - something like this in API?
$parts = [];
foreach ($methodDeclaration->getChildNodesAndTokens() as $i=>$child) {
if ($i === "compoundStatementOrSemicolon") {
return $parts;
}
$parts[] = $child instanceof Token
? $child->getText($methodDeclaration->getFileContents())
: $child->getText();
};
return $parts;
}