Search in sources :

Example 16 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class ClassTransformer method transformObject.

private List<JCTree> transformObject(Node def, Tree.Declaration annotated, Tree.SatisfiedTypes satisfiesTypes, Value model, Class klass, ClassDefinitionBuilder containingClassBuilder, boolean makeLocalInstance) {
    naming.clearSubstitutions(klass);
    String name = klass.getName();
    String javaClassName = Naming.quoteClassName(name);
    ClassDefinitionBuilder objectClassBuilder = ClassDefinitionBuilder.object(this, javaClassName, name, Decl.isLocal(klass)).forDefinition(klass);
    if (Strategy.introduceJavaIoSerializable(klass, typeFact().getJavaIoSerializable())) {
        objectClassBuilder.introduce(make().QualIdent(syms().serializableType.tsym));
        if (def instanceof Tree.ObjectDefinition && klass.isMember() && (ModelUtil.isCaptured(klass) || model.isCaptured())) {
            addWriteReplace(klass, objectClassBuilder);
        }
    }
    makeReadResolve(def, objectClassBuilder, klass, model);
    // Make sure top types satisfy reified type
    addReifiedTypeInterface(objectClassBuilder, klass);
    if (supportsReifiedAlias(klass))
        objectClassBuilder.reifiedAlias(klass.getType());
    CeylonVisitor visitor = gen().visitor;
    final ListBuffer<JCTree> prevDefs = visitor.defs;
    final boolean prevInInitializer = visitor.inInitializer;
    final ClassDefinitionBuilder prevClassBuilder = visitor.classBuilder;
    List<JCStatement> childDefs;
    try {
        visitor.defs = new ListBuffer<JCTree>();
        visitor.inInitializer = true;
        visitor.classBuilder = objectClassBuilder;
        def.visitChildren(visitor);
        childDefs = (List<JCStatement>) visitor.getResult().toList();
    } finally {
        visitor.classBuilder = prevClassBuilder;
        visitor.inInitializer = prevInInitializer;
        visitor.defs = prevDefs;
        naming.closeScopedSubstitutions(def.getScope());
    }
    addMissingUnrefinedMembers(def, klass, objectClassBuilder);
    satisfaction(satisfiesTypes, klass, objectClassBuilder);
    serialization(klass, objectClassBuilder);
    if (model != null && model.isToplevel() && def instanceof Tree.ObjectDefinition) {
        // generate a field and getter
        AttributeDefinitionBuilder builder = AttributeDefinitionBuilder.wrapped(this, model.getName(), model, true, null).userAnnotations(makeAtIgnore()).userAnnotationsSetter(makeAtIgnore()).immutable().initialValue(makeNewClass(naming.makeName(model, Naming.NA_FQ | Naming.NA_WRAPPER)), BoxingStrategy.BOXED).is(PUBLIC, klass.isShared()).is(STATIC, true);
        if (annotated != null) {
            builder.fieldAnnotations(expressionGen().transformAnnotations(OutputElement.FIELD, annotated));
            builder.userAnnotations(expressionGen().transformAnnotations(OutputElement.GETTER, annotated));
        }
        objectClassBuilder.defs(builder.build());
    }
    if (annotated != null) {
        objectClassBuilder.annotations(expressionGen().transformAnnotations(OutputElement.TYPE, annotated));
        objectClassBuilder.getInitBuilder().userAnnotations(expressionGen().transformAnnotations(OutputElement.CONSTRUCTOR, annotated));
    }
    // make sure we set the container in case we move it out
    addAtContainer(objectClassBuilder, klass);
    objectClassBuilder.annotations(makeAtObject()).satisfies(klass.getSatisfiedTypes()).defs(childDefs);
    objectClassBuilder.getInitBuilder().modifiers(PRIVATE);
    objectClassBuilder.addGetTypeMethod(klass.getType());
    if (model != null)
        objectClassBuilder.modelAnnotations(model.getAnnotations()).modifiers(modifierTransformation().object(model));
    at(def);
    List<JCTree> result = objectClassBuilder.build();
    if (makeLocalInstance && !model.isStatic()) {
        if (model.isSelfCaptured()) {
            // if it's captured we need to box it and define the var before the class, so it can access it
            JCNewClass newInstance = makeNewClass(objectClassBuilder.getClassName(), false, null);
            JCFieldAccess setter = naming.makeSelect(Naming.getLocalValueName(model), Naming.getSetterName(model));
            JCStatement assign = make().Exec(make().Assign(setter, newInstance));
            result = result.prepend(assign);
            JCVariableDecl localDecl = makeVariableBoxDecl(null, model);
            result = result.prepend(localDecl);
        } else {
            // not captured, we can define the var after the class
            JCVariableDecl localDecl = makeLocalIdentityInstance(name, objectClassBuilder.getClassName(), false);
            result = result.append(localDecl);
        }
    } else if (model != null && model.isClassOrInterfaceMember()) {
        boolean generateGetter = ModelUtil.isCaptured(model);
        JCExpression type = makeJavaType(klass.getType());
        if (generateGetter) {
            int modifiers = TRANSIENT | PRIVATE | (model.isStatic() ? STATIC : 0);
            JCExpression initialValue = makeNull();
            containingClassBuilder.field(modifiers, name, type, initialValue, false);
            AttributeDefinitionBuilder getter = AttributeDefinitionBuilder.getter(this, name, model).modifiers(modifierTransformation().getterSetter(model, false));
            if (def instanceof Tree.ObjectDefinition) {
                getter.userAnnotations(expressionGen().transformAnnotations(OutputElement.GETTER, ((Tree.ObjectDefinition) def)));
            }
            ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
            stmts.add(make().If(make().Binary(JCTree.Tag.EQ, naming.makeUnquotedIdent(Naming.quoteFieldName(name)), makeNull()), make().Exec(make().Assign(naming.makeUnquotedIdent(Naming.quoteFieldName(name)), makeNewClass(makeJavaType(klass.getType()), null))), null));
            stmts.add(make().Return(naming.makeUnquotedIdent(Naming.quoteFieldName(name))));
            getter.getterBlock(make().Block(0, stmts.toList()));
            result = result.appendList(getter.build());
        } else {
            int modifiers = FINAL | (model.isStatic() ? STATIC : 0);
            JCExpression initialValue = makeNewClass(makeJavaType(klass.getType()), null);
            containingClassBuilder.field(modifiers, name, type, initialValue, true);
        }
    }
    return result;
}
Also used : JCFieldAccess(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCFieldAccess) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) JCVariableDecl(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCVariableDecl) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) JCPrimitiveTypeTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) JCNewClass(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass)

