Search in sources :

Example 36 with FieldDeclaration

use of org.eclipse.jdt.internal.compiler.ast.FieldDeclaration in project lombok by rzwitserloot.

the class HandleEqualsAndHashCode method generateMethods.

public void generateMethods(EclipseNode typeNode, EclipseNode errorNode, List<String> excludes, List<String> includes, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<Annotation> onParam) {
    assert excludes == null || includes == null;
    TypeDeclaration typeDecl = null;
    if (typeNode.get() instanceof TypeDeclaration)
        typeDecl = (TypeDeclaration) typeNode.get();
    int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
    boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0;
    if (typeDecl == null || notAClass) {
        errorNode.addError("@EqualsAndHashCode is only supported on a class.");
        return;
    }
    boolean implicitCallSuper = callSuper == null;
    if (callSuper == null) {
        try {
            callSuper = ((Boolean) EqualsAndHashCode.class.getMethod("callSuper").getDefaultValue()).booleanValue();
        } catch (Exception ignore) {
            throw new InternalError("Lombok bug - this cannot happen - can't find callSuper field in EqualsAndHashCode annotation.");
        }
    }
    boolean isDirectDescendantOfObject = true;
    if (typeDecl.superclass != null) {
        String p = typeDecl.superclass.toString();
        isDirectDescendantOfObject = p.equals("Object") || p.equals("java.lang.Object");
    }
    if (isDirectDescendantOfObject && callSuper) {
        errorNode.addError("Generating equals/hashCode with a supercall to java.lang.Object is pointless.");
        return;
    }
    if (implicitCallSuper && !isDirectDescendantOfObject) {
        CallSuperType cst = typeNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_CALL_SUPER);
        if (cst == null)
            cst = CallSuperType.WARN;
        switch(cst) {
            default:
            case WARN:
                errorNode.addWarning("Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '@EqualsAndHashCode(callSuper=false)' to your type.");
                callSuper = false;
                break;
            case SKIP:
                callSuper = false;
                break;
            case CALL:
                callSuper = true;
                break;
        }
    }
    List<EclipseNode> nodesForEquality = new ArrayList<EclipseNode>();
    if (includes != null) {
        for (EclipseNode child : typeNode.down()) {
            if (child.getKind() != Kind.FIELD)
                continue;
            FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
            if (includes.contains(new String(fieldDecl.name)))
                nodesForEquality.add(child);
        }
    } else {
        for (EclipseNode child : typeNode.down()) {
            if (child.getKind() != Kind.FIELD)
                continue;
            FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
            if (!filterField(fieldDecl))
                continue;
            // Skip transient fields.
            if ((fieldDecl.modifiers & ClassFileConstants.AccTransient) != 0)
                continue;
            // Skip excluded fields.
            if (excludes != null && excludes.contains(new String(fieldDecl.name)))
                continue;
            nodesForEquality.add(child);
        }
    }
    boolean isFinal = (typeDecl.modifiers & ClassFileConstants.AccFinal) != 0;
    boolean needsCanEqual = !isFinal || !isDirectDescendantOfObject;
    MemberExistsResult equalsExists = methodExists("equals", typeNode, 1);
    MemberExistsResult hashCodeExists = methodExists("hashCode", typeNode, 0);
    MemberExistsResult canEqualExists = methodExists("canEqual", typeNode, 1);
    switch(Collections.max(Arrays.asList(equalsExists, hashCodeExists))) {
        case EXISTS_BY_LOMBOK:
            return;
        case EXISTS_BY_USER:
            if (whineIfExists) {
                String msg = "Not generating equals and hashCode: A method with one of those names already exists. (Either both or none of these methods will be generated).";
                errorNode.addWarning(msg);
            } else if (equalsExists == MemberExistsResult.NOT_EXISTS || hashCodeExists == MemberExistsResult.NOT_EXISTS) {
                // This means equals OR hashCode exists and not both.
                // Even though we should suppress the message about not generating these, this is such a weird and surprising situation we should ALWAYS generate a warning.
                // The user code couldn't possibly (barring really weird subclassing shenanigans) be in a shippable state anyway; the implementations of these 2 methods are
                // all inter-related and should be written by the same entity.
                String msg = String.format("Not generating %s: One of equals or hashCode exists. " + "You should either write both of these or none of these (in the latter case, lombok generates them).", equalsExists == MemberExistsResult.NOT_EXISTS ? "equals" : "hashCode");
                errorNode.addWarning(msg);
            }
            return;
        case NOT_EXISTS:
        default:
    }
    MethodDeclaration equalsMethod = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess, needsCanEqual, onParam);
    equalsMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration) typeNode.get()).scope);
    injectMethod(typeNode, equalsMethod);
    if (needsCanEqual && canEqualExists == MemberExistsResult.NOT_EXISTS) {
        MethodDeclaration canEqualMethod = createCanEqual(typeNode, errorNode.get(), onParam);
        canEqualMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration) typeNode.get()).scope);
        injectMethod(typeNode, canEqualMethod);
    }
    MethodDeclaration hashCodeMethod = createHashCode(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess);
    hashCodeMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration) typeNode.get()).scope);
    injectMethod(typeNode, hashCodeMethod);
}
Also used : MemberExistsResult(lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult) MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) EqualsAndHashCode(lombok.EqualsAndHashCode) ArrayList(java.util.ArrayList) FieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) EclipseNode(lombok.eclipse.EclipseNode) CallSuperType(lombok.core.configuration.CallSuperType) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)

