10
10
11
11
class DiagnosticsProvider {
12
12
13
- private static $ tokenKindToText ;
13
+ /**
14
+ * @param int $kind (must be a valid token kind)
15
+ * @return string
16
+ */
17
+ public static function getTextForTokenKind ($ kind ) {
18
+ static $ tokenKindToText ;
19
+ if (!isset ($ tokenKindToText )) {
20
+ $ tokenKindToText = \array_flip (\array_merge (
21
+ TokenStringMaps::OPERATORS_AND_PUNCTUATORS ,
22
+ TokenStringMaps::KEYWORDS ,
23
+ TokenStringMaps::RESERVED_WORDS
24
+ ));
25
+ }
26
+ return $ tokenKindToText [$ kind ];
27
+ }
14
28
15
29
/**
16
30
* Returns the diagnostic for $node, or null.
17
- * @param \Microsoft\PhpParser\Node $node
31
+ * @param \Microsoft\PhpParser\Node|\Microsoft\PhpParser\Token $node
18
32
* @return Diagnostic|null
19
33
*/
20
34
public static function checkDiagnostics ($ node ) {
21
- if (!isset (self ::$ tokenKindToText )) {
22
- self ::$ tokenKindToText = \array_flip (\array_merge (
35
+ if ($ node instanceof Token) {
36
+ if (\get_class ($ node ) === Token::class) {
37
+ return null ;
38
+ }
39
+ return self ::checkDiagnosticForUnexpectedToken ($ node );
40
+ }
41
+
42
+ if ($ node instanceof Node) {
43
+ return $ node ->getDiagnosticForNode ();
44
+ }
45
+ return null ;
46
+ }
47
+
48
+ /**
49
+ * @param Token $token
50
+ * @return Diagnostic|null
51
+ */
52
+ private static function checkDiagnosticForUnexpectedToken ($ token ) {
53
+ static $ tokenKindToText ;
54
+ if (!isset ($ tokenKindToText )) {
55
+ $ tokenKindToText = \array_flip (\array_merge (
23
56
TokenStringMaps::OPERATORS_AND_PUNCTUATORS ,
24
57
TokenStringMaps::KEYWORDS ,
25
58
TokenStringMaps::RESERVED_WORDS
26
59
));
27
60
}
28
-
29
61
if ($ node instanceof SkippedToken) {
30
62
// TODO - consider also attaching parse context information to skipped tokens
31
63
// this would allow us to provide more helpful error messages that inform users what to do
32
64
// about the problem rather than simply pointing out the mistake.
33
65
return new Diagnostic (
34
66
DiagnosticKind::Error,
35
67
"Unexpected ' " .
36
- (isset (self :: $ tokenKindToText [$ node ->kind ])
37
- ? self :: $ tokenKindToText [$ node ->kind ]
68
+ (isset ($ tokenKindToText [$ node ->kind ])
69
+ ? $ tokenKindToText [$ node ->kind ]
38
70
: Token::getTokenKindNameFromValue ($ node ->kind )) .
39
71
"' " ,
40
72
$ node ->start ,
@@ -44,93 +76,14 @@ public static function checkDiagnostics($node) {
44
76
return new Diagnostic (
45
77
DiagnosticKind::Error,
46
78
"' " .
47
- (isset (self :: $ tokenKindToText [$ node ->kind ])
48
- ? self :: $ tokenKindToText [$ node ->kind ]
79
+ (isset ($ tokenKindToText [$ node ->kind ])
80
+ ? $ tokenKindToText [$ node ->kind ]
49
81
: Token::getTokenKindNameFromValue ($ node ->kind )) .
50
82
"' expected. " ,
51
83
$ node ->start ,
52
84
$ node ->getEndPosition () - $ node ->start
53
85
);
54
86
}
55
-
56
- if ($ node === null || $ node instanceof Token) {
57
- return null ;
58
- }
59
-
60
- if ($ node instanceof Node) {
61
- if ($ node instanceof Node \MethodDeclaration) {
62
- foreach ($ node ->modifiers as $ modifier ) {
63
- if ($ modifier ->kind === TokenKind::VarKeyword) {
64
- return new Diagnostic (
65
- DiagnosticKind::Error,
66
- "Unexpected modifier ' " . self ::$ tokenKindToText [$ modifier ->kind ] . "' " ,
67
- $ modifier ->start ,
68
- $ modifier ->length
69
- );
70
- }
71
- }
72
- }
73
- elseif ($ node instanceof Node \Statement \NamespaceUseDeclaration) {
74
- if (
75
- $ node ->useClauses != null
76
- && \count ($ node ->useClauses ->children ) > 1
77
- ) {
78
- foreach ($ node ->useClauses ->children as $ useClause ) {
79
- if ($ useClause instanceof Node \NamespaceUseClause && !is_null ($ useClause ->openBrace )) {
80
- return new Diagnostic (
81
- DiagnosticKind::Error,
82
- "; expected. " ,
83
- $ useClause ->getEndPosition (),
84
- 1
85
- );
86
- }
87
- }
88
- }
89
- }
90
- else if ($ node instanceof Node \Statement \BreakOrContinueStatement) {
91
- if ($ node ->breakoutLevel === null ) {
92
- return null ;
93
- }
94
-
95
- $ breakoutLevel = $ node ->breakoutLevel ;
96
- while ($ breakoutLevel instanceof Node \Expression \ParenthesizedExpression) {
97
- $ breakoutLevel = $ breakoutLevel ->expression ;
98
- }
99
-
100
- if (
101
- $ breakoutLevel instanceof Node \NumericLiteral
102
- && $ breakoutLevel ->children ->kind === TokenKind::IntegerLiteralToken
103
- ) {
104
- $ literalString = $ breakoutLevel ->getText ();
105
- $ firstTwoChars = \substr ($ literalString , 0 , 2 );
106
-
107
- if ($ firstTwoChars === '0b ' || $ firstTwoChars === '0B ' ) {
108
- if (\bindec (\substr ($ literalString , 2 )) > 0 ) {
109
- return null ;
110
- }
111
- }
112
- else if (\intval ($ literalString , 0 ) > 0 ) {
113
- return null ;
114
- }
115
- }
116
-
117
- if ($ breakoutLevel instanceof Token) {
118
- $ start = $ breakoutLevel ->getStartPosition ();
119
- }
120
- else {
121
- $ start = $ breakoutLevel ->getStart ();
122
- }
123
- $ end = $ breakoutLevel ->getEndPosition ();
124
-
125
- return new Diagnostic (
126
- DiagnosticKind::Error,
127
- "Positive integer literal expected. " ,
128
- $ start ,
129
- $ end - $ start
130
- );
131
- }
132
- }
133
- return null ;
134
87
}
135
88
136
89
/**
@@ -141,11 +94,15 @@ public static function checkDiagnostics($node) {
141
94
public static function getDiagnostics (Node $ n ) : array {
142
95
$ diagnostics = [];
143
96
144
- foreach ($ n ->getDescendantNodesAndTokens () as $ node ) {
97
+ /**
98
+ * @param \Microsoft\PhpParser\Node|\Microsoft\PhpParser\Token $node
99
+ */
100
+ $ n ->walkDescendantNodesAndTokens (function ($ node ) use (&$ diagnostics ) {
101
+ // echo "Processing " . get_class($node) . "\n";
145
102
if (($ diagnostic = self ::checkDiagnostics ($ node )) !== null ) {
146
103
$ diagnostics [] = $ diagnostic ;
147
104
}
148
- }
105
+ });
149
106
150
107
return $ diagnostics ;
151
108
}
0 commit comments