Example 17 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class ClassTransformer method serializationGet.

private void serializationGet(Class model, ClassDefinitionBuilder classBuilder) {
    MethodDefinitionBuilder mdb = MethodDefinitionBuilder.systemMethod(this, Unfix.$get$.toString());
    mdb.isOverride(true);
    mdb.ignoreModelAnnotations();
    mdb.modifiers(PUBLIC);
    ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.systemParameter(this, Unfix.reference.toString());
    pdb.modifiers(FINAL);
    pdb.type(new TransformedType(make().Type(syms().ceylonReachableReferenceType), null, makeAtNonNull()));
    mdb.parameter(pdb);
    mdb.resultType(new TransformedType(make().Type(syms().objectType), null, makeAtNonNull()));
    /*
         * public void $get$(Object reference, Object instance) {
         *     switch((String)reference) {
         *     case ("attr1")
         *           return ...;
         *     // ... other fields of this class
         *     case ("lateAttr1")
         *           if (!$init$lateAttr1) {
         *               return ceylon.language.serialization.uninitializedLateValue.get_();
         *           }
         *           return ...;
         *     case (null):
         *           return Outer.this;
         *     default:
         *           return super.get(reference);
         */
    ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
    boolean[] needsLookup = new boolean[] { false };
    for (Declaration member : model.getMembers()) {
        if (hasField(member)) {
            if (member instanceof Function)
                // TODO: This class is not serializable
                continue;
            ListBuffer<JCStatement> caseStmts = new ListBuffer<JCStatement>();
            if (member instanceof Value && ((Value) member).isLate()) {
                // TODO this should be encapsulated so the ADB and this
                // code can just call something common
                JCExpression test = AttributeDefinitionBuilder.field(this, null, member.getName(), (Value) member, false).buildUninitTest();
                if (test != null) {
                    caseStmts.add(make().If(test, make().Return(makeLanguageSerializationValue("uninitializedLateValue")), null));
                }
            }
            caseStmts.add(make().Return(makeSerializationGetter((Value) member)));
            cases.add(make().Case(make().Literal(member.getQualifiedNameString()), caseStmts.toList()));
        }
    }
    SyntheticName reference = naming.synthetic(Unfix.reference);
    ListBuffer<JCStatement> defaultCase = new ListBuffer<JCStatement>();
    if (extendsSerializable(model)) {
        // super.get(reference);
        defaultCase.add(make().Return(make().Apply(null, naming.makeQualIdent(naming.makeSuper(), Unfix.$get$.toString()), List.<JCExpression>of(reference.makeIdent()))));
    } else {
        // throw (or pass to something else to throw, based on policy)
        defaultCase.add(make().Throw(make().NewClass(null, null, naming.makeQuotedFQIdent("java.lang.RuntimeException"), List.<JCExpression>of(make().Literal("unknown attribute")), null)));
    }
    cases.add(make().Case(null, defaultCase.toList()));
    ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
    if (needsLookup[0]) {
        // if we needed to use a lookup object to reset final fields,
        // prepend that variable
        stmts.add(makeVar(FINAL, "lookup", naming.makeQualIdent(make().Type(syms().methodHandlesType), "Lookup"), make().Apply(null, naming.makeQuotedFQIdent("java.lang.invoke.MethodHandles.lookup"), List.<JCExpression>nil())));
    }
    JCSwitch swtch = make().Switch(make().Apply(null, naming.makeSelect(make().Apply(null, naming.makeSelect(make().TypeCast(make().Type(syms().ceylonMemberType), reference.makeIdent()), "getAttribute"), List.<JCExpression>nil()), "getQualifiedName"), List.<JCExpression>nil()), cases.toList());
    if (model.isMember() && !model.getExtendedType().getDeclaration().isMember()) {
        stmts.add(make().If(make().TypeTest(reference.makeIdent(), make().Type(syms().ceylonOuterType)), make().Return(expressionGen().makeOuterExpr(((TypeDeclaration) model.getContainer()).getType())), swtch));
    } else {
        stmts.add(swtch);
    }
    mdb.body(stmts.toList());
    classBuilder.method(mdb);
}
Also used : ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) SyntheticName(org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) Function(org.eclipse.ceylon.model.typechecker.model.Function) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) JCSwitch(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCSwitch) Value(org.eclipse.ceylon.model.typechecker.model.Value) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) MethodDeclaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) JCCase(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCCase)

