| // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| // Test that the CPS IR code generator generates source information. |
| |
| library source_information_tests; |
| |
| import 'package:async_helper/async_helper.dart'; |
| import 'package:expect/expect.dart'; |
| import 'package:compiler/src/apiimpl.dart' |
| show Compiler; |
| import 'memory_compiler.dart'; |
| import 'package:compiler/src/cps_ir/cps_ir_nodes.dart' as ir; |
| import 'package:compiler/src/cps_ir/cps_ir_nodes_sexpr.dart' as ir; |
| import 'package:compiler/src/js/js.dart' as js; |
| import 'package:compiler/src/common.dart' show Element, ClassElement; |
| |
| const String TEST_MAIN_FILE = 'test.dart'; |
| |
| class TestEntry { |
| final String source; |
| final List<String> expectation; |
| final String elementName; |
| |
| const TestEntry(this.source, this.expectation) |
| : elementName = null; |
| |
| const TestEntry.forMethod(this.elementName, |
| this.source, this.expectation); |
| } |
| |
| String formatTest(Map test) { |
| return test[TEST_MAIN_FILE]; |
| } |
| |
| js.Node getCodeForMain(Compiler compiler) { |
| Element mainFunction = compiler.mainFunction; |
| return compiler.enqueuer.codegen.generatedCode[mainFunction]; |
| } |
| |
| js.Node getJsNodeForElement(Compiler compiler, Element element) { |
| return compiler.enqueuer.codegen.generatedCode[element]; |
| } |
| |
| String getCodeForMethod(Compiler compiler, String name) { |
| Element foundElement; |
| for (Element element in compiler.enqueuer.codegen.generatedCode.keys) { |
| if (element.toString() == name) { |
| if (foundElement != null) { |
| Expect.fail('Multiple compiled elements are called $name'); |
| } |
| foundElement = element; |
| } |
| } |
| |
| if (foundElement == null) { |
| Expect.fail('There is no compiled element called $name'); |
| } |
| |
| js.Node ast = compiler.enqueuer.codegen.generatedCode[foundElement]; |
| return js.prettyPrint(ast, compiler).getText(); |
| } |
| |
| runTests(List<TestEntry> tests) { |
| for (TestEntry test in tests) { |
| Map files = {TEST_MAIN_FILE: test.source}; |
| asyncTest(() { |
| Compiler compiler = compilerFor(files, options: <String>['--use-cps-ir']); |
| ir.FunctionDefinition irNodeForMain; |
| |
| void cacheIrNodeForMain(Element function, ir.FunctionDefinition irNode) { |
| if (function == compiler.mainFunction) { |
| assert(irNodeForMain == null); |
| irNodeForMain = irNode; |
| } |
| } |
| |
| Uri uri = Uri.parse('memory:$TEST_MAIN_FILE'); |
| compiler.irBuilder.builderCallback = cacheIrNodeForMain; |
| |
| return compiler.run(uri).then((bool success) { |
| Expect.isTrue(success); |
| |
| IrSourceInformationVisitor irVisitor = new IrSourceInformationVisitor(); |
| irNodeForMain.accept(irVisitor); |
| |
| js.Node jsNode = getJsNodeForElement(compiler, compiler.mainFunction); |
| JsSourceInformationVisitor jsVisitor = new JsSourceInformationVisitor(); |
| jsNode.accept(jsVisitor); |
| |
| List<String> expectation = test.expectation; |
| // Visiting of CPS is in structural order so we check for set equality. |
| Expect.setEquals(expectation, irVisitor.sourceInformation, |
| 'Unexpected IR source information. ' |
| 'Expected:\n$expectation\n' |
| 'but found\n${irVisitor.sourceInformation}\n' |
| 'in\n${test.source}' |
| 'CPS:\n${irNodeForMain.accept(new ir.SExpressionStringifier())}'); |
| Expect.listEquals(expectation, jsVisitor.sourceInformation, |
| 'Unexpected JS source information. ' |
| 'Expected:\n$expectation\n' |
| 'but found\n${jsVisitor.sourceInformation}\n' |
| 'in\n${test.source}'); |
| }).catchError((e) { |
| print(e); |
| Expect.fail('The following test failed to compile:\n' |
| '${formatTest(files)}'); |
| }); |
| }); |
| } |
| } |
| |
| class JsSourceInformationVisitor extends js.BaseVisitor { |
| List<String> sourceInformation = <String>[]; |
| |
| @override |
| visitCall(js.Call node) { |
| sourceInformation.add('${node.sourceInformation}'); |
| super.visitCall(node); |
| } |
| } |
| |
| class IrSourceInformationVisitor extends ir.RecursiveVisitor { |
| List<String> sourceInformation = <String>[]; |
| |
| @override |
| processInvokeStatic(ir.InvokeStatic node) { |
| sourceInformation.add('${node.sourceInformation}'); |
| } |
| } |
| |
| const List<TestEntry> tests = const [ |
| const TestEntry(""" |
| main() { print('Hello World'); } |
| """, const ['memory:test.dart:[1,10]']), |
| const TestEntry(""" |
| main() { |
| print('Hello'); |
| print('World'); |
| } |
| """, const ['memory:test.dart:[2,3]', |
| 'memory:test.dart:[3,3]']), |
| ]; |
| |
| void main() { |
| runTests(tests); |
| } |