Skip to content

Commit

Permalink
feat(transformer_conformance): test ScopeTree and SymbolTable after t…
Browse files Browse the repository at this point in the history
…ransformation
  • Loading branch information
Dunqing committed Jul 31, 2024
1 parent ae1d38f commit a6e9cca
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 11 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions tasks/transform_conformance/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ test = false
doctest = false

[dependencies]
oxc_ast = { workspace = true }
oxc_span = { workspace = true }
oxc_allocator = { workspace = true }
oxc_parser = { workspace = true }
oxc_codegen = { workspace = true }
oxc_semantic = { workspace = true }
oxc_transformer = { workspace = true }
oxc_tasks_common = { workspace = true }
oxc_diagnostics = { workspace = true }
Expand Down
135 changes: 130 additions & 5 deletions tasks/transform_conformance/babel.snap.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
commit: 12619ffe

Passed: 474/927
Passed: 350/927

# All Passed:
* babel-preset-react
* babel-plugin-transform-react-display-name
* babel-plugin-transform-react-jsx-self
* babel-plugin-transform-react-jsx-source
Expand Down Expand Up @@ -445,16 +444,56 @@ Passed: 474/927
* opts/optimizeConstEnums/input.ts
* opts/rewriteImportExtensions/input.ts

# babel-plugin-transform-typescript (130/151)
# babel-plugin-transform-typescript (90/151)
* catch-clause/param-type/input.ts
* class/accessor-allowDeclareFields-false/input.ts
* class/accessor-allowDeclareFields-true/input.ts
* enum/boolean-value/input.ts
* enum/const/input.ts
* enum/constant-folding/input.ts
* enum/enum-merging-inner-references/input.ts
* enum/enum-merging-inner-references-shadow/input.ts
* enum/export/input.ts
* enum/inferred/input.ts
* enum/inner-references/input.ts
* enum/mix-references/input.ts
* enum/non-foldable-constant/input.ts
* enum/non-scoped/input.ts
* enum/outer-references/input.ts
* enum/scoped/input.ts
* enum/string-value/input.ts
* enum/string-value-template/input.ts
* enum/string-values-computed/input.ts
* enum/ts5.0-const-foldable/input.ts
* exports/declared-types/input.ts
* exports/export-const-enums/input.ts
* exports/export-import=/input.ts
* exports/interface/input.ts
* imports/elide-type-referenced-in-imports-equal-no/input.ts
* imports/enum-id/input.ts
* imports/enum-value/input.ts
* imports/import=-module/input.ts
* imports/only-remove-type-imports/input.ts
* imports/type-only-export-specifier-2/input.ts
* imports/type-only-import-specifier-4/input.ts
* namespace/alias/input.ts
* namespace/clobber-class/input.ts
* namespace/clobber-enum/input.ts
* namespace/clobber-export/input.ts
* namespace/contentious-names/input.ts
* namespace/declare/input.ts
* namespace/declare-global-nested-namespace/input.ts
* namespace/empty-removed/input.ts
* namespace/export/input.ts
* namespace/module-nested/input.ts
* namespace/module-nested-export/input.ts
* namespace/multiple/input.ts
* namespace/mutable-fail/input.ts
* namespace/nested/input.ts
* namespace/nested-namespace/input.ts
* namespace/nested-shorthand/input.ts
* namespace/same-name/input.ts
* namespace/undeclared/input.ts
* optimize-const-enums/custom-values/input.ts
* optimize-const-enums/custom-values-exported/input.ts
* optimize-const-enums/declare/input.ts
Expand All @@ -468,9 +507,95 @@ Passed: 474/927
* optimize-const-enums/merged-exported/input.ts
* regression/15768/input.ts

# babel-plugin-transform-react-jsx (141/142)
# babel-preset-react (6/9)
* preset-options/development-runtime-automatic/input.js
* preset-options/empty-options/input.js
* preset-options/runtime-automatic/input.js

