Search in sources :

Example 1 with BuilderFieldData

use of lombok.eclipse.handlers.HandleBuilder.BuilderFieldData in project lombok by rzwitserloot.

the class HandleSuperBuilder method handle.

@Override
public void handle(AnnotationValues<SuperBuilder> annotation, Annotation ast, EclipseNode annotationNode) {
    handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.SUPERBUILDER_FLAG_USAGE, "@SuperBuilder");
    SuperBuilderJob job = new SuperBuilderJob();
    job.sourceNode = annotationNode;
    job.source = ast;
    job.checkerFramework = getCheckerFrameworkVersion(annotationNode);
    job.isStatic = true;
    SuperBuilder annInstance = annotation.getInstance();
    job.init(annotation, annInstance, annotationNode);
    boolean generateBuilderMethod;
    if (job.builderMethodName.isEmpty()) {
        generateBuilderMethod = false;
    } else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) {
        return;
    } else {
        generateBuilderMethod = true;
    }
    if (!checkName("buildMethodName", job.buildMethodName, annotationNode))
        return;
    EclipseNode parent = annotationNode.up();
    job.builderFields = new ArrayList<BuilderFieldData>();
    TypeReference buildMethodReturnType;
    boolean addCleaning = false;
    List<EclipseNode> nonFinalNonDefaultedFields = null;
    if (!isClass(parent)) {
        annotationNode.addError("@SuperBuilder is only supported on classes.");
        return;
    }
    if (!isStaticAllowed(parent)) {
        annotationNode.addError("@SuperBuilder is not supported on non-static nested classes.");
        return;
    }
    job.parentType = parent;
    TypeDeclaration td = (TypeDeclaration) parent.get();
    // Gather all fields of the class that should be set by the builder.
    List<EclipseNode> allFields = new ArrayList<EclipseNode>();
    boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent));
    for (EclipseNode fieldNode : HandleConstructor.findAllFields(parent, true)) {
        FieldDeclaration fd = (FieldDeclaration) fieldNode.get();
        EclipseNode isDefault = findAnnotation(Builder.Default.class, fieldNode);
        boolean isFinal = ((fd.modifiers & ClassFileConstants.AccFinal) != 0) || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode));
        Annotation[] copyableAnnotations = findCopyableAnnotations(fieldNode);
        BuilderFieldData bfd = new BuilderFieldData();
        bfd.rawName = fieldNode.getName().toCharArray();
        bfd.name = removePrefixFromField(fieldNode);
        bfd.builderFieldName = bfd.name;
        bfd.annotations = copyAnnotations(fd, copyableAnnotations);
        bfd.type = fd.type;
        bfd.singularData = getSingularData(fieldNode, ast, annInstance.setterPrefix());
        bfd.originalFieldNode = fieldNode;
        if (bfd.singularData != null && isDefault != null) {
            isDefault.addError("@Builder.Default and @Singular cannot be mixed.");
            isDefault = null;
        }
        if (fd.initialization == null && isDefault != null) {
            isDefault.addWarning("@Builder.Default requires an initializing expression (' = something;').");
            isDefault = null;
        }
        if (fd.initialization != null && isDefault == null) {
            if (isFinal)
                continue;
            if (nonFinalNonDefaultedFields == null)
                nonFinalNonDefaultedFields = new ArrayList<EclipseNode>();
            nonFinalNonDefaultedFields.add(fieldNode);
        }
        if (isDefault != null) {
            bfd.nameOfDefaultProvider = prefixWith(DEFAULT_PREFIX, bfd.name);
            bfd.nameOfSetFlag = prefixWith(bfd.name, SET_PREFIX);
            bfd.builderFieldName = prefixWith(bfd.name, VALUE_PREFIX);
            MethodDeclaration md = HandleBuilder.generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast);
            if (md != null)
                injectMethod(parent, md);
        }
        addObtainVia(bfd, fieldNode);
        job.builderFields.add(bfd);
        allFields.add(fieldNode);
    }
    job.typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0];
    buildMethodReturnType = job.createBuilderParentTypeReference();
    // <C, B> are the generics for our builder.
    String classGenericName = "C";
    String builderGenericName = "B";
    // We have to make sure that the generics' names do not collide with any generics on the annotated class,
    // the classname itself, or any member type name of the annotated class.
    // For instance, if there are generics <B, B2, C> on the annotated class, use "C2" and "B3" for our builder.
    java.util.Set<String> usedNames = gatherUsedTypeNames(job.typeParams, td);
    classGenericName = generateNonclashingNameFor(classGenericName, usedNames);
    builderGenericName = generateNonclashingNameFor(builderGenericName, usedNames);
    TypeParameter[] paddedTypeParameters;
    {
        paddedTypeParameters = new TypeParameter[job.typeParams.length + 2];
        System.arraycopy(job.typeParams, 0, paddedTypeParameters, 0, job.typeParams.length);
        TypeParameter c = new TypeParameter();
        c.name = classGenericName.toCharArray();
        c.type = cloneSelfType(job.parentType, job.source);
        paddedTypeParameters[paddedTypeParameters.length - 2] = c;
        TypeParameter b = new TypeParameter();
        b.name = builderGenericName.toCharArray();
        b.type = cloneSelfType(job.parentType, job.source);
        paddedTypeParameters[paddedTypeParameters.length - 1] = b;
    }
    job.builderTypeParams = job.builderTypeParams_ = paddedTypeParameters;
    TypeReference extendsClause = td.superclass;
    TypeReference superclassBuilderClass = null;
    TypeReference[] typeArguments = new TypeReference[] { new SingleTypeReference(classGenericName.toCharArray(), 0), new SingleTypeReference(builderGenericName.toCharArray(), 0) };
    if (extendsClause instanceof QualifiedTypeReference) {
        QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference) extendsClause;
        char[] superclassClassName = qualifiedTypeReference.getLastToken();
        String builderClassNameTemplate = BuilderJob.getBuilderClassNameTemplate(annotationNode, null);
        String superclassBuilderClassName = job.replaceBuilderClassName(superclassClassName, builderClassNameTemplate);
        char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1);
        tokens[tokens.length - 1] = superclassBuilderClassName.toCharArray();
        long[] poss = new long[tokens.length];
        Arrays.fill(poss, job.getPos());
        TypeReference[] superclassTypeArgs = getTypeParametersFrom(extendsClause);
        // Every token may potentially have type args. Here, we only have
        // type args for the last token, the superclass' builder.
        TypeReference[][] typeArgsForTokens = new TypeReference[tokens.length][];
        typeArgsForTokens[typeArgsForTokens.length - 1] = mergeTypeReferences(superclassTypeArgs, typeArguments);
        superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss);
    } else if (extendsClause != null) {
        char[] superclassClassName = extendsClause.getTypeName()[0];
        String builderClassNameTemplate = BuilderJob.getBuilderClassNameTemplate(annotationNode, null);
        String superclassBuilderClassName = job.replaceBuilderClassName(superclassClassName, builderClassNameTemplate);
        char[][] tokens = new char[][] { superclassClassName, superclassBuilderClassName.toCharArray() };
        long[] poss = new long[tokens.length];
        Arrays.fill(poss, job.getPos());
        TypeReference[] superclassTypeArgs = getTypeParametersFrom(extendsClause);
        // Every token may potentially have type args. Here, we only have
        // type args for the last token, the superclass' builder.
        TypeReference[][] typeArgsForTokens = new TypeReference[tokens.length][];
        typeArgsForTokens[typeArgsForTokens.length - 1] = mergeTypeReferences(superclassTypeArgs, typeArguments);
        superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss);
    }
    job.builderAbstractClassName = job.builderClassName = job.replaceBuilderClassName(td.name);
    job.builderAbstractClassNameArr = job.builderClassNameArr = job.builderAbstractClassName.toCharArray();
    job.builderImplClassName = job.builderAbstractClassName + "Impl";
    job.builderImplClassNameArr = job.builderImplClassName.toCharArray();
    if (!constructorExists(parent, job.builderClassName)) {
        generateBuilderBasedConstructor(job, superclassBuilderClass != null);
    }
    // Create the abstract builder class, or reuse an existing one.
    job.builderAbstractType = findInnerClass(parent, job.builderClassName);
    if (job.builderAbstractType == null) {
        job.builderAbstractType = generateBuilderAbstractClass(job, superclassBuilderClass, classGenericName, builderGenericName);
    } else {
        TypeDeclaration builderTypeDeclaration = (TypeDeclaration) job.builderAbstractType.get();
        if ((builderTypeDeclaration.modifiers & (ClassFileConstants.AccStatic | ClassFileConstants.AccAbstract)) == 0) {
            annotationNode.addError("Existing Builder must be an abstract static inner class.");
            return;
        }
        sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderAbstractType, annotationNode);
        // Generate errors for @Singular BFDs that have one already defined node.
        for (BuilderFieldData bfd : job.builderFields) {
            SingularData sd = bfd.singularData;
            if (sd == null)
                continue;
            EclipseSingularizer singularizer = sd.getSingularizer();
            if (singularizer == null)
                continue;
            if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderAbstractType, sd)) {
                bfd.singularData = null;
            }
        }
    }
    // Check validity of @ObtainVia fields, and add check if adding cleaning for @Singular is necessary.
    for (BuilderFieldData bfd : job.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;
            }
        }
    }
    // Generate the fields in the abstract builder class that hold the values for the instance.
    job.setBuilderToAbstract();
    generateBuilderFields(job);
    if (addCleaning) {
        FieldDeclaration cleanDecl = new FieldDeclaration(CLEAN_FIELD_NAME, 0, -1);
        cleanDecl.declarationSourceEnd = -1;
        cleanDecl.modifiers = ClassFileConstants.AccPrivate;
        cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
        injectFieldAndMarkGenerated(job.builderType, cleanDecl);
    }
    if (job.toBuilder) {
        // Generate $fillValuesFrom() method in the abstract builder.
        injectMethod(job.builderType, generateFillValuesMethod(job, superclassBuilderClass != null, builderGenericName, classGenericName));
        // Generate $fillValuesFromInstanceIntoBuilder() method in the builder implementation class.
        injectMethod(job.builderType, generateStaticFillValuesMethod(job, annInstance.setterPrefix()));
    }
    // Generate abstract self() and build() methods in the abstract builder.
    injectMethod(job.builderType, generateAbstractSelfMethod(job, superclassBuilderClass != null, builderGenericName));
    job.setBuilderToAbstract();
    injectMethod(job.builderType, generateAbstractBuildMethod(job, superclassBuilderClass != null, classGenericName));
    // Create the setter methods in the abstract builder.
    for (BuilderFieldData bfd : job.builderFields) {
        generateSetterMethodsForBuilder(job, bfd, builderGenericName, annInstance.setterPrefix());
    }
    // Create the toString() method for the abstract builder.
    if (methodExists("toString", job.builderType, 0) == MemberExistsResult.NOT_EXISTS) {
        List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>();
        for (BuilderFieldData bfd : job.builderFields) {
            for (EclipseNode f : bfd.createdFields) {
                fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true, false));
            }
        }
        // Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder.
        MethodDeclaration md = HandleToString.createToString(job.builderType, fieldNodes, true, superclassBuilderClass != null, ast, FieldAccess.ALWAYS_FIELD);
        if (md != null) {
            injectMethod(job.builderType, md);
        }
    }
    if (addCleaning) {
        job.setBuilderToAbstract();
        injectMethod(job.builderType, generateCleanMethod(job));
    }
    boolean isAbstract = (td.modifiers & ClassFileConstants.AccAbstract) != 0;
    if (isAbstract) {
        // Only non-abstract classes get the Builder implementation.
        return;
    }
    // Create the builder implementation class, or reuse an existing one.
    job.builderImplType = findInnerClass(parent, job.builderImplClassName);
    if (job.builderImplType == null) {
        job.builderImplType = generateBuilderImplClass(job, job.builderImplClassName);
    } else {
        TypeDeclaration builderImplTypeDeclaration = (TypeDeclaration) job.builderImplType.get();
        if ((builderImplTypeDeclaration.modifiers & ClassFileConstants.AccAbstract) != 0 || (builderImplTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) {
            annotationNode.addError("Existing BuilderImpl must be a non-abstract static inner class.");
            return;
        }
        sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderImplType, annotationNode);
    }
    job.setBuilderToImpl();
    if (job.toBuilder) {
        // Add the toBuilder() method to the annotated class.
        switch(methodExists(TO_BUILDER_METHOD_NAME_STRING, job.parentType, 0)) {
            case EXISTS_BY_USER:
                break;
            case NOT_EXISTS:
                injectMethod(parent, generateToBuilderMethod(job));
                break;
            default:
        }
    }
    // Create the self() and build() methods in the BuilderImpl.
    job.setBuilderToImpl();
    injectMethod(job.builderImplType, generateSelfMethod(job));
    if (methodExists(job.buildMethodName, job.builderImplType, -1) == MemberExistsResult.NOT_EXISTS) {
        job.setBuilderToImpl();
        injectMethod(job.builderImplType, generateBuildMethod(job, buildMethodReturnType));
    }
    // Add the builder() method to the annotated class.
    if (generateBuilderMethod && methodExists(job.builderMethodName, parent, -1) != MemberExistsResult.NOT_EXISTS)
        generateBuilderMethod = false;
    if (generateBuilderMethod) {
        MethodDeclaration md = generateBuilderMethod(job);
        if (md != null)
            injectMethod(parent, md);
    }
    if (nonFinalNonDefaultedFields != null && generateBuilderMethod) {
        for (EclipseNode fieldNode : nonFinalNonDefaultedFields) {
            fieldNode.addWarning("@SuperBuilder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.");
        }
    }
}
Also used : BuilderFieldData(lombok.eclipse.handlers.HandleBuilder.BuilderFieldData) SuperBuilder(lombok.experimental.SuperBuilder) TypeParameter(org.eclipse.jdt.internal.compiler.ast.TypeParameter) Builder(lombok.Builder) SuperBuilder(lombok.experimental.SuperBuilder) HandleBuilder(lombok.eclipse.handlers.HandleBuilder) ArrayList(java.util.ArrayList) ToString(lombok.ToString) FieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) EclipseSingularizer(lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer) TypeReference(org.eclipse.jdt.internal.compiler.ast.TypeReference) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) Included(lombok.core.handlers.InclusionExclusionUtils.Included) MarkerAnnotation(org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation) Annotation(org.eclipse.jdt.internal.compiler.ast.Annotation) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) SingularData(lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData) EclipseNode(lombok.eclipse.EclipseNode) ToString(lombok.ToString) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)

