-
Notifications
You must be signed in to change notification settings - Fork 79
PHPStan Level 3 #385
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PHPStan Level 3 #385
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
parameters: | ||
level: 2 | ||
level: 3 | ||
paths: | ||
- src/ | ||
ignoreErrors: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -140,6 +140,8 @@ public function getRoot() : Node { | |
while ($node->parent !== null) { | ||
$node = $node->parent; | ||
} | ||
|
||
/** @var SourceFileNode $node */ | ||
return $node; | ||
} | ||
|
||
|
@@ -613,6 +615,7 @@ public function getNamespaceDefinition() { | |
$namespaceDefinition = null; | ||
} | ||
|
||
/** @var NamespaceDefinition|null $namespaceDefinition */ | ||
return $namespaceDefinition; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we could add a runtime check for stuff like this or refactor but it's probably a risky move considering the number of similar changes needed across the whole code base. |
||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -691,7 +691,7 @@ private function parseClassDeclaration($parentNode) : Node { | |
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 @@ private function parseAttributeGroups($parentNode): array | |
} | ||
|
||
/** | ||
* @return DelimitedList\AttributeElementList | ||
* @return DelimitedList\AttributeElementList|null | ||
*/ | ||
private function parseAttributeElementList(AttributeGroup $parentNode) { | ||
return $this->parseDelimitedList( | ||
|
@@ -1638,13 +1638,14 @@ private function isParameterStartFn() { | |
} | ||
|
||
/** | ||
* @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 @@ private function parseWhileStatement($parentNode) { | |
/** | ||
* @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 @@ private function parseExpressionFn() { | |
|
||
/** | ||
* @param Node $parentNode | ||
* @return Expression | ||
* @return UnaryExpression|MissingToken|Variable|ThrowExpression | ||
*/ | ||
private function parseUnaryExpressionOrHigher($parentNode) { | ||
$token = $this->getCurrentToken(); | ||
|
@@ -3212,9 +3213,16 @@ private function parseMemberAccessExpression($expression):MemberAccessExpression | |
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LGTM overall for latest commits; they addressed review comments/nits. In followup PRs, that should hopefully be addressed by making parameter types more precise as well, assuming that phpstan can narrow a mix of subclasses of Node and definite non-subclassess to just the expected subclasses (Strict typing overall is useful so we don't accidentally write to an undeclared property, which would be a notice in 8.2 since the classes declared here aren't using |
||
// `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 @@ private function parseClassConstDeclaration($parentNode, $modifiers) { | |
} | ||
|
||
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 @@ private function parseQualifiedNameCatchList($parentNode) { | |
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 @@ private function parseInterfaceDeclaration($parentNode) { | |
return $interfaceDeclaration; | ||
} | ||
|
||
private function parseInterfaceMembers($parentNode) : Node { | ||
private function parseInterfaceMembers($parentNode) : InterfaceMembers { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably dozens of other places we can do this, but figure PHPStan will pick this up on level 4 or 5 |
||
$interfaceMembers = new InterfaceMembers(); | ||
$interfaceMembers->openBrace = $this->eat1(TokenKind::OpenBraceToken); | ||
$interfaceMembers->interfaceMemberDeclarations = $this->parseList($interfaceMembers, ParseContext::InterfaceMembers); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
required in
--dev
now as PHPStan is a PHAR