Example 18 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class ClassTransformer method makeDelegateToCompanion.

/**
 * Generates a method which delegates to the companion instance $Foo$impl
 */
private MethodDefinitionBuilder makeDelegateToCompanion(Interface iface, Reference typedMember, Type currentType, final long mods, final java.util.List<TypeParameter> typeParameters, final java.util.List<java.util.List<Type>> producedTypeParameterBounds, final Type methodType, final String methodName, final java.util.List<Parameter> parameters, boolean typeErased, final String targetMethodName, Parameter defaultedParam, boolean includeBody) {
    final MethodDefinitionBuilder concreteWrapper = MethodDefinitionBuilder.systemMethod(gen(), methodName);
    concreteWrapper.modifiers(mods);
    concreteWrapper.ignoreModelAnnotations();
    if ((mods & PRIVATE) == 0) {
        concreteWrapper.isOverride(true);
    }
    if (typeParameters != null) {
        concreteWrapper.reifiedTypeParametersFromModel(typeParameters);
    }
    Iterator<java.util.List<Type>> iterator = producedTypeParameterBounds.iterator();
    if (typeParameters != null) {
        for (TypeParameter tp : typeParameters) {
            concreteWrapper.typeParameter(tp, iterator.next());
        }
    }
    boolean explicitReturn = false;
    Declaration member = (defaultedParam != null ? typedMember.getTypedParameter(defaultedParam) : typedMember).getDeclaration();
    Type returnType = null;
    if (!isAnything(methodType) || ((member instanceof Function || member instanceof Value) && !Decl.isUnboxedVoid(member)) || (member instanceof Function && Strategy.useBoxedVoid((Function) member))) {
        explicitReturn = true;
        if (CodegenUtil.isHashAttribute(member)) {
            // delegates for hash attributes are int
            concreteWrapper.resultType(new TransformedType(make().Type(syms().intType)));
            returnType = typedMember.getType();
        } else if (typedMember instanceof TypedReference && defaultedParam == null) {
            TypedReference typedRef = (TypedReference) typedMember;
            // This is very much like for method refinement: if the supertype is erased -> go raw.
            // Except for some reason we only need to do it with multiple inheritance with different type
            // arguments, so let's not go overboard
            int flags = 0;
            if (CodegenUtil.hasTypeErased((TypedDeclaration) member.getRefinedDeclaration()) || CodegenUtil.hasTypeErased((TypedDeclaration) member) && isInheritedTwiceWithDifferentTypeArguments(currentType, iface)) {
                flags |= AbstractTransformer.JT_RAW;
            }
            concreteWrapper.resultTypeNonWidening(currentType, typedRef, typedMember.getType(), flags);
            // FIXME: this is redundant with what we computed in the previous line in concreteWrapper.resultTypeNonWidening
            TypedReference nonWideningTypedRef = gen().nonWideningTypeDecl(typedRef, currentType);
            returnType = gen().nonWideningType(typedRef, nonWideningTypedRef);
        } else if (defaultedParam != null) {
            TypedReference typedParameter = typedMember.getTypedParameter(defaultedParam);
            NonWideningParam nonWideningParam = concreteWrapper.getNonWideningParam(typedParameter, currentType.getDeclaration() instanceof Class ? WideningRules.FOR_MIXIN : WideningRules.NONE);
            returnType = nonWideningParam.nonWideningType;
            if (member instanceof Function)
                returnType = typeFact().getCallableType(returnType);
            concreteWrapper.resultType(new TransformedType(makeJavaType(returnType, nonWideningParam.flags)));
        } else {
            concreteWrapper.resultType(new TransformedType(makeJavaType((Type) typedMember)));
            returnType = (Type) typedMember;
        }
    }
    ListBuffer<JCExpression> arguments = new ListBuffer<JCExpression>();
    if (typeParameters != null) {
        for (TypeParameter tp : typeParameters) {
            arguments.add(naming.makeUnquotedIdent(naming.getTypeArgumentDescriptorName(tp)));
        }
    }
    Declaration declaration = typedMember.getDeclaration();
    if (declaration instanceof Constructor && !Decl.isDefaultConstructor((Constructor) declaration) && defaultedParam == null) {
        concreteWrapper.parameter(makeConstructorNameParameter((Constructor) declaration));
        arguments.add(naming.makeUnquotedIdent(Unfix.$name$));
    }
    int ii = 0;
    for (Parameter param : parameters) {
        Parameter parameter;
        if (declaration instanceof Functional) {
            parameter = ((Functional) declaration).getFirstParameterList().getParameters().get(ii++);
        } else if (declaration instanceof Setter) {
            parameter = ((Setter) declaration).getParameter();
        } else {
            throw BugException.unhandledDeclarationCase(declaration);
        }
        final TypedReference typedParameter = typedMember.getTypedParameter(parameter);
        concreteWrapper.parameter(null, param, typedParameter, null, FINAL, WideningRules.FOR_MIXIN);
        arguments.add(naming.makeName(param.getModel(), Naming.NA_MEMBER | Naming.NA_ALIASED));
    }
    if (includeBody) {
        JCExpression qualifierThis = makeUnquotedIdent(getCompanionFieldName(iface));
        // our impl accessor to get the expected bounds of the qualifying type
        if (explicitReturn) {
            Type javaType = getBestSatisfiedType(currentType, iface);
            Type ceylonType = typedMember.getQualifyingType();
            // don't even bother if the impl accessor is turned to raw because casting it to raw doesn't help
            if (!isTurnedToRaw(ceylonType) && // if it's exactly the same we don't need any cast
            !javaType.isExactly(ceylonType))
                // this will add the proper cast to the impl accessor
                qualifierThis = expressionGen().applyErasureAndBoxing(qualifierThis, currentType, false, true, BoxingStrategy.BOXED, ceylonType, ExpressionTransformer.EXPR_WANTS_COMPANION);
        }
        JCExpression expr = make().Apply(// TODO Type args
        null, makeSelect(qualifierThis, (targetMethodName != null) ? targetMethodName : methodName), arguments.toList());
        if (isUnimplementedMemberClass(currentType, typedMember)) {
            concreteWrapper.body(makeThrowUnresolvedCompilationError(// TODO encapsulate the error message
            "formal member '" + declaration.getName() + "' of '" + iface.getName() + "' not implemented in class hierarchy"));
            current().broken();
        } else if (!explicitReturn) {
            concreteWrapper.body(gen().make().Exec(expr));
        } else {
            // deal with erasure and stuff
            BoxingStrategy boxingStrategy;
            boolean exprBoxed;
            if (member instanceof TypedDeclaration) {
                TypedDeclaration typedDecl = (TypedDeclaration) member;
                exprBoxed = !CodegenUtil.isUnBoxed(typedDecl);
                boxingStrategy = CodegenUtil.getBoxingStrategy(typedDecl);
            } else {
                // must be a class or interface
                exprBoxed = true;
                boxingStrategy = BoxingStrategy.UNBOXED;
            }
            // to force an additional cast
            if (isTurnedToRaw(typedMember.getQualifyingType()) || // in invariant locations
            needsRawCastForMixinSuperCall(iface, methodType) || needsCastForErasedInstantiator(iface, methodName, member))
                typeErased = true;
            expr = gen().expressionGen().applyErasureAndBoxing(expr, methodType, typeErased, exprBoxed, boxingStrategy, returnType, 0);
            concreteWrapper.body(gen().make().Return(expr));
        }
    }
    return concreteWrapper;
}
Also used : TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) NonWideningParam(org.eclipse.ceylon.compiler.java.codegen.MethodDefinitionBuilder.NonWideningParam) TypedReference(org.eclipse.ceylon.model.typechecker.model.TypedReference) ThrowerCatchallConstructor(org.eclipse.ceylon.compiler.java.codegen.recovery.ThrowerCatchallConstructor) Constructor(org.eclipse.ceylon.model.typechecker.model.Constructor) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) Functional(org.eclipse.ceylon.model.typechecker.model.Functional) Function(org.eclipse.ceylon.model.typechecker.model.Function) Type(org.eclipse.ceylon.model.typechecker.model.Type) JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) Value(org.eclipse.ceylon.model.typechecker.model.Value) FunctionOrValue(org.eclipse.ceylon.model.typechecker.model.FunctionOrValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) Setter(org.eclipse.ceylon.model.typechecker.model.Setter) Parameter(org.eclipse.ceylon.model.typechecker.model.Parameter) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) ArrayList(java.util.ArrayList) AnnotationList(org.eclipse.ceylon.compiler.typechecker.tree.Tree.AnnotationList) List(org.eclipse.ceylon.langtools.tools.javac.util.List) ParameterList(org.eclipse.ceylon.model.typechecker.model.ParameterList) Class(org.eclipse.ceylon.model.typechecker.model.Class) JCNewClass(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) MethodDeclaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration)