Example 2 with BuilderFieldData

use of lombok.eclipse.handlers.HandleBuilder.BuilderFieldData in project lombok by rzwitserloot.

the class HandleSuperBuilder method generateStaticFillValuesMethod.

/**
 * Generates a <code>$fillValuesFromInstanceIntoBuilder()</code> method in
 * the builder implementation class that copies all fields from the instance
 * to the builder. It looks like this:
 *
 * <pre>
 * protected B $fillValuesFromInstanceIntoBuilder(Foobar instance, FoobarBuilder&lt;?, ?&gt; b) {
 * 	b.field(instance.field);
 * }
 * </pre>
 * @param setterPrefix the prefix for setter methods
 */
private MethodDeclaration generateStaticFillValuesMethod(BuilderJob job, String setterPrefix) {
    MethodDeclaration out = job.createNewMethodDeclaration();
    out.selector = FILL_VALUES_STATIC_METHOD_NAME;
    out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
    out.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic;
    out.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0);
    TypeReference[] wildcards = new TypeReference[] { new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND) };
    TypeReference builderType = generateParameterizedTypeReference(job.parentType, job.builderClassNameArr, false, mergeToTypeReferences(job.typeParams, wildcards), 0);
    Argument builderArgument = new Argument(BUILDER_VARIABLE_NAME, 0, builderType, Modifier.FINAL);
    TypeReference[] typerefs = null;
    if (job.typeParams.length > 0) {
        typerefs = new TypeReference[job.typeParams.length];
        for (int i = 0; i < job.typeParams.length; i++) typerefs[i] = new SingleTypeReference(job.typeParams[i].name, 0);
    }
    long p = job.getPos();
    TypeReference parentArgument = typerefs == null ? generateTypeReference(job.parentType, p) : generateParameterizedTypeReference(job.parentType, typerefs, p);
    out.arguments = new Argument[] { new Argument(INSTANCE_VARIABLE_NAME, 0, parentArgument, Modifier.FINAL), builderArgument };
    // Add type params if there are any.
    if (job.typeParams.length > 0)
        out.typeParameters = copyTypeParams(job.typeParams, job.source);
    List<Statement> body = new ArrayList<Statement>();
    // Call the builder's setter methods to fill the values from the instance.
    for (BuilderFieldData bfd : job.builderFields) {
        MessageSend exec = createSetterCallWithInstanceValue(bfd, job.parentType, job.source, setterPrefix);
        body.add(exec);
    }
    out.statements = body.isEmpty() ? null : body.toArray(new Statement[0]);
    out.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null);
    return out;
}
Also used : BuilderFieldData(lombok.eclipse.handlers.HandleBuilder.BuilderFieldData) Argument(org.eclipse.jdt.internal.compiler.ast.Argument) MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) Statement(org.eclipse.jdt.internal.compiler.ast.Statement) ReturnStatement(org.eclipse.jdt.internal.compiler.ast.ReturnStatement) IfStatement(org.eclipse.jdt.internal.compiler.ast.IfStatement) ArrayList(java.util.ArrayList) MessageSend(org.eclipse.jdt.internal.compiler.ast.MessageSend) Wildcard(org.eclipse.jdt.internal.compiler.ast.Wildcard) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) TypeReference(org.eclipse.jdt.internal.compiler.ast.TypeReference) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference)

