blob: 720c85dd479edd31e61b2fc087c2d66afd0b668a [file] [log] [blame]
// Copyright (c) 2012, 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.
import "../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart";
import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart";
import "../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart";
import "../../../sdk/lib/_internal/compiler/implementation/util/util.dart";
import "mock_compiler.dart";
import "parser_helper.dart";
import "dart:uri";
Compiler applyPatch(String script, String patch) {
String core = "$DEFAULT_CORELIB\n$script";
MockCompiler compiler = new MockCompiler(coreSource: core);
var uri = new Uri("core.dartp");
compiler.sourceFiles[uri.toString()] = new MockFile(patch);
var handler = new LibraryDependencyHandler(compiler);
compiler.patchParser.patchLibrary(handler, uri, compiler.coreLibrary);
handler.computeExports();
return compiler;
}
void expectHasBody(compiler, Element element) {
var node = element.parseNode(compiler);
Expect.isNotNull(node, "Element isn't parseable, when a body was expected");
Expect.isNotNull(node.body);
// If the element has a body it is either a Block or a Return statement,
// both with different begin and end tokens.
Expect.isTrue(node.body is Block || node.body is Return);
Expect.notEquals(node.body.getBeginToken(), node.body.getEndToken());
}
void expectHasNoBody(compiler, Element element) {
var node = element.parseNode(compiler);
Expect.isNotNull(node, "Element isn't parseable, when a body was expected");
Expect.isFalse(node.hasBody());
}
Element ensure(compiler,
String name,
Element lookup(name),
{bool isPatched: false,
bool isPatch: false,
bool isMethod: true,
bool isGetter: false,
bool isFound: true}) {
var element = lookup(buildSourceString(name));
if (!isFound) {
Expect.isNull(element);
return element;
}
Expect.isNotNull(element);
if (isGetter) {
Expect.isTrue(element is AbstractFieldElement);
Expect.isNotNull(element.getter);
element = element.getter;
}
Expect.equals(isPatched, element.isPatched);
if (isPatched) {
Expect.isNull(element.origin);
Expect.isNotNull(element.patch);
Expect.equals(element, element.declaration);
Expect.equals(element.patch, element.implementation);
if (isMethod) {
expectHasNoBody(compiler, element);
expectHasBody(compiler, element.patch);
}
} else {
Expect.isTrue(element.isImplementation);
}
Expect.equals(isPatch, element.isPatch);
if (isPatch) {
Expect.isNotNull(element.origin);
Expect.isNull(element.patch);
Expect.equals(element.origin, element.declaration);
Expect.equals(element, element.implementation);
if (isMethod) {
expectHasBody(compiler, element);
expectHasNoBody(compiler, element.origin);
}
} else {
Expect.isTrue(element.isDeclaration);
}
if (!(element.isPatched || element.isPatch)) {
Expect.isNull(element.origin);
Expect.isNull(element.patch);
Expect.equals(element, element.declaration);
Expect.equals(element, element.implementation);
if (isMethod) {
expectHasBody(compiler, element);
}
}
Expect.isFalse(element.isPatched && element.isPatch);
return element;
}
testPatchFunction() {
var compiler = applyPatch(
"external test();",
"patch test() { return 'string'; } ");
ensure(compiler, "test", compiler.coreLibrary.find, isPatched: true);
ensure(compiler, "test", compiler.coreLibrary.patch.find, isPatch: true);
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isTrue(compiler.errors.isEmpty,
"Unexpected errors: ${compiler.errors}");
}
testPatchMember() {
var compiler = applyPatch(
"""
class Class {
external String toString();
}
""",
"""
patch class Class {
patch String toString() => 'string';
}
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
isMethod: false, isPatched: true);
container.parseNode(compiler);
ensure(compiler, "Class", compiler.coreLibrary.patch.find,
isMethod: false, isPatch: true);
ensure(compiler, "toString", container.lookupLocalMember,
isPatched: true);
ensure(compiler, "toString", container.patch.lookupLocalMember,
isPatch: true);
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isTrue(compiler.errors.isEmpty,
"Unexpected errors: ${compiler.errors}");
}
testPatchGetter() {
var compiler = applyPatch(
"""
class Class {
external int get field;
}
""",
"""
patch class Class {
patch int get field => 5;
}
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
isPatched: true, isMethod: false);
container.parseNode(compiler);
ensure(compiler,
"field",
container.lookupLocalMember,
isGetter: true,
isPatched: true);
ensure(compiler,
"field",
container.patch.lookupLocalMember,
isGetter: true,
isPatch: true);
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isTrue(compiler.errors.isEmpty,
"Unexpected errors: ${compiler.errors}");
}
testRegularMember() {
var compiler = applyPatch(
"""
class Class {
void regular() {}
}
""",
"""
patch class Class {
}
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
isMethod: false, isPatched: true);
container.parseNode(compiler);
ensure(compiler, "Class", compiler.coreLibrary.patch.find,
isMethod: false, isPatch: true);
ensure(compiler, "regular", container.lookupLocalMember);
ensure(compiler, "regular", container.patch.lookupLocalMember);
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isTrue(compiler.errors.isEmpty,
"Unexpected errors: ${compiler.errors}");
}
testGhostMember() {
var compiler = applyPatch(
"""
class Class {
}
""",
"""
patch class Class {
void ghost() {}
}
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
isMethod: false, isPatched: true);
container.parseNode(compiler);
ensure(compiler, "Class", compiler.coreLibrary.patch.find,
isMethod: false, isPatch: true);
ensure(compiler, "ghost", container.lookupLocalMember, isFound: false);
ensure(compiler, "ghost", container.patch.lookupLocalMember);
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isTrue(compiler.errors.isEmpty,
"Unexpected errors: ${compiler.errors}");
}
testInjectFunction() {
var compiler = applyPatch(
"",
"int _function() => 5;");
ensure(compiler,
"_function",
compiler.coreLibrary.find,
isFound: false);
ensure(compiler,
"_function",
compiler.coreLibrary.patch.find);
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isTrue(compiler.errors.isEmpty,
"Unexpected errors: ${compiler.errors}");
}
testPatchSignatureCheck() {
var compiler = applyPatch(
"""
class Class {
external String method1();
external void method2(String str);
external void method3(String s1);
external void method4([String str]);
external void method5({String str});
external void method6({String str});
external void method7([String s1]);
external void method8({String s1});
}
""",
"""
patch class Class {
patch int method1() => 0;
patch void method2() {}
patch void method3(String s2) {}
patch void method4([String str, int i]) {}
patch void method5() {}
patch void method6([String str]) {}
patch void method7([String s2]) {}
patch void method8({String s2}) {}
}
""");
var container = ensure(compiler, "Class", compiler.coreLibrary.find,
isMethod: false, isPatched: true);
container.ensureResolved(compiler);
container.parseNode(compiler);
compiler.resolver.resolveMethodElement(
ensure(compiler, "method1", container.lookupLocalMember,
isPatched: true));
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isFalse(compiler.errors.isEmpty);
print('method1:${compiler.errors}');
compiler.warnings.clear();
compiler.errors.clear();
compiler.resolver.resolveMethodElement(
ensure(compiler, "method2", container.lookupLocalMember,
isPatched: true));
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isFalse(compiler.errors.isEmpty);
print('method2:${compiler.errors}');
compiler.warnings.clear();
compiler.errors.clear();
compiler.resolver.resolveMethodElement(
ensure(compiler, "method3", container.lookupLocalMember,
isPatched: true));
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isFalse(compiler.errors.isEmpty);
print('method3:${compiler.errors}');
compiler.warnings.clear();
compiler.errors.clear();
compiler.resolver.resolveMethodElement(
ensure(compiler, "method4", container.lookupLocalMember,
isPatched: true));
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isFalse(compiler.errors.isEmpty);
print('method4:${compiler.errors}');
compiler.warnings.clear();
compiler.errors.clear();
compiler.resolver.resolveMethodElement(
ensure(compiler, "method5", container.lookupLocalMember,
isPatched: true));
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isFalse(compiler.errors.isEmpty);
print('method5:${compiler.errors}');
compiler.warnings.clear();
compiler.errors.clear();
compiler.resolver.resolveMethodElement(
ensure(compiler, "method6", container.lookupLocalMember,
isPatched: true));
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isFalse(compiler.errors.isEmpty);
print('method6:${compiler.errors}');
compiler.warnings.clear();
compiler.errors.clear();
compiler.resolver.resolveMethodElement(
ensure(compiler, "method7", container.lookupLocalMember,
isPatched: true));
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isFalse(compiler.errors.isEmpty);
print('method7:${compiler.errors}');
compiler.warnings.clear();
compiler.errors.clear();
compiler.resolver.resolveMethodElement(
ensure(compiler, "method8", container.lookupLocalMember,
isPatched: true));
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
Expect.isFalse(compiler.errors.isEmpty);
print('method8:${compiler.errors}');
}
main() {
testPatchFunction();
testPatchMember();
testPatchGetter();
testRegularMember();
testGhostMember();
testInjectFunction();
testPatchSignatureCheck();
}