Example 37 with FieldDeclaration

use of org.eclipse.jdt.internal.compiler.ast.FieldDeclaration in project lombok by rzwitserloot.

the class HandleFieldDefaults method generateFieldDefaultsForType.

public boolean generateFieldDefaultsForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean makeFinal, boolean checkForTypeLevelFieldDefaults) {
    if (checkForTypeLevelFieldDefaults) {
        if (hasAnnotation(FieldDefaults.class, typeNode)) {
            // The annotation will make it happen, so we can skip it.
            return true;
        }
    }
    TypeDeclaration typeDecl = null;
    if (typeNode.get() instanceof TypeDeclaration)
        typeDecl = (TypeDeclaration) typeNode.get();
    int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
    boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation)) != 0;
    if (typeDecl == null || notAClass) {
        pos.addError("@FieldDefaults is only supported on a class or an enum.");
        return false;
    }
    for (EclipseNode field : typeNode.down()) {
        if (field.getKind() != Kind.FIELD)
            continue;
        FieldDeclaration fieldDecl = (FieldDeclaration) field.get();
        if (!filterField(fieldDecl, false))
            continue;
        Class<?> t = field.get().getClass();
        if (t == FieldDeclaration.class) {
            // There are various other things that extend FieldDeclaration that really
            // aren't field declarations. Typing 'ma' in an otherwise blank class is a
            // CompletionOnFieldType object (extends FieldDeclaration). If we mess with the
            // modifiers of such a thing, you take away template suggestions such as
            // 'main method'. See issue 411.
            setFieldDefaultsForField(field, pos.get(), level, makeFinal);
        }
    }
    return true;
}
Also used : EclipseNode(lombok.eclipse.EclipseNode) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) FieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)

Example 38 with FieldDeclaration

use of org.eclipse.jdt.internal.compiler.ast.FieldDeclaration in project lombok by rzwitserloot.

the class HandleLog method createField.

private static FieldDeclaration createField(LoggingFramework framework, Annotation source, ClassLiteralAccess loggingType, String logFieldName, boolean useStatic, String loggerTopic) {
    int pS = source.sourceStart, pE = source.sourceEnd;
    long p = (long) pS << 32 | pE;
    // private static final <loggerType> log = <factoryMethod>(<parameter>);
    FieldDeclaration fieldDecl = new FieldDeclaration(logFieldName.toCharArray(), 0, -1);
    setGeneratedBy(fieldDecl, source);
    fieldDecl.declarationSourceEnd = -1;
    fieldDecl.modifiers = Modifier.PRIVATE | (useStatic ? Modifier.STATIC : 0) | Modifier.FINAL;
    fieldDecl.type = createTypeReference(framework.getLoggerTypeName(), source);
    MessageSend factoryMethodCall = new MessageSend();
    setGeneratedBy(factoryMethodCall, source);
    factoryMethodCall.receiver = createNameReference(framework.getLoggerFactoryTypeName(), source);
    factoryMethodCall.selector = framework.getLoggerFactoryMethodName().toCharArray();
    Expression parameter;
    if (loggerTopic == null || loggerTopic.trim().length() == 0) {
        parameter = framework.createFactoryParameter(loggingType, source);
    } else {
        parameter = new StringLiteral(loggerTopic.toCharArray(), pS, pE, 0);
    }
    factoryMethodCall.arguments = new Expression[] { parameter };
    factoryMethodCall.nameSourcePosition = p;
    factoryMethodCall.sourceStart = pS;
    factoryMethodCall.sourceEnd = factoryMethodCall.statementEnd = pE;
    fieldDecl.initialization = factoryMethodCall;
    return fieldDecl;
}
Also used : MessageSend(org.eclipse.jdt.internal.compiler.ast.MessageSend) StringLiteral(org.eclipse.jdt.internal.compiler.ast.StringLiteral) Expression(org.eclipse.jdt.internal.compiler.ast.Expression) FieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)

Example 39 with FieldDeclaration

use of org.eclipse.jdt.internal.compiler.ast.FieldDeclaration in project lombok by rzwitserloot.

the class HandleSynchronized method createLockField.