Example 3 with BuilderFieldData

use of lombok.eclipse.handlers.HandleBuilder.BuilderFieldData in project lombok by rzwitserloot.

the class HandleSuperBuilder method generateCleanMethod.

private MethodDeclaration generateCleanMethod(BuilderJob job) {
    List<Statement> statements = new ArrayList<Statement>();
    for (BuilderFieldData bfd : job.builderFields) {
        if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
            bfd.singularData.getSingularizer().appendCleaningCode(bfd.singularData, job.builderType, statements);
        }
    }
    FieldReference thisUnclean = new FieldReference(CLEAN_FIELD_NAME, 0);
    thisUnclean.receiver = new ThisReference(0, 0);
    statements.add(new Assignment(thisUnclean, new FalseLiteral(0, 0), 0));
    MethodDeclaration decl = job.createNewMethodDeclaration();
    // new MethodDeclaration(((CompilationUnitDeclaration) builderType.top().get()).compilationResult);
    decl.selector = CLEAN_METHOD_NAME;
    decl.modifiers = ClassFileConstants.AccPrivate;
    decl.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
    decl.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0);
    decl.statements = statements.toArray(new Statement[0]);
    decl.traverse(new SetGeneratedByVisitor(job.source), (ClassScope) null);
    return decl;
}
Also used : Assignment(org.eclipse.jdt.internal.compiler.ast.Assignment) BuilderFieldData(lombok.eclipse.handlers.HandleBuilder.BuilderFieldData) FieldReference(org.eclipse.jdt.internal.compiler.ast.FieldReference) Statement(org.eclipse.jdt.internal.compiler.ast.Statement) ReturnStatement(org.eclipse.jdt.internal.compiler.ast.ReturnStatement) IfStatement(org.eclipse.jdt.internal.compiler.ast.IfStatement) MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) ArrayList(java.util.ArrayList) ThisReference(org.eclipse.jdt.internal.compiler.ast.ThisReference) FalseLiteral(org.eclipse.jdt.internal.compiler.ast.FalseLiteral)