# babel-plugin-transform-react-jsx (68/142)
* autoImport/after-polyfills/input.mjs
* autoImport/after-polyfills-2/input.mjs
* autoImport/after-polyfills-script-not-supported/input.js
* autoImport/auto-import-react-source-type-module/input.js
* autoImport/auto-import-react-source-type-script/input.js
* autoImport/complicated-scope-module/input.js
* autoImport/complicated-scope-script/input.js
* autoImport/import-source/input.js
* autoImport/import-source-pragma/input.js
* autoImport/react-defined/input.js
* pure/false-default-pragma-automatic-runtime/input.js
* pure/false-pragma-comment-automatic-runtime/input.js
* pure/false-pragma-option-automatic-runtime/input.js
* pure/true-default-pragma-automatic-runtime/input.js
* pure/true-pragma-comment-automatic-runtime/input.js
* pure/true-pragma-option-automatic-runtime/input.js
* pure/unset-default-pragma-automatic-runtime/input.js
* pure/unset-pragma-comment-automatic-runtime/input.js
* pure/unset-pragma-option-automatic-runtime/input.js
* react-automatic/adds-appropriate-newlines-when-using-spread-attribute/input.js
* react-automatic/arrow-functions/input.js
* react-automatic/assignment/input.js
* react-automatic/concatenates-adjacent-string-literals/input.js
* react-automatic/does-not-add-source-self-automatic/input.mjs
* react-automatic/dont-coerce-expression-containers/input.js
* react-automatic/duplicate-props/input.js
* react-automatic/flattens-spread/input.js
* react-automatic/handle-fragments/input.js
* react-automatic/handle-fragments-with-key/input.js
* react-automatic/handle-fragments-with-no-children/input.js
* react-automatic/handle-nonstatic-children/input.js
* react-automatic/handle-spread-with-proto/input.js
* react-automatic/handle-static-children/input.js
* react-automatic/jsx-with-retainlines-option/input.js
* react-automatic/jsx-without-retainlines-option/input.js
* react-automatic/key-undefined-works/input.js
* react-automatic/pragma-works-with-no-space-at-the-end/input.js
* react-automatic/should-allow-constructor-as-prop/input.js
* react-automatic/should-allow-deeper-js-namespacing/input.js
* react-automatic/should-allow-elements-as-attributes/input.js
* react-automatic/should-allow-js-namespacing/input.js
* react-automatic/should-allow-nested-fragments/input.js
* react-automatic/should-avoid-wrapping-in-extra-parens-if-not-needed/input.js
* react-automatic/should-convert-simple-tags/input.js
* react-automatic/should-convert-simple-text/input.js
* react-automatic/should-disallow-spread-children/input.js
* react-automatic/should-disallow-valueless-key/input.js
* react-automatic/should-disallow-xml-namespacing/input.js
* react-automatic/should-escape-xhtml-jsxattribute/input.js
* react-automatic/should-escape-xhtml-jsxtext/input.js
* react-automatic/should-handle-attributed-elements/input.js
* react-automatic/should-handle-has-own-property-correctly/input.js
* react-automatic/should-have-correct-comma-in-nested-children/input.js
* react-automatic/should-insert-commas-after-expressions-before-whitespace/input.js
* react-automatic/should-not-add-quotes-to-identifier-names/input.js
* react-automatic/should-not-mangle-expressioncontainer-attribute-values/input.js
* react-automatic/should-not-strip-nbsp-even-coupled-with-other-whitespace/input.js
* react-automatic/should-not-strip-tags-with-a-single-child-of-nbsp/input.js
* react-automatic/should-properly-handle-comments-between-props/input.js
* react-automatic/should-properly-handle-keys/input.js
* react-automatic/should-properly-handle-null-prop-spread/input.js
* react-automatic/should-quote-jsx-attributes/input.js
* react-automatic/should-support-xml-namespaces-if-flag/input.js
* react-automatic/should-throw-error-namespaces-if-not-flag/input.js
* react-automatic/should-transform-known-hyphenated-tags/input.js
* react-automatic/should-use-createElement-when-key-comes-after-spread/input.js
* react-automatic/should-use-jsx-when-key-comes-before-spread/input.js
* react-automatic/should-warn-when-pragma-or-pragmaFrag-is-set/input.js
* react-automatic/this-tag-name/input.js
* react-automatic/weird-symbols/input.js
* react-automatic/wraps-props-in-react-spread-for-last-spread-attributes/input.js
* react-automatic/wraps-props-in-react-spread-for-middle-spread-attributes/input.js
* runtime/defaults-to-automatic/input.js
* runtime/runtime-automatic/input.js

# babel-plugin-transform-react-jsx-development (9/10)
# babel-plugin-transform-react-jsx-development (1/10)
* cross-platform/auto-import-dev/input.js
* cross-platform/disallow-__self-as-jsx-attribute/input.js
* cross-platform/disallow-__source-as-jsx-attribute/input.js
* cross-platform/fragments/input.js
* cross-platform/handle-fragments-with-key/input.js
* cross-platform/handle-nonstatic-children/input.js
* cross-platform/handle-static-children/input.js
* cross-platform/within-derived-classes-constructor/input.js
* cross-platform/within-ts-module-block/input.ts

13 changes: 10 additions & 3 deletions tasks/transform_conformance/oxc.snap.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
commit: 12619ffe

Passed: 7/7
Passed: 3/7

# All Passed:
* babel-plugin-transform-typescript
* babel-plugin-transform-react-jsx



# babel-plugin-transform-typescript (3/6)
* computed-constant-value/input.ts
* enum-member-reference/input.ts
* export-elimination/input.ts

# babel-plugin-transform-react-jsx (0/1)
* unicode/input.jsx

1 change: 1 addition & 0 deletions tasks/transform_conformance/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use oxc_tasks_common::{normalize_path, project_root, Snapshot};
use test_case::TestCaseKind;
use walkdir::WalkDir;

mod semantic;
mod test_case;

