Merge pull request #385 from dantleech/phpstan-level-3

PHPStan Level 3
This commit is contained in:
Rob Lourens 2022-11-21 14:14:04 -08:00 коммит произвёл GitHub
Родитель 3eccfd2733 937564f03f
Коммит 6bd3e3ba00
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 49 добавлений и 38 удалений

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

@ -25,7 +25,6 @@ cache:
- validation/frameworks
before_script:
- if [[ $STATIC_ANALYSIS = true ]]; then composer require phpstan/phpstan --no-update; fi
- composer install
- set -e # Stop on first error.
- phpenv config-rm xdebug.ini || true

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

@ -6,7 +6,8 @@
"php": ">=7.2"
},
"require-dev": {
"phpunit/phpunit": "^8.5.15"
"phpunit/phpunit": "^8.5.15",
"phpstan/phpstan": "^1.8"
},
"license": "MIT",
"authors": [

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

@ -1,5 +1,5 @@
parameters:
level: 2
level: 3
paths:
- src/
ignoreErrors:

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

@ -140,6 +140,8 @@ abstract class Node implements \JsonSerializable {
while ($node->parent !== null) {
$node = $node->parent;
}
/** @var SourceFileNode $node */
return $node;
}
@ -613,6 +615,7 @@ abstract class Node implements \JsonSerializable {
$namespaceDefinition = null;
}
/** @var NamespaceDefinition|null $namespaceDefinition */
return $namespaceDefinition;
}

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