Example 4 with BuilderFieldData

use of lombok.eclipse.handlers.HandleBuilder.BuilderFieldData in project lombok by rzwitserloot.

the class HandleSuperBuilder method generateBuilderFields.

private void generateBuilderFields(BuilderJob job) {
    List<EclipseNode> existing = new ArrayList<EclipseNode>();
    for (EclipseNode child : job.builderType.down()) {
        if (child.getKind() == Kind.FIELD)
            existing.add(child);
    }
    for (BuilderFieldData bfd : job.builderFields) {
        if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
            bfd.createdFields.addAll(bfd.singularData.getSingularizer().generateFields(bfd.singularData, job.builderType));
        } else {
            EclipseNode field = null, setFlag = null;
            for (EclipseNode exists : existing) {
                char[] n = ((FieldDeclaration) exists.get()).name;
                if (Arrays.equals(n, bfd.builderFieldName))
                    field = exists;
                if (bfd.nameOfSetFlag != null && Arrays.equals(n, bfd.nameOfSetFlag))
                    setFlag = exists;
            }
            if (field == null) {
                FieldDeclaration fd = new FieldDeclaration(bfd.builderFieldName, 0, 0);
                fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
                fd.modifiers = ClassFileConstants.AccPrivate;
                fd.type = copyType(bfd.type);
                fd.traverse(new SetGeneratedByVisitor(job.source), (MethodScope) null);
                field = injectFieldAndMarkGenerated(job.builderType, fd);
            }
            if (setFlag == null && bfd.nameOfSetFlag != null) {
                FieldDeclaration fd = new FieldDeclaration(bfd.nameOfSetFlag, 0, 0);
                fd.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG;
                fd.modifiers = ClassFileConstants.AccPrivate;
                fd.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
                fd.traverse(new SetGeneratedByVisitor(job.source), (MethodScope) null);
                injectFieldAndMarkGenerated(job.builderType, fd);
            }
            bfd.createdFields.add(field);
        }
    }
}
Also used : BuilderFieldData(lombok.eclipse.handlers.HandleBuilder.BuilderFieldData) ArrayList(java.util.ArrayList) EclipseNode(lombok.eclipse.EclipseNode) FieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)

