Search in sources :

Example 46 with JavacNode

use of lombok.javac.JavacNode in project lombok by rzwitserloot.

the class HandleConstructor method findFields.

public static List<JavacNode> findFields(JavacNode typeNode, boolean nullMarked) {
    ListBuffer<JavacNode> fields = new ListBuffer<JavacNode>();
    for (JavacNode child : typeNode.down()) {
        if (child.getKind() != Kind.FIELD)
            continue;
        JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
        //Skip fields that start with $
        if (fieldDecl.name.toString().startsWith("$"))
            continue;
        long fieldFlags = fieldDecl.mods.flags;
        //Skip static fields.
        if ((fieldFlags & Flags.STATIC) != 0)
            continue;
        boolean isFinal = (fieldFlags & Flags.FINAL) != 0;
        boolean isNonNull = nullMarked && !findAnnotations(child, NON_NULL_PATTERN).isEmpty();
        if ((isFinal || isNonNull) && fieldDecl.init == null)
            fields.append(child);
    }
    return fields.toList();
}
Also used : JavacNode(lombok.javac.JavacNode) ListBuffer(com.sun.tools.javac.util.ListBuffer) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl)

Example 47 with JavacNode

use of lombok.javac.JavacNode in project lombok by rzwitserloot.

the class HandleData method handle.

@Override
public void handle(AnnotationValues<Data> annotation, JCAnnotation ast, JavacNode annotationNode) {
    handleFlagUsage(annotationNode, ConfigurationKeys.DATA_FLAG_USAGE, "@Data");
    deleteAnnotationIfNeccessary(annotationNode, Data.class);
    JavacNode typeNode = annotationNode.up();
    boolean notAClass = !isClass(typeNode);
    if (notAClass) {
        annotationNode.addError("@Data is only supported on a class.");
        return;
    }
    String staticConstructorName = annotation.getInstance().staticConstructor();
    // TODO move this to the end OR move it to the top in eclipse.
    new HandleConstructor().generateRequiredArgsConstructor(typeNode, AccessLevel.PUBLIC, staticConstructorName, SkipIfConstructorExists.YES, annotationNode);
    new HandleGetter().generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
    new HandleSetter().generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
    new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode);
    new HandleToString().generateToStringForType(typeNode, annotationNode);
}
Also used : JavacNode(lombok.javac.JavacNode)

Example 48 with JavacNode

use of lombok.javac.JavacNode in project lombok by rzwitserloot.

the class HandleDelegate method checkConflictOfTypeVarNames.

/**
	 * There's a rare but problematic case if a delegate method has its own type variables, and the delegated type does too, and the method uses both.
	 * If for example the delegated type has {@code <E>}, and the method has {@code <T>}, but in our class we have a {@code <T>} at the class level, then we have two different
	 * type variables both named {@code T}. We detect this situation and error out asking the programmer to rename their type variable.
	 * 
	 * @throws CantMakeDelegates If there's a conflict. Conflict list is in ex.conflicted.
	 */