@ -16,7 +16,7 @@ class EnumCaseDeclaration extends Node {
/** @var Token */
public $caseKeyword;
/** @var QualifiedName */
/** @var Token */
public $name;
/** @var Token|null */

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

@ -11,7 +11,7 @@ use Microsoft\PhpParser\Token;
class AssignmentExpression extends BinaryExpression {
/** @var Expression */
/** @var Expression|Token */
public $leftOperand;
/** @var Token */

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

@ -11,13 +11,13 @@ use Microsoft\PhpParser\Token;
class BinaryExpression extends Expression {
/** @var Expression */
/** @var Expression|Token */
public $leftOperand;
/** @var Token */
public $operator;
/** @var Expression */
/** @var Expression|Token */
public $rightOperand;
const CHILD_NAMES = [

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

@ -13,9 +13,6 @@ class PrefixUpdateExpression extends UnaryExpression {
/** @var Token */
public $incrementOrDecrementOperator;
/** @var Variable */
public $operand;
const CHILD_NAMES = [
'incrementOrDecrementOperator',
'operand'

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

@ -6,6 +6,7 @@
namespace Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\MissingToken;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Token;
@ -17,7 +18,7 @@ class SubscriptExpression extends Expression {
/** @var Token */
public $openBracketOrBrace;
/** @var Expression */
/** @var Expression|MissingToken */
public $accessExpression;
/** @var Token */

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

@ -7,9 +7,10 @@
namespace Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Node\Expression;
use Microsoft\PhpParser\Token;
class UnaryExpression extends Expression {
/** @var UnaryExpression|Variable */
/** @var Expression|Variable|Token */
public $operand;
const CHILD_NAMES = [

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

@ -13,9 +13,6 @@ class UnaryOpExpression extends UnaryExpression {
/** @var Token */
public $operator;
/** @var UnaryExpression */
public $operand;
const CHILD_NAMES = [
'operator',
'operand'

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

@ -6,6 +6,7 @@
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\MissingToken;
use Microsoft\PhpParser\Token;
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
/** @var Token|null */
public $questionToken;
/** @var DelimitedList\QualifiedNameList|null */
/** @var DelimitedList\QualifiedNameList|null|MissingToken */
public $returnTypeList;
}

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

@ -6,6 +6,7 @@
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\MissingToken;
use Microsoft\PhpParser\ModifiedTypeInterface;
use Microsoft\PhpParser\ModifiedTypeTrait;
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 */
public $questionToken;
/** @var DelimitedList\QualifiedNameList|null */
/** @var DelimitedList\QualifiedNameList|null|MissingToken */
public $typeDeclarationList;
const CHILD_NAMES = [

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

@ -6,12 +6,13 @@
namespace Microsoft\PhpParser\Node;
use Microsoft\PhpParser\MissingToken;
use Microsoft\PhpParser\Node;
use Microsoft\PhpParser\Node\DelimitedList;
use Microsoft\PhpParser\Token;
class NamespaceUseClause extends Node {
/** @var QualifiedName */
/** @var QualifiedName|MissingToken */
public $namespaceName;
/** @var NamespaceAliasingClause */
public $namespaceAliasingClause;

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

@ -20,7 +20,7 @@ class InlineHtml extends StatementNode {
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,
* and is deliberately excluded from CHILD_NAMES.

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

@ -6,6 +6,7 @@
namespace Microsoft\PhpParser\Node\Statement;
use Microsoft\PhpParser\MissingToken;
use Microsoft\PhpParser\Node\QualifiedName;
use Microsoft\PhpParser\Node\StatementNode;
use Microsoft\PhpParser\Token;
@ -17,7 +18,7 @@ use Microsoft\PhpParser\Node\SourceFileNode;
class NamespaceDefinition extends StatementNode {
/** @var Token */
public $namespaceKeyword;
/** @var QualifiedName|null */
/** @var QualifiedName|null|MissingToken */
public $name;
/** @var CompoundStatementNode|Token */
public $compoundStatementOrSemicolon;

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

@ -691,7 +691,7 @@ class Parser {
return $classNode;
}
private function parseClassMembers($parentNode) : Node {
private function parseClassMembers($parentNode) : ClassMembersNode {
$classMembers = new ClassMembersNode();
$classMembers->openBrace = $this->eat1(TokenKind::OpenBraceToken);
$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) {
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 callable $isElementStartFn
* @param callable $parseElementFn
* @param Node $parentNode
* @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) {
// TODO consider allowing empty delimiter to be more tolerant
@ -1994,7 +1995,7 @@ class Parser {
/**
* @param Node $parentNode
* @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) {
$token = $this->getCurrentToken();
@ -2020,7 +2021,7 @@ class Parser {
/**
* @param Node $parentNode
* @return Expression
* @return UnaryExpression|MissingToken|Variable|ThrowExpression
*/
private function parseUnaryExpressionOrHigher($parentNode) {
$token = $this->getCurrentToken();
@ -3212,9 +3213,16 @@ class Parser {
private function parseScopedPropertyAccessExpression($expression, $fallbackParentNode): ScopedPropertyAccessExpression {
$scopedPropertyAccessExpression = new ScopedPropertyAccessExpression();
$scopedPropertyAccessExpression->parent = $expression->parent ?? $fallbackParentNode;
if ($expression instanceof Node) {
$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);
@ -3362,18 +3370,18 @@ class Parser {
}
private function parseEnumCaseDeclaration($parentNode) {
$classConstDeclaration = new EnumCaseDeclaration();
$classConstDeclaration->parent = $parentNode;
$classConstDeclaration->caseKeyword = $this->eat1(TokenKind::CaseKeyword);
$classConstDeclaration->name = $this->eat($this->nameOrKeywordOrReservedWordTokens);
$classConstDeclaration->equalsToken = $this->eatOptional1(TokenKind::EqualsToken);
if ($classConstDeclaration->equalsToken !== null) {
$enumCaseDeclaration = new EnumCaseDeclaration();
$enumCaseDeclaration->parent = $parentNode;
$enumCaseDeclaration->caseKeyword = $this->eat1(TokenKind::CaseKeyword);
$enumCaseDeclaration->name = $this->eat($this->nameOrKeywordOrReservedWordTokens);
$enumCaseDeclaration->equalsToken = $this->eatOptional1(TokenKind::EqualsToken);
if ($enumCaseDeclaration->equalsToken !== null) {
// 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;
}
private function parseInterfaceDeclaration($parentNode) {
private function parseInterfaceDeclaration($parentNode): InterfaceDeclaration {
$interfaceDeclaration = new InterfaceDeclaration(); // TODO verify not nested
$interfaceDeclaration->parent = $parentNode;
$interfaceDeclaration->interfaceKeyword = $this->eat1(TokenKind::InterfaceKeyword);
@ -3456,7 +3464,7 @@ class Parser {
return $interfaceDeclaration;
}
private function parseInterfaceMembers($parentNode) : Node {
private function parseInterfaceMembers($parentNode) : InterfaceMembers {
$interfaceMembers = new InterfaceMembers();
$interfaceMembers->openBrace = $this->eat1(TokenKind::OpenBraceToken);
$interfaceMembers->interfaceMemberDeclarations = $this->parseList($interfaceMembers, ParseContext::InterfaceMembers);