From 4c6c85c185ed412af0b33038029867292efd8a6b Mon Sep 17 00:00:00 2001 From: Grzegorz Kossakowski Date: Fri, 6 Apr 2012 22:55:03 +0200 Subject: [PATCH 1/2] Ported jribble tests from scalagwt-old branch. Tests were written by @stephenh for old scalagwt branch. All I did was to check them out and slightly adapt to newer code. Also, I fixed resource loading. Specifically: * adapted AST building in tests to small changes in protobuf descriptor * changed resource loading to rely on classpath-based resource loading by using Guava's Resources class * dump asts to disk only if they do not match those defined for given test Verified that both all tests and checkstyle passes. --- .../gwt/dev/jjs/impl/jribble/AstUtils.java | 227 ++++++++ .../impl/jribble/JribbleAstBuilderTest.java | 517 ++++++++++++++++++ .../JribbleAstBuilderTest.testArrays.ast | 25 + ...rTest.testBinaryOperationTypePromotion.ast | 22 + ...JribbleAstBuilderTest.testConstructors.ast | 24 + .../JribbleAstBuilderTest.testEmptyClass.ast | 18 + .../JribbleAstBuilderTest.testFields.ast | 35 ++ .../JribbleAstBuilderTest.testInterface.ast | 8 + ...ibbleAstBuilderTest.testLocalVariables.ast | 25 + .../JribbleAstBuilderTest.testNewCall.ast | 23 + ...bbleAstBuilderTest.testOneStringMethod.ast | 22 + ...ribbleAstBuilderTest.testOneVoidMethod.ast | 22 + .../JribbleAstBuilderTest.testSuperCall.ast | 22 + ...bbleAstBuilderTest.testTryCatchFinally.ast | 28 + .../jribble/JribbleReferenceMapperTest.java | 61 +++ 15 files changed, 1079 insertions(+) create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/AstUtils.java create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.java create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testArrays.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testBinaryOperationTypePromotion.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testConstructors.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testEmptyClass.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testFields.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testInterface.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testLocalVariables.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testNewCall.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testOneStringMethod.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testOneVoidMethod.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testSuperCall.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testTryCatchFinally.ast create mode 100644 dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleReferenceMapperTest.java diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/AstUtils.java b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/AstUtils.java new file mode 100644 index 000000000..58d21f1f8 --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/AstUtils.java @@ -0,0 +1,227 @@ +package com.google.gwt.dev.jjs.impl.jribble; + +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.*; + +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Declaration.DeclarationType; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Expr.ExprType; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Literal.LiteralType; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Statement.StatementType; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Type.TypeType; +import com.google.gwt.dev.protobuf.Descriptors.FieldDescriptor; + +import static java.util.Arrays.asList; + +import java.util.List; + +public class AstUtils { + + static GlobalName toGlobalName(String name) { + GlobalName.Builder b = GlobalName.newBuilder(); + int i = name.lastIndexOf("."); + if (i == -1) { + b.setName(name); + } else { + b.setPkg(name.substring(0, i)); + b.setName(name.substring(i + 1)); + } + return b.build(); + } + + static Type toGlobalNameType(String name) { + return Type.newBuilder().setType(TypeType.Named). + setNamedType(toGlobalName(name)).build(); + } + + static Type voidType() { + return Type.newBuilder().setType(TypeType.Void).build(); + } + + static Type stringType() { + return toGlobalNameType("java.lang.String"); + } + + static Type intType() { + return Type.newBuilder().setType(TypeType.Primitive). + setPrimitiveType(PrimitiveType.Int).build(); + } + + static MethodSignature signature(String owner, String name, List paramType, + Type returnType) { + return MethodSignature.newBuilder().setOwner(toGlobalName(owner)).setName(name). + addAllParamType(paramType).setReturnType(returnType).build(); + } + + static Expr expr(MethodCall methodCall) { + return Expr.newBuilder().setType(ExprType.MethodCall). + setMethodCall(methodCall).build(); + } + + static Expr expr(VarRef varRef) { + return Expr.newBuilder().setType(ExprType.VarRef).setVarRef(varRef). + build(); + } + + static Statement statement(Expr expr) { + return Statement.newBuilder().setType(StatementType.Expr). + setExpr(expr).build(); + } + + static Declaration declaration(Method method) { + return Declaration.newBuilder().setType(DeclarationType.Method). + setModifiers(Modifiers.getDefaultInstance()).setMethod(method).build(); + } + + static Declaration declaration(Modifiers mods, Method method) { + return Declaration.newBuilder().setType(DeclarationType.Method). + setModifiers(mods).setMethod(method).build(); + } + + static Declaration declaration(Modifiers mods, FieldDef field) { + return Declaration.newBuilder().setType(DeclarationType.Field). + setModifiers(mods).setFieldDef(field).build(); + } + + static ParamDef paramDef(String name, Type tpe) { + return ParamDef.newBuilder().setName(name).setTpe(tpe).build(); + } + + static Type primitive(PrimitiveType tpe) { + return Type.newBuilder().setType(TypeType.Primitive). + setPrimitiveType(tpe).build(); + } + + static Expr methodCall(Expr receiver, MethodSignature signature, Expr... args) { + MethodCall.Builder b = MethodCall.newBuilder(); + if (receiver != null) { + b.setReceiver(receiver); + } + b.setSignature(signature); + b.addAllArgument(asList(args)); + return expr(b.build()); + } + + static Expr varRef(String name) { + return expr(VarRef.newBuilder().setName(name).build()); + } + + static Type arrayType(Type elementType) { + return Type.newBuilder().setType(TypeType.Array). + setArrayElementType(elementType).build(); + } + + static Statement varDef(Type tpe, String name, Expr initializer) { + VarDef.Builder b = VarDef.newBuilder(); + b.setTpe(tpe).setName(name); + if (initializer != null) { + b.setInitializer(initializer); + } + return Statement.newBuilder().setType(StatementType.VarDef). + setVarDef(b.build()).build(); + } + + static Expr newArray(Type elementType, Expr... dims) { + NewArray n = NewArray.newBuilder().setElementType(elementType). + setDimensions(dims.length).addAllDimensionExpr(asList(dims)).build(); + return Expr.newBuilder().setType(ExprType.NewArray).setNewArray(n).build(); + } + + static Expr arrayInitializer(Type elementType, Expr... values) { + NewArray n = NewArray.newBuilder().setElementType(elementType). + setDimensions(1).addAllInitExpr(asList(values)).build(); + return Expr.newBuilder().setType(ExprType.NewArray).setNewArray(n).build(); + } + + static Expr literal(int x) { + Literal l = Literal.newBuilder().setType(LiteralType.Int). + setIntValue(x).build(); + return Expr.newBuilder().setType(ExprType.Literal).setLiteral(l).build(); + } + + static Expr literal(String x) { + Literal l = Literal.newBuilder().setType(LiteralType.String). + setStringValue(x).build(); + return Expr.newBuilder().setType(ExprType.Literal).setLiteral(l).build(); + } + + static Expr assignment(Expr lhs, Expr rhs) { + Assignment a = Assignment.newBuilder().setLhs(lhs).setRhs(rhs).build(); + return Expr.newBuilder().setType(ExprType.Assignment).setAssignment(a). + build(); + } + + static Expr arrayRef(Expr array, Expr index) { + ArrayRef ref = ArrayRef.newBuilder().setArray(array).setIndex(index).build(); + return Expr.newBuilder().setType(ExprType.ArrayRef).setArrayRef(ref).build(); + } + + static FieldDef fieldDef(Type tpe, String name, Expr initializer) { + FieldDef.Builder b = FieldDef.newBuilder(); + b.setTpe(tpe).setName(name); + if (initializer != null) { + b.setInitializer(initializer); + } + return b.build(); + } + + static String capitalize(String x) { + return Character.toUpperCase(x.charAt(0)) + x.substring(1); + } + + static Modifiers modifiers(String... modifs) { + Modifiers.Builder b = Modifiers.newBuilder(); + for (String x : asList(modifs)) { + FieldDescriptor desc = Modifiers.getDescriptor(). + findFieldByName("is" + capitalize(x)); + b.setField(desc, Boolean.TRUE); + } + return b.build(); + } + + static Expr fieldRef(Expr qualifier, String enclosingType, String name, Type tpe) { + FieldRef.Builder b = FieldRef.newBuilder(); + b.setEnclosingType(toGlobalName(enclosingType)).setName(name); + b.setTpe(tpe); + if (qualifier != null) { + b.setQualifier(qualifier); + } + return Expr.newBuilder().setType(ExprType.FieldRef). + setFieldRef(b.build()).build(); + } + + static Statement block(Statement... stmts) { + Block b = Block.newBuilder().addAllStatement(asList(stmts)).build(); + return Statement.newBuilder().setType(StatementType.Block). + setBlock(b).build(); + } + + static Expr newObject(String clazz, MethodSignature signature, Expr... args) { + assert signature.getName().equals("new"); + NewObject x = NewObject.newBuilder().setClazz(toGlobalName(clazz)). + setSignature(signature).addAllArgument(asList(args)).build(); + return Expr.newBuilder().setType(ExprType.NewObject).setNewObject(x).build(); + } + + static Catch catchh(String tpe, String param, Statement body) { + return Catch.newBuilder().setTpe(toGlobalName(tpe)).setParam(param). + setBody(body).build(); + } + + static Statement tryy(Statement block, Statement finalizer, Catch... catches) { + Try.Builder b = Try.newBuilder(); + b.setBlock(block).addAllCatch(asList(catches)); + if (finalizer != null) { + b.setFinalizer(finalizer); + } + return Statement.newBuilder().setType(StatementType.Try).setTryStat(b.build()).build(); + } + + static Statement returnn(Expr expr) { + Return.Builder b = Return.newBuilder(); + if (expr != null) { + b.setExpression(expr); + } + return Statement.newBuilder().setType(StatementType.Return). + setReturnStat(b.build()).build(); + } + +} diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.java new file mode 100644 index 000000000..93fd59dae --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.java @@ -0,0 +1,517 @@ +/* + * Copyright 2012 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.dev.jjs.impl.jribble; + +import static com.google.gwt.dev.jjs.impl.jribble.AstUtils.*; + +import com.google.gwt.dev.jjs.ast.JClassType; +import com.google.gwt.dev.jjs.ast.JDeclarationStatement; +import com.google.gwt.dev.jjs.ast.JDeclaredType; +import com.google.gwt.dev.jjs.ast.JExpressionStatement; +import com.google.gwt.dev.jjs.ast.JMethod; +import com.google.gwt.dev.jjs.ast.JMethodBody; +import com.google.gwt.dev.jjs.ast.JMethodCall; +import com.google.gwt.dev.jjs.ast.JNewArray; +import com.google.gwt.dev.jjs.ast.JNode; +import com.google.gwt.dev.jjs.ast.JPrimitiveType; +import com.google.gwt.dev.jjs.impl.SourceGenerationVisitor; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Block; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Catch; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Declaration; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.DeclaredType; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Expr; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Expr.ExprType; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.GlobalName; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Literal; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Literal.LiteralType; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Method; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.MethodCall; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.MethodSignature; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Modifiers; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.ParamDef; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.PrimitiveType; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Statement; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Statement.StatementType; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Type; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.VarRef; +import com.google.gwt.dev.util.AbstractTextOutput; +import com.google.gwt.dev.util.DefaultTextOutput; +import com.google.gwt.dev.util.TextOutput; +import com.google.gwt.thirdparty.guava.common.base.Charsets; +import com.google.gwt.thirdparty.guava.common.io.Resources; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import static java.util.Arrays.asList; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Collections; +import java.util.List; + +/** + * Tests for {@link JribbleAstBuilder}. + */ +public class JribbleAstBuilderTest extends TestCase { + + private static class DeclaredTypeBuilder { + private Modifiers modifs = Modifiers.getDefaultInstance(); + private GlobalName ext = toGlobalName("java.lang.Object"); + private List impls = Collections.emptyList(); + private List classBody = Collections.emptyList(); + private Declaration defaultCstr; + + private DeclaredType.Builder b = DeclaredType.newBuilder(); + + private DeclaredTypeBuilder(String name, boolean isInterface) { + b.setName(toGlobalName(name)); + b.setIsInterface(isInterface); + MethodDefBuilder cstr = new MethodDefBuilder("new"); + cstr.stmts = asList(statement(newSuperCstrCall("java.lang.Object"))); + defaultCstr = declaration(cstr.buildCstr()); + } + + private DeclaredType build() { + if (ext != null) { + b.setExt(ext); + } + b.addAllImplements(impls); + b.addAllMember(classBody); + b.setModifiers(modifs); + return b.build(); + } + } + private static class MethodDefBuilder { + private final String name; + List params = java.util.Collections.emptyList(); + List stmts = java.util.Collections.emptyList(); + Type returnType = voidType(); + + private Method.Builder b = Method.newBuilder(); + + private MethodDefBuilder(String name) { + this.name = name; + } + + private Method build() { + b.setReturnType(returnType); + b.setName(name); + b.addAllParamDef(params); + Block block = Block.newBuilder().addAllStatement(stmts).build(); + Statement stmt = Statement.newBuilder().setType(StatementType.Block) + .setBlock(block).build(); + b.setBody(stmt); + return b.build(); + } + + private Method buildCstr() { + b.setIsConstructor(true); + b.setReturnType(returnType); + b.setName(name); + b.addAllParamDef(params); + Block block = Block.newBuilder().addAllStatement(stmts).build(); + Statement stmt = Statement.newBuilder().setType(StatementType.Block) + .setBlock(block).build(); + b.setBody(stmt); + return b.build(); + } + } + private static final List noTypes = Collections.emptyList(); + + private static final Expr superRef = + Expr.newBuilder().setType(ExprType.SuperRef).build(); + + private static final Expr thisRef = + Expr.newBuilder().setType(ExprType.ThisRef).build(); + + private static Expr newSuperCstrCall(String superClassName) { + // jribble uses "super" when calling super constructors, e.g.: + // (Ljava/lang/Object;::super()V;)(); + MethodSignature.Builder msb = MethodSignature.newBuilder(); + msb.setName("new"); + msb.setOwner(toGlobalName(superClassName)); + msb.setReturnType(voidType()); + MethodCall.Builder mb = MethodCall.newBuilder(); + mb.setSignature(msb.build()); + return Expr.newBuilder().setType(ExprType.MethodCall) + .setMethodCall(mb.build()).build(); + } + + private static Statement newWindowAlert(Expr message) { + MethodCall.Builder b = MethodCall.newBuilder(); + MethodSignature s = signature("gwt.Window", "alert", + asList(toGlobalNameType("java.lang.String")), voidType()); + b.setSignature(s); + b.addArgument(message); + return statement(expr(b.build())); + } + + private static Statement newWindowAlert(String message) { + Literal lit = Literal.newBuilder().setType(LiteralType.String) + .setStringValue(message).build(); + Expr alertParam = Expr.newBuilder().setType(ExprType.Literal) + .setLiteral(lit).build(); + return newWindowAlert(alertParam); + } + + private static Statement newWindowAlertVar(String varName) { + VarRef varRef = VarRef.newBuilder().setName(varName).build(); + return newWindowAlert(expr(varRef)); + } + + private static JDeclaredType process(DeclaredTypeBuilder foo) { + return new JribbleAstBuilder().process(foo.build()).types.get(0); + } + + public void testArrays() throws Exception { + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + MethodDefBuilder zaz = new MethodDefBuilder("zaz"); + + Type stringA = arrayType(stringType()); + Type stringAA = arrayType(stringA); + + Statement s1 = varDef(stringAA, "aa", newArray(stringType(), literal(1), literal(1))); + + Statement s2 = statement(assignment(arrayRef(arrayRef(varRef("aa"), literal(0)), + literal(0)), literal("s"))); + + Statement s3 = varDef(stringA, "a", arrayInitializer(stringType(), + literal("1"), literal("2"))); + + Statement s4 = statement(assignment(arrayRef(varRef("a"), literal(0)), literal("0"))); + + zaz.stmts = asList(s1, s2, s3, s4); + foo.classBody = asList(declaration(zaz.build()), foo.defaultCstr); + + JClassType fooType = (JClassType) process(foo); + assertEquals(fooType, "testArrays"); + JMethod zazMethod = fooType.getMethods().get(3); + // String[][] + JDeclarationStatement decl1 = (JDeclarationStatement) ((JMethodBody) zazMethod.getBody()).getStatements().get(0); + Assert.assertEquals(2, ((JNewArray) decl1.getInitializer()).dims.size()); + Assert.assertEquals(2, ((JNewArray) decl1.getInitializer()).getArrayType().getDims()); + // String[] + JDeclarationStatement decl2 = (JDeclarationStatement) ((JMethodBody) zazMethod.getBody()).getStatements().get(2); + Assert.assertEquals(null, ((JNewArray) decl2.getInitializer()).dims); + Assert.assertEquals(1, ((JNewArray) decl2.getInitializer()).getArrayType().getDims()); + } + + public void testConstructors() throws Exception { + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + + MethodDefBuilder b1 = new MethodDefBuilder("new"); + b1.params = asList(paramDef("s", stringType())); + b1.stmts = asList(statement(newSuperCstrCall("java.lang.Object")), + newWindowAlertVar("s")); + Declaration cstr1 = declaration(b1.buildCstr()); + + // cstr2 calls cstr1, which means it shouldn't have an $init call + Expr cstr1Call = methodCall(thisRef, signature("foo.Bar", "new", + asList(stringType()), voidType()), literal("a")); + + MethodDefBuilder b2 = new MethodDefBuilder("new"); + b2.params = asList(paramDef("i", toGlobalNameType("java.lang.Integer"))); + b2.stmts = asList(statement(cstr1Call), newWindowAlertVar("i")); + Declaration cstr2 = declaration(b2.buildCstr()); + + foo.classBody = asList(cstr1, cstr2); + + JClassType fooType = (JClassType) process(foo); + assertEquals(fooType, "testConstructors"); + + // ensure cstr2 calls cstr1 + JMethod cstr1m = fooType.getMethods().get(3); + JMethod cstr2m = fooType.getMethods().get(4); + JMethodCall c = + (JMethodCall) ((JExpressionStatement) ((JMethodBody) cstr2m.getBody()).getStatements().get( + 0)).getExpr(); + Assert.assertEquals(cstr1m, c.getTarget()); + Assert.assertEquals(true, c.isStaticDispatchOnly()); + } + + public void testEmptyClass() throws Exception { + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + foo.ext = null; + foo.classBody = asList(foo.defaultCstr); + JDeclaredType fooType = process(foo); + assertEquals(fooType, "testEmptyClass"); + } + + public void testFields() throws Exception { + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + + // initialized + Declaration f1 = declaration(modifiers("private"), + fieldDef(stringType(), "f1", literal("f1"))); + + // un-initialized + Declaration f2 = declaration(modifiers("private"), + fieldDef(stringType(), "f2", null)); + + // static initialized + Declaration f3 = declaration(modifiers("private", "static"), + fieldDef(stringType(), "f3", literal("f3"))); + + // static un-initialized + Declaration f4 = declaration(modifiers("private", "static"), + fieldDef(stringType(), "f4", null)); + + MethodDefBuilder zaz = new MethodDefBuilder("zaz"); + zaz.params = asList(paramDef("other", toGlobalNameType("foo.Bar"))); + + Statement assignf1 = statement( + assignment(fieldRef(thisRef, "foo.Bar", "f1", stringType()), literal("f11"))); + + Statement assignf2 = statement( + assignment(fieldRef(varRef("other"), "foo.Bar", "f2", stringType()), literal("f22"))); + + Statement assignf3 = statement( + assignment(fieldRef(null, "foo.Bar", "f3", stringType()), literal("f33"))); + + Statement assignfOther = statement( + assignment(fieldRef(null, "foo.Other", "i", intType()), literal(1))); + + zaz.stmts = asList(assignf1, assignf2, assignf3, assignfOther); + foo.classBody = asList(f1, f2, f3, f4, + declaration(zaz.build()), foo.defaultCstr); + + JDeclaredType fooType = process(foo); + assertEquals(fooType, "testFields"); + assertEquals(4, fooType.getFields().size()); + } + + public void testInterface() throws Exception { + // are interface methods abstract? otherwise SourceGenerationVisitor fails + + MethodDefBuilder b = new MethodDefBuilder("zaz"); + b.returnType = stringType(); + b.params = asList(paramDef("x", toGlobalNameType("java.lang.Integer"))); + Declaration zaz = declaration( + Modifiers.newBuilder().setIsAbstract(true).build(), + b.build()); + + DeclaredTypeBuilder b1 = new DeclaredTypeBuilder("foo.SpecialList", true); + b1.modifs = Modifiers.newBuilder().setIsPrivate(true).build(); + b1.impls = asList(toGlobalName("java.util.List")); + b1.classBody = asList(zaz); + DeclaredType specialList = b1.build(); + + JDeclaredType fooType = new JribbleAstBuilder().process(specialList).types.get(0); + assertEquals(fooType, "testInterface"); + Assert.assertTrue(fooType.getMethods().get(1).isAbstract()); + } + + public void testInterfacesTreatedAsClasses() throws Exception { + JribbleAstBuilder jab = new JribbleAstBuilder(); + // do one unit that refers to another via a method call, assumed to be a class + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + MethodDefBuilder zaz = new MethodDefBuilder("zaz"); + zaz.params = asList(paramDef("l", toGlobalNameType("java.util.List"))); + Statement s1 = statement(methodCall(varRef("l"), signature("java.util.List", "add", + asList(toGlobalNameType("java.lang.Object")), voidType()), + varRef("l"))); + zaz.stmts = asList(s1); + foo.classBody = asList(foo.defaultCstr, declaration(zaz.build())); + jab.process(foo.build()); + // now do another unit that implements java.util.List, that requires it to be an interface + DeclaredTypeBuilder foo2 = new DeclaredTypeBuilder("foo.Bar2", false); + foo2.impls = asList(toGlobalName("java.util.List")); + JDeclaredType foo2Type = process(foo2); + assertEquals(foo2Type.getImplements().get(0).getName(), "java.util.List"); + } + + public void testLocalVariables() throws Exception { + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + MethodDefBuilder zaz = new MethodDefBuilder("zaz"); + + Statement intDef = varDef(primitive(PrimitiveType.Int), "i", null); + Statement intAssignment = statement(assignment(varRef("i"), literal(10))); + Statement stringDef = varDef(toGlobalNameType("java.lang.String"), "s", null); + Statement stringAssignment = statement(assignment(varRef("s"), literal("string"))); + + zaz.stmts = asList(intDef, intAssignment, stringDef, stringAssignment); + foo.classBody = asList(declaration(zaz.build()), foo.defaultCstr); + + JDeclaredType fooType = process(foo); + assertEquals(fooType, "testLocalVariables"); + } + + public void testMethodCall() throws Exception { + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + MethodDefBuilder zaz = new MethodDefBuilder("zaz"); + zaz.stmts = asList(newWindowAlert("hello")); + foo.classBody = asList(foo.defaultCstr, declaration(zaz.build())); + + JDeclaredType fooType = process(foo); + JMethodCall call = + (JMethodCall) ((JExpressionStatement) ((JMethodBody) fooType.getMethods().get(4) + .getBody()).getStatements().get(0)).getExpr(); + Assert.assertEquals("alert(Ljava/lang/String;)V", call.getTarget().getSignature()); + } + + public void testNewCall() throws Exception { + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + MethodDefBuilder zaz = new MethodDefBuilder("zaz"); + + MethodSignature cstrSig = signature("java.util.ArrayList", "new", + asList(primitive(PrimitiveType.Int)), toGlobalNameType("java.util.ArrayList")); + + Expr cstrArg = literal(1); + Statement varDef = varDef(toGlobalNameType("java.util.List"), "l", + newObject("java.util.ArrayList", cstrSig, cstrArg)); + + MethodSignature addSig = signature("java.util.List", "add", + asList(toGlobalNameType("java.lang.Object")), voidType()); + + Expr addParam = literal(1); // should be boxed + Statement addCall = statement(methodCall(varRef("l"), addSig, addParam)); + + zaz.stmts = asList(varDef, addCall); + foo.classBody = asList(declaration(zaz.build()), foo.defaultCstr); + + JDeclaredType fooType = process(foo); + assertEquals(fooType, "testNewCall"); + // ensure the external JMethod was frozen so getSignature doesn't NPE + JExpressionStatement addStmt = + (JExpressionStatement) ((JMethodBody) fooType.getMethods().get(3).getBody()).getBlock() + .getStatements().get(1); + Assert.assertEquals("add(Ljava/lang/Object;)V", ((JMethodCall) addStmt.getExpr()).getTarget().getSignature()); + } + + public void testOneStringMethod() throws Exception { + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + MethodDefBuilder zaz = new MethodDefBuilder("zaz"); + zaz.returnType = toGlobalNameType("java.lang.String"); + zaz.stmts = asList(returnn(literal("hello"))); + foo.classBody = asList(declaration(zaz.build()), foo.defaultCstr); + + JDeclaredType fooType = process(foo); + assertEquals(fooType, "testOneStringMethod"); + Assert.assertEquals("zaz()Ljava/lang/String;", fooType.getMethods().get(3).getSignature()); + Assert.assertFalse(fooType.isExternal()); + Assert.assertTrue(fooType.getMethods().get(3).getOriginalReturnType().isExternal()); + } + + public void testOneVoidMethod() throws Exception { + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + MethodDefBuilder zaz = new MethodDefBuilder("zaz"); + zaz.stmts = asList(returnn(null)); + foo.classBody = asList(declaration(zaz.build()),foo.defaultCstr); + + JDeclaredType fooType = process(foo); + assertEquals(fooType, "testOneVoidMethod"); + Assert.assertEquals("zaz()V", fooType.getMethods().get(3).getSignature()); + Assert.assertFalse(fooType.isExternal()); + Assert.assertEquals(JPrimitiveType.VOID, fooType.getMethods().get(3).getOriginalReturnType()); + } + + public void testSuperCall() throws Exception { + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + MethodDefBuilder zaz = new MethodDefBuilder("toString"); + MethodCall.Builder b = MethodCall.newBuilder(); + b.setSignature(signature("java.lang.Object", "toString", noTypes, stringType())); + b.setReceiver(superRef); + Statement superCall = statement(expr(b.build())); + zaz.stmts = asList(superCall); + zaz.returnType = toGlobalNameType("java.lang.String"); + foo.classBody = asList(declaration(zaz.build()), foo.defaultCstr); + + assertEquals(process(foo), "testSuperCall"); + } + + public void testTryCatchFinally() throws Exception { + DeclaredTypeBuilder foo = new DeclaredTypeBuilder("foo.Bar", false); + MethodDefBuilder zaz = new MethodDefBuilder("zaz"); + + Statement intDef = varDef(primitive(PrimitiveType.Int), "i", null); + Statement tryBlock = block(intDef); + + Catch catchh = catchh("java.lang.Exception", "e", block(newWindowAlert("caught"))); + + Statement finalBlock = block(newWindowAlert("finally")); + + Statement tryStmt = tryy(tryBlock, finalBlock, catchh); + + zaz.stmts = asList(tryStmt); + foo.classBody = asList(declaration(zaz.build()), foo.defaultCstr); + + JDeclaredType fooType = process(foo); + assertEquals(fooType, "testTryCatchFinally"); + JMethodBody body = (JMethodBody) fooType.getMethods().get(3).getBody(); + Assert.assertEquals("zaz", body.getMethod().getName()); + // ensure both "int i" and "Exception e" are locals + Assert.assertEquals(2, body.getLocals().size()); + } + + /** + * Dumps @{code node} and checks if result is equal to one stored + * in file described by @{code name}. In case both dumps are not + * equal the actual result is dumped to file so it can be further + * inspected. + * @param node AST to be dumped + * @param name part of file name that describes the dump. + * @throws IOException + */ + private void assertEquals(JNode node, String name) throws IOException { + TextOutput out = new DefaultTextOutput(false); + SourceGenerationVisitor v = new SourceGenerationVisitor(out); + v.accept(node); + final String actual = out.toString(); + + final String expected; + { + String resourceName = + getClass().getName().replace('.', '/') + "." + name + ".ast"; + java.net.URL url = Resources.getResource(resourceName); + expected = Resources.toString(url, Charsets.UTF_8); + } + + try { + Assert.assertEquals(expected, actual); + } catch (AssertionError ex) { + dump(node, name); + throw ex; + } + } + + /** + * Dumps {@code node} to file relative to current directory. + * @param node AST to be dumped. + * @param name part of file name that describes the dump. + * @throws IOException + */ + private void dump(JNode node, String name) throws IOException { + String dumpFilePath = + getClass().getName().replace('.', '/') + "." + name + ".ast.actual"; + File dumpFile = new File(dumpFilePath); + System.out.println("Dumping ast to " + dumpFile.getCanonicalPath()); + dumpFile.getParentFile().mkdirs(); + dumpFile.createNewFile(); + + FileOutputStream os = new FileOutputStream(dumpFile, false); + final PrintWriter pw = new PrintWriter(os); + TextOutput out = new AbstractTextOutput(false) { + { + setPrintWriter(pw); + } + }; + SourceGenerationVisitor v = new SourceGenerationVisitor(out); + v.accept(node); + pw.close(); + } + +} diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testArrays.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testArrays.ast new file mode 100644 index 000000000..2d30e7754 --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testArrays.ast @@ -0,0 +1,25 @@ +class Bar extends Object { + private static final void $clinit(){ + Object.$clinit(); + } + + private final void $init(){ + } + + public Class getClass(){ + return Bar.class; + } + + void zaz(){ + String[][] aa = new String[][][1][1]; + aa[0][0] = "s"; + String[] a = new String[] {"1", "2"}; + a[0] = "0"; + } + + public Bar(){ + this.$init(); + super(); + } + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testBinaryOperationTypePromotion.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testBinaryOperationTypePromotion.ast new file mode 100644 index 000000000..4bbb0aea7 --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testBinaryOperationTypePromotion.ast @@ -0,0 +1,22 @@ +class Bar extends Object { + private static final void $clinit(){ + Object.$clinit(); + } + + private final void $init(){ + } + + public Class getClass(){ + return Bar.class; + } + + void zaz(){ + double d = 10.0 + 1; + } + + public Bar(){ + this.$init(); + super(); + } + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testConstructors.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testConstructors.ast new file mode 100644 index 000000000..91fe4c803 --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testConstructors.ast @@ -0,0 +1,24 @@ +class Bar extends Object { + private static final void $clinit(){ + Object.$clinit(); + } + + private final void $init(){ + } + + public Class getClass(){ + return Bar.class; + } + + public Bar(String s){ + this.$init(); + super(); + Window.alert(s); + } + + public Bar(Integer i){ + this("a"); + Window.alert(i); + } + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testEmptyClass.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testEmptyClass.ast new file mode 100644 index 000000000..88e6d73b4 --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testEmptyClass.ast @@ -0,0 +1,18 @@ +class Bar extends Object { + private static final void $clinit(){ + Object.$clinit(); + } + + private final void $init(){ + } + + public Class getClass(){ + return Bar.class; + } + + public Bar(){ + this.$init(); + super(); + } + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testFields.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testFields.ast new file mode 100644 index 000000000..2d8713ca3 --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testFields.ast @@ -0,0 +1,35 @@ +class Bar extends Object { + String f1 + + String f2 + + static String f3 + + static String f4 + + private static final void $clinit(){ + Object.$clinit(); + static String f3 = "f3"; + } + + private final void $init(){ + String f1 = "f1"; + } + + public Class getClass(){ + return Bar.class; + } + + void zaz(Bar other){ + this.f1 = "f11"; + other.f2 = "f22"; + Bar.f3 = "f33"; + Other.i = 1; + } + + public Bar(){ + this.$init(); + super(); + } + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testInterface.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testInterface.ast new file mode 100644 index 000000000..19ec6ca5d --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testInterface.ast @@ -0,0 +1,8 @@ +interface SpecialList extends List { + private static final void $clinit(){ + } + + abstract String zaz(Integer x); + + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testLocalVariables.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testLocalVariables.ast new file mode 100644 index 000000000..36113bd62 --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testLocalVariables.ast @@ -0,0 +1,25 @@ +class Bar extends Object { + private static final void $clinit(){ + Object.$clinit(); + } + + private final void $init(){ + } + + public Class getClass(){ + return Bar.class; + } + + void zaz(){ + int i; + i = 10; + String s; + s = "string"; + } + + public Bar(){ + this.$init(); + super(); + } + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testNewCall.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testNewCall.ast new file mode 100644 index 000000000..2a31a0e7f --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testNewCall.ast @@ -0,0 +1,23 @@ +class Bar extends Object { + private static final void $clinit(){ + Object.$clinit(); + } + + private final void $init(){ + } + + public Class getClass(){ + return Bar.class; + } + + void zaz(){ + List l = new ArrayList(1); + l.add(1); + } + + public Bar(){ + this.$init(); + super(); + } + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testOneStringMethod.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testOneStringMethod.ast new file mode 100644 index 000000000..c122adcda --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testOneStringMethod.ast @@ -0,0 +1,22 @@ +class Bar extends Object { + private static final void $clinit(){ + Object.$clinit(); + } + + private final void $init(){ + } + + public Class getClass(){ + return Bar.class; + } + + String zaz(){ + return "hello"; + } + + public Bar(){ + this.$init(); + super(); + } + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testOneVoidMethod.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testOneVoidMethod.ast new file mode 100644 index 000000000..33c64c337 --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testOneVoidMethod.ast @@ -0,0 +1,22 @@ +class Bar extends Object { + private static final void $clinit(){ + Object.$clinit(); + } + + private final void $init(){ + } + + public Class getClass(){ + return Bar.class; + } + + void zaz(){ + return; + } + + public Bar(){ + this.$init(); + super(); + } + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testSuperCall.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testSuperCall.ast new file mode 100644 index 000000000..4ba86dea5 --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testSuperCall.ast @@ -0,0 +1,22 @@ +class Bar extends Object { + private static final void $clinit(){ + Object.$clinit(); + } + + private final void $init(){ + } + + public Class getClass(){ + return Bar.class; + } + + String toString(){ + super(); + } + + public Bar(){ + this.$init(); + super(); + } + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testTryCatchFinally.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testTryCatchFinally.ast new file mode 100644 index 000000000..dab94202a --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testTryCatchFinally.ast @@ -0,0 +1,28 @@ +class Bar extends Object { + private static final void $clinit(){ + Object.$clinit(); + } + + private final void $init(){ + } + + public Class getClass(){ + return Bar.class; + } + + void zaz(){ + try { + int i; + } catch (Exception e) { + Window.alert("caught"); + } finally { + Window.alert("finally"); + } + } + + public Bar(){ + this.$init(); + super(); + } + +} \ No newline at end of file diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleReferenceMapperTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleReferenceMapperTest.java new file mode 100644 index 000000000..affc68454 --- /dev/null +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleReferenceMapperTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012 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.dev.jjs.impl.jribble; + +import static com.google.gwt.dev.jjs.impl.jribble.AstUtils.*; +import static com.google.gwt.thirdparty.guava.common.collect.Sets.newHashSet; + +import com.google.gwt.dev.jjs.SourceOrigin; +import com.google.gwt.dev.jjs.ast.JClassType; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.DeclaredType; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.Modifiers; +import com.google.gwt.dev.jjs.impl.jribble.JribbleProtos.PrimitiveType; + +import junit.framework.Assert; +import junit.framework.TestCase; + +/** + * Tests for {@link JribbleReferenceMapper}. + */ +public class JribbleReferenceMapperTest extends TestCase { + + public void testSourceTypeIsNotConsideredTouched() { + JribbleReferenceMapper m = new JribbleReferenceMapper(); + JClassType gwtType = new JClassType(SourceOrigin.UNKNOWN, "foo.T5", false, false); + DeclaredType decl = DeclaredType.newBuilder() + .setName(toGlobalName("foo.T5")).setModifiers(Modifiers.getDefaultInstance()).build(); + m.setSourceType(decl, gwtType); + Assert.assertEquals(newHashSet(), m.getTouchedTypes()); + } + + public void testTouchedTypes() { + JribbleReferenceMapper m = new JribbleReferenceMapper(); + m.getType(toGlobalNameType("foo.T1")); + m.getType(voidType()); + m.getType(primitive(PrimitiveType.Int)); + m.getType(arrayType(toGlobalNameType(("foo.T4")))); + m.getType(arrayType(primitive(PrimitiveType.Double))); + m.getClassType("foo.T2"); + m.getInterfaceType("foo.T3"); + Assert.assertEquals(newHashSet("foo.T1", "foo.T2", "foo.T3", "foo.T4"), m.getTouchedTypes()); + + m.clearSource(); + Assert.assertEquals(newHashSet(), m.getTouchedTypes()); + + m.getType(toGlobalNameType("foo.T1")); + m.getType(arrayType(primitive(PrimitiveType.Double))); + Assert.assertEquals(newHashSet("foo.T1"), m.getTouchedTypes()); + } + +} From e0b81f144b57e273b80af68f88fe50d3996d0433 Mon Sep 17 00:00:00 2001 From: Grzegorz Kossakowski Date: Sat, 7 Apr 2012 19:47:22 +0200 Subject: [PATCH 2/2] Fix handling of empty array literals. Basically, the logic handling NewArray message confused two expressions: Object[] foo = {}; //legal in Java Object[] foo = new Object[]; //not legal For NewArray encoding the first case it would interpret it as second one and feed it to GWT. We can fix it by realizing that checking getDimensionExprCount which determines nature of NewArray. If it's equal to zero we can be sure that NewArray message encodes array literal. Added documentation that explains how different cases are encoded so others should have easier time following logic processing NewArray messages. Also, added a test covering this case. Fixes #33. --- .../jjs/impl/jribble/JribbleAstBuilder.java | 19 ++++++++------ .../gwt/dev/jjs/impl/jribble/jribble.proto | 25 +++++++++++++++++++ .../impl/jribble/JribbleAstBuilderTest.java | 9 ++++++- .../JribbleAstBuilderTest.testArrays.ast | 1 + 4 files changed, 45 insertions(+), 9 deletions(-) diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilder.java index b0ee6dd4c..5b9610caf 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilder.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilder.java @@ -584,18 +584,14 @@ private JStatement methodStatement(Statement s, LocalStack local) { } private JNewArray newArray(NewArray expr, LocalStack local) { + // semantics of NewArray are tricky, check jribble.proto file + // for examples JType type = mapper.getType(expr.getElementType()); // this is the element // type assert (expr.getInitExprCount() > 0 && expr.getDimensions() == 1) || expr.getInitExprCount() == 0; - if (expr.getInitExprCount() > 0) { - JArrayType arrayType = new JArrayType(type); - List initializers = new LinkedList(); - for (Expr e : expr.getInitExprList()) { - initializers.add(expression(e, local)); - } - return JNewArray.createInitializers(UNKNOWN, arrayType, initializers); - } else { + + if (expr.getDimensionExprCount() > 0) { for (int i = 0; i < expr.getDimensions(); i++) { type = new JArrayType(type); } @@ -607,6 +603,13 @@ private JNewArray newArray(NewArray expr, LocalStack local) { dims.add(JAbsentArrayDimension.INSTANCE); } return JNewArray.createDims(UNKNOWN, (JArrayType) type, dims); + } else { + JArrayType arrayType = new JArrayType(type); + List initializers = new LinkedList(); + for (Expr e : expr.getInitExprList()) { + initializers.add(expression(e, local)); + } + return JNewArray.createInitializers(UNKNOWN, arrayType, initializers); } } diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/jribble/jribble.proto b/dev/core/src/com/google/gwt/dev/jjs/impl/jribble/jribble.proto index a94f4a5db..dddd5b7ed 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/jribble/jribble.proto +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/jribble/jribble.proto @@ -275,6 +275,31 @@ message MethodSignature { required Type returnType = 4; } +/* Encodes both new array expresions and array literals. + * Below there are Java expressions and corresponding + * protobufs that encode them. + * + * new Object[7] + * newArray { + * elementType ... //encoding for java.lang.Object + * dimensions: 1 + * dimensionExpr { ... //expr encoding 7 } + * } + * + * new Object[] {} + * newArray { + * elementType ... //encoding for java.lang.Object + * dimensions: 1 + * } + * + * new Object[] { ex1, ex2 } + * newArray { + * elementType ... //encoding for java.lang.Object + * dimensions: 1 + * initExpr { ... } //encoding for ex1 + * initExpr { ... } //encoding for ex2 + * } + */ message NewArray { required Type elementType = 1; required int32 dimensions = 2; diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.java index 93fd59dae..961f9d974 100644 --- a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.java +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.java @@ -194,7 +194,9 @@ public void testArrays() throws Exception { Statement s4 = statement(assignment(arrayRef(varRef("a"), literal(0)), literal("0"))); - zaz.stmts = asList(s1, s2, s3, s4); + Statement s5 = varDef(stringA, "b", arrayInitializer(stringType())); + + zaz.stmts = asList(s1, s2, s3, s4, s5); foo.classBody = asList(declaration(zaz.build()), foo.defaultCstr); JClassType fooType = (JClassType) process(foo); @@ -208,6 +210,11 @@ public void testArrays() throws Exception { JDeclarationStatement decl2 = (JDeclarationStatement) ((JMethodBody) zazMethod.getBody()).getStatements().get(2); Assert.assertEquals(null, ((JNewArray) decl2.getInitializer()).dims); Assert.assertEquals(1, ((JNewArray) decl2.getInitializer()).getArrayType().getDims()); + // String[] {} + JDeclarationStatement decl3 = (JDeclarationStatement) ((JMethodBody) zazMethod.getBody()).getStatements().get(4); + Assert.assertEquals(null, ((JNewArray) decl3.getInitializer()).dims); + Assert.assertEquals(Collections.EMPTY_LIST, ((JNewArray) decl3.getInitializer()).initializers); + Assert.assertEquals(1, ((JNewArray) decl3.getInitializer()).getArrayType().getDims()); } public void testConstructors() throws Exception { diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testArrays.ast b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testArrays.ast index 2d30e7754..0e3e07245 100644 --- a/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testArrays.ast +++ b/dev/core/test/com/google/gwt/dev/jjs/impl/jribble/JribbleAstBuilderTest.testArrays.ast @@ -15,6 +15,7 @@ class Bar extends Object { aa[0][0] = "s"; String[] a = new String[] {"1", "2"}; a[0] = "0"; + String[] b = new String[] {}; } public Bar(){