Example 19 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class ClassTransformer method serializationReferences.

/**
 * <p>Generates the {@code $deserialize$()} method to deserialize
 * the classes state, which:</p>
 * <ul>
 * <li>invokes {@code super.$deserialize$()}, if the super class is also
 *     serializable,</li>
 * <li>assigns each reified type argument in the
 *     class by invoking {@code dted.getTypeArgument()},</li>
 * <li>assigns each field in the
 *     class by invoking {@code dted.getValue()}.</li>
 * </ul>
 */
private void serializationReferences(Class model, ClassDefinitionBuilder classBuilder) {
    MethodDefinitionBuilder mdb = MethodDefinitionBuilder.systemMethod(this, Unfix.$references$.toString());
    mdb.isOverride(true);
    mdb.ignoreModelAnnotations();
    mdb.modifiers(PUBLIC);
    mdb.resultType(new TransformedType(make().TypeApply(naming.makeQuotedFQIdent("java.util.Collection"), List.<JCExpression>of(make().Type(syms().ceylonReachableReferenceType))), null, makeAtNonNull()));
    ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
    // TODO this is all static information, but the method itself needs to be
    // callable virtually, so we should cache it somehow.
    SyntheticName r = naming.synthetic(Unfix.reference);
    if (extendsSerializable(model)) {
        // prepend the invocation of super.$serialize$()
        stmts.add(makeVar(r, make().TypeApply(naming.makeQuotedFQIdent("java.util.Collection"), List.<JCExpression>of(make().Type(syms().ceylonReachableReferenceType))), make().Apply(null, naming.makeQualIdent(naming.makeSuper(), Unfix.$references$.toString()), List.<JCExpression>nil())));
    } else {
        stmts.add(makeVar(r, make().TypeApply(naming.makeQuotedFQIdent("java.util.Collection"), List.<JCExpression>of(make().Type(syms().ceylonReachableReferenceType))), make().NewClass(null, null, make().TypeApply(naming.makeQuotedFQIdent("java.util.ArrayList"), List.<JCExpression>of(make().Type(syms().ceylonReachableReferenceType))), List.<JCExpression>nil(), null)));
    }
    if (model.isMember()) {
        JCExpressionStatement outer = make().Exec(make().Apply(null, naming.makeQualIdent(r.makeIdent(), "add"), List.<JCExpression>of(make().Apply(null, naming.makeQualIdent(make().Type(syms().ceylonOuterImplType), "get_"), List.<JCExpression>nil()))));
        stmts.add(outer);
    }
    for (Declaration member : model.getMembers()) {
        if (hasField(member)) {
            // Obtain a ValueDeclaration
            JCExpression valueDeclaration = expressionGen().makeMemberValueOrFunctionDeclarationLiteral(null, member, false);
            // Create a MemberImpl
            JCExpression mi = make().NewClass(null, null, make().QualIdent(syms().ceylonMemberImplType.tsym), List.of(valueDeclaration), null);
            JCExpressionStatement attribute = make().Exec(make().Apply(null, naming.makeQualIdent(r.makeIdent(), "add"), List.of(mi)));
            stmts.add(attribute);
        }
    }
    stmts.add(make().Return(r.makeIdent()));
    mdb.body(stmts.toList());
    classBuilder.method(mdb);
}
Also used : JCExpression(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) SyntheticName(org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) Declaration(org.eclipse.ceylon.model.typechecker.model.Declaration) TypedDeclaration(org.eclipse.ceylon.model.typechecker.model.TypedDeclaration) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) MethodDeclaration(org.eclipse.ceylon.compiler.typechecker.tree.Tree.MethodDeclaration) JCExpressionStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpressionStatement)

Example 20 with ListBuffer

use of org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer in project ceylon by eclipse.

the class ClassTransformer method transform.

public List<JCTree> transform(final Tree.ClassOrInterface def) {
    final ClassOrInterface model = def.getDeclarationModel();
    if (model.isToplevel() && isEe(model)) {
        replaceModifierTransformation(new EeModifierTransformation());
    }
    // in that case
    if (model.isAlias() && Decl.isAncestorLocal(model))
        return List.nil();
    naming.clearSubstitutions(model);
    final String javaClassName;
    String ceylonClassName = def.getIdentifier().getText();
    if (def instanceof Tree.AnyInterface) {
        javaClassName = naming.makeTypeDeclarationName(model, QUALIFIED).replaceFirst(".*\\.", "");
    } else {
        javaClassName = Naming.quoteClassName(ceylonClassName);
    }
    ClassDefinitionBuilder instantiatorImplCb;
    ClassDefinitionBuilder instantiatorDeclCb;
    if (model.isInterfaceMember()) {
        instantiatorImplCb = gen().current().getCompanionBuilder((Interface) model.getContainer());
        instantiatorDeclCb = gen().current();
    } else {
        instantiatorImplCb = gen().current();
        instantiatorDeclCb = null;
    }
    ClassDefinitionBuilder classBuilder = ClassDefinitionBuilder.klass(this, javaClassName, ceylonClassName, Decl.isLocal(model)).forDefinition(model).hasDelegatingConstructors(CodegenUtil.hasDelegatingConstructors(def));
    classBuilder.getInitBuilder().deprecated(model.isDeprecated());
    // Very special case for Anything
    if (model.isAnything()) {
        classBuilder.extending(model.getType(), null);
    }
    if (def instanceof Tree.AnyClass) {
        classBuilder.getInitBuilder().modifiers(modifierTransformation().constructor(model));
        Tree.AnyClass classDef = (Tree.AnyClass) def;
        Class cls = classDef.getDeclarationModel();
        // Member classes need a instantiator method
        boolean generateInstantiator = Strategy.generateInstantiator(cls);
        if (!cls.hasConstructors()) {
            classBuilder.getInitBuilder().userAnnotations(expressionGen().transformAnnotations(OutputElement.CONSTRUCTOR, def));
        }
        if (generateInstantiator && !cls.hasConstructors() && !cls.hasEnumerated()) {
            if (!cls.isStatic()) {
                classBuilder.getInitBuilder().modifiers(PROTECTED);
            }
            generateInstantiators(classBuilder, cls, null, instantiatorDeclCb, instantiatorImplCb, classDef, classDef.getParameterList());
        }
        classBuilder.annotations(expressionGen().transformAnnotations(OutputElement.TYPE, def));
        if (def instanceof Tree.ClassDefinition) {
            transformClass((Tree.ClassDefinition) def, cls, classBuilder, classDef.getParameterList(), generateInstantiator, instantiatorDeclCb, instantiatorImplCb);
        } else {
            // class alias
            classBuilder.getInitBuilder().modifiers(PRIVATE);
            transformClassAlias((Tree.ClassDeclaration) def, classBuilder);
        }
        addMissingUnrefinedMembers(def, cls, classBuilder);
    }
    if (def instanceof Tree.AnyInterface) {
        classBuilder.annotations(expressionGen().transformAnnotations(OutputElement.TYPE, def));
        if (def instanceof Tree.InterfaceDefinition) {
            transformInterface(def, (Interface) model, classBuilder);
        } else {
            // interface alias
            classBuilder.annotations(makeAtAlias(model.getExtendedType(), null));
            classBuilder.isAlias(true);
        }
        classBuilder.isDynamic(model.isDynamic());
    }
    // make sure we set the container in case we move it out
    addAtContainer(classBuilder, model);
    transformTypeParameters(classBuilder, model);
    // Transform the class/interface members
    List<JCStatement> childDefs = visitClassOrInterfaceDefinition(def, classBuilder);
    // everything else is synthetic
    at(null);
    TransformationPlan plan = errors().hasDeclarationError(def);
    if (plan instanceof ThrowerCatchallConstructor) {
        classBuilder.broken();
        MethodDefinitionBuilder initBuilder = classBuilder.noInitConstructor().addConstructor(model.isDeprecated());
        initBuilder.body(statementGen().makeThrowUnresolvedCompilationError(plan.getErrorMessage().getMessage()));
        // Although we have the class pl which we could use we don't know
        // that it won't collide with the default named constructor's pl
        // which would cause a javac error about two constructors with the same sig
        // so we generate a Object... here. There's still a risk of collision though
        // when the default constructor has pl (ObjectArray).
        ParameterDefinitionBuilder pdb = ParameterDefinitionBuilder.implicitParameter(this, "ignored");
        pdb.modifiers(VARARGS);
        pdb.type(new TransformedType(make().TypeArray(make().Type(syms().objectType))));
        initBuilder.parameter(pdb);
    } else if (plan instanceof PrivateConstructorOnly) {
        classBuilder.broken();
        MethodDefinitionBuilder initBuilder = classBuilder.noInitConstructor().addConstructor(model.isDeprecated());
        initBuilder.body(statementGen().makeThrowUnresolvedCompilationError(plan.getErrorMessage().getMessage()));
        initBuilder.modifiers(PRIVATE);
    }
    // If it's a Class without initializer parameters...
    if (Strategy.generateMain(def)) {
        // ... then add a main() method
        classBuilder.method(makeMainForClass(model));
    }
    classBuilder.modelAnnotations(model.getAnnotations()).modifiers(modifierTransformation().classFlags(model)).satisfies(model.getSatisfiedTypes()).caseTypes(model.getCaseTypes(), model.getSelfType()).defs(childDefs);
    // aliases and native headers don't need a $getType method
    if (!model.isAlias()) {
        // only classes get a $getType method
        if (model instanceof Class)
            classBuilder.addGetTypeMethod(model.getType());
        if (supportsReifiedAlias(model))
            classBuilder.reifiedAlias(model.getType());
    }
    // we can add things which depend on knowing all the fields
    if (Strategy.generateJpaCtor(model) && plan instanceof Generate) {
        buildJpaConstructor((Class) model, classBuilder);
    }
    if (model instanceof Class && !(model instanceof ClassAlias) && plan instanceof Generate) {
        Class c = (Class) model;
        if (Strategy.introduceJavaIoSerializable(c, typeFact().getJavaIoSerializable())) {
            classBuilder.introduce(make().QualIdent(syms().serializableType.tsym));
            if (Strategy.useSerializationProxy(c) && noValueConstructorErrors((Tree.ClassDefinition) def)) {
                at(def);
                addWriteReplace(c, classBuilder);
            }
        }
        serialization(c, classBuilder);
    }
    // reset position before initializer constructor is generated.
    at(def);
    classBuilder.at(def);
    List<JCTree> result;
    if (Decl.isAnnotationClass(def.getDeclarationModel())) {
        ListBuffer<JCTree> trees = new ListBuffer<JCTree>();
        trees.addAll(transformAnnotationClass((Tree.AnyClass) def));
        transformAnnotationClassConstructor((Tree.AnyClass) def, classBuilder);
        // you only need that method if you satisfy Annotation which is erased to j.l.a.Annotation
        if (model.inherits(typeFact().getAnnotationDeclaration()))
            classBuilder.addAnnotationTypeMethod(model.getType());
        trees.addAll(classBuilder.build());
        result = trees.toList();
    } else {
        result = classBuilder.build();
    }
    if (model.isToplevel() && isEe(model)) {
        replaceModifierTransformation(new ModifierTransformation());
    }
    return result;
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) ClassAlias(org.eclipse.ceylon.model.typechecker.model.ClassAlias) ListBuffer(org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer) JCStatement(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement) PrivateConstructorOnly(org.eclipse.ceylon.compiler.java.codegen.recovery.PrivateConstructorOnly) Generate(org.eclipse.ceylon.compiler.java.codegen.recovery.Generate) JCPrimitiveTypeTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) Tree(org.eclipse.ceylon.compiler.typechecker.tree.Tree) JCTree(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree) ThrowerCatchallConstructor(org.eclipse.ceylon.compiler.java.codegen.recovery.ThrowerCatchallConstructor) Class(org.eclipse.ceylon.model.typechecker.model.Class) JCNewClass(org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass) Interface(org.eclipse.ceylon.model.typechecker.model.Interface) ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) LazyInterface(org.eclipse.ceylon.model.loader.model.LazyInterface) TransformationPlan(org.eclipse.ceylon.compiler.java.codegen.recovery.TransformationPlan)

Aggregations

ListBuffer (org.eclipse.ceylon.langtools.tools.javac.util.ListBuffer)67 JCExpression (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCExpression)53 JCTree (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree)30 Type (org.eclipse.ceylon.model.typechecker.model.Type)23 JCStatement (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCStatement)22 Tree (org.eclipse.ceylon.compiler.typechecker.tree.Tree)20 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)16 TypedDeclaration (org.eclipse.ceylon.model.typechecker.model.TypedDeclaration)16 Parameter (org.eclipse.ceylon.model.typechecker.model.Parameter)15 Declaration (org.eclipse.ceylon.model.typechecker.model.Declaration)14 JCAnnotation (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCAnnotation)13 JCNewClass (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCNewClass)12 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)12 SyntheticName (org.eclipse.ceylon.compiler.java.codegen.Naming.SyntheticName)11 Function (org.eclipse.ceylon.model.typechecker.model.Function)10 Class (org.eclipse.ceylon.model.typechecker.model.Class)9 JCTypeParameter (org.eclipse.ceylon.langtools.tools.javac.tree.JCTree.JCTypeParameter)8 FunctionOrValue (org.eclipse.ceylon.model.typechecker.model.FunctionOrValue)8 UnionType (org.eclipse.ceylon.model.typechecker.model.UnionType)8 ClassOrInterface (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface)7