Skip to content

Commit 6bd3e3b

Browse files
authored
Merge pull request microsoft#385 from dantleech/phpstan-level-3
PHPStan Level 3
2 parents 3eccfd2 + 937564f commit 6bd3e3b

17 files changed

+49
-38
lines changed

.travis.yml

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ cache:
2525
- validation/frameworks
2626

2727
before_script:
28-
- if [[ $STATIC_ANALYSIS = true ]]; then composer require phpstan/phpstan --no-update; fi
2928
- composer install
3029
- set -e # Stop on first error.
3130
- phpenv config-rm xdebug.ini || true

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"php": ">=7.2"
77
},
88
"require-dev": {
9-
"phpunit/phpunit": "^8.5.15"
9+
"phpunit/phpunit": "^8.5.15",
10+
"phpstan/phpstan": "^1.8"
1011
},
1112
"license": "MIT",
1213
"authors": [

phpstan.neon

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
parameters:
2-
level: 2
2+
level: 3
33
paths:
44
- src/
55
ignoreErrors:

src/Node.php

+3
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ public function getRoot() : Node {
140140
while ($node->parent !== null) {
141141
$node = $node->parent;
142142
}
143+
144+
/** @var SourceFileNode $node */
143145
return $node;
144146
}
145147

@@ -613,6 +615,7 @@ public function getNamespaceDefinition() {
613615
$namespaceDefinition = null;
614616
}
615617

618+
/** @var NamespaceDefinition|null $namespaceDefinition */
616619
return $namespaceDefinition;
617620
}
618621