public char[] createLockField(AnnotationValues<Synchronized> annotation, EclipseNode annotationNode, boolean isStatic, boolean reportErrors) {
    char[] lockName = annotation.getInstance().value().toCharArray();
    Annotation source = (Annotation) annotationNode.get();
    boolean autoMake = false;
    if (lockName.length == 0) {
        autoMake = true;
        lockName = isStatic ? STATIC_LOCK_NAME : INSTANCE_LOCK_NAME;
    }
    if (fieldExists(new String(lockName), annotationNode) == MemberExistsResult.NOT_EXISTS) {
        if (!autoMake) {
            if (reportErrors)
                annotationNode.addError(String.format("The field %s does not exist.", new String(lockName)));
            return null;
        }
        FieldDeclaration fieldDecl = new FieldDeclaration(lockName, 0, -1);
        setGeneratedBy(fieldDecl, source);
        fieldDecl.declarationSourceEnd = -1;
        fieldDecl.modifiers = (isStatic ? Modifier.STATIC : 0) | Modifier.FINAL | Modifier.PRIVATE;
        // We use 'new Object[0];' because unlike 'new Object();', empty arrays *ARE* serializable!
        ArrayAllocationExpression arrayAlloc = new ArrayAllocationExpression();
        setGeneratedBy(arrayAlloc, source);
        arrayAlloc.dimensions = new Expression[] { makeIntLiteral("0".toCharArray(), source) };
        arrayAlloc.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { 0, 0, 0 });
        setGeneratedBy(arrayAlloc.type, source);
        fieldDecl.type = new QualifiedTypeReference(TypeConstants.JAVA_LANG_OBJECT, new long[] { 0, 0, 0 });
        setGeneratedBy(fieldDecl.type, source);
        fieldDecl.initialization = arrayAlloc;
        // TODO temporary workaround for issue 217. http://code.google.com/p/projectlombok/issues/detail?id=217
        // injectFieldSuppressWarnings(annotationNode.up().up(), fieldDecl);
        injectField(annotationNode.up().up(), fieldDecl);
    }
    return lockName;
}
Also used : ArrayAllocationExpression(org.eclipse.jdt.internal.compiler.ast.ArrayAllocationExpression) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) Annotation(org.eclipse.jdt.internal.compiler.ast.Annotation) FieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)

Example 40 with FieldDeclaration

use of org.eclipse.jdt.internal.compiler.ast.FieldDeclaration in project lombok by rzwitserloot.

the class HandleWither method generateWitherForType.

public boolean generateWitherForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelWither) {
    if (checkForTypeLevelWither) {
        if (hasAnnotation(Wither.class, typeNode)) {
            // The annotation will make it happen, so we can skip it.
            return true;
        }
    }
    TypeDeclaration typeDecl = null;
    if (typeNode.get() instanceof TypeDeclaration)
        typeDecl = (TypeDeclaration) typeNode.get();
    int modifiers = typeDecl == null ? 0 : typeDecl.modifiers;
    boolean notAClass = (modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccAnnotation | ClassFileConstants.AccEnum)) != 0;
    if (typeDecl == null || notAClass) {
        pos.addError("@Wither is only supported on a class or a field.");
        return false;
    }
    for (EclipseNode field : typeNode.down()) {
        if (field.getKind() != Kind.FIELD)
            continue;
        FieldDeclaration fieldDecl = (FieldDeclaration) field.get();
        if (!filterField(fieldDecl))
            continue;
        // Skip final fields.
        if ((fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0 && fieldDecl.initialization != null)
            continue;
        generateWitherForField(field, pos, level);
    }
    return true;
}
Also used : EclipseNode(lombok.eclipse.EclipseNode) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) FieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)

Aggregations

FieldDeclaration (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)40 EclipseNode (lombok.eclipse.EclipseNode)21 MethodDeclaration (org.eclipse.jdt.internal.compiler.ast.MethodDeclaration)17 TypeDeclaration (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)17 ArrayList (java.util.ArrayList)15 TypeReference (org.eclipse.jdt.internal.compiler.ast.TypeReference)11 Expression (org.eclipse.jdt.internal.compiler.ast.Expression)10 QualifiedTypeReference (org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference)10 ReturnStatement (org.eclipse.jdt.internal.compiler.ast.ReturnStatement)10 AbstractMethodDeclaration (org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)7 Annotation (org.eclipse.jdt.internal.compiler.ast.Annotation)7 SingleNameReference (org.eclipse.jdt.internal.compiler.ast.SingleNameReference)7 Statement (org.eclipse.jdt.internal.compiler.ast.Statement)7 ASTNode (org.eclipse.jdt.internal.compiler.ast.ASTNode)6 AllocationExpression (org.eclipse.jdt.internal.compiler.ast.AllocationExpression)6 Argument (org.eclipse.jdt.internal.compiler.ast.Argument)6 ArrayTypeReference (org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference)4 Assignment (org.eclipse.jdt.internal.compiler.ast.Assignment)4 EqualExpression (org.eclipse.jdt.internal.compiler.ast.EqualExpression)4 MessageSend (org.eclipse.jdt.internal.compiler.ast.MessageSend)4