Коммит
6bd3e3ba00
|
@ -25,7 +25,6 @@ cache:
|
||||||
- validation/frameworks
|
- validation/frameworks
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- if [[ $STATIC_ANALYSIS = true ]]; then composer require phpstan/phpstan --no-update; fi
|
|
||||||
- composer install
|
- composer install
|
||||||
- set -e # Stop on first error.
|
- set -e # Stop on first error.
|
||||||
- phpenv config-rm xdebug.ini || true
|
- phpenv config-rm xdebug.ini || true
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
"php": ">=7.2"
|
"php": ">=7.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^8.5.15"
|
"phpunit/phpunit": "^8.5.15",
|
||||||
|
"phpstan/phpstan": "^1.8"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
parameters:
|
parameters:
|
||||||
level: 2
|
level: 3
|
||||||
paths:
|
paths:
|
||||||
- src/
|
- src/
|
||||||
ignoreErrors:
|
ignoreErrors:
|
||||||
|
|
|
@ -140,6 +140,8 @@ abstract class Node implements \JsonSerializable {
|
||||||
while ($node->parent !== null) {
|
while ($node->parent !== null) {
|
||||||
$node = $node->parent;
|
$node = $node->parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var SourceFileNode $node */
|
||||||
return $node;
|
return $node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,6 +615,7 @@ abstract class Node implements \JsonSerializable {
|
||||||
$namespaceDefinition = null;
|
$namespaceDefinition = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var NamespaceDefinition|null $namespaceDefinition */
|
||||||
return $namespaceDefinition;
|
return $namespaceDefinition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ class EnumCaseDeclaration extends Node {
|
||||||
/** @var Token */
|
/** @var Token */
|
||||||
public $caseKeyword;
|
public $caseKeyword;
|
||||||
|
|
||||||
/** @var QualifiedName */
|
/** @var Token */
|
||||||
public $name;
|
public $name;
|
||||||
|
|
||||||
/** @var Token|null */
|
/** @var Token|null */
|
||||||
|
|
|
@ -11,7 +11,7 @@ use Microsoft\PhpParser\Token;
|
||||||
|
|
||||||
class AssignmentExpression extends BinaryExpression {
|
class AssignmentExpression extends BinaryExpression {
|
||||||
|
|
||||||
/** @var Expression */
|
/** @var Expression|Token */
|
||||||
public $leftOperand;
|
public $leftOperand;
|
||||||
|
|
||||||
/** @var Token */
|
/** @var Token */
|
||||||
|
|
|
@ -11,13 +11,13 @@ use Microsoft\PhpParser\Token;
|
||||||
|
|
||||||
class BinaryExpression extends Expression {
|
class BinaryExpression extends Expression {
|
||||||
|
|
||||||
/** @var Expression */
|
/** @var Expression|Token */
|
||||||
public $leftOperand;
|
public $leftOperand;
|
||||||
|
|
||||||
/** @var Token */
|
/** @var Token */
|
||||||
public $operator;
|
public $operator;
|
||||||
|
|
||||||
/** @var Expression */
|
/** @var Expression|Token */
|
||||||
public $rightOperand;
|
public $rightOperand;
|
||||||
|
|
||||||
const CHILD_NAMES = [
|
const CHILD_NAMES = [
|
||||||
|
|
|
@ -13,9 +13,6 @@ class PrefixUpdateExpression extends UnaryExpression {
|
||||||
/** @var Token */
|
/** @var Token */
|
||||||
public $incrementOrDecrementOperator;
|
public $incrementOrDecrementOperator;
|
||||||
|
|
||||||
/** @var Variable */
|
|
||||||
public $operand;
|
|
||||||
|
|
||||||
const CHILD_NAMES = [
|
const CHILD_NAMES = [
|
||||||
'incrementOrDecrementOperator',
|
'incrementOrDecrementOperator',
|
||||||
'operand'
|
'operand'
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
namespace Microsoft\PhpParser\Node\Expression;
|
namespace Microsoft\PhpParser\Node\Expression;
|
||||||
|
|
||||||
|
use Microsoft\PhpParser\MissingToken;
|
||||||
use Microsoft\PhpParser\Node\Expression;
|
use Microsoft\PhpParser\Node\Expression;
|
||||||
use Microsoft\PhpParser\Token;
|
use Microsoft\PhpParser\Token;
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ class SubscriptExpression extends Expression {
|
||||||
/** @var Token */
|
/** @var Token */
|
||||||
public $openBracketOrBrace;
|
public $openBracketOrBrace;
|
||||||
|
|
||||||
/** @var Expression */
|
/** @var Expression|MissingToken */
|
||||||
public $accessExpression;
|
public $accessExpression;
|
||||||
|
|
||||||
/** @var Token */
|
/** @var Token */
|
||||||
|
|
|
@ -7,9 +7,10 @@
|
||||||
namespace Microsoft\PhpParser\Node\Expression;
|
namespace Microsoft\PhpParser\Node\Expression;
|
||||||
|
|
||||||
use Microsoft\PhpParser\Node\Expression;
|
use Microsoft\PhpParser\Node\Expression;
|
||||||
|
use Microsoft\PhpParser\Token;
|
||||||
|
|
||||||
class UnaryExpression extends Expression {
|
class UnaryExpression extends Expression {
|
||||||
/** @var UnaryExpression|Variable */
|
/** @var Expression|Variable|Token */
|
||||||
public $operand;
|
public $operand;
|
||||||
|
|
||||||
const CHILD_NAMES = [
|
const CHILD_NAMES = [
|
||||||
|
|
|
@ -13,9 +13,6 @@ class UnaryOpExpression extends UnaryExpression {
|
||||||
/** @var Token */
|
/** @var Token */
|
||||||
public $operator;
|
public $operator;
|
||||||
|
|
||||||
/** @var UnaryExpression */
|
|
||||||
public $operand;
|
|
||||||
|
|
||||||
const CHILD_NAMES = [
|
const CHILD_NAMES = [
|
||||||
'operator',
|
'operator',
|
||||||
'operand'
|
'operand'
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
namespace Microsoft\PhpParser\Node;
|
namespace Microsoft\PhpParser\Node;
|
||||||
|
|
||||||
|
use Microsoft\PhpParser\MissingToken;
|
||||||
use Microsoft\PhpParser\Token;
|
use Microsoft\PhpParser\Token;
|
||||||
|
|
||||||
trait FunctionReturnType {
|
trait FunctionReturnType {
|
||||||
|
@ -14,6 +15,6 @@ trait FunctionReturnType {
|
||||||
// TODO: This may be the wrong choice if ?type can ever be mixed with other types in union types
|
// TODO: This may be the wrong choice if ?type can ever be mixed with other types in union types
|
||||||
/** @var Token|null */
|
/** @var Token|null */
|
||||||
public $questionToken;
|
public $questionToken;
|
||||||
/** @var DelimitedList\QualifiedNameList|null */
|
/** @var DelimitedList\QualifiedNameList|null|MissingToken */
|
||||||
public $returnTypeList;
|
public $returnTypeList;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
namespace Microsoft\PhpParser\Node;
|
namespace Microsoft\PhpParser\Node;
|
||||||
|
|
||||||
|
use Microsoft\PhpParser\MissingToken;
|
||||||
use Microsoft\PhpParser\ModifiedTypeInterface;
|
use Microsoft\PhpParser\ModifiedTypeInterface;
|
||||||
use Microsoft\PhpParser\ModifiedTypeTrait;
|
use Microsoft\PhpParser\ModifiedTypeTrait;
|
||||||
use Microsoft\PhpParser\Node;
|
use Microsoft\PhpParser\Node;
|
||||||
|
@ -20,7 +21,7 @@ class MissingMemberDeclaration extends Node implements ModifiedTypeInterface {
|
||||||
/** @var Token|null needed along with typeDeclaration for what looked like typed property declarations but was missing VariableName */
|
/** @var Token|null needed along with typeDeclaration for what looked like typed property declarations but was missing VariableName */
|
||||||
public $questionToken;
|
public $questionToken;
|
||||||
|
|
||||||
/** @var DelimitedList\QualifiedNameList|null */
|
/** @var DelimitedList\QualifiedNameList|null|MissingToken */
|
||||||
public $typeDeclarationList;
|
public $typeDeclarationList;
|
||||||
|
|
||||||
const CHILD_NAMES = [
|
const CHILD_NAMES = [
|
||||||
|
|
|
@ -6,12 +6,13 @@
|
||||||
|
|
||||||
namespace Microsoft\PhpParser\Node;
|
namespace Microsoft\PhpParser\Node;
|
||||||
|
|
||||||
|
use Microsoft\PhpParser\MissingToken;
|
||||||
use Microsoft\PhpParser\Node;
|
use Microsoft\PhpParser\Node;
|
||||||
use Microsoft\PhpParser\Node\DelimitedList;
|
use Microsoft\PhpParser\Node\DelimitedList;
|
||||||
use Microsoft\PhpParser\Token;
|
use Microsoft\PhpParser\Token;
|
||||||
|
|
||||||
class NamespaceUseClause extends Node {
|
class NamespaceUseClause extends Node {
|
||||||
/** @var QualifiedName */
|
/** @var QualifiedName|MissingToken */
|
||||||
public $namespaceName;
|
public $namespaceName;
|
||||||
/** @var NamespaceAliasingClause */
|
/** @var NamespaceAliasingClause */
|
||||||
public $namespaceAliasingClause;
|
public $namespaceAliasingClause;
|
||||||
|
|
|
@ -20,7 +20,7 @@ class InlineHtml extends StatementNode {
|
||||||
public $scriptSectionStartTag;
|
public $scriptSectionStartTag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ExpressionStatement|null used to represent the expression echoed by `<?=` while parsing.
|
* @var EchoStatement|null used to represent the expression echoed by `<?=` while parsing.
|
||||||
*
|
*
|
||||||
* This should always be null in the returned AST,
|
* This should always be null in the returned AST,
|
||||||
* and is deliberately excluded from CHILD_NAMES.
|
* and is deliberately excluded from CHILD_NAMES.
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
namespace Microsoft\PhpParser\Node\Statement;
|
namespace Microsoft\PhpParser\Node\Statement;
|
||||||
|
|
||||||
|
use Microsoft\PhpParser\MissingToken;
|
||||||
use Microsoft\PhpParser\Node\QualifiedName;
|
use Microsoft\PhpParser\Node\QualifiedName;
|
||||||
use Microsoft\PhpParser\Node\StatementNode;
|
use Microsoft\PhpParser\Node\StatementNode;
|
||||||
use Microsoft\PhpParser\Token;
|
use Microsoft\PhpParser\Token;
|
||||||
|
@ -17,7 +18,7 @@ use Microsoft\PhpParser\Node\SourceFileNode;
|
||||||
class NamespaceDefinition extends StatementNode {
|
class NamespaceDefinition extends StatementNode {
|
||||||
/** @var Token */
|
/** @var Token */
|
||||||
public $namespaceKeyword;
|
public $namespaceKeyword;
|
||||||
/** @var QualifiedName|null */
|
/** @var QualifiedName|null|MissingToken */
|
||||||
public $name;
|
public $name;
|
||||||
/** @var CompoundStatementNode|Token */
|
/** @var CompoundStatementNode|Token */
|
||||||
public $compoundStatementOrSemicolon;
|
public $compoundStatementOrSemicolon;
|
||||||
|
|
|
@ -691,7 +691,7 @@ class Parser {
|
||||||
return $classNode;
|
return $classNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseClassMembers($parentNode) : Node {
|
private function parseClassMembers($parentNode) : ClassMembersNode {
|
||||||
$classMembers = new ClassMembersNode();
|
$classMembers = new ClassMembersNode();
|
||||||
$classMembers->openBrace = $this->eat1(TokenKind::OpenBraceToken);
|
$classMembers->openBrace = $this->eat1(TokenKind::OpenBraceToken);
|
||||||
$classMembers->classMemberDeclarations = $this->parseList($classMembers, ParseContext::ClassMembers);
|
$classMembers->classMemberDeclarations = $this->parseList($classMembers, ParseContext::ClassMembers);
|
||||||
|
@ -804,7 +804,7 @@ class Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return DelimitedList\AttributeElementList
|
* @return DelimitedList\AttributeElementList|null
|
||||||
*/
|
*/
|
||||||
private function parseAttributeElementList(AttributeGroup $parentNode) {
|
private function parseAttributeElementList(AttributeGroup $parentNode) {
|
||||||
return $this->parseDelimitedList(
|
return $this->parseDelimitedList(
|
||||||
|
@ -1638,13 +1638,14 @@ class Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $className (name of subclass of DelimitedList)
|
* @template TDelimitedList of DelimitedList
|
||||||
|
* @param class-string<TDelimitedList> $className (name of subclass of DelimitedList)
|
||||||
* @param int|int[] $delimiter
|
* @param int|int[] $delimiter
|
||||||
* @param callable $isElementStartFn
|
* @param callable $isElementStartFn
|
||||||
* @param callable $parseElementFn
|
* @param callable $parseElementFn
|
||||||
* @param Node $parentNode
|
* @param Node $parentNode
|
||||||
* @param bool $allowEmptyElements
|
* @param bool $allowEmptyElements
|
||||||
* @return DelimitedList|null instance of $className
|
* @return TDelimitedList|null instance of $className
|
||||||
*/
|
*/
|
||||||
private function parseDelimitedList($className, $delimiter, $isElementStartFn, $parseElementFn, $parentNode, $allowEmptyElements = false) {
|
private function parseDelimitedList($className, $delimiter, $isElementStartFn, $parseElementFn, $parentNode, $allowEmptyElements = false) {
|
||||||
// TODO consider allowing empty delimiter to be more tolerant
|
// TODO consider allowing empty delimiter to be more tolerant
|
||||||
|
@ -1994,7 +1995,7 @@ class Parser {
|
||||||
/**
|
/**
|
||||||
* @param Node $parentNode
|
* @param Node $parentNode
|
||||||
* @param bool $force
|
* @param bool $force
|
||||||
* @return Node|MissingToken|array - The expression, or a missing token, or (if $force) an array containing a missed and skipped token
|
* @return Expression|MissingToken|array - The expression, or a missing token, or (if $force) an array containing a missed and skipped token
|
||||||
*/
|
*/
|
||||||
private function parseExpression($parentNode, $force = false) {
|
private function parseExpression($parentNode, $force = false) {
|
||||||
$token = $this->getCurrentToken();
|
$token = $this->getCurrentToken();
|
||||||
|
@ -2020,7 +2021,7 @@ class Parser {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Node $parentNode
|
* @param Node $parentNode
|
||||||
* @return Expression
|
* @return UnaryExpression|MissingToken|Variable|ThrowExpression
|
||||||
*/
|
*/
|
||||||
private function parseUnaryExpressionOrHigher($parentNode) {
|
private function parseUnaryExpressionOrHigher($parentNode) {
|
||||||
$token = $this->getCurrentToken();
|
$token = $this->getCurrentToken();
|
||||||
|
@ -3212,9 +3213,16 @@ class Parser {
|
||||||
private function parseScopedPropertyAccessExpression($expression, $fallbackParentNode): ScopedPropertyAccessExpression {
|
private function parseScopedPropertyAccessExpression($expression, $fallbackParentNode): ScopedPropertyAccessExpression {
|
||||||
$scopedPropertyAccessExpression = new ScopedPropertyAccessExpression();
|
$scopedPropertyAccessExpression = new ScopedPropertyAccessExpression();
|
||||||
$scopedPropertyAccessExpression->parent = $expression->parent ?? $fallbackParentNode;
|
$scopedPropertyAccessExpression->parent = $expression->parent ?? $fallbackParentNode;
|
||||||
|
|
||||||
if ($expression instanceof Node) {
|
if ($expression instanceof Node) {
|
||||||
$expression->parent = $scopedPropertyAccessExpression;
|
$expression->parent = $scopedPropertyAccessExpression;
|
||||||
$scopedPropertyAccessExpression->scopeResolutionQualifier = $expression; // TODO ensure always a Node
|
|
||||||
|
// scopeResolutionQualifier does not accept `Node` but
|
||||||
|
// `Expression|QualifiedName|Token`. I'm not sure if we can depend
|
||||||
|
// on that being the case.
|
||||||
|
//
|
||||||
|
// @phpstan-ignore-next-line
|
||||||
|
$scopedPropertyAccessExpression->scopeResolutionQualifier = $expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
$scopedPropertyAccessExpression->doubleColon = $this->eat1(TokenKind::ColonColonToken);
|
$scopedPropertyAccessExpression->doubleColon = $this->eat1(TokenKind::ColonColonToken);
|
||||||
|
@ -3362,18 +3370,18 @@ class Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseEnumCaseDeclaration($parentNode) {
|
private function parseEnumCaseDeclaration($parentNode) {
|
||||||
$classConstDeclaration = new EnumCaseDeclaration();
|
$enumCaseDeclaration = new EnumCaseDeclaration();
|
||||||
$classConstDeclaration->parent = $parentNode;
|
$enumCaseDeclaration->parent = $parentNode;
|
||||||
$classConstDeclaration->caseKeyword = $this->eat1(TokenKind::CaseKeyword);
|
$enumCaseDeclaration->caseKeyword = $this->eat1(TokenKind::CaseKeyword);
|
||||||
$classConstDeclaration->name = $this->eat($this->nameOrKeywordOrReservedWordTokens);
|
$enumCaseDeclaration->name = $this->eat($this->nameOrKeywordOrReservedWordTokens);
|
||||||
$classConstDeclaration->equalsToken = $this->eatOptional1(TokenKind::EqualsToken);
|
$enumCaseDeclaration->equalsToken = $this->eatOptional1(TokenKind::EqualsToken);
|
||||||
if ($classConstDeclaration->equalsToken !== null) {
|
if ($enumCaseDeclaration->equalsToken !== null) {
|
||||||
// TODO add post-parse rule that checks for invalid assignments
|
// TODO add post-parse rule that checks for invalid assignments
|
||||||
$classConstDeclaration->assignment = $this->parseExpression($classConstDeclaration);
|
$enumCaseDeclaration->assignment = $this->parseExpression($enumCaseDeclaration);
|
||||||
}
|
}
|
||||||
$classConstDeclaration->semicolon = $this->eat1(TokenKind::SemicolonToken);
|
$enumCaseDeclaration->semicolon = $this->eat1(TokenKind::SemicolonToken);
|
||||||
|
|
||||||
return $classConstDeclaration;
|
return $enumCaseDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3446,7 +3454,7 @@ class Parser {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseInterfaceDeclaration($parentNode) {
|
private function parseInterfaceDeclaration($parentNode): InterfaceDeclaration {
|
||||||
$interfaceDeclaration = new InterfaceDeclaration(); // TODO verify not nested
|
$interfaceDeclaration = new InterfaceDeclaration(); // TODO verify not nested
|
||||||
$interfaceDeclaration->parent = $parentNode;
|
$interfaceDeclaration->parent = $parentNode;
|
||||||
$interfaceDeclaration->interfaceKeyword = $this->eat1(TokenKind::InterfaceKeyword);
|
$interfaceDeclaration->interfaceKeyword = $this->eat1(TokenKind::InterfaceKeyword);
|
||||||
|
@ -3456,7 +3464,7 @@ class Parser {
|
||||||
return $interfaceDeclaration;
|
return $interfaceDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseInterfaceMembers($parentNode) : Node {
|
private function parseInterfaceMembers($parentNode) : InterfaceMembers {
|
||||||
$interfaceMembers = new InterfaceMembers();
|
$interfaceMembers = new InterfaceMembers();
|
||||||
$interfaceMembers->openBrace = $this->eat1(TokenKind::OpenBraceToken);
|
$interfaceMembers->openBrace = $this->eat1(TokenKind::OpenBraceToken);
|
||||||
$interfaceMembers->interfaceMemberDeclarations = $this->parseList($interfaceMembers, ParseContext::InterfaceMembers);
|
$interfaceMembers->interfaceMemberDeclarations = $this->parseList($interfaceMembers, ParseContext::InterfaceMembers);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче