Search in sources :

Example 1 with JCPrimitiveTypeTree

use of com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree in project lombok by rzwitserloot.

the class HandleBuilder method handle.

@Override
public void handle(AnnotationValues<Builder> annotation, JCAnnotation ast, JavacNode annotationNode) {
    Builder builderInstance = annotation.getInstance();
    // These exist just to support the 'old' lombok.experimental.Builder, which had these properties. lombok.Builder no longer has them.
    boolean fluent = toBoolean(annotation.getActualExpression("fluent"), true);
    boolean chain = toBoolean(annotation.getActualExpression("chain"), true);
    String builderMethodName = builderInstance.builderMethodName();
    String buildMethodName = builderInstance.buildMethodName();
    String builderClassName = builderInstance.builderClassName();
    String toBuilderMethodName = "toBuilder";
    boolean toBuilder = builderInstance.toBuilder();
    java.util.List<Name> typeArgsForToBuilder = null;
    if (builderMethodName == null)
        builderMethodName = "builder";
    if (buildMethodName == null)
        buildMethodName = "build";
    if (builderClassName == null)
        builderClassName = "";
    if (!checkName("builderMethodName", builderMethodName, annotationNode))
        return;
    if (!checkName("buildMethodName", buildMethodName, annotationNode))
        return;
    if (!builderClassName.isEmpty()) {
        if (!checkName("builderClassName", builderClassName, annotationNode))
            return;
    }
    @SuppressWarnings("deprecation") Class<? extends Annotation> oldExperimentalBuilder = lombok.experimental.Builder.class;
    deleteAnnotationIfNeccessary(annotationNode, Builder.class, oldExperimentalBuilder);
    JavacNode parent = annotationNode.up();
    java.util.List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>();
    JCExpression returnType;
    List<JCTypeParameter> typeParams = List.nil();
    List<JCExpression> thrownExceptions = List.nil();
    Name nameOfBuilderMethod;
    JavacNode tdParent;
    JavacNode fillParametersFrom = parent.get() instanceof JCMethodDecl ? parent : null;
    boolean addCleaning = false;
    boolean isStatic = true;
    if (parent.get() instanceof JCClassDecl) {
        tdParent = parent;
        JCClassDecl td = (JCClassDecl) tdParent.get();
        ListBuffer<JavacNode> allFields = new ListBuffer<JavacNode>();
        @SuppressWarnings("deprecation") boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation(lombok.experimental.Value.class, parent));
        for (JavacNode fieldNode : HandleConstructor.findAllFields(tdParent)) {
            JCVariableDecl fd = (JCVariableDecl) fieldNode.get();
            // Value will only skip making a field final if it has an explicit @NonFinal annotation, so we check for that.
            if (fd.init != null && valuePresent && !hasAnnotation(NonFinal.class, fieldNode))
                continue;
            BuilderFieldData bfd = new BuilderFieldData();
            bfd.rawName = fd.name;
            bfd.name = removePrefixFromField(fieldNode);
            bfd.type = fd.vartype;
            bfd.singularData = getSingularData(fieldNode);
            addObtainVia(bfd, fieldNode);
            builderFields.add(bfd);
            allFields.append(fieldNode);
        }
        new HandleConstructor().generateConstructor(tdParent, AccessLevel.PACKAGE, List.<JCAnnotation>nil(), allFields.toList(), false, null, SkipIfConstructorExists.I_AM_BUILDER, annotationNode);
        returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams);
        typeParams = td.typarams;
        thrownExceptions = List.nil();
        nameOfBuilderMethod = null;
        if (builderClassName.isEmpty())
            builderClassName = td.name.toString() + "Builder";
    } else if (fillParametersFrom != null && fillParametersFrom.getName().toString().equals("<init>")) {
        JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get();
        if (!jmd.typarams.isEmpty()) {
            annotationNode.addError("@Builder is not supported on constructors with constructor type parameters.");
            return;
        }
        tdParent = parent.up();
        JCClassDecl td = (JCClassDecl) tdParent.get();
        returnType = namePlusTypeParamsToTypeReference(tdParent.getTreeMaker(), td.name, td.typarams);
        typeParams = td.typarams;
        thrownExceptions = jmd.thrown;
        nameOfBuilderMethod = null;
        if (builderClassName.isEmpty())
            builderClassName = td.name.toString() + "Builder";
    } else if (fillParametersFrom != null) {
        tdParent = parent.up();
        JCClassDecl td = (JCClassDecl) tdParent.get();
        JCMethodDecl jmd = (JCMethodDecl) fillParametersFrom.get();
        isStatic = (jmd.mods.flags & Flags.STATIC) != 0;
        JCExpression fullReturnType = jmd.restype;
        returnType = fullReturnType;
        typeParams = jmd.typarams;
        thrownExceptions = jmd.thrown;
        nameOfBuilderMethod = jmd.name;
        if (returnType instanceof JCTypeApply) {
            returnType = ((JCTypeApply) returnType).clazz;
        }
        if (builderClassName.isEmpty()) {
            if (returnType instanceof JCFieldAccess) {
                builderClassName = ((JCFieldAccess) returnType).name.toString() + "Builder";
            } else if (returnType instanceof JCIdent) {
                Name n = ((JCIdent) returnType).name;
                for (JCTypeParameter tp : typeParams) {
                    if (tp.name.equals(n)) {
                        annotationNode.addError("@Builder requires specifying 'builderClassName' if used on methods with a type parameter as return type.");
                        return;
                    }
                }
                builderClassName = n.toString() + "Builder";
            } else if (returnType instanceof JCPrimitiveTypeTree) {
                builderClassName = returnType.toString() + "Builder";
                if (Character.isLowerCase(builderClassName.charAt(0))) {
                    builderClassName = Character.toTitleCase(builderClassName.charAt(0)) + builderClassName.substring(1);
                }
            } else {
                // This shouldn't happen.
                System.err.println("Lombok bug ID#20140614-1651: javac HandleBuilder: return type to name conversion failed: " + returnType.getClass());
                builderClassName = td.name.toString() + "Builder";
            }
        }
        if (toBuilder) {
            final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type.";
            if (returnType instanceof JCArrayTypeTree) {
                annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
                return;
            }
            Name simpleName;
            String pkg;
            List<JCExpression> tpOnRet = List.nil();
            if (fullReturnType instanceof JCTypeApply) {
                tpOnRet = ((JCTypeApply) fullReturnType).arguments;
            }
            if (returnType instanceof JCIdent) {
                simpleName = ((JCIdent) returnType).name;
                pkg = null;
            } else if (returnType instanceof JCFieldAccess) {
                JCFieldAccess jcfa = (JCFieldAccess) returnType;
                simpleName = jcfa.name;
                pkg = unpack(jcfa.selected);
                if (pkg.startsWith("ERR:")) {
                    String err = pkg.substring(4, pkg.indexOf("__ERR__"));
                    annotationNode.addError(err);
                    return;
                }
            } else {
                annotationNode.addError("Expected a (parameterized) type here instead of a " + returnType.getClass().getName());
                return;
            }
            if (pkg != null && !parent.getPackageDeclaration().equals(pkg)) {
                annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
                return;
            }
            if (!tdParent.getName().contentEquals(simpleName)) {
                annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
                return;
            }
            List<JCTypeParameter> tpOnMethod = jmd.typarams;
            List<JCTypeParameter> tpOnType = ((JCClassDecl) tdParent.get()).typarams;
            typeArgsForToBuilder = new ArrayList<Name>();
            for (JCTypeParameter tp : tpOnMethod) {
                int pos = -1;
                int idx = -1;
                for (JCExpression tOnRet : tpOnRet) {
                    idx++;
                    if (!(tOnRet instanceof JCIdent))
                        continue;
                    if (((JCIdent) tOnRet).name != tp.name)
                        continue;
                    pos = idx;
                }
                if (pos == -1 || tpOnType.size() <= pos) {
                    annotationNode.addError("@Builder(toBuilder=true) requires that each type parameter on the static method is part of the typeargs of the return value. Type parameter " + tp.name + " is not part of the return type.");
                    return;
                }
                typeArgsForToBuilder.add(tpOnType.get(pos).name);
            }
        }
    } else {
        annotationNode.addError("@Builder is only supported on types, constructors, and methods.");
        return;
    }
    if (fillParametersFrom != null) {
        for (JavacNode param : fillParametersFrom.down()) {
            if (param.getKind() != Kind.ARGUMENT)
                continue;
            BuilderFieldData bfd = new BuilderFieldData();
            JCVariableDecl raw = (JCVariableDecl) param.get();
            bfd.name = raw.name;
            bfd.rawName = raw.name;
            bfd.type = raw.vartype;
            bfd.singularData = getSingularData(param);
            addObtainVia(bfd, param);
            builderFields.add(bfd);
        }
    }
    JavacNode builderType = findInnerClass(tdParent, builderClassName);
    if (builderType == null) {
        builderType = makeBuilderClass(isStatic, annotationNode, tdParent, builderClassName, typeParams, ast);
    } else {
        JCClassDecl builderTypeDeclaration = (JCClassDecl) builderType.get();
        if (isStatic && !builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) {
            annotationNode.addError("Existing Builder must be a static inner class.");
            return;
        } else if (!isStatic && builderTypeDeclaration.getModifiers().getFlags().contains(Modifier.STATIC)) {
            annotationNode.addError("Existing Builder must be a non-static inner class.");
            return;
        }
        sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode);
        /* generate errors for @Singular BFDs that have one already defined node. */
        {
            for (BuilderFieldData bfd : builderFields) {
                SingularData sd = bfd.singularData;
                if (sd == null)
                    continue;
                JavacSingularizer singularizer = sd.getSingularizer();
                if (singularizer == null)
                    continue;
                if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) {
                    bfd.singularData = null;
                }
            }
        }
    }
    for (BuilderFieldData bfd : builderFields) {
        if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
            if (bfd.singularData.getSingularizer().requiresCleaning()) {
                addCleaning = true;
                break;
            }
        }
        if (bfd.obtainVia != null) {
            if (bfd.obtainVia.field().isEmpty() == bfd.obtainVia.method().isEmpty()) {
                bfd.obtainViaNode.addError("The syntax is either @ObtainVia(field = \"fieldName\") or @ObtainVia(method = \"methodName\").");
                return;
            }
            if (bfd.obtainVia.method().isEmpty() && bfd.obtainVia.isStatic()) {
                bfd.obtainViaNode.addError("@ObtainVia(isStatic = true) is not valid unless 'method' has been set.");
                return;
            }
        }
    }
    generateBuilderFields(builderType, builderFields, ast);
    if (addCleaning) {
        JavacTreeMaker maker = builderType.getTreeMaker();
        JCVariableDecl uncleanField = maker.VarDef(maker.Modifiers(Flags.PRIVATE), builderType.toName("$lombokUnclean"), maker.TypeIdent(CTC_BOOLEAN), null);
        injectFieldAndMarkGenerated(builderType, uncleanField);
    }
    if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) {
        JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, List.<JCAnnotation>nil(), builderType, List.<JavacNode>nil(), false, annotationNode);
        if (cd != null)
            injectMethod(builderType, cd);
    }
    for (BuilderFieldData bfd : builderFields) {
        makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain);
    }
    if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) {
        JCMethodDecl md = generateBuildMethod(isStatic, buildMethodName, nameOfBuilderMethod, returnType, builderFields, builderType, thrownExceptions, ast, addCleaning);
        if (md != null)
            injectMethod(builderType, md);
    }
    if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) {
        java.util.List<JavacNode> fieldNodes = new ArrayList<JavacNode>();
        for (BuilderFieldData bfd : builderFields) {
            fieldNodes.addAll(bfd.createdFields);
        }
        JCMethodDecl md = HandleToString.createToString(builderType, fieldNodes, true, false, FieldAccess.ALWAYS_FIELD, ast);
        if (md != null)
            injectMethod(builderType, md);
    }
    if (addCleaning)
        injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast));
    if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) {
        JCMethodDecl md = generateBuilderMethod(isStatic, builderMethodName, builderClassName, annotationNode, tdParent, typeParams);
        recursiveSetGeneratedBy(md, ast, annotationNode.getContext());
        if (md != null)
            injectMethod(tdParent, md);
    }
    if (toBuilder) {
        switch(methodExists(toBuilderMethodName, tdParent, 0)) {
            case EXISTS_BY_USER:
                annotationNode.addWarning("Not generating toBuilder() as it already exists.");
                return;
            case NOT_EXISTS:
                List<JCTypeParameter> tps = typeParams;
                if (typeArgsForToBuilder != null) {
                    ListBuffer<JCTypeParameter> lb = new ListBuffer<JCTypeParameter>();
                    JavacTreeMaker maker = tdParent.getTreeMaker();
                    for (Name n : typeArgsForToBuilder) {
                        lb.append(maker.TypeParameter(n, List.<JCExpression>nil()));
                    }
                    tps = lb.toList();
                }
                JCMethodDecl md = generateToBuilderMethod(toBuilderMethodName, builderClassName, tdParent, tps, builderFields, fluent, ast);
                if (md != null)
                    injectMethod(tdParent, md);
        }
    }
    recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext());
}
Also used : JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) Builder(lombok.Builder) ListBuffer(com.sun.tools.javac.util.ListBuffer) ArrayList(java.util.ArrayList) JCTypeApply(com.sun.tools.javac.tree.JCTree.JCTypeApply) JavacSingularizer(lombok.javac.handlers.JavacSingularsRecipes.JavacSingularizer) Name(com.sun.tools.javac.util.Name) JCPrimitiveTypeTree(com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JavacNode(lombok.javac.JavacNode) JCArrayTypeTree(com.sun.tools.javac.tree.JCTree.JCArrayTypeTree) JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JCIdent(com.sun.tools.javac.tree.JCTree.JCIdent) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JavacTreeMaker(lombok.javac.JavacTreeMaker) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) JCTypeParameter(com.sun.tools.javac.tree.JCTree.JCTypeParameter) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) SingularData(lombok.javac.handlers.JavacSingularsRecipes.SingularData)

Example 2 with JCPrimitiveTypeTree

use of com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree in project lombok by rzwitserloot.

the class HandleBuilder method generateBuildMethod.

private JCMethodDecl generateBuildMethod(boolean isStatic, String buildName, Name builderName, JCExpression returnType, java.util.List<BuilderFieldData> builderFields, JavacNode type, List<JCExpression> thrownExceptions, JCTree source, boolean addCleaning) {
    JavacTreeMaker maker = type.getTreeMaker();
    JCExpression call;
    ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
    if (addCleaning) {
        JCExpression notClean = maker.Unary(CTC_NOT, maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")));
        JCStatement invokeClean = maker.Exec(maker.Apply(List.<JCExpression>nil(), maker.Ident(type.toName("$lombokClean")), List.<JCExpression>nil()));
        JCIf ifUnclean = maker.If(notClean, invokeClean, null);
        statements.append(ifUnclean);
    }
    for (BuilderFieldData bfd : builderFields) {
        if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
            bfd.singularData.getSingularizer().appendBuildCode(bfd.singularData, type, source, statements, bfd.name);
        }
    }
    ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
    for (BuilderFieldData bfd : builderFields) {
        args.append(maker.Ident(bfd.name));
    }
    if (addCleaning) {
        statements.append(maker.Exec(maker.Assign(maker.Select(maker.Ident(type.toName("this")), type.toName("$lombokUnclean")), maker.Literal(CTC_BOOLEAN, true))));
    }
    if (builderName == null) {
        call = maker.NewClass(null, List.<JCExpression>nil(), returnType, args.toList(), null);
        statements.append(maker.Return(call));
    } else {
        ListBuffer<JCExpression> typeParams = new ListBuffer<JCExpression>();
        for (JCTypeParameter tp : ((JCClassDecl) type.get()).typarams) {
            typeParams.append(maker.Ident(tp.name));
        }
        JCExpression callee = maker.Ident(((JCClassDecl) type.up().get()).name);
        if (!isStatic)
            callee = maker.Select(callee, type.up().toName("this"));
        JCExpression fn = maker.Select(callee, builderName);
        call = maker.Apply(typeParams.toList(), fn, args.toList());
        if (returnType instanceof JCPrimitiveTypeTree && CTC_VOID.equals(typeTag(returnType))) {
            statements.append(maker.Exec(call));
        } else {
            statements.append(maker.Return(call));
        }
    }
    JCBlock body = maker.Block(0, statements.toList());
    return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName(buildName), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null);
}
Also used : JCTypeParameter(com.sun.tools.javac.tree.JCTree.JCTypeParameter) JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JCPrimitiveTypeTree(com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCBlock(com.sun.tools.javac.tree.JCTree.JCBlock) JavacTreeMaker(lombok.javac.JavacTreeMaker) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCIf(com.sun.tools.javac.tree.JCTree.JCIf) ListBuffer(com.sun.tools.javac.util.ListBuffer) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement)

Example 3 with JCPrimitiveTypeTree

use of com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree in project lombok by rzwitserloot.

the class HandleEqualsAndHashCode method createHashCode.

public JCMethodDecl createHashCode(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, JCTree source) {
    JavacTreeMaker maker = typeNode.getTreeMaker();
    JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil());
    JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation));
    JCExpression returnType = maker.TypeIdent(CTC_INT);
    ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
    Name primeName = typeNode.toName(PRIME_NAME);
    Name resultName = typeNode.toName(RESULT_NAME);
    long finalFlag = JavacHandlerUtil.addFinalIfNeeded(0L, typeNode.getContext());
    /* final int PRIME = X; */
    {
        if (!fields.isEmpty() || callSuper) {
            statements.append(maker.VarDef(maker.Modifiers(finalFlag), primeName, maker.TypeIdent(CTC_INT), maker.Literal(HandlerUtil.primeForHashcode())));
        }
    }
    /* int result = 1; */
    {
        statements.append(maker.VarDef(maker.Modifiers(0), resultName, maker.TypeIdent(CTC_INT), maker.Literal(1)));
    }
    if (callSuper) {
        JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("hashCode")), List.<JCExpression>nil());
        statements.append(createResultCalculation(typeNode, callToSuper));
    }
    Name dollar = typeNode.toName("$");
    for (JavacNode fieldNode : fields) {
        JCExpression fType = getFieldType(fieldNode, fieldAccess);
        JCExpression fieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
        if (fType instanceof JCPrimitiveTypeTree) {
            switch(((JCPrimitiveTypeTree) fType).getPrimitiveTypeKind()) {
                case BOOLEAN:
                    /* this.fieldName ? X : Y */
                    statements.append(createResultCalculation(typeNode, maker.Parens(maker.Conditional(fieldAccessor, maker.Literal(HandlerUtil.primeForTrue()), maker.Literal(HandlerUtil.primeForFalse())))));
                    break;
                case LONG:
                    {
                        Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
                        statements.append(maker.VarDef(maker.Modifiers(finalFlag), dollarFieldName, maker.TypeIdent(CTC_LONG), fieldAccessor));
                        statements.append(createResultCalculation(typeNode, longToIntForHashCode(maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName))));
                    }
                    break;
                case FLOAT:
                    /* Float.floatToIntBits(this.fieldName) */
                    statements.append(createResultCalculation(typeNode, maker.Apply(List.<JCExpression>nil(), genJavaLangTypeRef(typeNode, "Float", "floatToIntBits"), List.of(fieldAccessor))));
                    break;
                case DOUBLE:
                    {
                        /* longToIntForHashCode(Double.doubleToLongBits(this.fieldName)) */
                        Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
                        JCExpression init = maker.Apply(List.<JCExpression>nil(), genJavaLangTypeRef(typeNode, "Double", "doubleToLongBits"), List.of(fieldAccessor));
                        statements.append(maker.VarDef(maker.Modifiers(finalFlag), dollarFieldName, maker.TypeIdent(CTC_LONG), init));
                        statements.append(createResultCalculation(typeNode, longToIntForHashCode(maker, maker.Ident(dollarFieldName), maker.Ident(dollarFieldName))));
                    }
                    break;
                default:
                case BYTE:
                case SHORT:
                case INT:
                case CHAR:
                    /* just the field */
                    statements.append(createResultCalculation(typeNode, fieldAccessor));
                    break;
            }
        } else if (fType instanceof JCArrayTypeTree) {
            /* java.util.Arrays.deepHashCode(this.fieldName) //use just hashCode() for primitive arrays. */
            boolean multiDim = ((JCArrayTypeTree) fType).elemtype instanceof JCArrayTypeTree;
            boolean primitiveArray = ((JCArrayTypeTree) fType).elemtype instanceof JCPrimitiveTypeTree;
            boolean useDeepHC = multiDim || !primitiveArray;
            JCExpression hcMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepHC ? "deepHashCode" : "hashCode");
            statements.append(createResultCalculation(typeNode, maker.Apply(List.<JCExpression>nil(), hcMethod, List.of(fieldAccessor))));
        } else /* objects */
        {
            /* final java.lang.Object $fieldName = this.fieldName; */
            /* ($fieldName == null ? NULL_PRIME : $fieldName.hashCode()) */
            Name dollarFieldName = dollar.append(((JCVariableDecl) fieldNode.get()).name);
            statements.append(maker.VarDef(maker.Modifiers(finalFlag), dollarFieldName, genJavaLangTypeRef(typeNode, "Object"), fieldAccessor));
            JCExpression hcCall = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(dollarFieldName), typeNode.toName("hashCode")), List.<JCExpression>nil());
            JCExpression thisEqualsNull = maker.Binary(CTC_EQUAL, maker.Ident(dollarFieldName), maker.Literal(CTC_BOT, null));
            statements.append(createResultCalculation(typeNode, maker.Parens(maker.Conditional(thisEqualsNull, maker.Literal(HandlerUtil.primeForNull()), hcCall))));
        }
    }
    /* return result; */
    {
        statements.append(maker.Return(maker.Ident(resultName)));
    }
    JCBlock body = maker.Block(0, statements.toList());
    return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("hashCode"), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null), source, typeNode.getContext());
}
Also used : JCBlock(com.sun.tools.javac.tree.JCTree.JCBlock) JavacTreeMaker(lombok.javac.JavacTreeMaker) ListBuffer(com.sun.tools.javac.util.ListBuffer) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) Name(com.sun.tools.javac.util.Name) JCTypeParameter(com.sun.tools.javac.tree.JCTree.JCTypeParameter) JCMethodInvocation(com.sun.tools.javac.tree.JCTree.JCMethodInvocation) JCPrimitiveTypeTree(com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JavacNode(lombok.javac.JavacNode) JCModifiers(com.sun.tools.javac.tree.JCTree.JCModifiers) JCAnnotation(com.sun.tools.javac.tree.JCTree.JCAnnotation) JCArrayTypeTree(com.sun.tools.javac.tree.JCTree.JCArrayTypeTree)

Example 4 with JCPrimitiveTypeTree

use of com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree in project lombok by rzwitserloot.

the class HandleGetter method createLazyGetterBody.

public List<JCStatement> createLazyGetterBody(JavacTreeMaker maker, JavacNode fieldNode, JCTree source) {
    /*
		java.lang.Object value = this.fieldName.get();
		if (value == null) {
			synchronized (this.fieldName) {
				value = this.fieldName.get();
				if (value == null) {
					final RawValueType actualValue = INITIALIZER_EXPRESSION;
					[IF PRIMITIVE]
					value = actualValue;
					[ELSE]
					value = actualValue == null ? this.fieldName : actualValue;
					[END IF]
					this.fieldName.set(value);
				}
			}
		}
		[IF PRIMITIVE]
		return (BoxedValueType) value;
		[ELSE]
		return (BoxedValueType) (value == this.fieldName ? null : value);
		[END IF]
		*/
    ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
    JCVariableDecl field = (JCVariableDecl) fieldNode.get();
    JCExpression copyOfRawFieldType = copyType(maker, field);
    JCExpression copyOfBoxedFieldType = null;
    field.type = null;
    boolean isPrimitive = false;
    if (field.vartype instanceof JCPrimitiveTypeTree) {
        String boxed = TYPE_MAP.get(typeTag(field.vartype));
        if (boxed != null) {
            isPrimitive = true;
            field.vartype = genJavaLangTypeRef(fieldNode, boxed);
            copyOfBoxedFieldType = genJavaLangTypeRef(fieldNode, boxed);
        }
    }
    if (copyOfBoxedFieldType == null)
        copyOfBoxedFieldType = copyType(maker, field);
    Name valueName = fieldNode.toName("value");
    Name actualValueName = fieldNode.toName("actualValue");
    /* java.lang.Object value = this.fieldName.get();*/
    {
        JCExpression valueVarType = genJavaLangTypeRef(fieldNode, "Object");
        statements.append(maker.VarDef(maker.Modifiers(0), valueName, valueVarType, callGet(fieldNode, createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD))));
    }
    /* if (value == null) { */
    {
        JCSynchronized synchronizedStatement;
        /* synchronized (this.fieldName) { */
        {
            ListBuffer<JCStatement> synchronizedStatements = new ListBuffer<JCStatement>();
            /* value = this.fieldName.get(); */
            {
                JCExpressionStatement newAssign = maker.Exec(maker.Assign(maker.Ident(valueName), callGet(fieldNode, createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD))));
                synchronizedStatements.append(newAssign);
            }
            /* if (value == null) { */
            {
                ListBuffer<JCStatement> innerIfStatements = new ListBuffer<JCStatement>();
                /* final RawValueType actualValue = INITIALIZER_EXPRESSION; */
                {
                    innerIfStatements.append(maker.VarDef(maker.Modifiers(Flags.FINAL), actualValueName, copyOfRawFieldType, field.init));
                }
                /* [IF primitive] value = actualValue; */
                {
                    if (isPrimitive) {
                        JCStatement statement = maker.Exec(maker.Assign(maker.Ident(valueName), maker.Ident(actualValueName)));
                        innerIfStatements.append(statement);
                    }
                }
                /* [ELSE] value = actualValue == null ? this.fieldName : actualValue; */
                {
                    if (!isPrimitive) {
                        JCExpression actualValueIsNull = maker.Binary(CTC_EQUAL, maker.Ident(actualValueName), maker.Literal(CTC_BOT, null));
                        JCExpression thisDotFieldName = createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD);
                        JCExpression ternary = maker.Conditional(actualValueIsNull, thisDotFieldName, maker.Ident(actualValueName));
                        JCStatement statement = maker.Exec(maker.Assign(maker.Ident(valueName), ternary));
                        innerIfStatements.append(statement);
                    }
                }
                /* this.fieldName.set(value); */
                {
                    JCStatement statement = callSet(fieldNode, createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD), maker.Ident(valueName));
                    innerIfStatements.append(statement);
                }
                JCBinary isNull = maker.Binary(CTC_EQUAL, maker.Ident(valueName), maker.Literal(CTC_BOT, null));
                JCIf ifStatement = maker.If(isNull, maker.Block(0, innerIfStatements.toList()), null);
                synchronizedStatements.append(ifStatement);
            }
            synchronizedStatement = maker.Synchronized(createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD), maker.Block(0, synchronizedStatements.toList()));
        }
        JCBinary isNull = maker.Binary(CTC_EQUAL, maker.Ident(valueName), maker.Literal(CTC_BOT, null));
        JCIf ifStatement = maker.If(isNull, maker.Block(0, List.<JCStatement>of(synchronizedStatement)), null);
        statements.append(ifStatement);
    }
    /* [IF PRIMITIVE] return (BoxedValueType) value; */
    {
        if (isPrimitive) {
            statements.append(maker.Return(maker.TypeCast(copyOfBoxedFieldType, maker.Ident(valueName))));
        }
    }
    /* [ELSE] return (BoxedValueType) (value == this.fieldName ? null : value); */
    {
        if (!isPrimitive) {
            JCExpression valueEqualsSelf = maker.Binary(CTC_EQUAL, maker.Ident(valueName), createFieldAccessor(maker, fieldNode, FieldAccess.ALWAYS_FIELD));
            JCExpression ternary = maker.Conditional(valueEqualsSelf, maker.Literal(CTC_BOT, null), maker.Ident(valueName));
            JCExpression typeCast = maker.TypeCast(copyOfBoxedFieldType, maker.Parens(ternary));
            statements.append(maker.Return(typeCast));
        }
    }
    // update the field type and init last
    /*	private final java.util.concurrent.atomic.AtomicReference<Object> fieldName = new java.util.concurrent.atomic.AtomicReference<Object>(); */
    {
        field.vartype = recursiveSetGeneratedBy(maker.TypeApply(chainDotsString(fieldNode, AR), List.<JCExpression>of(genJavaLangTypeRef(fieldNode, "Object"))), source, fieldNode.getContext());
        field.init = recursiveSetGeneratedBy(maker.NewClass(null, NIL_EXPRESSION, copyType(maker, field), NIL_EXPRESSION, null), source, fieldNode.getContext());
    }
    return statements.toList();
}
Also used : ListBuffer(com.sun.tools.javac.util.ListBuffer) JCBinary(com.sun.tools.javac.tree.JCTree.JCBinary) JCSynchronized(com.sun.tools.javac.tree.JCTree.JCSynchronized) JCStatement(com.sun.tools.javac.tree.JCTree.JCStatement) JCExpressionStatement(com.sun.tools.javac.tree.JCTree.JCExpressionStatement) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) Name(com.sun.tools.javac.util.Name) JCPrimitiveTypeTree(com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCIf(com.sun.tools.javac.tree.JCTree.JCIf)

Example 5 with JCPrimitiveTypeTree

use of com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree in project ceylon-compiler by ceylon.

the class ClassTransformer method appendDefaultFieldInits.

protected void appendDefaultFieldInits(ClassDefinitionBuilder model, final ListBuffer<JCStatement> stmts, Collection<String> excludeFields) {
    for (JCVariableDecl field : model.getFields()) {
        String fieldName = field.name.toString();
        if (excludeFields != null && excludeFields.contains(fieldName)) {
            continue;
        }
        if (field.mods != null && (field.mods.flags & STATIC) != 0) {
            continue;
        }
        // initialize all reference fields to null and all primitive 
        // fields to a default value.
        JCExpression nullOrZero;
        if (field.vartype instanceof JCPrimitiveTypeTree) {
            switch(((JCPrimitiveTypeTree) field.vartype).typetag) {
                case TypeTags.BYTE:
                case TypeTags.SHORT:
                case TypeTags.INT:
                    nullOrZero = make().Literal(0);
                    break;
                case TypeTags.LONG:
                    nullOrZero = make().Literal(0L);
                    break;
                case TypeTags.FLOAT:
                    nullOrZero = make().Literal(0.0f);
                    break;
                case TypeTags.DOUBLE:
                    nullOrZero = make().Literal(0.0);
                    break;
                case TypeTags.BOOLEAN:
                    nullOrZero = make().Literal(false);
                    break;
                case TypeTags.CHAR:
                    nullOrZero = make().Literal('\0');
                    break;
                default:
                    throw new RuntimeException();
            }
        } else {
            nullOrZero = makeNull();
        }
        stmts.add(make().Exec(make().Assign(naming.makeQualIdent(naming.makeThis(), fieldName), nullOrZero)));
    }
}
Also used : JCPrimitiveTypeTree(com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl)

Aggregations

JCPrimitiveTypeTree (com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree)9 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)8 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)7 JCArrayTypeTree (com.sun.tools.javac.tree.JCTree.JCArrayTypeTree)6 JCTypeParameter (com.sun.tools.javac.tree.JCTree.JCTypeParameter)6 ListBuffer (com.sun.tools.javac.util.ListBuffer)6 JCBlock (com.sun.tools.javac.tree.JCTree.JCBlock)5 JCStatement (com.sun.tools.javac.tree.JCTree.JCStatement)5 JavacTreeMaker (lombok.javac.JavacTreeMaker)5 JCAnnotation (com.sun.tools.javac.tree.JCTree.JCAnnotation)4 JCMethodInvocation (com.sun.tools.javac.tree.JCTree.JCMethodInvocation)4 JCModifiers (com.sun.tools.javac.tree.JCTree.JCModifiers)4 JavacNode (lombok.javac.JavacNode)4 JCClassDecl (com.sun.tools.javac.tree.JCTree.JCClassDecl)3 JCFieldAccess (com.sun.tools.javac.tree.JCTree.JCFieldAccess)3 JCIdent (com.sun.tools.javac.tree.JCTree.JCIdent)3 JCIf (com.sun.tools.javac.tree.JCTree.JCIf)3 JCTypeApply (com.sun.tools.javac.tree.JCTree.JCTypeApply)3 Name (com.sun.tools.javac.util.Name)3 JCBinary (com.sun.tools.javac.tree.JCTree.JCBinary)2