Example 5 with BuilderFieldData

use of lombok.eclipse.handlers.HandleBuilder.BuilderFieldData in project lombok by rzwitserloot.

the class HandleSuperBuilder method generateBuilderBasedConstructor.

/**
 * Generates a constructor that has a builder as the only parameter.
 * The values from the builder are used to initialize the fields of new instances.
 *
 * @param callBuilderBasedSuperConstructor
 *            If {@code true}, the constructor will explicitly call a super
 *            constructor with the builder as argument. Requires
 *            {@code builderClassAsParameter != null}.
 */
private void generateBuilderBasedConstructor(BuilderJob job, boolean callBuilderBasedSuperConstructor) {
    TypeDeclaration typeDeclaration = ((TypeDeclaration) job.parentType.get());
    long p = job.getPos();
    ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) job.parentType.top().get()).compilationResult);
    constructor.modifiers = toEclipseModifier(AccessLevel.PROTECTED);
    constructor.selector = typeDeclaration.name;
    if (callBuilderBasedSuperConstructor) {
        constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.Super);
        constructor.constructorCall.arguments = new Expression[] { new SingleNameReference(BUILDER_VARIABLE_NAME, p) };
    } else {
        constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
    }
    constructor.constructorCall.sourceStart = job.source.sourceStart;
    constructor.constructorCall.sourceEnd = job.source.sourceEnd;
    constructor.thrownExceptions = null;
    constructor.typeParameters = null;
    constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
    constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = job.source.sourceStart;
    constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = job.source.sourceEnd;
    TypeReference[] wildcards = new TypeReference[] { new Wildcard(Wildcard.UNBOUND), new Wildcard(Wildcard.UNBOUND) };
    TypeReference builderType = generateParameterizedTypeReference(job.parentType, job.builderClassNameArr, false, mergeToTypeReferences(job.typeParams, wildcards), p);
    constructor.arguments = new Argument[] { new Argument(BUILDER_VARIABLE_NAME, p, builderType, Modifier.FINAL) };
    List<Statement> statements = new ArrayList<Statement>();
    for (BuilderFieldData fieldNode : job.builderFields) {
        FieldReference fieldInThis = new FieldReference(fieldNode.rawName, p);
        int s = (int) (p >> 32);
        int e = (int) p;
        fieldInThis.receiver = new ThisReference(s, e);
        Expression assignmentExpr;
        if (fieldNode.singularData != null && fieldNode.singularData.getSingularizer() != null) {
            fieldNode.singularData.getSingularizer().appendBuildCode(fieldNode.singularData, job.parentType, statements, fieldNode.builderFieldName, BUILDER_VARIABLE_NAME_STRING);
            assignmentExpr = new SingleNameReference(fieldNode.builderFieldName, p);
        } else {
            char[][] variableInBuilder = new char[][] { BUILDER_VARIABLE_NAME, fieldNode.builderFieldName };
            long[] positions = new long[] { p, p };
            assignmentExpr = new QualifiedNameReference(variableInBuilder, positions, s, e);
        }
        Statement assignment = new Assignment(fieldInThis, assignmentExpr, (int) p);
        // In case of @Builder.Default, set the value to the default if it was NOT set in the builder.
        if (fieldNode.nameOfSetFlag != null) {
            char[][] setVariableInBuilder = new char[][] { BUILDER_VARIABLE_NAME, fieldNode.nameOfSetFlag };
            long[] positions = new long[] { p, p };
            QualifiedNameReference setVariableInBuilderRef = new QualifiedNameReference(setVariableInBuilder, positions, s, e);
            MessageSend defaultMethodCall = new MessageSend();
            defaultMethodCall.sourceStart = job.source.sourceStart;
            defaultMethodCall.sourceEnd = job.source.sourceEnd;
            defaultMethodCall.receiver = generateNameReference(job.parentType, 0L);
            defaultMethodCall.selector = fieldNode.nameOfDefaultProvider;
            defaultMethodCall.typeArguments = typeParameterNames(((TypeDeclaration) job.parentType.get()).typeParameters);
            Statement defaultAssignment = new Assignment(fieldInThis, defaultMethodCall, (int) p);
            IfStatement ifBlockForDefault = new IfStatement(setVariableInBuilderRef, assignment, defaultAssignment, s, e);
            statements.add(ifBlockForDefault);
        } else {
            statements.add(assignment);
        }
        if (hasNonNullAnnotations(fieldNode.originalFieldNode)) {
            Statement nullCheck = generateNullCheck((FieldDeclaration) fieldNode.originalFieldNode.get(), job.sourceNode, null);
            if (nullCheck != null)
                statements.add(nullCheck);
        }
    }
    constructor.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]);
    if (job.checkerFramework.generateSideEffectFree()) {
        constructor.annotations = new Annotation[] { generateNamedAnnotation(job.source, CheckerFrameworkVersion.NAME__SIDE_EFFECT_FREE) };
    }
    constructor.traverse(new SetGeneratedByVisitor(job.source), typeDeclaration.scope);
    injectMethod(job.parentType, constructor);
}
Also used : BuilderFieldData(lombok.eclipse.handlers.HandleBuilder.BuilderFieldData) FieldReference(org.eclipse.jdt.internal.compiler.ast.FieldReference) Argument(org.eclipse.jdt.internal.compiler.ast.Argument) Statement(org.eclipse.jdt.internal.compiler.ast.Statement) ReturnStatement(org.eclipse.jdt.internal.compiler.ast.ReturnStatement) IfStatement(org.eclipse.jdt.internal.compiler.ast.IfStatement) ArrayList(java.util.ArrayList) ThisReference(org.eclipse.jdt.internal.compiler.ast.ThisReference) SingleNameReference(org.eclipse.jdt.internal.compiler.ast.SingleNameReference) Assignment(org.eclipse.jdt.internal.compiler.ast.Assignment) ExplicitConstructorCall(org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall) MessageSend(org.eclipse.jdt.internal.compiler.ast.MessageSend) IfStatement(org.eclipse.jdt.internal.compiler.ast.IfStatement) Wildcard(org.eclipse.jdt.internal.compiler.ast.Wildcard) Expression(org.eclipse.jdt.internal.compiler.ast.Expression) ConditionalExpression(org.eclipse.jdt.internal.compiler.ast.ConditionalExpression) AllocationExpression(org.eclipse.jdt.internal.compiler.ast.AllocationExpression) EqualExpression(org.eclipse.jdt.internal.compiler.ast.EqualExpression) ConstructorDeclaration(org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration) TypeReference(org.eclipse.jdt.internal.compiler.ast.TypeReference) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) QualifiedNameReference(org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference)

