@samitouri / QOS-React-2 / commits / 3df04725bd

[rust][sema] For statements and JSX

Adds semantic analysis support for normal `for` statements and for JSX. The main catch with JSX is that there are a bunch of identifiers that we have to ignore since they aren't variable references: jsx attribute names, namespace names, jsx member expression properties, and closing elements.

Joe Savona committed Aug 4, 2023 at 12:02 UTC 3df04725bd58d37e834dee071d6cd6257f6d3516
7 files changed +1457 -82
compiler/forget/crates/forget_estree/src/generated_extensions.rs
+23 -1
@@ -1,5 +1,8 @@
1 // Manual extensions to generated types
2 -use crate::{Pattern, SourceRange, SourceType};
2 +use crate::{
3 + JSXElementName, JSXMemberExpression, JSXMemberExpressionOrIdentifier, Pattern, SourceRange,
4 + SourceType,
5 +};
6
7 /// Sentinel trait to distinguish AST *node* types
8 pub trait ESTreeNode {}
@@ -21,3 +24,22 @@ impl Pattern {
24 }
25 }
26 }
27 +
28 +impl JSXElementName {
29 + pub fn root_name(&self) -> &str {
30 + match self {
31 + Self::JSXIdentifier(name) => &name.name,
32 + Self::JSXMemberExpression(name) => name.root_name(),
33 + Self::JSXNamespacedName(name) => &name.namespace.name,
34 + }
35 + }
36 +}
37 +
38 +impl JSXMemberExpression {
39 + pub fn root_name(&self) -> &str {
40 + match &self.object {
41 + JSXMemberExpressionOrIdentifier::JSXMemberExpression(object) => object.root_name(),
42 + JSXMemberExpressionOrIdentifier::JSXIdentifier(object) => &object.name,
43 + }
44 + }
45 +}
compiler/forget/crates/forget_semantic_analysis/src/analyzer.rs
+104 -12
@@ -1,8 +1,8 @@
1 use forget_diagnostics::Diagnostic;
2 use forget_estree::{
3 AssignmentOperator, AssignmentPropertyOrRestElement, AssignmentTarget, Expression,
4 - ExpressionOrSuper, ForInInit, Function, FunctionBody, Identifier, Pattern, Program,
5 - SourceRange, SourceType, Statement, VariableDeclarationKind, Visitor2,
4 + ExpressionOrSuper, ForInInit, ForInit, Function, FunctionBody, Identifier, JSXElementName,
5 + Pattern, Program, SourceRange, SourceType, Statement, VariableDeclarationKind, Visitor2,
6 };
7
8 use crate::{AstNode, DeclarationKind, LabelKind, ReferenceKind, ScopeId, ScopeKind, ScopeManager};
@@ -190,7 +190,7 @@ impl Analyzer {
190 left: &ForInInit,
191 right: &Expression,
192 body: &Statement,
193 - range: Option<SourceRange>,
193 + _range: Option<SourceRange>,
194 ) {
195 // Record an anonymous label for the statement to resolve unlabeled break/continue
196 let label = self
@@ -455,17 +455,31 @@ impl Visitor2 for Analyzer {
455 );
456 }
457
458 - fn visit_identifier(&mut self, ast: &forget_estree::Identifier) {
459 - Analyzer::visit_reference_identifier(
460 - self,
461 - &ast.name,
462 - AstNode::from(ast),
463 - ReferenceKind::Read,
464 - ast.range,
465 - );
458 + fn visit_for_statement(&mut self, ast: &forget_estree::ForStatement) {
459 + let mut for_scope: Option<ScopeId> = None;
460 + if let Some(init) = &ast.init {
461 + if let ForInit::VariableDeclaration(init) = init {
462 + if init.kind != VariableDeclarationKind::Var {
463 + for_scope = Some(self.enter_scope(ScopeKind::For));
464 + }
465 + }
466 + }
467 + if let Some(init) = &ast.init {
468 + self.visit_for_init(init);
469 + }
470 + if let Some(test) = &ast.test {
471 + self.visit_expression(test);
472 + }
473 + if let Some(update) = &ast.update {
474 + self.visit_expression(update);
475 + }
476 + self.visit_statement(&ast.body);
477 + if let Some(for_scope) = for_scope {
478 + self.close_scope(for_scope);
479 + }
480 }
481
468 - fn visit_jsxidentifier(&mut self, ast: &forget_estree::JSXIdentifier) {
482 + fn visit_identifier(&mut self, ast: &forget_estree::Identifier) {
483 Analyzer::visit_reference_identifier(
484 self,
485 &ast.name,
@@ -561,4 +575,82 @@ impl Visitor2 for Analyzer {
575 }
576 }
577 }
578 +
579 + fn visit_jsxattribute(&mut self, ast: &forget_estree::JSXAttribute) {
580 + // NOTE: skip visiting the attribute name, attributes are like non-computed
581 + // object properties where the identifier is not a variable reference
582 + if let Some(value) = &ast.value {
583 + self.visit_jsxattribute_value(value);
584 + }
585 + }
586 +
587 + fn visit_jsxclosing_element(&mut self, _ast: &forget_estree::JSXClosingElement) {
588 + // no-op, should not be counted as a reference
589 + }
590 +
591 + fn visit_jsxidentifier(&mut self, ast: &forget_estree::JSXIdentifier) {
592 + Analyzer::visit_reference_identifier(
593 + self,
594 + &ast.name,
595 + AstNode::from(ast),
596 + ReferenceKind::Read,
597 + ast.range,
598 + );
599 + }
600 +
601 + fn visit_jsxfragment(&mut self, ast: &forget_estree::JSXFragment) {
602 + // TODO: record the pragmas
603 + for child in &ast.children {
604 + self.visit_jsxchild_item(child);
605 + }
606 + }
607 +
608 + fn visit_jsxmember_expression(&mut self, ast: &forget_estree::JSXMemberExpression) {
609 + // NOTE: ignore the 'property' since JSX doesn't support computed properties
610 + self.visit_jsxmember_expression_or_identifier(&ast.object);
611 + }
612 +
613 + fn visit_jsxnamespaced_name(&mut self, ast: &forget_estree::JSXNamespacedName) {
614 + // NOTE: ignore the 'name' since it doesn't refer to a variable
615 + self.visit_jsxidentifier(&ast.namespace);
616 + }
617 +
618 + fn visit_jsxopening_element(&mut self, ast: &forget_estree::JSXOpeningElement) {
619 + // TODO: record jsx pragma if root_name is not an FBT name
620 + let root_name = ast.name.root_name();
621 +
622 + match &ast.name {
623 + JSXElementName::JSXIdentifier(name) => {
624 + // lowercase names are builtins, only visit if this is a user-defined
625 + // component
626 + if let Some(first) = root_name.chars().next() {
627 + if first == first.to_ascii_uppercase() {
628 + self.visit_jsxidentifier(name);
629 + }
630 + } else {
631 + // TODO: this likely indicates a parse error, since a valid parse
632 + // should never result in an empty JSXIdentifier node. but just in
633 + // case we report this rather than silently fail
634 + self.manager.diagnostics.push(Diagnostic::invalid_syntax(
635 + "Expected JSXOpenintElement.name to be non-empty",
636 + name.range,
637 + ));
638 + }
639 + }
640 + JSXElementName::JSXMemberExpression(name) => {
641 + if root_name != "this" {
642 + self.visit_jsxmember_expression(name);
643 + }
644 + }
645 + JSXElementName::JSXNamespacedName(name) => {
646 + if root_name != "this" {
647 + self.visit_jsxnamespaced_name(name);
648 + }
649 + }
650 + }
651 +
652 + for attribute in &ast.attributes {
653 + self.visit_jsxattribute_or_spread(attribute);
654 + }
655 + }
656 }
compiler/forget/crates/forget_semantic_analysis/src/scope_manager.rs
+4
@@ -65,6 +65,10 @@ impl ScopeManager {
65 }
66 }
67
68 + pub fn diagnostics(&mut self) -> Vec<Diagnostic> {
69 + std::mem::take(&mut self.diagnostics)
70 + }
71 +
72 pub fn root(&self) -> &Scope {
73 &self.scopes[self.root.0]
74 }
compiler/forget/crates/forget_semantic_analysis/tests/analysis_test.rs
+10 -3
@@ -1,3 +1,5 @@
1 +use std::fmt::Write;
2 +
3 use forget_hermes_parser::parse;
4 use forget_semantic_analysis::analyze;
5 use insta::{assert_snapshot, glob};
@@ -8,12 +10,17 @@ fn fixtures() {
10 println!("fixture {}", path.to_str().unwrap());
11 let input = std::fs::read_to_string(path).unwrap();
12 let ast = parse(&input, path.to_str().unwrap()).unwrap();
11 - let analysis = analyze(&ast);
13 + let mut analysis = analyze(&ast);
14
15 let ast_output = serde_json::to_string_pretty(&ast).unwrap();
14 - let analysis_output = format!("{:#?}", analysis.debug());
16 + let mut output = String::new();
17 + writeln!(&mut output, "{:#?}", analysis.debug()).unwrap();
18 + let diagnostics = analysis.diagnostics();
19 + for diagnostic in diagnostics {
20 + writeln!(&mut output, "{:#?}", diagnostic).unwrap();
21 + }
22 assert_snapshot!(format!(
16 - "Input:\n{input}\n\nAST:\n{ast_output}\n\nAnalysis:\n{analysis_output}"
23 + "Input:\n{input}\n\nAST:\n{ast_output}\n\nAnalysis:\n{output}"
24 ));
25 });
26 }
compiler/forget/crates/forget_semantic_analysis/tests/fixtures/globals-and-imports.js new
+17
@@ -0,0 +1,17 @@
1 +import Foo from "foo";
2 +import * as Bar from "bar";
3 +import { Baz } from "baz";
4 +
5 +function Component(props) {
6 + let g = global;
7 + let y = new Array(props.count);
8 + let s = String("hello");
9 + let b = Boolean(true);
10 + let n = Number(0);
11 + let x = Math.min(props.x, props.y);
12 + setTimeout(() => {}, 0);
13 + setInterval(() => {}, 0);
14 + Foo;
15 + Bar;
16 + Baz;
17 +}
compiler/forget/crates/forget_semantic_analysis/tests/snapshots/analysis_test__fixtures@globals-and-imports.js.snap new
+1219
@@ -0,0 +1,1219 @@
1 +---
2 +source: crates/forget_semantic_analysis/tests/analysis_test.rs
3 +expression: "format!(\"Input:\\n{input}\\n\\nAST:\\n{ast_output}\\n\\nAnalysis:\\n{output}\")"
4 +input_file: crates/forget_semantic_analysis/tests/fixtures/globals-and-imports.js
5 +---
6 +Input:
7 +import Foo from "foo";
8 +import * as Bar from "bar";
9 +import { Baz } from "baz";
10 +
11 +function Component(props) {
12 + let g = global;
13 + let y = new Array(props.count);
14 + let s = String("hello");
15 + let b = Boolean(true);
16 + let n = Number(0);
17 + let x = Math.min(props.x, props.y);
18 + setTimeout(() => {}, 0);
19 + setInterval(() => {}, 0);
20 + Foo;
21 + Bar;
22 + Baz;
23 +}
24 +
25 +
26 +AST:
27 +{
28 + "type": "Program",
29 + "body": [
30 + {
31 + "type": "ImportDeclaration",
32 + "specifiers": [
33 + {
34 + "type": "ImportDefaultSpecifier",
35 + "local": {
36 + "type": "Identifier",
37 + "name": "Foo",
38 + "typeAnnotation": null,
39 + "loc": null,
40 + "range": {
41 + "start": 0,
42 + "end": 1
43 + }
44 + },
45 + "loc": null,
46 + "range": {
47 + "start": 0,
48 + "end": 1
49 + }
50 + }
51 + ],
52 + "source": {
53 + "type": "StringLiteral",
54 + "value": "foo",
55 + "loc": null,
56 + "range": {
57 + "start": 0,
58 + "end": 1
59 + }
60 + },
61 + "loc": null,
62 + "range": {
63 + "start": 0,
64 + "end": 1
65 + }
66 + },
67 + {
68 + "type": "ImportDeclaration",
69 + "specifiers": [
70 + {
71 + "type": "ImportNamespaceSpecifier",
72 + "local": {
73 + "type": "Identifier",
74 + "name": "Bar",
75 + "typeAnnotation": null,
76 + "loc": null,
77 + "range": {
78 + "start": 0,
79 + "end": 1
80 + }
81 + },
82 + "loc": null,
83 + "range": {
84 + "start": 0,
85 + "end": 1
86 + }
87 + }
88 + ],
89 + "source": {
90 + "type": "StringLiteral",
91 + "value": "bar",
92 + "loc": null,
93 + "range": {
94 + "start": 0,
95 + "end": 1
96 + }
97 + },
98 + "loc": null,
99 + "range": {
100 + "start": 0,
101 + "end": 1
102 + }
103 + },
104 + {
105 + "type": "ImportDeclaration",
106 + "specifiers": [
107 + {
108 + "type": "ImportSpecifier",
109 + "imported": {
110 + "type": "Identifier",
111 + "name": "Baz",
112 + "typeAnnotation": null,
113 + "loc": null,
114 + "range": {
115 + "start": 0,
116 + "end": 1
117 + }
118 + },
119 + "local": {
120 + "type": "Identifier",
121 + "name": "Baz",
122 + "typeAnnotation": null,
123 + "loc": null,
124 + "range": {
125 + "start": 0,
126 + "end": 1
127 + }
128 + },
129 + "loc": null,
130 + "range": {
131 + "start": 0,
132 + "end": 1
133 + }
134 + }
135 + ],
136 + "source": {
137 + "type": "StringLiteral",
138 + "value": "baz",
139 + "loc": null,
140 + "range": {
141 + "start": 0,
142 + "end": 1
143 + }
144 + },
145 + "loc": null,
146 + "range": {
147 + "start": 0,
148 + "end": 1
149 + }
150 + },
151 + {
152 + "type": "FunctionDeclaration",
153 + "id": {
154 + "type": "Identifier",
155 + "name": "Component",
156 + "typeAnnotation": null,
157 + "loc": null,
158 + "range": {
159 + "start": 0,
160 + "end": 1
161 + }
162 + },
163 + "params": [
164 + {
165 + "type": "Identifier",
166 + "name": "props",
167 + "typeAnnotation": null,
168 + "loc": null,
169 + "range": {
170 + "start": 0,
171 + "end": 1
172 + }
173 + }
174 + ],
175 + "body": {
176 + "type": "BlockStatement",
177 + "body": [
178 + {
179 + "type": "VariableDeclaration",
180 + "kind": "let",
181 + "declarations": [
182 + {
183 + "type": "VariableDeclarator",
184 + "id": {
185 + "type": "Identifier",
186 + "name": "g",
187 + "typeAnnotation": null,
188 + "loc": null,
189 + "range": {
190 + "start": 0,
191 + "end": 1
192 + }
193 + },
194 + "init": {
195 + "type": "Identifier",
196 + "name": "global",
197 + "typeAnnotation": null,
198 + "loc": null,
199 + "range": {
200 + "start": 0,
201 + "end": 1
202 + }
203 + },
204 + "loc": null,
205 + "range": {
206 + "start": 0,
207 + "end": 1
208 + }
209 + }
210 + ],
211 + "loc": null,
212 + "range": {
213 + "start": 0,
214 + "end": 1
215 + }
216 + },
217 + {
218 + "type": "VariableDeclaration",
219 + "kind": "let",
220 + "declarations": [
221 + {
222 + "type": "VariableDeclarator",
223 + "id": {
224 + "type": "Identifier",
225 + "name": "y",
226 + "typeAnnotation": null,
227 + "loc": null,
228 + "range": {
229 + "start": 0,
230 + "end": 1
231 + }
232 + },
233 + "init": {
234 + "type": "NewExpression",
235 + "callee": {
236 + "type": "Identifier",
237 + "name": "Array",
238 + "typeAnnotation": null,
239 + "loc": null,
240 + "range": {
241 + "start": 0,
242 + "end": 1
243 + }
244 + },
245 + "arguments": [
246 + {
247 + "type": "MemberExpression",
248 + "object": {
249 + "type": "Identifier",
250 + "name": "props",
251 + "typeAnnotation": null,
252 + "loc": null,
253 + "range": {
254 + "start": 0,
255 + "end": 1
256 + }
257 + },
258 + "property": {
259 + "type": "Identifier",
260 + "name": "count",
261 + "typeAnnotation": null,
262 + "loc": null,
263 + "range": {
264 + "start": 0,
265 + "end": 1
266 + }
267 + },
268 + "computed": false,
269 + "loc": null,
270 + "range": {
271 + "start": 0,
272 + "end": 1
273 + }
274 + }
275 + ],
276 + "loc": null,
277 + "range": {
278 + "start": 0,
279 + "end": 1
280 + }
281 + },
282 + "loc": null,
283 + "range": {
284 + "start": 0,
285 + "end": 1
286 + }
287 + }
288 + ],
289 + "loc": null,
290 + "range": {
291 + "start": 0,
292 + "end": 1
293 + }
294 + },
295 + {
296 + "type": "VariableDeclaration",
297 + "kind": "let",
298 + "declarations": [
299 + {
300 + "type": "VariableDeclarator",
301 + "id": {
302 + "type": "Identifier",
303 + "name": "s",
304 + "typeAnnotation": null,
305 + "loc": null,
306 + "range": {
307 + "start": 0,
308 + "end": 1
309 + }
310 + },
311 + "init": {
312 + "type": "CallExpression",
313 + "callee": {
314 + "type": "Identifier",
315 + "name": "String",
316 + "typeAnnotation": null,
317 + "loc": null,
318 + "range": {
319 + "start": 0,
320 + "end": 1
321 + }
322 + },
323 + "arguments": [
324 + {
325 + "type": "StringLiteral",
326 + "value": "hello",
327 + "loc": null,
328 + "range": {
329 + "start": 0,
330 + "end": 1
331 + }
332 + }
333 + ],
334 + "loc": null,
335 + "range": {
336 + "start": 0,
337 + "end": 1
338 + }
339 + },
340 + "loc": null,
341 + "range": {
342 + "start": 0,
343 + "end": 1
344 + }
345 + }
346 + ],
347 + "loc": null,
348 + "range": {
349 + "start": 0,
350 + "end": 1
351 + }
352 + },
353 + {
354 + "type": "VariableDeclaration",
355 + "kind": "let",
356 + "declarations": [
357 + {
358 + "type": "VariableDeclarator",
359 + "id": {
360 + "type": "Identifier",
361 + "name": "b",
362 + "typeAnnotation": null,
363 + "loc": null,
364 + "range": {
365 + "start": 0,
366 + "end": 1
367 + }
368 + },
369 + "init": {
370 + "type": "CallExpression",
371 + "callee": {
372 + "type": "Identifier",
373 + "name": "Boolean",
374 + "typeAnnotation": null,
375 + "loc": null,
376 + "range": {
377 + "start": 0,
378 + "end": 1
379 + }
380 + },
381 + "arguments": [
382 + {
383 + "type": "BooleanLiteral",
384 + "value": true,
385 + "loc": null,
386 + "range": {
387 + "start": 0,
388 + "end": 1
389 + }
390 + }
391 + ],
392 + "loc": null,
393 + "range": {
394 + "start": 0,
395 + "end": 1
396 + }
397 + },
398 + "loc": null,
399 + "range": {
400 + "start": 0,
401 + "end": 1
402 + }
403 + }
404 + ],
405 + "loc": null,
406 + "range": {
407 + "start": 0,
408 + "end": 1
409 + }
410 + },
411 + {
412 + "type": "VariableDeclaration",
413 + "kind": "let",
414 + "declarations": [
415 + {
416 + "type": "VariableDeclarator",
417 + "id": {
418 + "type": "Identifier",
419 + "name": "n",
420 + "typeAnnotation": null,
421 + "loc": null,
422 + "range": {
423 + "start": 0,
424 + "end": 1
425 + }
426 + },
427 + "init": {
428 + "type": "CallExpression",
429 + "callee": {
430 + "type": "Identifier",
431 + "name": "Number",
432 + "typeAnnotation": null,
433 + "loc": null,
434 + "range": {
435 + "start": 0,
436 + "end": 1
437 + }
438 + },
439 + "arguments": [
440 + {
441 + "type": "NumericLiteral",
442 + "value": 0,
443 + "loc": null,
444 + "range": {
445 + "start": 0,
446 + "end": 1
447 + }
448 + }
449 + ],
450 + "loc": null,
451 + "range": {
452 + "start": 0,
453 + "end": 1
454 + }
455 + },
456 + "loc": null,
457 + "range": {
458 + "start": 0,
459 + "end": 1
460 + }
461 + }
462 + ],
463 + "loc": null,
464 + "range": {
465 + "start": 0,
466 + "end": 1
467 + }
468 + },
469 + {
470 + "type": "VariableDeclaration",
471 + "kind": "let",
472 + "declarations": [
473 + {
474 + "type": "VariableDeclarator",
475 + "id": {
476 + "type": "Identifier",
477 + "name": "x",
478 + "typeAnnotation": null,
479 + "loc": null,
480 + "range": {
481 + "start": 0,
482 + "end": 1
483 + }
484 + },
485 + "init": {
486 + "type": "CallExpression",
487 + "callee": {
488 + "type": "MemberExpression",
489 + "object": {
490 + "type": "Identifier",
491 + "name": "Math",
492 + "typeAnnotation": null,
493 + "loc": null,
494 + "range": {
495 + "start": 0,
496 + "end": 1
497 + }
498 + },
499 + "property": {
500 + "type": "Identifier",
501 + "name": "min",
502 + "typeAnnotation": null,
503 + "loc": null,
504 + "range": {
505 + "start": 0,
506 + "end": 1
507 + }
508 + },
509 + "computed": false,
510 + "loc": null,
511 + "range": {
512 + "start": 0,
513 + "end": 1
514 + }
515 + },
516 + "arguments": [
517 + {
518 + "type": "MemberExpression",
519 + "object": {
520 + "type": "Identifier",
521 + "name": "props",
522 + "typeAnnotation": null,
523 + "loc": null,
524 + "range": {
525 + "start": 0,
526 + "end": 1
527 + }
528 + },
529 + "property": {
530 + "type": "Identifier",
531 + "name": "x",
532 + "typeAnnotation": null,
533 + "loc": null,
534 + "range": {
535 + "start": 0,
536 + "end": 1
537 + }
538 + },
539 + "computed": false,
540 + "loc": null,
541 + "range": {
542 + "start": 0,
543 + "end": 1
544 + }
545 + },
546 + {
547 + "type": "MemberExpression",
548 + "object": {
549 + "type": "Identifier",
550 + "name": "props",
551 + "typeAnnotation": null,
552 + "loc": null,
553 + "range": {
554 + "start": 0,
555 + "end": 1
556 + }
557 + },
558 + "property": {
559 + "type": "Identifier",
560 + "name": "y",
561 + "typeAnnotation": null,
562 + "loc": null,
563 + "range": {
564 + "start": 0,
565 + "end": 1
566 + }
567 + },
568 + "computed": false,
569 + "loc": null,
570 + "range": {
571 + "start": 0,
572 + "end": 1
573 + }
574 + }
575 + ],
576 + "loc": null,
577 + "range": {
578 + "start": 0,
579 + "end": 1
580 + }
581 + },
582 + "loc": null,
583 + "range": {
584 + "start": 0,
585 + "end": 1
586 + }
587 + }
588 + ],
589 + "loc": null,
590 + "range": {
591 + "start": 0,
592 + "end": 1
593 + }
594 + },
595 + {
596 + "type": "ExpressionStatement",
597 + "expression": {
598 + "type": "CallExpression",
599 + "callee": {
600 + "type": "Identifier",
601 + "name": "setTimeout",
602 + "typeAnnotation": null,
603 + "loc": null,
604 + "range": {
605 + "start": 0,
606 + "end": 1
607 + }
608 + },
609 + "arguments": [
610 + {
611 + "type": "ArrowFunctionExpression",
612 + "id": null,
613 + "params": [],
614 + "body": {
615 + "type": "BlockStatement",
616 + "body": [],
617 + "loc": null,
618 + "range": {
619 + "start": 0,
620 + "end": 1
621 + }
622 + },
623 + "generator": false,
624 + "async": false,
625 + "loc": null,
626 + "range": {
627 + "start": 0,
628 + "end": 1
629 + },
630 + "expression": false,
631 + "loc": null,
632 + "range": {
633 + "start": 0,
634 + "end": 1
635 + }
636 + },
637 + {
638 + "type": "NumericLiteral",
639 + "value": 0,
640 + "loc": null,
641 + "range": {
642 + "start": 0,
643 + "end": 1
644 + }
645 + }
646 + ],
647 + "loc": null,
648 + "range": {
649 + "start": 0,
650 + "end": 1
651 + }
652 + },
653 + "directive": null,
654 + "loc": null,
655 + "range": {
656 + "start": 0,
657 + "end": 1
658 + }
659 + },
660 + {
661 + "type": "ExpressionStatement",
662 + "expression": {
663 + "type": "CallExpression",
664 + "callee": {
665 + "type": "Identifier",
666 + "name": "setInterval",
667 + "typeAnnotation": null,
668 + "loc": null,
669 + "range": {
670 + "start": 0,
671 + "end": 1
672 + }
673 + },
674 + "arguments": [
675 + {
676 + "type": "ArrowFunctionExpression",
677 + "id": null,
678 + "params": [],
679 + "body": {
680 + "type": "BlockStatement",
681 + "body": [],
682 + "loc": null,
683 + "range": {
684 + "start": 0,
685 + "end": 1
686 + }
687 + },
688 + "generator": false,
689 + "async": false,
690 + "loc": null,
691 + "range": {
692 + "start": 0,
693 + "end": 1
694 + },
695 + "expression": false,
696 + "loc": null,
697 + "range": {
698 + "start": 0,
699 + "end": 1
700 + }
701 + },
702 + {
703 + "type": "NumericLiteral",
704 + "value": 0,
705 + "loc": null,
706 + "range": {
707 + "start": 0,
708 + "end": 1
709 + }
710 + }
711 + ],
712 + "loc": null,
713 + "range": {
714 + "start": 0,
715 + "end": 1
716 + }
717 + },
718 + "directive": null,
719 + "loc": null,
720 + "range": {
721 + "start": 0,
722 + "end": 1
723 + }
724 + },
725 + {
726 + "type": "ExpressionStatement",
727 + "expression": {
728 + "type": "Identifier",
729 + "name": "Foo",
730 + "typeAnnotation": null,
731 + "loc": null,
732 + "range": {
733 + "start": 0,
734 + "end": 1
735 + }
736 + },
737 + "directive": null,
738 + "loc": null,
739 + "range": {
740 + "start": 0,
741 + "end": 1
742 + }
743 + },
744 + {
745 + "type": "ExpressionStatement",
746 + "expression": {
747 + "type": "Identifier",
748 + "name": "Bar",
749 + "typeAnnotation": null,
750 + "loc": null,
751 + "range": {
752 + "start": 0,
753 + "end": 1
754 + }
755 + },
756 + "directive": null,
757 + "loc": null,
758 + "range": {
759 + "start": 0,
760 + "end": 1
761 + }
762 + },
763 + {
764 + "type": "ExpressionStatement",
765 + "expression": {
766 + "type": "Identifier",
767 + "name": "Baz",
768 + "typeAnnotation": null,
769 + "loc": null,
770 + "range": {
771 + "start": 0,
772 + "end": 1
773 + }
774 + },
775 + "directive": null,
776 + "loc": null,
777 + "range": {
778 + "start": 0,
779 + "end": 1
780 + }
781 + }
782 + ],
783 + "loc": null,
784 + "range": {
785 + "start": 0,
786 + "end": 1
787 + }
788 + },
789 + "generator": false,
790 + "async": false,
791 + "loc": null,
792 + "range": {
793 + "start": 0,
794 + "end": 1
795 + },
796 + "loc": null,
797 + "range": {
798 + "start": 0,
799 + "end": 1
800 + }
801 + }
802 + ],
803 + "sourceType": "module",
804 + "loc": null,
805 + "range": {
806 + "start": 0,
807 + "end": 1
808 + }
809 +}
810 +
811 +Analysis:
812 +Scope {
813 + id: ScopeId(
814 + 0,
815 + ),
816 + kind: Global,
817 + labels: {},
818 + declarations: {},
819 + references: [],
820 + children: [
821 + Scope {
822 + id: ScopeId(
823 + 1,
824 + ),
825 + kind: Module,
826 + labels: {},
827 + declarations: {
828 + "Component": Declaration {
829 + id: DeclarationId(
830 + 0,
831 + ),
832 + kind: FunctionDeclaration,
833 + scope: ScopeId(
834 + 1,
835 + ),
836 + },
837 + },
838 + references: [],
839 + children: [
840 + Scope {
841 + id: ScopeId(
842 + 2,
843 + ),
844 + kind: Function,
845 + labels: {},
846 + declarations: {
847 + "props": Declaration {
848 + id: DeclarationId(
849 + 1,
850 + ),
851 + kind: FunctionDeclaration,
852 + scope: ScopeId(
853 + 2,
854 + ),
855 + },
856 + "g": Declaration {
857 + id: DeclarationId(
858 + 2,
859 + ),
860 + kind: Let,
861 + scope: ScopeId(
862 + 2,
863 + ),
864 + },
865 + "y": Declaration {
866 + id: DeclarationId(
867 + 3,
868 + ),
869 + kind: Let,
870 + scope: ScopeId(
871 + 2,
872 + ),
873 + },
874 + "s": Declaration {
875 + id: DeclarationId(
876 + 4,
877 + ),
878 + kind: Let,
879 + scope: ScopeId(
880 + 2,
881 + ),
882 + },
883 + "b": Declaration {
884 + id: DeclarationId(
885 + 5,
886 + ),
887 + kind: Let,
888 + scope: ScopeId(
889 + 2,
890 + ),
891 + },
892 + "n": Declaration {
893 + id: DeclarationId(
894 + 6,
895 + ),
896 + kind: Let,
897 + scope: ScopeId(
898 + 2,
899 + ),
900 + },
901 + "x": Declaration {
902 + id: DeclarationId(
903 + 7,
904 + ),
905 + kind: Let,
906 + scope: ScopeId(
907 + 2,
908 + ),
909 + },
910 + },
911 + references: [
912 + Reference {
913 + id: ReferenceId(
914 + 0,
915 + ),
916 + kind: Read,
917 + declaration: DeclarationId(
918 + 1,
919 + ),
920 + declaration (name): "props",
921 + scope: ScopeId(
922 + 2,
923 + ),
924 + },
925 + Reference {
926 + id: ReferenceId(
927 + 1,
928 + ),
929 + kind: Read,
930 + declaration: DeclarationId(
931 + 1,
932 + ),
933 + declaration (name): "props",
934 + scope: ScopeId(
935 + 2,
936 + ),
937 + },
938 + Reference {
939 + id: ReferenceId(
940 + 2,
941 + ),
942 + kind: Read,
943 + declaration: DeclarationId(
944 + 1,
945 + ),
946 + declaration (name): "props",
947 + scope: ScopeId(
948 + 2,
949 + ),
950 + },
951 + ],
952 + children: [
953 + Scope {
954 + id: ScopeId(
955 + 3,
956 + ),
957 + kind: Function,
958 + labels: {},
959 + declarations: {},
960 + references: [],
961 + children: [],
962 + },
963 + Scope {
964 + id: ScopeId(
965 + 4,
966 + ),
967 + kind: Function,
968 + labels: {},
969 + declarations: {},
970 + references: [],
971 + children: [],
972 + },
973 + ],
974 + },
975 + ],
976 + },
977 + ],
978 +}
979 +Diagnostic(
980 + DiagnosticData {
981 + message: "Undefined variable",
982 + span: Some(
983 + SourceSpan {
984 + offset: SourceOffset(
985 + 0,
986 + ),
987 + length: 1,
988 + },
989 + ),
990 + related_information: [],
991 + severity: InvalidSyntax,
992 + data: [],
993 + },
994 +)
995 +Diagnostic(
996 + DiagnosticData {
997 + message: "Undefined variable",
998 + span: Some(
999 + SourceSpan {
1000 + offset: SourceOffset(
1001 + 0,
1002 + ),
1003 + length: 1,
1004 + },
1005 + ),
1006 + related_information: [],
1007 + severity: InvalidSyntax,
1008 + data: [],
1009 + },
1010 +)
1011 +Diagnostic(
1012 + DiagnosticData {
1013 + message: "Undefined variable",
1014 + span: Some(
1015 + SourceSpan {
1016 + offset: SourceOffset(
1017 + 0,
1018 + ),
1019 + length: 1,
1020 + },
1021 + ),
1022 + related_information: [],
1023 + severity: InvalidSyntax,
1024 + data: [],
1025 + },
1026 +)
1027 +Diagnostic(
1028 + DiagnosticData {
1029 + message: "Undefined variable",
1030 + span: Some(
1031 + SourceSpan {
1032 + offset: SourceOffset(
1033 + 0,
1034 + ),
1035 + length: 1,
1036 + },
1037 + ),
1038 + related_information: [],
1039 + severity: InvalidSyntax,
1040 + data: [],
1041 + },
1042 +)
1043 +Diagnostic(
1044 + DiagnosticData {
1045 + message: "Undefined variable",
1046 + span: Some(
1047 + SourceSpan {
1048 + offset: SourceOffset(
1049 + 0,
1050 + ),
1051 + length: 1,
1052 + },
1053 + ),
1054 + related_information: [],
1055 + severity: InvalidSyntax,
1056 + data: [],
1057 + },
1058 +)
1059 +Diagnostic(
1060 + DiagnosticData {
1061 + message: "Undefined variable",
1062 + span: Some(
1063 + SourceSpan {
1064 + offset: SourceOffset(
1065 + 0,
1066 + ),
1067 + length: 1,
1068 + },
1069 + ),
1070 + related_information: [],
1071 + severity: InvalidSyntax,
1072 + data: [],
1073 + },
1074 +)
1075 +Diagnostic(
1076 + DiagnosticData {
1077 + message: "Undefined variable",
1078 + span: Some(
1079 + SourceSpan {
1080 + offset: SourceOffset(
1081 + 0,
1082 + ),
1083 + length: 1,
1084 + },
1085 + ),
1086 + related_information: [],
1087 + severity: InvalidSyntax,
1088 + data: [],
1089 + },
1090 +)
1091 +Diagnostic(
1092 + DiagnosticData {
1093 + message: "Undefined variable",
1094 + span: Some(
1095 + SourceSpan {
1096 + offset: SourceOffset(
1097 + 0,
1098 + ),
1099 + length: 1,
1100 + },
1101 + ),
1102 + related_information: [],
1103 + severity: InvalidSyntax,
1104 + data: [],
1105 + },
1106 +)
1107 +Diagnostic(
1108 + DiagnosticData {
1109 + message: "Undefined variable",
1110 + span: Some(
1111 + SourceSpan {
1112 + offset: SourceOffset(
1113 + 0,
1114 + ),
1115 + length: 1,
1116 + },
1117 + ),
1118 + related_information: [],
1119 + severity: InvalidSyntax,
1120 + data: [],
1121 + },
1122 +)
1123 +Diagnostic(
1124 + DiagnosticData {
1125 + message: "Undefined variable",
1126 + span: Some(
1127 + SourceSpan {
1128 + offset: SourceOffset(
1129 + 0,
1130 + ),
1131 + length: 1,
1132 + },
1133 + ),
1134 + related_information: [],
1135 + severity: InvalidSyntax,
1136 + data: [],
1137 + },
1138 +)
1139 +Diagnostic(
1140 + DiagnosticData {
1141 + message: "Undefined variable",
1142 + span: Some(
1143 + SourceSpan {
1144 + offset: SourceOffset(
1145 + 0,
1146 + ),
1147 + length: 1,
1148 + },
1149 + ),
1150 + related_information: [],
1151 + severity: InvalidSyntax,
1152 + data: [],
1153 + },
1154 +)
1155 +Diagnostic(
1156 + DiagnosticData {
1157 + message: "Undefined variable",
1158 + span: Some(
1159 + SourceSpan {
1160 + offset: SourceOffset(
1161 + 0,
1162 + ),
1163 + length: 1,
1164 + },
1165 + ),
1166 + related_information: [],
1167 + severity: InvalidSyntax,
1168 + data: [],
1169 + },
1170 +)
1171 +Diagnostic(
1172 + DiagnosticData {
1173 + message: "Undefined variable",
1174 + span: Some(
1175 + SourceSpan {
1176 + offset: SourceOffset(
1177 + 0,
1178 + ),
1179 + length: 1,
1180 + },
1181 + ),
1182 + related_information: [],
1183 + severity: InvalidSyntax,
1184 + data: [],
1185 + },
1186 +)
1187 +Diagnostic(
1188 + DiagnosticData {
1189 + message: "Undefined variable",
1190 + span: Some(
1191 + SourceSpan {
1192 + offset: SourceOffset(
1193 + 0,
1194 + ),
1195 + length: 1,
1196 + },
1197 + ),
1198 + related_information: [],
1199 + severity: InvalidSyntax,
1200 + data: [],
1201 + },
1202 +)
1203 +Diagnostic(
1204 + DiagnosticData {
1205 + message: "Undefined variable",
1206 + span: Some(
1207 + SourceSpan {
1208 + offset: SourceOffset(
1209 + 0,
1210 + ),
1211 + length: 1,
1212 + },
1213 + ),
1214 + related_information: [],
1215 + severity: InvalidSyntax,
1216 + data: [],
1217 + },
1218 +)
1219 +
compiler/forget/crates/forget_semantic_analysis/tests/snapshots/analysis_test__fixtures@labels.js.snap renamed
+80 -66
@@ -1,6 +1,6 @@
1 ---
2 source: crates/forget_semantic_analysis/tests/analysis_test.rs
3 -expression: "format!(\"Input:\\n{input}\\n\\nAST:\\n{ast_output}\\n\\nAnalysis:\\n{analysis_output}\")"
3 +expression: "format!(\"Input:\\n{input}\\n\\nAST:\\n{ast_output}\\n\\nAnalysis:\\n{output}\")"
4 input_file: crates/forget_semantic_analysis/tests/fixtures/labels.js
5 ---
6 Input:
@@ -517,43 +517,8 @@ Scope {
517 2,
518 ),
519 },
520 - "x": Declaration {
521 - id: DeclarationId(
522 - 3,
523 - ),
524 - kind: Let,
525 - scope: ScopeId(
526 - 2,
527 - ),
528 - },
520 },
521 references: [
531 - Reference {
532 - id: ReferenceId(
533 - 0,
534 - ),
535 - kind: Read,
536 - declaration: DeclarationId(
537 - 3,
538 - ),
539 - declaration (name): "x",
540 - scope: ScopeId(
541 - 2,
542 - ),
543 - },
544 - Reference {
545 - id: ReferenceId(
546 - 1,
547 - ),
548 - kind: Read,
549 - declaration: DeclarationId(
550 - 3,
551 - ),
552 - declaration (name): "x",
553 - scope: ScopeId(
554 - 2,
555 - ),
556 - },
522 Reference {
523 id: ReferenceId(
524 6,
@@ -573,39 +538,23 @@ Scope {
538 id: ScopeId(
539 3,
540 ),
576 - kind: Block,
541 + kind: For,
542 labels: {},
578 - declarations: {},
579 - references: [
580 - Reference {
581 - id: ReferenceId(
582 - 2,
583 - ),
584 - kind: Read,
585 - declaration: DeclarationId(
586 - 3,
587 - ),
588 - declaration (name): "x",
589 - scope: ScopeId(
543 + declarations: {
544 + "x": Declaration {
545 + id: DeclarationId(
546 3,
547 ),
592 - },
593 - Reference {
594 - id: ReferenceId(
595 - 3,
596 - ),
597 - kind: ReadWrite,
598 - declaration: DeclarationId(
599 - 2,
600 - ),
601 - declaration (name): "y",
548 + kind: Let,
549 scope: ScopeId(
550 3,
551 ),
552 },
553 + },
554 + references: [
555 Reference {
556 id: ReferenceId(
608 - 4,
557 + 0,
558 ),
559 kind: Read,
560 declaration: DeclarationId(
@@ -618,13 +567,13 @@ Scope {
567 },
568 Reference {
569 id: ReferenceId(
621 - 5,
570 + 1,
571 ),
572 kind: Read,
573 declaration: DeclarationId(
625 - 2,
574 + 3,
575 ),
627 - declaration (name): "y",
576 + declaration (name): "x",
577 scope: ScopeId(
578 3,
579 ),
@@ -638,14 +587,78 @@ Scope {
587 kind: Block,
588 labels: {},
589 declarations: {},
641 - references: [],
642 - children: [],
590 + references: [
591 + Reference {
592 + id: ReferenceId(
593 + 2,
594 + ),
595 + kind: Read,
596 + declaration: DeclarationId(
597 + 3,
598 + ),
599 + declaration (name): "x",
600 + scope: ScopeId(
601 + 4,
602 + ),
603 + },
604 + Reference {
605 + id: ReferenceId(
606 + 3,
607 + ),
608 + kind: ReadWrite,
609 + declaration: DeclarationId(
610 + 2,
611 + ),
612 + declaration (name): "y",
613 + scope: ScopeId(
614 + 4,
615 + ),
616 + },
617 + Reference {
618 + id: ReferenceId(
619 + 4,
620 + ),
621 + kind: Read,
622 + declaration: DeclarationId(
623 + 3,
624 + ),
625 + declaration (name): "x",
626 + scope: ScopeId(
627 + 4,
628 + ),
629 + },
630 + Reference {
631 + id: ReferenceId(
632 + 5,
633 + ),
634 + kind: Read,
635 + declaration: DeclarationId(
636 + 2,
637 + ),
638 + declaration (name): "y",
639 + scope: ScopeId(
640 + 4,
641 + ),
642 + },
643 + ],
644 + children: [
645 + Scope {
646 + id: ScopeId(
647 + 5,
648 + ),
649 + kind: Block,
650 + labels: {},
651 + declarations: {},
652 + references: [],
653 + children: [],
654 + },
655 + ],
656 },
657 ],
658 },
659 Scope {
660 id: ScopeId(
648 - 5,
661 + 6,
662 ),
663 kind: Block,
664 labels: {},
@@ -659,3 +672,4 @@ Scope {
672 },
673 ],
674 }
675 +