public void checkConflictOfTypeVarNames(MethodSig sig, JavacNode annotation) throws CantMakeDelegates {
    if (sig.elem.getTypeParameters().isEmpty())
        return;
    Set<String> usedInOurType = new HashSet<String>();
    JavacNode enclosingType = annotation;
    while (enclosingType != null) {
        if (enclosingType.getKind() == Kind.TYPE) {
            List<JCTypeParameter> typarams = ((JCClassDecl) enclosingType.get()).typarams;
            if (typarams != null)
                for (JCTypeParameter param : typarams) {
                    if (param.name != null)
                        usedInOurType.add(param.name.toString());
                }
        }
        enclosingType = enclosingType.up();
    }
    Set<String> usedInMethodSig = new HashSet<String>();
    for (TypeParameterElement param : sig.elem.getTypeParameters()) {
        usedInMethodSig.add(param.getSimpleName().toString());
    }
    usedInMethodSig.retainAll(usedInOurType);
    if (usedInMethodSig.isEmpty())
        return;
    // We might be delegating a List<T>, and we are making method <T> toArray(). A conflict is possible.
    // But only if the toArray method also uses type vars from its class, otherwise we're only shadowing,
    // which is okay as we'll add a @SuppressWarnings.
    FindTypeVarScanner scanner = new FindTypeVarScanner();
    sig.elem.asType().accept(scanner, null);
    Set<String> names = new HashSet<String>(scanner.getTypeVariables());
    names.removeAll(usedInMethodSig);
    if (!names.isEmpty()) {
        // We have a confirmed conflict. We could dig deeper as this may still be a false alarm, but its already an exceedingly rare case.
        CantMakeDelegates cmd = new CantMakeDelegates();
        cmd.conflicted = usedInMethodSig;
        throw cmd;
    }
}
Also used : JCTypeParameter(com.sun.tools.javac.tree.JCTree.JCTypeParameter) JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) FindTypeVarScanner(lombok.javac.FindTypeVarScanner) JavacNode(lombok.javac.JavacNode) HashSet(java.util.HashSet) TypeParameterElement(javax.lang.model.element.TypeParameterElement)

Example 49 with JavacNode

use of lombok.javac.JavacNode in project lombok by rzwitserloot.

the class HandleEqualsAndHashCode method createTypeReference.

public JCExpression createTypeReference(JavacNode type, boolean addWildcards) {
    java.util.List<String> list = new ArrayList<String>();
    list.add(type.getName());
    JavacNode tNode = type.up();
    while (tNode != null && tNode.getKind() == Kind.TYPE) {
        list.add(tNode.getName());
        tNode = tNode.up();
    }
    Collections.reverse(list);
    JCClassDecl typeDecl = (JCClassDecl) type.get();
    JavacTreeMaker maker = type.getTreeMaker();
    JCExpression chain = maker.Ident(type.toName(list.get(0)));
    for (int i = 1; i < list.size(); i++) {
        chain = maker.Select(chain, type.toName(list.get(i)));
    }
    if (!addWildcards || typeDecl.typarams.length() == 0)
        return chain;
    ListBuffer<JCExpression> wildcards = new ListBuffer<JCExpression>();
    for (int i = 0; i < typeDecl.typarams.length(); i++) {
        wildcards.append(maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null));
    }
    return maker.TypeApply(chain, wildcards.toList());
}
Also used : JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JavacTreeMaker(lombok.javac.JavacTreeMaker) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JavacNode(lombok.javac.JavacNode) ListBuffer(com.sun.tools.javac.util.ListBuffer) ArrayList(java.util.ArrayList)

Example 50 with JavacNode

use of lombok.javac.JavacNode in project lombok by rzwitserloot.

the class HandleEqualsAndHashCode method createEquals.

