Skip to content

Commit e719ac1

Browse files
authored
Merge pull request microsoft#96 from runz0rd/master
Updated parseNamespaceUseDeclaration to group clauses without braces
2 parents aa2ed9d + 3824871 commit e719ac1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2263
-1272
lines changed

src/DiagnosticsProvider.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@ public static function getDiagnostics($node) : \Generator {
6565
}
6666
}
6767
}
68+
elseif ($node instanceof Node\Statement\NamespaceUseDeclaration) {
69+
if (\count($node->useClauses->children) > 1) {
70+
foreach ($node->useClauses->children as $useClause) {
71+
if($useClause instanceof Node\NamespaceUseClause && !is_null($useClause->openBrace)) {
72+
yield new Diagnostic(
73+
DiagnosticKind::Error,
74+
"; expected.",
75+
$useClause->getEndPosition(),
76+
1
77+
);
78+
}
79+
}
80+
}
81+
}
6882
}
6983

7084
foreach ($node->getChildNodesAndTokens() as $child) {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
/*---------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All rights reserved.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
namespace Microsoft\PhpParser\Node\DelimitedList;
8+
9+
use Microsoft\PhpParser\Node\DelimitedList;
10+
11+
class NamespaceUseClauseList extends DelimitedList {
12+
}

src/Node/NamespaceUseClause.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/*---------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All rights reserved.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
namespace Microsoft\PhpParser\Node;
8+
9+
use Microsoft\PhpParser\Node;
10+
use Microsoft\PhpParser\Node\DelimitedList;
11+
use Microsoft\PhpParser\Token;
12+
13+
class NamespaceUseClause extends Node {
14+
/** @var QualifiedName */
15+
public $namespaceName;
16+
/** @var NamespaceAliasingClause */
17+
public $namespaceAliasingClause;
18+
/** @var Token | null */
19+
public $openBrace;
20+
/** @var DelimitedList\NamespaceUseGroupClauseList | null */
21+
public $groupClauses;
22+
/** @var Token | null */
23+
public $closeBrace;
24+
}

src/Node/Statement/NamespaceUseDeclaration.php

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66

77
namespace Microsoft\PhpParser\Node\Statement;
88

9-
use Microsoft\PhpParser\Node\DelimitedList;
10-
use Microsoft\PhpParser\Node\NamespaceAliasingClause;
11-
use Microsoft\PhpParser\Node\QualifiedName;
9+
use Microsoft\PhpParser\Node\DelimitedList\NamespaceUseClauseList;
1210
use Microsoft\PhpParser\Node\StatementNode;
1311
use Microsoft\PhpParser\Token;
1412

@@ -17,16 +15,8 @@ class NamespaceUseDeclaration extends StatementNode {
1715
public $useKeyword;
1816
/** @var Token */
1917
public $functionOrConst;
20-
/** @var QualifiedName */
21-
public $namespaceName;
22-
/** @var NamespaceAliasingClause */
23-
public $namespaceAliasingClause;
24-
/** @var Token | null */
25-
public $openBrace;
26-
/** @var DelimitedList\NamespaceUseGroupClauseList | null */
27-
public $groupClauses;
28-
/** @var Token | null */
29-
public $closeBrace;
18+
/** @var NamespaceUseClauseList */
19+
public $useClauses;
3020
/** @var Token */
3121
public $semicolon;
3222
}

src/Parser.php

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
use Microsoft\PhpParser\Node\ReservedWord;
6767
use Microsoft\PhpParser\Node\StringLiteral;
6868
use Microsoft\PhpParser\Node\MethodDeclaration;
69-
use Microsoft\PhpParser\Node;
7069
use Microsoft\PhpParser\Node\Parameter;
7170
use Microsoft\PhpParser\Node\QualifiedName;
7271
use Microsoft\PhpParser\Node\RelativeSpecifier;
@@ -103,6 +102,7 @@
103102
use Microsoft\PhpParser\Node\TraitSelectOrAliasClause;
104103
use Microsoft\PhpParser\Node\TraitUseClause;
105104
use Microsoft\PhpParser\Node\UseVariableName;
105+
use Microsoft\PhpParser\Node\NamespaceUseClause;
106106

