diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java index 73d3673dfb0..53c40d71fc3 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java +++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java @@ -51,15 +51,28 @@ public enum JsPropertyAccessorType { /** * A getter property accessor. Usually in the form of getX()/isX(). */ - GETTER, + GETTER("get"), /** * A setter property accessor. Usually in the form of setX(x). */ - SETTER, + SETTER("set"), /** * A property accessor but doesn't match setter/getter patterns. */ - UNDEFINED, + UNDEFINED; + + private String key; + + JsPropertyAccessorType() { + } + + JsPropertyAccessorType(String key) { + this.key = key; + } + + public String getKey() { + return key; + } } public static final Comparator BY_SIGNATURE_COMPARATOR = new Comparator() { diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java index 8fff14e650d..480c4c30643 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java @@ -64,6 +64,7 @@ import com.google.gwt.dev.jjs.ast.JLocalRef; import com.google.gwt.dev.jjs.ast.JMember; import com.google.gwt.dev.jjs.ast.JMethod; +import com.google.gwt.dev.jjs.ast.JMethod.JsPropertyAccessorType; import com.google.gwt.dev.jjs.ast.JMethodBody; import com.google.gwt.dev.jjs.ast.JMethodCall; import com.google.gwt.dev.jjs.ast.JNameOf; @@ -142,7 +143,6 @@ import com.google.gwt.dev.js.ast.JsPostfixOperation; import com.google.gwt.dev.js.ast.JsPrefixOperation; import com.google.gwt.dev.js.ast.JsProgram; -import com.google.gwt.dev.js.ast.JsPropertyInitializer; import com.google.gwt.dev.js.ast.JsReturn; import com.google.gwt.dev.js.ast.JsRootScope; import com.google.gwt.dev.js.ast.JsScope; @@ -190,7 +190,6 @@ * Creates a JavaScript AST from a JProgram node. */ public class GenerateJavaScriptAST { - /** * Finds the nodes that are targets of JNameOf so that a name is assigned to them. */ @@ -368,7 +367,7 @@ public boolean visit(JMethod x, Context ctx) { } else if (x.isPackagePrivate()) { polyName = interfaceScope.declareName(mangleNameForPackagePrivatePoly(x), name); } else { - boolean isJsMethod = x.isOrOverridesJsMethod() && !x.isJsPropertyAccessor(); + boolean isJsMethod = x.isOrOverridesJsMethod(); polyName = isJsMethod ? interfaceScope.declareUnobfuscatableName(x.getJsName()) @@ -520,9 +519,20 @@ private void recordSymbol private class GenerateJavaScriptTransformer extends JTransformer { - public static final String GOOG_INHERITS = "goog.inherits"; public static final String GOOG_ABSTRACT_METHOD = "goog.abstractMethod"; + public static final String GOOG_INHERITS = "goog.inherits"; public static final String GOOG_OBJECT_CREATE_SET = "goog.object.createSet"; + public static final String JCHSU = "JavaClassHierarchySetupUtil"; + public static final String JCHSU_COPY_OBJECT_PROPERTIES = JCHSU + ".copyObjectProperties"; + public static final String JCHSU_DEFINE_CLASS = JCHSU + ".defineClass"; + public static final String JCHSU_DEFINE_PROPERTIES = JCHSU + ".defineProperties"; + public static final String JCHSU_EMPTY_METHOD = JCHSU + ".emptyMethod"; + public static final String JCHSU_GET_CLASS_PROTOTYPE = JCHSU + ".getClassPrototype"; + public static final String JCHSU_MAKE_LAMBDA_FUNCTION = JCHSU + ".makeLambdaFunction"; + public static final String JCHSU_MODERNIZE_BROWSER = JCHSU + ".modernizeBrowser"; + public static final String JCHSU_TYPE_MARKER_FN = JCHSU + ".typeMarkerFn"; + public static final String OBJECT_TYPEMARKER = "Object.typeMarker"; + private final Set alreadyRan = Sets.newLinkedHashSet(); private final Map exportedMembersByExportName = new TreeMap(); @@ -946,7 +956,7 @@ private JsExpression getPrototypeQualifierViaLookup(JDeclaredType type, SourceIn // TODO(rluble): Ideally we would want to construct the inheritance chain the JS way and // then we could do Type.prototype.polyname.call(this, ...). Currently prototypes do not // have global names instead they are stuck into the prototypesByTypeId array. - return constructInvocation(sourceInfo, "JavaClassHierarchySetupUtil.getClassPrototype", + return constructInvocation(sourceInfo, JCHSU_GET_CLASS_PROTOTYPE, (JsExpression) transform(getRuntimeTypeReference(type))); } } @@ -958,20 +968,11 @@ private JsExpression dispatchToJsFunction( private JsExpression dispatchToInstanceMethod( JsExpression instance, JMethod method, List args, SourceInfo sourceInfo) { - JsNameRef reference = - method.isJsPropertyAccessor() - ? new JsNameRef(sourceInfo, method.getJsName()) - : polymorphicNames.get(method).makeRef(sourceInfo); - reference.setQualifier(instance); + JsNameRef reference = polymorphicNames.get(method).makeQualifiedRef(sourceInfo, instance); - switch (method.getJsPropertyAccessorType()) { - case SETTER: - return createAssignment(reference, args.get(0)); - case GETTER: - return reference; - default: - return new JsInvocation(sourceInfo, reference, args); - } + JsPropertyAccessorType propertyAccessorType = method.getJsPropertyAccessorType(); + return JsUtils + .createInvocationOrPropertyAccess(sourceInfo, propertyAccessorType, reference, args); } @Override @@ -1012,6 +1013,7 @@ public JsNode transformNewInstance(JNewInstance newInstance) { if (newInstance.getClassType().isJsFunctionImplementation()) { return constructJsFunctionObject(sourceInfo, newInstance.getClassType(), ctorName, newExpr); } + return newExpr; } @@ -1023,8 +1025,7 @@ private JsNode constructJsFunctionObject(SourceInfo sourceInfo, JClassType type, ctorName, prototype, polymorphicNames.get(jsFunctionMethod)); // makeLambdaFunction(Foo.prototype.functionMethodName, new Foo(...)) - return constructInvocation(sourceInfo, "JavaClassHierarchySetupUtil.makeLambdaFunction", - funcNameRef, newExpr); + return constructInvocation(sourceInfo, JCHSU_MAKE_LAMBDA_FUNCTION, funcNameRef, newExpr); } private JMethod getJsFunctionMethod(JClassType type) { @@ -1242,9 +1243,8 @@ private Set generatePreamble(JProgram program) { // Perform necessary polyfills. addTypeDefinitionStatement( - program.getIndexedType("JavaClassHierarchySetupUtil"), - constructInvocation( - program.getSourceInfo(), "JavaClassHierarchySetupUtil.modernizeBrowser").makeStmt()); + program.getIndexedType(JCHSU), + constructInvocation(program.getSourceInfo(), JCHSU_MODERNIZE_BROWSER).makeStmt()); Set alreadyProcessed = Sets.newLinkedHashSet(program.immortalCodeGenTypes); @@ -1601,8 +1601,7 @@ public void endVisit(JsNameRef x, JsContext ctx) { if (jsName == null) { // this can occur when JSNI references an instance method on a // type that was never actually instantiated. - jsName = - indexedFunctions.get("JavaClassHierarchySetupUtil.emptyMethod").getName(); + jsName = indexedFunctions.get(JCHSU_EMPTY_METHOD).getName(); } x.resolve(jsName); } @@ -1658,14 +1657,13 @@ private JsExpression buildJsCastMapLiteral(List runtimeTypeIdLiter return buildClosureStyleCastMapFromArrayLiteral(runtimeTypeIdLiterals, sourceInfo); } - JsObjectLiteral objectLiteral = new JsObjectLiteral(sourceInfo); - objectLiteral.setInternable(); - List initializers = objectLiteral.getPropertyInitializers(); JsNumberLiteral one = new JsNumberLiteral(sourceInfo, 1); + JsObjectLiteral.Builder objectLiteralBuilder = JsObjectLiteral.builder(sourceInfo) + .setInternable(); for (JsExpression runtimeTypeIdLiteral : runtimeTypeIdLiterals) { - initializers.add(new JsPropertyInitializer(sourceInfo, runtimeTypeIdLiteral, one)); + objectLiteralBuilder.add(runtimeTypeIdLiteral, one); } - return objectLiteral; + return objectLiteralBuilder.build(); } private JsExpression buildClosureStyleCastMapFromArrayLiteral( @@ -2005,13 +2003,13 @@ private void generateCallToDefineClass(JClassType type, List construc // JavaClassHierarchySetupUtil.defineClass(typeId, superTypeId, castableMap, constructors) JsStatement defineClassStatement = constructInvocation(type.getSourceInfo(), - "JavaClassHierarchySetupUtil.defineClass", defineClassArguments).makeStmt(); + JCHSU_DEFINE_CLASS, defineClassArguments).makeStmt(); addTypeDefinitionStatement(type, defineClassStatement); if (jsPrototype != null) { JsStatement statement = constructInvocation(type.getSourceInfo(), - "JavaClassHierarchySetupUtil.copyObjectProperties", + JCHSU_COPY_OBJECT_PROPERTIES, getPrototypeQualifierViaLookup(program.getTypeJavaLangObject(), type.getSourceInfo()), globalTemp.makeRef(type.getSourceInfo())) .makeStmt(); @@ -2144,7 +2142,7 @@ private void generateInlinedDefineClass(JDeclaredType type, JsName classVar) { if (jsPrototype != null) { JsStatement statement = constructInvocation(info, - "JavaClassHierarchySetupUtil.copyObjectProperties", + JCHSU_COPY_OBJECT_PROPERTIES, getPrototypeQualifierOf(program.getTypeJavaLangObject(), info), getPrototypeQualifierOf(type, info)).makeStmt(); addTypeDefinitionStatement(type, statement); @@ -2157,9 +2155,8 @@ private void setupCastMapOnPrototype(JDeclaredType type) { } private void setupTypeMarkerOnJavaLangObjectPrototype(JDeclaredType type) { - JsFunction typeMarkerMethod = indexedFunctions.get( - "JavaClassHierarchySetupUtil.typeMarkerFn"); - generatePrototypeAssignmentForJavaField(type, "Object.typeMarker", + JsFunction typeMarkerMethod = indexedFunctions.get(JCHSU_TYPE_MARKER_FN); + generatePrototypeAssignmentForJavaField(type, OBJECT_TYPEMARKER, typeMarkerMethod.getName().makeRef(type.getSourceInfo())); } @@ -2231,14 +2228,52 @@ private void maybeGenerateToStringAlias(JDeclaredType type) { } } - /** - * Create a vtable assignment of the form _.polyname = rhs; and register the line as - * created for {@code method}. - */ - private void generatePrototypeAssignment(JMethod method, JsName name, JsExpression rhs) { + private void generatePrototypeAssignment(JMethod method, JsName name, JsExpression rhs) { + generatePrototypeAssignment(method, name, rhs, method.getJsPropertyAccessorType()); + } + + /** + * Create a vtable assignment of the form _.polyname = rhs; and register the line as + * created for {@code method}. + */ + private void generatePrototypeAssignment(JMethod method, JsName name, JsExpression rhs, + JsPropertyAccessorType accessorType) { SourceInfo sourceInfo = method.getSourceInfo(); - JsNameRef lhs = name.makeQualifiedRef(sourceInfo, getPrototypeQualifierOf(method)); - emitMethodImplementation(method, lhs, createAssignment(lhs, rhs).makeStmt()); + JsNameRef prototypeQualifierOf = getPrototypeQualifierOf(method); + JsNameRef lhs = name.makeQualifiedRef(sourceInfo, prototypeQualifierOf); + switch (accessorType) { + case GETTER: + case SETTER: + emitPropertyImplementation(method, prototypeQualifierOf, name.makeRef(sourceInfo), rhs); + break; + default: + emitMethodImplementation(method, lhs, createAssignment(lhs, rhs).makeStmt()); + break; + } + } + + private void emitPropertyImplementation(JMethod method, JsNameRef prototype, JsNameRef name, + JsExpression methodDefinitionStatement) { + SourceInfo sourceInfo = method.getSourceInfo(); + + // We use Object.defineProperties instead of Object.defineProperty to make sure the + // property name appears as an identifier and not as a string. + // Some JS optimizers, e.g. the closure compiler, relies on this subtle difference for + // obfuscating property names. + JsNameRef definePropertyMethod = + indexedFunctions.get(JCHSU_DEFINE_PROPERTIES).getName().makeRef(sourceInfo); + + JsObjectLiteral definePropertyLiteral = + JsObjectLiteral.builder(sourceInfo) + // {name: {get: function() { ..... }} or {set : function (v) {....}}} + .add(name, JsObjectLiteral.builder(sourceInfo) + // {get: function() { ..... }} or {set : function (v) {....}} + .add(method.getJsPropertyAccessorType().getKey(), methodDefinitionStatement) + .build()) + .build(); + + addMethodDefinitionStatement(method, new JsInvocation(sourceInfo, definePropertyMethod, + prototype, definePropertyLiteral).makeStmt()); } private void emitMethodImplementation(JMethod method, JsNameRef functionNameRef, @@ -2255,14 +2290,15 @@ private void generatePrototypeDefinitionAlias(JMethod method, JsName alias) { JsName polyName = polymorphicNames.get(method); JsExpression bridge = JsUtils.createBridge(method, polyName, topScope); // Aliases are never property accessors. - generatePrototypeAssignment(method, alias, bridge); + generatePrototypeAssignment(method, alias, bridge, JsPropertyAccessorType.NONE); } private JsExprStmt outputDisplayName(JsNameRef function, JMethod method) { JsNameRef displayName = new JsNameRef(function.getSourceInfo(), "displayName"); displayName.setQualifier(function); String displayStringName = getDisplayName(method); - JsStringLiteral displayMethodName = new JsStringLiteral(function.getSourceInfo(), displayStringName); + JsStringLiteral displayMethodName = + new JsStringLiteral(function.getSourceInfo(), displayStringName); return createAssignment(displayName, displayMethodName).makeStmt(); } @@ -2407,7 +2443,7 @@ private void handleClinit(JDeclaredType type, JsFunction clinitFunction) { // provides a better debug experience that does not step into already used clinits. JsFunction emptyFunctionFn = incremental ? objectConstructorFunction - : indexedFunctions.get("JavaClassHierarchySetupUtil.emptyMethod"); + : indexedFunctions.get(JCHSU_EMPTY_METHOD); JsExpression assignment = createAssignment(clinitFunction.getName().makeRef(sourceInfo), emptyFunctionFn.getName().makeRef(sourceInfo)); statements.add(0, assignment.makeStmt()); diff --git a/dev/core/src/com/google/gwt/dev/js/CoverageInstrumentor.java b/dev/core/src/com/google/gwt/dev/js/CoverageInstrumentor.java index f9371025187..f5e8aaaedda 100644 --- a/dev/core/src/com/google/gwt/dev/js/CoverageInstrumentor.java +++ b/dev/core/src/com/google/gwt/dev/js/CoverageInstrumentor.java @@ -74,9 +74,9 @@ public static void exec(JsProgram jsProgram, Multimap instrumen @VisibleForTesting static JsObjectLiteral baselineCoverage(SourceInfo info, Multimap instrumentableLines) { - JsObjectLiteral.Builder baselineBuilder = JsObjectLiteral.builder().setSourceInfo(info); + JsObjectLiteral.Builder baselineBuilder = JsObjectLiteral.builder(info); for (String filename : instrumentableLines.keySet()) { - JsObjectLiteral.Builder linesBuilder = JsObjectLiteral.builder().setSourceInfo(info); + JsObjectLiteral.Builder linesBuilder = JsObjectLiteral.builder(info); for (int line : instrumentableLines.get(filename)) { linesBuilder.add(new JsNumberLiteral(info, line), new JsNumberLiteral(info, 0)); } diff --git a/dev/core/src/com/google/gwt/dev/js/JsParser.java b/dev/core/src/com/google/gwt/dev/js/JsParser.java index 370aff78101..6e0773c449b 100644 --- a/dev/core/src/com/google/gwt/dev/js/JsParser.java +++ b/dev/core/src/com/google/gwt/dev/js/JsParser.java @@ -844,8 +844,8 @@ private JsExpression mapNumber(Node numberNode) { } private JsExpression mapObjectLit(Node objLitNode) throws JsParserException { - JsObjectLiteral.Builder objectLiteralBuilder = JsObjectLiteral.builder() - .setSourceInfo(makeSourceInfo(objLitNode)); + JsObjectLiteral.Builder objectLiteralBuilder = + JsObjectLiteral.builder(makeSourceInfo(objLitNode)); Node fromPropInit = objLitNode.getFirstChild(); while (fromPropInit != null) { diff --git a/dev/core/src/com/google/gwt/dev/js/JsUtils.java b/dev/core/src/com/google/gwt/dev/js/JsUtils.java index 38877521d78..9bceaae9f50 100644 --- a/dev/core/src/com/google/gwt/dev/js/JsUtils.java +++ b/dev/core/src/com/google/gwt/dev/js/JsUtils.java @@ -17,6 +17,7 @@ import com.google.gwt.dev.jjs.SourceInfo; import com.google.gwt.dev.jjs.ast.JMethod; +import com.google.gwt.dev.jjs.ast.JMethod.JsPropertyAccessorType; import com.google.gwt.dev.jjs.ast.JParameter; import com.google.gwt.dev.jjs.ast.JPrimitiveType; import com.google.gwt.dev.js.ast.JsBinaryOperation; @@ -35,6 +36,9 @@ import com.google.gwt.dev.js.ast.JsStatement; import com.google.gwt.dev.js.ast.JsThisRef; import com.google.gwt.dev.util.StringInterner; +import com.google.gwt.thirdparty.guava.common.collect.Lists; + +import java.util.List; /** * Utils for JS AST. @@ -94,11 +98,14 @@ public static JsFunction createBridge(JMethod method, JsName polyName, JsScope s } JsNameRef ref = polyName.makeRef(sourceInfo); ref.setQualifier(new JsThisRef(sourceInfo)); - JsInvocation invocation = new JsInvocation(sourceInfo, ref); + List args = Lists.newArrayList(); for (JsParameter p : bridge.getParameters()) { - invocation.getArguments().add(p.getName().makeRef(sourceInfo)); + args.add(p.getName().makeRef(sourceInfo)); } + JsExpression invocation = + createInvocationOrPropertyAccess(sourceInfo, method.getJsPropertyAccessorType(), ref, args); + JsBlock block = new JsBlock(sourceInfo); if (method.getType() == JPrimitiveType.VOID) { block.getStatements().add(invocation.makeStmt()); @@ -150,6 +157,20 @@ public static JsNameRef createQualifiedNameRef(SourceInfo info, JsName... names return result; } + public static JsExpression createInvocationOrPropertyAccess(SourceInfo sourceInfo, + JsPropertyAccessorType propertyAccessorType, JsNameRef reference, List args) { + switch (propertyAccessorType) { + case SETTER: + assert args.size() == 1; + return createAssignment(reference, args.get(0)); + case GETTER: + assert args.size() == 0; + return reference; + default: + return new JsInvocation(sourceInfo, reference, args); + } + } + /** * Given a string qualifier such as 'foo.bar.Baz', returns a chain of JsNameRef's representing * this qualifier. diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsObjectLiteral.java b/dev/core/src/com/google/gwt/dev/js/ast/JsObjectLiteral.java index 3d9a71b2b30..77af6cb9908 100644 --- a/dev/core/src/com/google/gwt/dev/js/ast/JsObjectLiteral.java +++ b/dev/core/src/com/google/gwt/dev/js/ast/JsObjectLiteral.java @@ -14,7 +14,6 @@ package com.google.gwt.dev.js.ast; import com.google.gwt.dev.jjs.SourceInfo; -import com.google.gwt.dev.jjs.SourceOrigin; import com.google.gwt.thirdparty.guava.common.collect.Lists; import java.util.List; @@ -24,8 +23,8 @@ */ public final class JsObjectLiteral extends JsLiteral { - public static Builder builder() { - return new Builder(); + public static Builder builder(SourceInfo info) { + return new Builder(info); } /** @@ -33,10 +32,12 @@ public static Builder builder() { */ public static class Builder { - private Builder() { } + private Builder(SourceInfo info) { + this.sourceInfo = info; + } private List propertyInitializers = Lists.newArrayList(); - private SourceInfo sourceInfo = SourceOrigin.UNKNOWN; + private final SourceInfo sourceInfo; private boolean internable = false; public Builder add(String property, JsExpression value) { @@ -54,11 +55,6 @@ public Builder add(SourceInfo sourceInfo, JsExpression property, JsExpression va return this; } - public Builder setSourceInfo(SourceInfo info) { - sourceInfo = info; - return this; - } - public Builder setInternable() { internable = true; return this; diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java index 687225f567d..121c98cceee 100644 --- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java +++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/JavaClassHierarchySetupUtil.java @@ -207,4 +207,12 @@ static native void emptyMethod() /*-{ static native JavaScriptObject uniqueId(String id) /*-{ return jsinterop.closure.getUniqueId(id); }-*/; + + static native void defineProperties( + JavaScriptObject proto, JavaScriptObject propertyDefinition) /*-{ + for (var key in propertyDefinition) { + propertyDefinition[key]['configurable'] = true; + } + Object.defineProperties(proto, propertyDefinition); + }-*/; } diff --git a/user/test/com/google/gwt/core/CoreJsInteropSuite.java b/user/test/com/google/gwt/core/CoreJsInteropSuite.java index 69a399f9518..82ccbd82673 100644 --- a/user/test/com/google/gwt/core/CoreJsInteropSuite.java +++ b/user/test/com/google/gwt/core/CoreJsInteropSuite.java @@ -17,6 +17,7 @@ import com.google.gwt.core.client.interop.JsExportTest; import com.google.gwt.core.client.interop.JsFunctionTest; +import com.google.gwt.core.client.interop.JsPropertyTest; import com.google.gwt.core.client.interop.JsTypeArrayTest; import com.google.gwt.core.client.interop.JsTypeTest; @@ -31,6 +32,7 @@ public static Test suite() { TestSuite suite = new TestSuite("All core js interop tests"); suite.addTestSuite(JsTypeTest.class); + suite.addTestSuite(JsPropertyTest.class); suite.addTestSuite(JsTypeArrayTest.class); suite.addTestSuite(JsExportTest.class); suite.addTestSuite(JsFunctionTest.class); diff --git a/user/test/com/google/gwt/core/client/interop/JsPropertyTest.java b/user/test/com/google/gwt/core/client/interop/JsPropertyTest.java new file mode 100644 index 00000000000..73c6a64376d --- /dev/null +++ b/user/test/com/google/gwt/core/client/interop/JsPropertyTest.java @@ -0,0 +1,419 @@ +/* + * Copyright 2015 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.core.client.interop; + +import static com.google.gwt.core.client.ScriptInjector.TOP_WINDOW; + +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.core.client.ScriptInjector; +import com.google.gwt.core.client.js.JsProperty; +import com.google.gwt.core.client.js.JsType; +import com.google.gwt.junit.client.GWTTestCase; + +/** + * Tests JsProperty functionality. + */ +public class JsPropertyTest extends GWTTestCase { + + private static final int SET_PARENT_X = 500; + private static final int GET_PARENT_X = 1000; + private static final int GET_X = 100; + private static final int SET_X = 50; + + @Override + public String getModuleName() { + return "com.google.gwt.core.Core"; + } + + @Override + protected void gwtSetUp() throws Exception { + ScriptInjector.fromString("function JsPropertyTest_MyNativeJsType() {}\n" + + "JsPropertyTest_MyNativeJsType.staticX = 33;" + + "JsPropertyTest_MyNativeJsType.answerToLife = function() { return 42;};" + + "JsPropertyTest_MyNativeJsType.prototype.sum = " + + " function sum(bias) { return this.x + bias; };" + + "function JsPropertyTest_MyNativeJsTypeInterface() {}\n" + + "JsPropertyTest_MyNativeJsTypeInterface.prototype.sum = " + + " function sum(bias) { return this.x + bias; };") + .setWindow(TOP_WINDOW).inject(); + } + + @JsType + interface MyJsTypeInterfaceWithProperty { + @JsProperty + int getX(); + + @JsProperty + void setX(int x); + } + + static class MyJavaTypeImplementingMyJsTypeInterfaceWithProperty + implements MyJsTypeInterfaceWithProperty { + private int x; + + public int getX() { + return x + GET_X; + } + + public void setX(int x) { + this.x = x + SET_X; + } + } + + public void testJavaClassImplementingMyJsTypeInterfaceWithProperty() { + MyJavaTypeImplementingMyJsTypeInterfaceWithProperty obj = + new MyJavaTypeImplementingMyJsTypeInterfaceWithProperty(); + assertEquals(0 + GET_X, getProperty(obj, "x")); + assertEquals(0 + GET_X, obj.getX()); + assertEquals(0, obj.x); + + setProperty(obj, "x", 10); + assertEquals(10 + GET_X + SET_X, getProperty(obj, "x")); + assertEquals(10 + GET_X + SET_X, obj.getX()); + assertEquals(10 + SET_X, obj.x); + + obj.setX(12); + assertEquals(12 + GET_X + SET_X, getProperty(obj, "x")); + assertEquals(12 + GET_X + SET_X, obj.getX()); + assertEquals(12 + SET_X, obj.x); + + MyJsTypeInterfaceWithProperty intf = new MyJavaTypeImplementingMyJsTypeInterfaceWithProperty(); + assertEquals(0 + GET_X, getProperty(intf, "x")); + assertEquals(0 + GET_X, intf.getX()); + assertEquals(0, ((MyJavaTypeImplementingMyJsTypeInterfaceWithProperty) intf).x); + + setProperty(intf, "x", 10); + assertEquals(10 + GET_X + SET_X, getProperty(intf, "x")); + assertEquals(10 + GET_X + SET_X, intf.getX()); + assertEquals(10 + SET_X, ((MyJavaTypeImplementingMyJsTypeInterfaceWithProperty) intf).x); + + intf.setX(12); + assertEquals(12 + GET_X + SET_X, getProperty(intf, "x")); + assertEquals(12 + GET_X + SET_X, intf.getX()); + assertEquals(12 + SET_X, ((MyJavaTypeImplementingMyJsTypeInterfaceWithProperty) intf).x); + } + + @JsType + static class MyConcreteJsType { + private int x; + + @JsProperty + public int getY() { + return x + GET_X; + } + + @JsProperty + public void setY(int x) { + this.x = x + SET_X; + } + } + + public void testConcreteJsType() { + MyConcreteJsType obj = new MyConcreteJsType(); + assertEquals(0 + GET_X, getProperty(obj, "y")); + assertEquals(0 + GET_X,obj.getY()); + assertEquals(0, obj.x); + + setProperty(obj, "y", 10); + assertEquals(10 + GET_X + SET_X, getProperty(obj, "y")); + assertEquals(10 + GET_X + SET_X, obj.getY()); + assertEquals(10 + SET_X, obj.x); + + obj.setY(12); + assertEquals(12 + GET_X + SET_X, getProperty(obj, "y")); + assertEquals(12 + GET_X + SET_X, obj.getY()); + assertEquals(12 + SET_X, obj.x); + } + + @JsType(prototype = "JsPropertyTest_MyNativeJsType") + static class MyNativeJsType { + + public static int staticX; + + public static native int answerToLife(); + + public int x; + + @JsProperty + public native int getY(); + + @JsProperty + public native void setY(int x); + + public native int sum(int bias); + } + + public void testNativeJsType() { + assertEquals(33, MyNativeJsType.staticX); + MyNativeJsType.staticX = 34; + assertEquals(34, MyNativeJsType.staticX); + assertEquals(42, MyNativeJsType.answerToLife()); + + MyNativeJsType obj = new MyNativeJsType(); + assertTrue(isUndefined(obj.x)); + obj.x = 72; + assertEquals(72, obj.x); + assertEquals(74, obj.sum(2)); + + assertTrue(isUndefined(obj.getY())); + obj.setY(91); + assertEquals(91, obj.getY()); + } + + static class MyNativeJsTypeSubclass extends MyNativeJsType { + + MyNativeJsTypeSubclass() { + this.x = 42; + setY(52); + } + + @Override + public int sum(int bias) { + return super.sum(bias) + GET_X; + } + } + + public void testNativeJsTypeSubclass() { + MyNativeJsTypeSubclass mc = new MyNativeJsTypeSubclass(); + assertEquals(143, mc.sum(1)); + + mc.x = -mc.x; + assertEquals(58, mc.sum(0)); + + assertEquals(52, mc.getY()); + } + + @JsType(prototype = "JsPropertyTest_MyNativeJsTypeInterface") + interface MyNativeJsTypeInterface { + @JsProperty + int getX(); + + @JsProperty + void setX(int x); + } + + static class MyNativeNativeJsTypeTypeInterfaceSubclassNeedingBridge + extends AccidentaImplementer implements MyNativeJsTypeInterface { + } + + static abstract class AccidentaImplementer { + private int x; + + public int getX() { + return x + GET_X; + } + + public void setX(int x) { + this.x = x + SET_X; + } + + public int sum(int bias) { + return bias + x; + } + } + + public void testJsPropertyBridges() { + MyNativeJsTypeInterface object = new MyNativeNativeJsTypeTypeInterfaceSubclassNeedingBridge(); + + object.setX(3); + assertEquals(3 + 150, object.getX()); + assertEquals(3 + SET_X, ((AccidentaImplementer) object).x); + + AccidentaImplementer accidentaImplementer = (AccidentaImplementer) object; + + accidentaImplementer.setX(3); + assertEquals(3 + 150, accidentaImplementer.getX()); + assertEquals(3 + 150, getProperty(object, "x")); + assertEquals(3 + SET_X, accidentaImplementer.x); + + setProperty(object, "x", 4); + assertEquals(4 + 150, accidentaImplementer.getX()); + assertEquals(4 + 150, getProperty(object, "x")); + assertEquals(4 + SET_X, accidentaImplementer.x); + + assertEquals(3 + 4 + SET_X, accidentaImplementer.sum(3)); + } + + static class MyNativeJsTypeInterfaceImplNeedingBridgeSubclassed + extends OtherAccidentalImplementer implements MyNativeJsTypeInterface { + } + + static abstract class OtherAccidentalImplementer { + private int x; + + public int getX() { + return x + GET_PARENT_X; + } + + public void setX(int x) { + this.x = x + SET_PARENT_X; + } + + public int sum(int bias) { + return bias + x; + } + } + + static class MyNativeJsTypeInterfaceImplNeedingBridgeSubclass + extends MyNativeJsTypeInterfaceImplNeedingBridgeSubclassed { + private int y; + + public int getX() { + return y + GET_X; + } + + public void setX(int y) { + this.y = y + SET_X; + } + + public void setParentX(int value) { + super.setX(value); + } + + public int getXPlusY() { + return super.getX() + y; + } + } + + public void testJsPropertyBridgesSubclass() { + MyNativeJsTypeInterface object = new MyNativeJsTypeInterfaceImplNeedingBridgeSubclass(); + + object.setX(3); + assertEquals(3 + 150, object.getX()); + + OtherAccidentalImplementer simple = (OtherAccidentalImplementer) object; + + simple.setX(3); + assertEquals(3 + GET_X + SET_X, simple.getX()); + assertEquals(3 + GET_X + SET_X, getProperty(object, "x")); + assertEquals(3 + SET_X, ((MyNativeJsTypeInterfaceImplNeedingBridgeSubclass) object).y); + assertEquals(0, ((OtherAccidentalImplementer) object).x); + + setProperty(object, "x", 4); + assertEquals(4 + GET_X + SET_X, simple.getX()); + assertEquals(4 + GET_X + SET_X, getProperty(object, "x")); + assertEquals(4 + SET_X, ((MyNativeJsTypeInterfaceImplNeedingBridgeSubclass) object).y); + assertEquals(0, ((OtherAccidentalImplementer) object).x); + + MyNativeJsTypeInterfaceImplNeedingBridgeSubclass subclass = + (MyNativeJsTypeInterfaceImplNeedingBridgeSubclass) object; + + subclass.setParentX(5); + assertEquals(8 + SET_PARENT_X, simple.sum(3)); + assertEquals(9 + SET_PARENT_X + GET_PARENT_X + SET_X, subclass.getXPlusY()); + assertEquals(4 + SET_X, ((MyNativeJsTypeInterfaceImplNeedingBridgeSubclass) object).y); + assertEquals(5 + SET_PARENT_X, ((OtherAccidentalImplementer) object).x); + } + + @JsType + interface MyJsTypeInterfaceWithProtectedNames { + String var(); + + @JsProperty + String getNullField(); // Defined in object scope but shouldn't obfuscate + + @JsProperty + String getImport(); + + @JsProperty + void setImport(String str); + } + + public void testProtectedNames() { + MyJsTypeInterfaceWithProtectedNames obj = createMyJsInterfaceWithProtectedNames(); + assertEquals("var", obj.var()); + assertEquals("nullField", obj.getNullField()); + assertEquals("import", obj.getImport()); + obj.setImport("import2"); + assertEquals("import2", obj.getImport()); + } + + @JsType + interface JsTypeIsProperty { + + @JsProperty + boolean isX(); + + @JsProperty + void setX(boolean x); + } + + public void testJsPropertyIsX() { + JsTypeIsProperty object = (JsTypeIsProperty) JavaScriptObject.createObject(); + + assertFalse(object.isX()); + object.setX(true); + assertTrue(object.isX()); + object.setX(false); + assertFalse(object.isX()); + } + + @JsType + interface JsTypeGetProperty { + + @JsProperty + int getX(); + + @JsProperty + void setX(int x); + } + + public void testJsPropertyGetX() { + JsTypeGetProperty object = (JsTypeGetProperty) JavaScriptObject.createObject(); + + assertTrue(isUndefined(object.getX())); + object.setX(10); + assertEquals(10, object.getX()); + object.setX(0); + assertEquals(0, object.getX()); + } + + private static native MyJsTypeInterfaceWithProtectedNames createMyJsInterfaceWithProtectedNames() /*-{ + var a = {}; + a["nullField"] = "nullField"; + a["import"] = "import"; + a["var"] = function() { return "var"; }; + return a; + }-*/; + + private static native boolean isUndefined(int value) /*-{ + return value === undefined; + }-*/; + + private static native boolean hasField(Object object, String fieldName) /*-{ + return object[fieldName] != undefined; + }-*/; + + private static native int getProperty(Object object, String name) /*-{ + return object[name]; + }-*/; + + private static native void setProperty(Object object, String name, int value) /*-{ + object[name] = value; + }-*/; + + public static void assertJsTypeHasFields(Object obj, String... fields) { + for (String field : fields) { + assertTrue("Field '" + field + "' should be exported", hasField(obj, field)); + } + } + + public static void assertJsTypeDoesntHaveFields(Object obj, String... fields) { + for (String field : fields) { + assertFalse("Field '" + field + "' should not be exported", hasField(obj, field)); + } + } +} diff --git a/user/test/com/google/gwt/core/client/interop/JsTypeGetProperty.java b/user/test/com/google/gwt/core/client/interop/JsTypeGetProperty.java deleted file mode 100644 index 3b51172c355..00000000000 --- a/user/test/com/google/gwt/core/client/interop/JsTypeGetProperty.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.core.client.interop; - -import com.google.gwt.core.client.js.JsProperty; -import com.google.gwt.core.client.js.JsType; - -/** - * An interface to test 'get' JsProperty getters. - */ -@JsType -public interface JsTypeGetProperty { - - @JsProperty - int getX(); - - @JsProperty - void setX(int x); -} diff --git a/user/test/com/google/gwt/core/client/interop/JsTypeIsProperty.java b/user/test/com/google/gwt/core/client/interop/JsTypeIsProperty.java deleted file mode 100644 index 403220ea682..00000000000 --- a/user/test/com/google/gwt/core/client/interop/JsTypeIsProperty.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.core.client.interop; - -import com.google.gwt.core.client.js.JsProperty; -import com.google.gwt.core.client.js.JsType; - -/** - * An interface to test 'is' JsProperty getters. - */ -@JsType -public interface JsTypeIsProperty { - - @JsProperty - boolean isX(); - - @JsProperty - void setX(boolean x); -} diff --git a/user/test/com/google/gwt/core/client/interop/JsTypeTest.java b/user/test/com/google/gwt/core/client/interop/JsTypeTest.java index 02c71abf27c..14d9ae90d74 100644 --- a/user/test/com/google/gwt/core/client/interop/JsTypeTest.java +++ b/user/test/com/google/gwt/core/client/interop/JsTypeTest.java @@ -20,6 +20,7 @@ import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.ScriptInjector; import com.google.gwt.core.client.js.JsFunction; +import com.google.gwt.core.client.js.JsProperty; import com.google.gwt.core.client.js.JsType; import com.google.gwt.junit.client.GWTTestCase; @@ -28,7 +29,6 @@ /** * Tests JsType functionality. */ -// TODO(cromwellian): Add test cases for property overriding of @JsProperty methods in java object public class JsTypeTest extends GWTTestCase { @Override @@ -38,21 +38,13 @@ public String getModuleName() { @Override protected void gwtSetUp() throws Exception { - ScriptInjector.fromString("function MyJsInterface() {}\n" - + "MyJsInterface.staticX = 33;" - + "MyJsInterface.answerToLife = function() { return 42;};" - + "MyJsInterface.prototype.sum = function sum(bias) { return this.x + bias; };") + ScriptInjector.fromString("function JsTypeTest_MyNativeJsTypeInterface() {}\n" + + "function JsTypeTest_MyNativeJsType() {}\n" + + "JsTypeTest_MyNativeJsType.prototype.sum = " + + " function sum(bias) { return this.y + bias; };") .setWindow(TOP_WINDOW).inject(); - patchPrototype(MyClassExtendsJsPrototype.class); } - /** - * Workaround for the fact that the script is injected after defineClass() has been called. - */ - private native void patchPrototype(Class myClass) /*-{ - @java.lang.Class::getPrototypeForClass(Ljava/lang/Class;)(myClass).prototype = $wnd.MyClass; - }-*/; - public void testVirtualUpRefs() { ListImpl listWithExport = new ListImpl(); // Exports .add(). FooImpl listNoExport = new FooImpl(); // Does not export .add(). @@ -149,78 +141,21 @@ public int publicMethodAlsoExposedAsNonJsMethod() { assertEquals(100, subclassInterface.publicMethodAlsoExposedAsNonJsMethod()); } - public void testConcreteNativeType() { - assertEquals(33, MyJsClassWithPrototype.staticX); - MyJsClassWithPrototype.staticX = 34; - assertEquals(34, MyJsClassWithPrototype.staticX); - assertEquals(42, MyJsClassWithPrototype.answerToLife()); - - MyJsClassWithPrototype obj = new MyJsClassWithPrototype(); - assertTrue(isUndefined(obj.x)); - obj.x = 72; - assertEquals(72, obj.x); - assertEquals(74, obj.sum(2)); - - assertTrue(isUndefined(obj.getY())); - obj.setY(91); - assertEquals(91, obj.getY()); + @JsType(prototype = "JsTypeTest_MyNativeJsTypeInterface") + interface MyNativeJsTypeInterface { } - public void testConcreteNativeType_sublasss() { - MyClassExtendsJsPrototype mc = new MyClassExtendsJsPrototype(); - assertEquals(143, mc.sum(1)); - - mc.x = -mc.x; - assertEquals(58, mc.sum(0)); - - assertEquals(52, mc.getY()); + class MyNativeJsTypeInterfaceImpl implements MyNativeJsTypeInterface { } - public void testJsPropertyIsX() { - JsTypeIsProperty object = (JsTypeIsProperty) JavaScriptObject.createObject(); - - assertFalse(object.isX()); - object.setX(true); - assertTrue(object.isX()); - object.setX(false); - assertFalse(object.isX()); - } - - public void testJsPropertyGetX() { - JsTypeGetProperty object = (JsTypeGetProperty) JavaScriptObject.createObject(); - - assertTrue(isUndefined(object.getX())); - object.setX(10); - assertEquals(10, object.getX()); - object.setX(0); - assertEquals(0, object.getX()); - } - - public void testProtectedNames() { - MyJsInterfaceWithProtectedNames obj = createMyJsInterfaceWithProtectedNames(); - assertEquals("var", obj.var()); - assertEquals("nullField", obj.getNullField()); - assertEquals("import", obj.getImport()); - obj.setImport("import2"); - assertEquals("import2", obj.getImport()); - } - - private static native MyJsInterfaceWithProtectedNames createMyJsInterfaceWithProtectedNames() /*-{ - var a = {}; - a["nullField"] = "nullField"; - a["import"] = "import"; - a["var"] = function() { return "var"; }; - return a; - }-*/; - public void testCasts() { Object myClass; - assertNotNull(myClass = (ElementLikeJsInterface) createMyJsInterface()); - assertNotNull(myClass = (MyJsInterfaceWithPrototype) createMyJsInterface()); + assertNotNull(myClass = (ElementLikeJsInterface) createMyNativeJsTypeInterface()); + assertNotNull(myClass = (MyNativeJsTypeInterface) createMyNativeJsTypeInterface()); assertNotNull(myClass = (HTMLElement) createNativeButton()); try { - assertNotNull(myClass = (HTMLElement) createMyJsInterface()); + assertNotNull(myClass = (HTMLElement) createMyNativeJsTypeInterface()); fail(); } catch (ClassCastException cce) { // Expected. @@ -239,16 +174,23 @@ public void testCasts() { assertNotNull(nativeButton2); } + /** + * A test class marked with JsType but isn't referenced from any Java code except instanceof. + */ + @JsType(prototype = "JsTypeTest_MyNativeJsTypeInterface") + public interface MyJsInterfaceWithPrototypeAndOnlyInstanceofReference { + } + public void testInstanceOf_jsoWithProto() { - Object object = createMyJsInterface(); + Object object = createMyNativeJsTypeInterface(); assertTrue(object instanceof Object); assertFalse(object instanceof HTMLAnotherElement); assertFalse(object instanceof HTMLButtonElement); assertFalse(object instanceof HTMLElement); assertFalse(object instanceof Iterator); - assertTrue(object instanceof MyJsInterfaceWithPrototype); - assertFalse(object instanceof MyJsInterfaceWithPrototypeImpl); + assertTrue(object instanceof MyNativeJsTypeInterface); + assertFalse(object instanceof MyNativeJsTypeInterfaceImpl); assertTrue(object instanceof ElementLikeJsInterface); assertFalse(object instanceof ElementLikeJsInterfaceImpl); assertTrue(object instanceof MyJsInterfaceWithOnlyInstanceofReference); @@ -265,8 +207,8 @@ public void testInstanceOf_jsoWithoutProto() { assertFalse(object instanceof HTMLButtonElement); assertFalse(object instanceof HTMLElement); assertFalse(object instanceof Iterator); - assertFalse(object instanceof MyJsInterfaceWithPrototype); - assertFalse(object instanceof MyJsInterfaceWithPrototypeImpl); + assertFalse(object instanceof MyNativeJsTypeInterface); + assertFalse(object instanceof MyNativeJsTypeInterfaceImpl); assertTrue(object instanceof ElementLikeJsInterface); assertFalse(object instanceof ElementLikeJsInterfaceImpl); assertTrue(object instanceof MyJsInterfaceWithOnlyInstanceofReference); @@ -283,8 +225,8 @@ public void testInstanceOf_jsoWithNativeButtonProto() { assertTrue(object instanceof HTMLButtonElement); assertTrue(object instanceof HTMLElement); assertFalse(object instanceof Iterator); - assertFalse(object instanceof MyJsInterfaceWithPrototype); - assertFalse(object instanceof MyJsInterfaceWithPrototypeImpl); + assertFalse(object instanceof MyNativeJsTypeInterface); + assertFalse(object instanceof MyNativeJsTypeInterfaceImpl); assertTrue(object instanceof ElementLikeJsInterface); assertFalse(object instanceof ElementLikeJsInterfaceImpl); assertTrue(object instanceof MyJsInterfaceWithOnlyInstanceofReference); @@ -302,8 +244,8 @@ public void testInstanceOf_implementsJsType() { assertFalse(object instanceof HTMLButtonElement); assertFalse(object instanceof HTMLElement); assertFalse(object instanceof Iterator); - assertFalse(object instanceof MyJsInterfaceWithPrototype); - assertFalse(object instanceof MyJsInterfaceWithPrototypeImpl); + assertFalse(object instanceof MyNativeJsTypeInterface); + assertFalse(object instanceof MyNativeJsTypeInterfaceImpl); assertTrue(object instanceof ElementLikeJsInterface); assertTrue(object instanceof ElementLikeJsInterfaceImpl); assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference); @@ -314,15 +256,15 @@ public void testInstanceOf_implementsJsType() { public void testInstanceOf_implementsJsTypeWithPrototype() { // Foils type tightening. - Object object = alwaysTrue() ? new MyJsInterfaceWithPrototypeImpl() : new Object(); + Object object = alwaysTrue() ? new MyNativeJsTypeInterfaceImpl() : new Object(); assertTrue(object instanceof Object); assertFalse(object instanceof HTMLAnotherElement); assertFalse(object instanceof HTMLButtonElement); assertFalse(object instanceof HTMLElement); assertFalse(object instanceof Iterator); - assertTrue(object instanceof MyJsInterfaceWithPrototype); - assertTrue(object instanceof MyJsInterfaceWithPrototypeImpl); + assertTrue(object instanceof MyNativeJsTypeInterface); + assertTrue(object instanceof MyNativeJsTypeInterfaceImpl); assertFalse(object instanceof ElementLikeJsInterface); assertFalse(object instanceof ElementLikeJsInterfaceImpl); assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference); @@ -340,8 +282,8 @@ public void testInstanceOf_concreteJsType() { assertFalse(object instanceof HTMLButtonElement); assertFalse(object instanceof HTMLElement); assertFalse(object instanceof Iterator); - assertFalse(object instanceof MyJsInterfaceWithPrototype); - assertFalse(object instanceof MyJsInterfaceWithPrototypeImpl); + assertFalse(object instanceof MyNativeJsTypeInterface); + assertFalse(object instanceof MyNativeJsTypeInterfaceImpl); assertFalse(object instanceof ElementLikeJsInterface); assertFalse(object instanceof ElementLikeJsInterfaceImpl); assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference); @@ -359,8 +301,8 @@ public void testInstanceOf_extendsJsTypeWithProto() { assertTrue(object instanceof HTMLButtonElement); assertTrue(object instanceof HTMLElement); assertTrue(object instanceof Iterable); - assertFalse(object instanceof MyJsInterfaceWithPrototype); - assertFalse(object instanceof MyJsInterfaceWithPrototypeImpl); + assertFalse(object instanceof MyNativeJsTypeInterface); + assertFalse(object instanceof MyNativeJsTypeInterfaceImpl); assertFalse(object instanceof ElementLikeJsInterface); assertFalse(object instanceof ElementLikeJsInterfaceImpl); assertFalse(object instanceof MyJsInterfaceWithOnlyInstanceofReference); @@ -369,12 +311,39 @@ public void testInstanceOf_extendsJsTypeWithProto() { assertFalse(object instanceof ConcreteJsType); } - public void testInstanceOfWithNameSpace() { + @JsType(prototype = "JsTypeTest_MyNativeJsType") + static class MyNativeJsType { + @JsProperty + public native int getY(); + + @JsProperty + public native void setY(int value); + + public native int sum(int bias); + } + + static class MyNativeJsTypeSubclass extends MyNativeJsType { + } + + // TODO(rluble): enable when the subclass is setup correctly. + public void _disabled_testNativeJsTypeSubclass() { + MyNativeJsTypeSubclass myNativeJsTypeSubclass = new MyNativeJsTypeSubclass(); + myNativeJsTypeSubclass.setY(12); + assertEquals(42, myNativeJsTypeSubclass.sum(30)); + assertTrue(myNativeJsTypeSubclass instanceof MyNativeJsType); + assertTrue(myNativeJsTypeSubclass instanceof MyNativeJsTypeSubclass); + } + + @JsType(prototype = "testfoo.bar.MyNativeType") + interface MyNamespacedJsInterface { + } + + public void testInstanceOf_withNameSpace() { Object obj1 = createMyNamespacedJsInterface(); Object obj2 = createMyWrongNamespacedJsInterface(); assertTrue(obj1 instanceof MyNamespacedJsInterface); - assertFalse(obj1 instanceof MyJsInterfaceWithPrototype); + assertFalse(obj1 instanceof MyNativeJsTypeInterface); assertFalse(obj2 instanceof MyNamespacedJsInterface); } @@ -409,20 +378,20 @@ private static native Object createNativeButton() /*-{ return $doc.createElement("button"); }-*/; - private static native Object createMyJsInterface() /*-{ - return new $wnd.MyJsInterface(); + private static native Object createMyNativeJsTypeInterface() /*-{ + return new $wnd.JsTypeTest_MyNativeJsTypeInterface(); }-*/; private static native Object createMyNamespacedJsInterface() /*-{ $wnd.testfoo = {}; $wnd.testfoo.bar = {}; - $wnd.testfoo.bar.MyJsInterface = function(){}; - return new $wnd.testfoo.bar.MyJsInterface(); + $wnd.testfoo.bar.MyNativeType = function(){}; + return new $wnd.testfoo.bar.MyNativeType(); }-*/; private static native Object createMyWrongNamespacedJsInterface() /*-{ - $wnd["testfoo.bar.MyJsInterface"] = function(){}; - return new $wnd['testfoo.bar.MyJsInterface'](); + $wnd["testfoo.bar.MyNativeType"] = function(){}; + return new $wnd['testfoo.bar.MyNativeType'](); }-*/; private static native boolean isUndefined(int value) /*-{ @@ -523,4 +492,8 @@ public void testSingleJavaConcreteJsFunction() { assertSame(5, new JavaConcreteJsFunction().m()); assertSame(3, ((JsFunctionInterface) nativeJsFunction()).m()); } + + private static native void setProperty(Object object, String name, int value) /*-{ + object[name] = value; + }-*/; } diff --git a/user/test/com/google/gwt/core/client/interop/MyClassExtendsJsPrototype.java b/user/test/com/google/gwt/core/client/interop/MyClassExtendsJsPrototype.java deleted file mode 100644 index 6f3ac8ae9fe..00000000000 --- a/user/test/com/google/gwt/core/client/interop/MyClassExtendsJsPrototype.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2014 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.core.client.interop; - -class MyClassExtendsJsPrototype extends MyJsClassWithPrototype { - - MyClassExtendsJsPrototype() { - this.x = 42; - setY(52); - } - - @Override - public int sum(int bias) { - return super.sum(bias) + 100; - } -} diff --git a/user/test/com/google/gwt/core/client/interop/MyJsClassWithPrototype.java b/user/test/com/google/gwt/core/client/interop/MyJsClassWithPrototype.java deleted file mode 100644 index 99cce7735f9..00000000000 --- a/user/test/com/google/gwt/core/client/interop/MyJsClassWithPrototype.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.core.client.interop; - -import com.google.gwt.core.client.js.JsProperty; -import com.google.gwt.core.client.js.JsType; - -/** - * A class that represents an existing native type. - */ -@JsType(prototype = "MyJsInterface") -public class MyJsClassWithPrototype { - - public static int staticX; - - public static native int answerToLife(); - - public int x; - - @JsProperty - public native int getY(); - - @JsProperty - public native void setY(int x); - - public native int sum(int bias); -} diff --git a/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithProtectedNames.java b/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithProtectedNames.java deleted file mode 100644 index 185d8a26556..00000000000 --- a/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithProtectedNames.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.core.client.interop; - -import com.google.gwt.core.client.js.JsProperty; -import com.google.gwt.core.client.js.JsType; - -@JsType -interface MyJsInterfaceWithProtectedNames { - - String var(); - - @JsProperty - String getNullField(); // Defined in object scope but shouldn't obfuscate - - @JsProperty - String getImport(); - - @JsProperty - void setImport(String str); -} diff --git a/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototype.java b/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototype.java deleted file mode 100644 index a80f7d18081..00000000000 --- a/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototype.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.core.client.interop; - -import com.google.gwt.core.client.js.JsProperty; -import com.google.gwt.core.client.js.JsType; - -@JsType(prototype = "MyJsInterface") -interface MyJsInterfaceWithPrototype { - - @JsProperty - int getX(); - - @JsProperty - void setX(int a); - - int sum(int bias); -} diff --git a/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototypeAndOnlyInstanceofReference.java b/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototypeAndOnlyInstanceofReference.java deleted file mode 100644 index a5a7d7ea92b..00000000000 --- a/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototypeAndOnlyInstanceofReference.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.core.client.interop; - -import com.google.gwt.core.client.js.JsType; - -/** - * A test class marked with JsType but isn't referenced from any Java code except instanceof. - */ -@JsType(prototype = "MyJsInterface") -public interface MyJsInterfaceWithPrototypeAndOnlyInstanceofReference { -} diff --git a/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototypeImpl.java b/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototypeImpl.java deleted file mode 100644 index 4ad44a976ef..00000000000 --- a/user/test/com/google/gwt/core/client/interop/MyJsInterfaceWithPrototypeImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.core.client.interop; - -/** - * Implements MyJsInterface. - */ -public class MyJsInterfaceWithPrototypeImpl implements MyJsInterfaceWithPrototype { - private int x; - - @Override - public int getX() { - return x; - } - - @Override - public void setX(int x) { - this.x = x; - } - - @Override - public int sum(int bias) { - return bias; - } -} diff --git a/user/test/com/google/gwt/core/client/interop/MyNamespacedJsInterface.java b/user/test/com/google/gwt/core/client/interop/MyNamespacedJsInterface.java deleted file mode 100644 index b5f0c55f09a..00000000000 --- a/user/test/com/google/gwt/core/client/interop/MyNamespacedJsInterface.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.core.client.interop; - -import com.google.gwt.core.client.js.JsType; - -@JsType(prototype = "testfoo.bar.MyJsInterface") -interface MyNamespacedJsInterface { -}