public JCMethodDecl createEquals(JavacNode typeNode, List<JavacNode> fields, boolean callSuper, FieldAccess fieldAccess, boolean needsCanEqual, JCTree source, List<JCAnnotation> onParam) {
    JavacTreeMaker maker = typeNode.getTreeMaker();
    Name oName = typeNode.toName("o");
    Name otherName = typeNode.toName("other");
    Name thisName = typeNode.toName("this");
    JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(typeNode, "Override"), List.<JCExpression>nil());
    JCModifiers mods = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation));
    JCExpression objectType = genJavaLangTypeRef(typeNode, "Object");
    JCExpression returnType = maker.TypeIdent(CTC_BOOLEAN);
    long finalFlag = JavacHandlerUtil.addFinalIfNeeded(0L, typeNode.getContext());
    ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>();
    final List<JCVariableDecl> params = List.of(maker.VarDef(maker.Modifiers(finalFlag | Flags.PARAMETER, onParam), oName, objectType, null));
    /* if (o == this) return true; */
    {
        statements.append(maker.If(maker.Binary(CTC_EQUAL, maker.Ident(oName), maker.Ident(thisName)), returnBool(maker, true), null));
    }
    /* if (!(o instanceof Outer.Inner.MyType)) return false; */
    {
        JCUnary notInstanceOf = maker.Unary(CTC_NOT, maker.Parens(maker.TypeTest(maker.Ident(oName), createTypeReference(typeNode, false))));
        statements.append(maker.If(notInstanceOf, returnBool(maker, false), null));
    }
    /* Outer.Inner.MyType<?> other = (Outer.Inner.MyType<?>) o; */
    {
        if (!fields.isEmpty() || needsCanEqual) {
            final JCExpression selfType1 = createTypeReference(typeNode, true), selfType2 = createTypeReference(typeNode, true);
            statements.append(maker.VarDef(maker.Modifiers(finalFlag), otherName, selfType1, maker.TypeCast(selfType2, maker.Ident(oName))));
        }
    }
    /* if (!other.canEqual((java.lang.Object) this)) return false; */
    {
        if (needsCanEqual) {
            List<JCExpression> exprNil = List.nil();
            JCExpression thisRef = maker.Ident(thisName);
            JCExpression castThisRef = maker.TypeCast(genJavaLangTypeRef(typeNode, "Object"), thisRef);
            JCExpression equalityCheck = maker.Apply(exprNil, maker.Select(maker.Ident(otherName), typeNode.toName("canEqual")), List.of(castThisRef));
            statements.append(maker.If(maker.Unary(CTC_NOT, equalityCheck), returnBool(maker, false), null));
        }
    }
    /* if (!super.equals(o)) return false; */
    if (callSuper) {
        JCMethodInvocation callToSuper = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(typeNode.toName("super")), typeNode.toName("equals")), List.<JCExpression>of(maker.Ident(oName)));
        JCUnary superNotEqual = maker.Unary(CTC_NOT, callToSuper);
        statements.append(maker.If(superNotEqual, returnBool(maker, false), null));
    }
    Name thisDollar = typeNode.toName("this$");
    Name otherDollar = typeNode.toName("other$");
    for (JavacNode fieldNode : fields) {
        JCExpression fType = getFieldType(fieldNode, fieldAccess);
        JCExpression thisFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess);
        JCExpression otherFieldAccessor = createFieldAccessor(maker, fieldNode, fieldAccess, maker.Ident(otherName));
        if (fType instanceof JCPrimitiveTypeTree) {
            switch(((JCPrimitiveTypeTree) fType).getPrimitiveTypeKind()) {
                case FLOAT:
                    /* if (Float.compare(this.fieldName, other.fieldName) != 0) return false; */
                    statements.append(generateCompareFloatOrDouble(thisFieldAccessor, otherFieldAccessor, maker, typeNode, false));
                    break;
                case DOUBLE:
                    /* if (Double.compare(this.fieldName, other.fieldName) != 0) return false; */
                    statements.append(generateCompareFloatOrDouble(thisFieldAccessor, otherFieldAccessor, maker, typeNode, true));
                    break;
                default:
                    /* if (this.fieldName != other.fieldName) return false; */
                    statements.append(maker.If(maker.Binary(CTC_NOT_EQUAL, thisFieldAccessor, otherFieldAccessor), returnBool(maker, false), null));
                    break;
            }
        } else if (fType instanceof JCArrayTypeTree) {
            /* if (!java.util.Arrays.deepEquals(this.fieldName, other.fieldName)) return false; //use equals for primitive arrays. */
            boolean multiDim = ((JCArrayTypeTree) fType).elemtype instanceof JCArrayTypeTree;
            boolean primitiveArray = ((JCArrayTypeTree) fType).elemtype instanceof JCPrimitiveTypeTree;
            boolean useDeepEquals = multiDim || !primitiveArray;
            JCExpression eqMethod = chainDots(typeNode, "java", "util", "Arrays", useDeepEquals ? "deepEquals" : "equals");
            List<JCExpression> args = List.of(thisFieldAccessor, otherFieldAccessor);
            statements.append(maker.If(maker.Unary(CTC_NOT, maker.Apply(List.<JCExpression>nil(), eqMethod, args)), returnBool(maker, false), null));
        } else /* objects */
        {
            /* final java.lang.Object this$fieldName = this.fieldName; */
            /* final java.lang.Object other$fieldName = other.fieldName; */
            /* if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false; */
            Name fieldName = ((JCVariableDecl) fieldNode.get()).name;
            Name thisDollarFieldName = thisDollar.append(fieldName);
            Name otherDollarFieldName = otherDollar.append(fieldName);
            statements.append(maker.VarDef(maker.Modifiers(finalFlag), thisDollarFieldName, genJavaLangTypeRef(typeNode, "Object"), thisFieldAccessor));
            statements.append(maker.VarDef(maker.Modifiers(finalFlag), otherDollarFieldName, genJavaLangTypeRef(typeNode, "Object"), otherFieldAccessor));
            JCExpression thisEqualsNull = maker.Binary(CTC_EQUAL, maker.Ident(thisDollarFieldName), maker.Literal(CTC_BOT, null));
            JCExpression otherNotEqualsNull = maker.Binary(CTC_NOT_EQUAL, maker.Ident(otherDollarFieldName), maker.Literal(CTC_BOT, null));
            JCExpression thisEqualsThat = maker.Apply(List.<JCExpression>nil(), maker.Select(maker.Ident(thisDollarFieldName), typeNode.toName("equals")), List.<JCExpression>of(maker.Ident(otherDollarFieldName)));
            JCExpression fieldsAreNotEqual = maker.Conditional(thisEqualsNull, otherNotEqualsNull, maker.Unary(CTC_NOT, thisEqualsThat));
            statements.append(maker.If(fieldsAreNotEqual, returnBool(maker, false), null));
        }
    }
    /* return true; */
    {
        statements.append(returnBool(maker, true));
    }
    JCBlock body = maker.Block(0, statements.toList());
    return recursiveSetGeneratedBy(maker.MethodDef(mods, typeNode.toName("equals"), returnType, List.<JCTypeParameter>nil(), params, 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) JCUnary(com.sun.tools.javac.tree.JCTree.JCUnary) ArrayList(java.util.ArrayList) List(com.sun.tools.javac.util.List) JCAnnotation(com.sun.tools.javac.tree.JCTree.JCAnnotation) JCArrayTypeTree(com.sun.tools.javac.tree.JCTree.JCArrayTypeTree)

Aggregations

JavacNode (lombok.javac.JavacNode)52 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)27 JCClassDecl (com.sun.tools.javac.tree.JCTree.JCClassDecl)23 ListBuffer (com.sun.tools.javac.util.ListBuffer)18 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)15 JavacTreeMaker (lombok.javac.JavacTreeMaker)15 JCAnnotation (com.sun.tools.javac.tree.JCTree.JCAnnotation)13 JCMethodDecl (com.sun.tools.javac.tree.JCTree.JCMethodDecl)13 Name (com.sun.tools.javac.util.Name)11 JCTypeParameter (com.sun.tools.javac.tree.JCTree.JCTypeParameter)9 JCStatement (com.sun.tools.javac.tree.JCTree.JCStatement)8 JCModifiers (com.sun.tools.javac.tree.JCTree.JCModifiers)7 JCBlock (com.sun.tools.javac.tree.JCTree.JCBlock)6 ArrayList (java.util.ArrayList)6 JCMethodInvocation (com.sun.tools.javac.tree.JCTree.JCMethodInvocation)5 JCTree (com.sun.tools.javac.tree.JCTree)4 JCArrayTypeTree (com.sun.tools.javac.tree.JCTree.JCArrayTypeTree)4 JCFieldAccess (com.sun.tools.javac.tree.JCTree.JCFieldAccess)4 JCPrimitiveTypeTree (com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree)4 AccessLevel (lombok.AccessLevel)4