107107
class Parser {
108108
private $lexer;
@@ -2556,42 +2556,62 @@ private function parseNamespaceDefinition($parentNode) {
25562556
private function parseNamespaceUseDeclaration($parentNode) {
25572557
$namespaceUseDeclaration = new NamespaceUseDeclaration();
25582558
$namespaceUseDeclaration->parent = $parentNode;
2559-
25602559
$namespaceUseDeclaration->useKeyword = $this->eat(TokenKind::UseKeyword);
25612560
$namespaceUseDeclaration->functionOrConst = $this->eatOptional(TokenKind::FunctionKeyword, TokenKind::ConstKeyword);
2562-
$namespaceUseDeclaration->namespaceName = $this->parseQualifiedName($namespaceUseDeclaration);
2563-
if (!$this->checkToken(TokenKind::OpenBraceToken)) {
2564-
if ($this->checkToken(TokenKind::AsKeyword)) {
2565-
$namespaceUseDeclaration->namespaceAliasingClause = $this->parseNamespaceAliasingClause($namespaceUseDeclaration);
2566-
}
2567-
} else {
2568-
$namespaceUseDeclaration->openBrace = $this->eat(TokenKind::OpenBraceToken);
2569-
$namespaceUseDeclaration->groupClauses = $this->parseDelimitedList(
2570-
DelimitedList\NamespaceUseGroupClauseList::class,
2571-
TokenKind::CommaToken,
2572-
function ($token) {
2573-
return $this->isQualifiedNameStart($token) || $token->kind === TokenKind::FunctionKeyword || $token->kind === TokenKind::ConstKeyword;
2574-
},
2575-
function ($parentNode) {
2576-
$namespaceUseGroupClause = new NamespaceUseGroupClause();
2577-
$namespaceUseGroupClause->parent = $parentNode;
2578-
2579-
$namespaceUseGroupClause->functionOrConst = $this->eatOptional(TokenKind::FunctionKeyword, TokenKind::ConstKeyword);
2580-
$namespaceUseGroupClause->namespaceName = $this->parseQualifiedName($namespaceUseGroupClause);
2581-
if ($this->checkToken(TokenKind::AsKeyword)) {
2582-
$namespaceUseGroupClause->namespaceAliasingClause = $this->parseNamespaceAliasingClause($namespaceUseGroupClause);
2583-
}
2584-
2585-
return $namespaceUseGroupClause;
2586-
},
2587-
$namespaceUseDeclaration
2588-
);
2589-
$namespaceUseDeclaration->closeBrace = $this->eat(TokenKind::CloseBraceToken);
2590-
}
2561+
$namespaceUseDeclaration->useClauses = $this->parseNamespaceUseClauseList($namespaceUseDeclaration);
25912562
$namespaceUseDeclaration->semicolon = $this->eatSemicolonOrAbortStatement();
25922563
return $namespaceUseDeclaration;
25932564
}
25942565

2566+
private function parseNamespaceUseClauseList($parentNode) {
2567+
return $this->parseDelimitedList(
2568+
DelimitedList\NamespaceUseClauseList::class,
2569+
TokenKind::CommaToken,
2570+
function ($token) {
2571+
return $this->isQualifiedNameStart($token) || $token->kind === TokenKind::FunctionKeyword || $token->kind === TokenKind::ConstKeyword;
2572+
},
2573+
function ($parentNode) {
2574+
$namespaceUseClause = new NamespaceUseClause();
2575+
$namespaceUseClause->parent = $parentNode;
2576+
$namespaceUseClause->namespaceName = $this->parseQualifiedName($namespaceUseClause);
2577+
if ($this->checkToken(TokenKind::AsKeyword)) {
2578+
$namespaceUseClause->namespaceAliasingClause = $this->parseNamespaceAliasingClause($namespaceUseClause);
2579+
}
2580+
elseif ($this->checkToken(TokenKind::OpenBraceToken)) {
2581+
$namespaceUseClause->openBrace = $this->eat(TokenKind::OpenBraceToken);
2582+
$namespaceUseClause->groupClauses = $this->parseNamespaceUseGroupClauseList($namespaceUseClause);
2583+
$namespaceUseClause->closeBrace = $this->eat(TokenKind::CloseBraceToken);
2584+
}
2585+
2586+
return $namespaceUseClause;
2587+
},
2588+
$parentNode
2589+
);
2590+
}
2591+
2592+
private function parseNamespaceUseGroupClauseList($parentNode) {
2593+
return $this->parseDelimitedList(
2594+
DelimitedList\NamespaceUseGroupClauseList::class,
2595+
TokenKind::CommaToken,
2596+
function ($token) {
2597+
return $this->isQualifiedNameStart($token) || $token->kind === TokenKind::FunctionKeyword || $token->kind === TokenKind::ConstKeyword;
2598+
},
2599+
function ($parentNode) {
2600+
$namespaceUseGroupClause = new NamespaceUseGroupClause();
2601+
$namespaceUseGroupClause->parent = $parentNode;
2602+
2603+
$namespaceUseGroupClause->functionOrConst = $this->eatOptional(TokenKind::FunctionKeyword, TokenKind::ConstKeyword);
2604+
$namespaceUseGroupClause->namespaceName = $this->parseQualifiedName($namespaceUseGroupClause);
2605+
if ($this->checkToken(TokenKind::AsKeyword)) {
2606+
$namespaceUseGroupClause->namespaceAliasingClause = $this->parseNamespaceAliasingClause($namespaceUseGroupClause);
2607+
}
2608+
2609+
return $namespaceUseGroupClause;
2610+
},
2611+
$parentNode
2612+
);
2613+
}
2614+
25952615
private function parseNamespaceAliasingClause($parentNode) {
25962616
$namespaceAliasingClause = new NamespaceAliasingClause();
25972617
$namespaceAliasingClause->parent = $parentNode;

tests/cases/parser/namespaceUseDeclaration1.php.tree

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,34 +21,44 @@
2121
"kind": "FunctionKeyword",
2222
"textLength": 8
2323
},
24-
"namespaceName": {
25-
"QualifiedName": {
26-
"globalSpecifier": null,
27-
"relativeSpecifier": null,
28-
"nameParts": {
29-
"QualifiedNameParts": {
30-
"children": [
31-
{
32-
"kind": "Name",
33-
"textLength": 1
24+
"useClauses": {
25+
"NamespaceUseClauseList": {
26+
"children": [
27+
{
28+
"NamespaceUseClause": {
29+
"namespaceName": {
30+
"QualifiedName": {
31+
"globalSpecifier": null,
32+
"relativeSpecifier": null,
33+
"nameParts": {
34+
"QualifiedNameParts": {
35+
"children": [
36+
{
37+
"kind": "Name",
38+
"textLength": 1
39+
},
40+
{
41+
"kind": "BackslashToken",
42+
"textLength": 1
43+
},
44+
{
45+
"kind": "Name",
46+
"textLength": 1
47+
}
48+
]
49+
}
50+
}
51+
}
3452
},
35-
{
36-
"kind": "BackslashToken",
37-
"textLength": 1
38-
},
39-
{
40-
"kind": "Name",
41-
"textLength": 1
42-
}
43-
]
53+
"namespaceAliasingClause": null,
54+
"openBrace": null,
55+
"groupClauses": null,
56+
"closeBrace": null
57+
}
4458
}
45-
}
59+
]
4660
}
4761
},
48-
"namespaceAliasingClause": null,
49-
"openBrace": null,
50-
"groupClauses": null,
51-
"closeBrace": null,
5262
"semicolon": {
5363
"kind": "SemicolonToken",
5464
"textLength": 1

tests/cases/parser/namespaceUseDeclaration10.php.tree

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,37 @@
1818
"textLength": 3
1919
},
2020
"functionOrConst": null,
21-
"namespaceName": null,
22-
"namespaceAliasingClause": {
23-
"NamespaceAliasingClause": {
24-
"asKeyword": {
25-
"kind": "AsKeyword",
26-
"textLength": 2
27-
},
28-
"name": {
29-
"kind": "Name",
30-
"textLength": 1
21+
"useClauses": null,
22+
"semicolon": {
23+
"error": "MissingToken",
24+
"kind": "SemicolonToken",
25+
"textLength": 0
26+
}
27+
}
28+
},
29+
{
30+
"error": "SkippedToken",
31+
"kind": "AsKeyword",
32+
"textLength": 2
33+
},
34+
{
35+
"ExpressionStatement": {
36+
"expression": {
37+
"QualifiedName": {
38+
"globalSpecifier": null,
39+
"relativeSpecifier": null,
40+
"nameParts": {
41+
"QualifiedNameParts": {
42+
"children": [
43+
{
44+
"kind": "Name",
45+
"textLength": 1
46+
}
47+
]
48+
}
3149
}
3250
}
3351
},
34-
"openBrace": null,
35-
"groupClauses": null,
36-
"closeBrace": null,
3752
"semicolon": {
3853
"kind": "SemicolonToken",
3954
"textLength": 1

0 commit comments

Comments
 (0)