src/Node/EnumCaseDeclaration.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class EnumCaseDeclaration extends Node {
1616
/** @var Token */
1717
public $caseKeyword;
1818

19-
/** @var QualifiedName */
19+
/** @var Token */
2020
public $name;
2121

2222
/** @var Token|null */

src/Node/Expression/AssignmentExpression.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
class AssignmentExpression extends BinaryExpression {
1313

14-
/** @var Expression */
14+
/** @var Expression|Token */
1515
public $leftOperand;
1616

1717
/** @var Token */

src/Node/Expression/BinaryExpression.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111

1212
class BinaryExpression extends Expression {
1313

14-
/** @var Expression */
14+
/** @var Expression|Token */
1515
public $leftOperand;
1616

1717
/** @var Token */
1818
public $operator;
1919

20-
/** @var Expression */
20+
/** @var Expression|Token */
2121
public $rightOperand;
2222

2323
const CHILD_NAMES = [

src/Node/Expression/PrefixUpdateExpression.php

-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ class PrefixUpdateExpression extends UnaryExpression {
1313
/** @var Token */
1414
public $incrementOrDecrementOperator;
1515

16-
/** @var Variable */
17-
public $operand;
18-
1916
const CHILD_NAMES = [
2017
'incrementOrDecrementOperator',
2118
'operand'

src/Node/Expression/SubscriptExpression.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
namespace Microsoft\PhpParser\Node\Expression;
88

9+
use Microsoft\PhpParser\MissingToken;
910
use Microsoft\PhpParser\Node\Expression;
1011
use Microsoft\PhpParser\Token;
1112

@@ -17,7 +18,7 @@ class SubscriptExpression extends Expression {
1718
/** @var Token */
1819
public $openBracketOrBrace;
1920

20-
/** @var Expression */
21+
/** @var Expression|MissingToken */
2122
public $accessExpression;
2223

2324
/** @var Token */

src/Node/Expression/UnaryExpression.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77
namespace Microsoft\PhpParser\Node\Expression;
88

99
use Microsoft\PhpParser\Node\Expression;
10+
use Microsoft\PhpParser\Token;
1011

1112
class UnaryExpression extends Expression {
12-
/** @var UnaryExpression|Variable */
13+
/** @var Expression|Variable|Token */
1314
public $operand;
1415

1516
const CHILD_NAMES = [

src/Node/Expression/UnaryOpExpression.php

-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ class UnaryOpExpression extends UnaryExpression {
1313
/** @var Token */
1414
public $operator;
1515

16-
/** @var UnaryExpression */
17-
public $operand;
18-
1916
const CHILD_NAMES = [
2017
'operator',
2118
'operand'

src/Node/FunctionReturnType.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
namespace Microsoft\PhpParser\Node;
88

9+
use Microsoft\PhpParser\MissingToken;
910
use Microsoft\PhpParser\Token;
1011

1112
trait FunctionReturnType {
@@ -14,6 +15,6 @@ trait FunctionReturnType {
1415
// TODO: This may be the wrong choice if ?type can ever be mixed with other types in union types
1516
/** @var Token|null */
1617
public $questionToken;
17-
/** @var DelimitedList\QualifiedNameList|null */
18+
/** @var DelimitedList\QualifiedNameList|null|MissingToken */
1819
public $returnTypeList;
1920
}

src/Node/MissingMemberDeclaration.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
namespace Microsoft\PhpParser\Node;
88

9+
use Microsoft\PhpParser\MissingToken;
910
use Microsoft\PhpParser\ModifiedTypeInterface;
1011
use Microsoft\PhpParser\ModifiedTypeTrait;
1112
use Microsoft\PhpParser\Node;
@@ -20,7 +21,7 @@ class MissingMemberDeclaration extends Node implements ModifiedTypeInterface {
2021
/** @var Token|null needed along with typeDeclaration for what looked like typed property declarations but was missing VariableName */
2122
public $questionToken;
2223

23-
/** @var DelimitedList\QualifiedNameList|null */
24+
/** @var DelimitedList\QualifiedNameList|null|MissingToken */
2425
public $typeDeclarationList;
2526

2627
const CHILD_NAMES = [

src/Node/NamespaceUseClause.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66

77
namespace Microsoft\PhpParser\Node;
88

9+
use Microsoft\PhpParser\MissingToken;
910
use Microsoft\PhpParser\Node;
1011
use Microsoft\PhpParser\Node\DelimitedList;
1112
use Microsoft\PhpParser\Token;
1213

1314
class NamespaceUseClause extends Node {
14-
/** @var QualifiedName */
15+
/** @var QualifiedName|MissingToken */
1516
public $namespaceName;
1617
/** @var NamespaceAliasingClause */
1718
public $namespaceAliasingClause;

src/Node/Statement/InlineHtml.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class InlineHtml extends StatementNode {
2020
public $scriptSectionStartTag;
2121

2222
/**
23-
* @var ExpressionStatement|null used to represent the expression echoed by `<?=` while parsing.
23+
* @var EchoStatement|null used to represent the expression echoed by `<?=` while parsing.
2424
*
2525
* This should always be null in the returned AST,
2626
* and is deliberately excluded from CHILD_NAMES.

src/Node/Statement/NamespaceDefinition.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
namespace Microsoft\PhpParser\Node\Statement;
88

9+
use Microsoft\PhpParser\MissingToken;
910
use Microsoft\PhpParser\Node\QualifiedName;
1011
use Microsoft\PhpParser\Node\StatementNode;
1112
use Microsoft\PhpParser\Token;
@@ -17,7 +18,7 @@
1718
class NamespaceDefinition extends StatementNode {
1819
/** @var Token */
1920
public $namespaceKeyword;
20-
/** @var QualifiedName|null */
21+
/** @var QualifiedName|null|MissingToken */
2122
public $name;
2223
/** @var CompoundStatementNode|Token */
2324
public $compoundStatementOrSemicolon;

src/Parser.php

+26-18
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ private function parseClassDeclaration($parentNode) : Node {
691691
return $classNode;
692692
}
693693

694-
private function parseClassMembers($parentNode) : Node {
694+
private function parseClassMembers($parentNode) : ClassMembersNode {
695695
$classMembers = new ClassMembersNode();
696696
$classMembers->openBrace = $this->eat1(TokenKind::OpenBraceToken);
697697
$classMembers->classMemberDeclarations = $this->parseList($classMembers, ParseContext::ClassMembers);
@@ -804,7 +804,7 @@ private function parseAttributeGroups($parentNode): array
804804
}
805805

806806
/**
807-
* @return DelimitedList\AttributeElementList
807+
* @return DelimitedList\AttributeElementList|null
808808
*/
809809
private function parseAttributeElementList(AttributeGroup $parentNode) {
810810
return $this->parseDelimitedList(
@@ -1638,13 +1638,14 @@ private function isParameterStartFn() {
16381638
}
16391639

16401640
/**
1641-
* @param string $className (name of subclass of DelimitedList)
1641+
* @template TDelimitedList of DelimitedList
1642+
* @param class-string<TDelimitedList> $className (name of subclass of DelimitedList)
16421643
* @param int|int[] $delimiter
16431644
* @param callable $isElementStartFn
16441645
* @param callable $parseElementFn
16451646
* @param Node $parentNode
16461647
* @param bool $allowEmptyElements
1647-
* @return DelimitedList|null instance of $className
1648+
* @return TDelimitedList|null instance of $className
16481649
*/
16491650
private function parseDelimitedList($className, $delimiter, $isElementStartFn, $parseElementFn, $parentNode, $allowEmptyElements = false) {
16501651
// TODO consider allowing empty delimiter to be more tolerant
@@ -1994,7 +1995,7 @@ private function parseWhileStatement($parentNode) {
19941995
/**
19951996
* @param Node $parentNode
19961997
* @param bool $force
1997-
* @return Node|MissingToken|array - The expression, or a missing token, or (if $force) an array containing a missed and skipped token
1998+
* @return Expression|MissingToken|array - The expression, or a missing token, or (if $force) an array containing a missed and skipped token
19981999
*/
19992000
private function parseExpression($parentNode, $force = false) {
20002001
$token = $this->getCurrentToken();
@@ -2020,7 +2021,7 @@ private function parseExpressionFn() {
20202021

20212022
/**
20222023
* @param Node $parentNode
2023-
* @return Expression
2024+
* @return UnaryExpression|MissingToken|Variable|ThrowExpression
20242025
*/
20252026
private function parseUnaryExpressionOrHigher($parentNode) {
20262027
$token = $this->getCurrentToken();
@@ -3212,9 +3213,16 @@ private function parseMemberAccessExpression($expression):MemberAccessExpression
32123213
private function parseScopedPropertyAccessExpression($expression, $fallbackParentNode): ScopedPropertyAccessExpression {
32133214
$scopedPropertyAccessExpression = new ScopedPropertyAccessExpression();
32143215
$scopedPropertyAccessExpression->parent = $expression->parent ?? $fallbackParentNode;
3216+
32153217
if ($expression instanceof Node) {
32163218
$expression->parent = $scopedPropertyAccessExpression;
3217-
$scopedPropertyAccessExpression->scopeResolutionQualifier = $expression; // TODO ensure always a Node
3219+
3220+
// scopeResolutionQualifier does not accept `Node` but
3221+
// `Expression|QualifiedName|Token`. I'm not sure if we can depend
3222+
// on that being the case.
3223+
//
3224+
// @phpstan-ignore-next-line
3225+
$scopedPropertyAccessExpression->scopeResolutionQualifier = $expression;
32183226
}
32193227

32203228
$scopedPropertyAccessExpression->doubleColon = $this->eat1(TokenKind::ColonColonToken);
@@ -3362,18 +3370,18 @@ private function parseClassConstDeclaration($parentNode, $modifiers) {
33623370
}
33633371

33643372
private function parseEnumCaseDeclaration($parentNode) {
3365-
$classConstDeclaration = new EnumCaseDeclaration();
3366-
$classConstDeclaration->parent = $parentNode;
3367-
$classConstDeclaration->caseKeyword = $this->eat1(TokenKind::CaseKeyword);
3368-
$classConstDeclaration->name = $this->eat($this->nameOrKeywordOrReservedWordTokens);
3369-
$classConstDeclaration->equalsToken = $this->eatOptional1(TokenKind::EqualsToken);
3370-
if ($classConstDeclaration->equalsToken !== null) {
3373+
$enumCaseDeclaration = new EnumCaseDeclaration();
3374+
$enumCaseDeclaration->parent = $parentNode;
3375+
$enumCaseDeclaration->caseKeyword = $this->eat1(TokenKind::CaseKeyword);
3376+
$enumCaseDeclaration->name = $this->eat($this->nameOrKeywordOrReservedWordTokens);
3377+
$enumCaseDeclaration->equalsToken = $this->eatOptional1(TokenKind::EqualsToken);
3378+
if ($enumCaseDeclaration->equalsToken !== null) {
33713379
// TODO add post-parse rule that checks for invalid assignments
3372-
$classConstDeclaration->assignment = $this->parseExpression($classConstDeclaration);
3380+
$enumCaseDeclaration->assignment = $this->parseExpression($enumCaseDeclaration);
33733381
}
3374-
$classConstDeclaration->semicolon = $this->eat1(TokenKind::SemicolonToken);
3382+
$enumCaseDeclaration->semicolon = $this->eat1(TokenKind::SemicolonToken);
33753383

3376-
return $classConstDeclaration;
3384+
return $enumCaseDeclaration;
33773385
}
33783386

33793387
/**
@@ -3446,7 +3454,7 @@ private function parseQualifiedNameCatchList($parentNode) {
34463454
return $result;
34473455
}
34483456

3449-
private function parseInterfaceDeclaration($parentNode) {
3457+
private function parseInterfaceDeclaration($parentNode): InterfaceDeclaration {
34503458
$interfaceDeclaration = new InterfaceDeclaration(); // TODO verify not nested
34513459
$interfaceDeclaration->parent = $parentNode;
34523460
$interfaceDeclaration->interfaceKeyword = $this->eat1(TokenKind::InterfaceKeyword);
@@ -3456,7 +3464,7 @@ private function parseInterfaceDeclaration($parentNode) {
34563464
return $interfaceDeclaration;
34573465
}
34583466

3459-
private function parseInterfaceMembers($parentNode) : Node {
3467+
private function parseInterfaceMembers($parentNode) : InterfaceMembers {
34603468
$interfaceMembers = new InterfaceMembers();
34613469
$interfaceMembers->openBrace = $this->eat1(TokenKind::OpenBraceToken);
34623470
$interfaceMembers->interfaceMemberDeclarations = $this->parseList($interfaceMembers, ParseContext::InterfaceMembers);

0 commit comments

Comments
 (0)