Aggregations

ArrayList (java.util.ArrayList)5 BuilderFieldData (lombok.eclipse.handlers.HandleBuilder.BuilderFieldData)5 AbstractMethodDeclaration (org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)3 IfStatement (org.eclipse.jdt.internal.compiler.ast.IfStatement)3 MethodDeclaration (org.eclipse.jdt.internal.compiler.ast.MethodDeclaration)3 ParameterizedQualifiedTypeReference (org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference)3 ParameterizedSingleTypeReference (org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference)3 QualifiedTypeReference (org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference)3 ReturnStatement (org.eclipse.jdt.internal.compiler.ast.ReturnStatement)3 SingleTypeReference (org.eclipse.jdt.internal.compiler.ast.SingleTypeReference)3 Statement (org.eclipse.jdt.internal.compiler.ast.Statement)3 TypeReference (org.eclipse.jdt.internal.compiler.ast.TypeReference)3 EclipseNode (lombok.eclipse.EclipseNode)2 Argument (org.eclipse.jdt.internal.compiler.ast.Argument)2 Assignment (org.eclipse.jdt.internal.compiler.ast.Assignment)2 FieldDeclaration (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)2 FieldReference (org.eclipse.jdt.internal.compiler.ast.FieldReference)2 MessageSend (org.eclipse.jdt.internal.compiler.ast.MessageSend)2 ThisReference (org.eclipse.jdt.internal.compiler.ast.ThisReference)2 TypeDeclaration (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)2