#[test]
Expand Down
86 changes: 86 additions & 0 deletions tasks/transform_conformance/src/semantic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use oxc_ast::{
ast::{BindingIdentifier, ExportSpecifier, ImportSpecifier, ModuleExportName, Program},
visit::walk::walk_import_specifier,
Visit,
};
use oxc_semantic::{ScopeTree, SymbolTable};

pub struct SemanticTester {
scopes: ScopeTree,
symbols: SymbolTable,
errors: Vec<String>,
}

impl SemanticTester {
pub fn new(scopes: ScopeTree, symbols: SymbolTable) -> Self {
Self { scopes, symbols, errors: Vec::new() }
}

pub fn test(mut self, program: &Program) -> Vec<String> {
self.visit_program(program);
self.errors
}
}

impl<'a> Visit<'a> for SemanticTester {
fn visit_binding_identifier(&mut self, it: &BindingIdentifier<'a>) {
let symbol_id = it.symbol_id.get();
if let Some(symbol_id) = symbol_id {
if self.symbols.get_flag(symbol_id).is_empty() {
self.errors.push(format!(
"Expect SymbolFlags for BindingIdentifier({}) to not be empty",
it.name
));
}
if !self.scopes.has_binding(self.symbols.get_scope_id(symbol_id), &it.name) {
self.errors.push(format!(
"Cannot find BindingIdentifier({}) in the Scope corresponding to the Symbol",
it.name
));
}
} else {
self.errors.push(format!("Expect BindingIdentifier({}) to have a symbol_id", it.name));
}
}
fn visit_identifier_reference(&mut self, it: &oxc_ast::ast::IdentifierReference<'a>) {
if let Some(reference_id) = it.reference_id.get() {
let reference = self.symbols.get_reference(reference_id);
if reference.flag().is_empty() {
self.errors.push(format!(
"Expect ReferenceFlags for IdentifierReference({}) to not be empty",
it.name
));
}
} else {
self.errors
.push(format!("Expect IdentifierReference({}) to have a reference_id", it.name));
}
}
fn visit_import_specifier(&mut self, it: &ImportSpecifier<'a>) {
let symbol_id = it.local.symbol_id.get();
if let Some(symbol_id) = symbol_id {
if !self.symbols.get_flag(symbol_id).is_import() {
self.errors.push(format!(
"Expect SymbolFlags for ImportSpecifier({}) should contain SymbolFlags::Import",
it.local.name
));
}
}
walk_import_specifier(self, it);
}
fn visit_export_specifier(&mut self, it: &ExportSpecifier<'a>) {
if let ModuleExportName::IdentifierReference(ident) = &it.local {
let reference_id = ident.reference_id.get();
if let Some(symbol_id) = reference_id
.and_then(|reference_id| self.symbols.get_reference(reference_id).symbol_id())
{
if self.symbols.get_flag(symbol_id).is_empty() {
self.errors.push(format!(
"Expect SymbolFlags for ExportSpecifier({}) should contain SymbolFlags::Import",
it.local
));
}
}
}
}
}
19 changes: 16 additions & 3 deletions tasks/transform_conformance/src/test_case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use oxc_transformer::{BabelOptions, TransformOptions, Transformer};

use crate::{
constants::{PLUGINS_NOT_SUPPORTED_YET, SKIP_TESTS},
fixture_root, packages_root, TestRunnerEnv,
fixture_root, packages_root,
semantic::SemanticTester,
TestRunnerEnv,
};

#[derive(Debug)]
Expand Down Expand Up @@ -252,6 +254,7 @@ impl TestCase for ConformanceTestCase {

let mut transformed_code = String::new();
let mut actual_errors = String::new();
let mut semantic_errors = Vec::default();

let transform_options = match self.transform_options() {
Ok(transform_options) => {
Expand All @@ -267,6 +270,9 @@ impl TestCase for ConformanceTestCase {
transform_options.clone(),
);
let ret = transformer.build(&mut program);

semantic_errors = SemanticTester::new(ret.scopes, ret.symbols).test(&program);

if ret.errors.is_empty() {
transformed_code = CodeGenerator::new().build(&program).source_text;
} else {
Expand Down Expand Up @@ -313,8 +319,10 @@ impl TestCase for ConformanceTestCase {
},
);

let passed =
transformed_code == output || (!output.is_empty() && actual_errors.contains(&output));
let passed = semantic_errors.is_empty()
&& (transformed_code == output
|| (!output.is_empty() && actual_errors.contains(&output)));

if filtered {
println!("Options:");
println!("{transform_options:#?}\n");
Expand All @@ -341,6 +349,11 @@ impl TestCase for ConformanceTestCase {
print_diff_in_terminal(&output, &transformed_code);
}
}

if !semantic_errors.is_empty() {
println!("\nSemantic Errors:\n\n{}\n", semantic_errors.join("\n"));
}

println!("Passed: {passed}");
}
passed
Expand Down

0 comments on commit a6e9cca

Please sign in to comment.