Search in sources :

Example 16 with JCClassDecl

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

the class HandleToString method generateToString.

public void generateToString(JavacNode typeNode, JavacNode source, List<String> excludes, List<String> includes, boolean includeFieldNames, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess) {
    boolean notAClass = true;
    if (typeNode.get() instanceof JCClassDecl) {
        long flags = ((JCClassDecl) typeNode.get()).mods.flags;
        notAClass = (flags & (Flags.INTERFACE | Flags.ANNOTATION)) != 0;
    }
    if (callSuper == null) {
        try {
            callSuper = ((Boolean) ToString.class.getMethod("callSuper").getDefaultValue()).booleanValue();
        } catch (Exception ignore) {
        }
    }
    if (notAClass) {
        source.addError("@ToString is only supported on a class or enum.");
        return;
    }
    ListBuffer<JavacNode> nodesForToString = new ListBuffer<JavacNode>();
    if (includes != null) {
        for (JavacNode child : typeNode.down()) {
            if (child.getKind() != Kind.FIELD)
                continue;
            JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
            if (includes.contains(fieldDecl.name.toString()))
                nodesForToString.append(child);
        }
    } else {
        for (JavacNode child : typeNode.down()) {
            if (child.getKind() != Kind.FIELD)
                continue;
            JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
            // Skip static fields.
            if ((fieldDecl.mods.flags & Flags.STATIC) != 0)
                continue;
            // Skip excluded fields.
            if (excludes != null && excludes.contains(fieldDecl.name.toString()))
                continue;
            // Skip fields that start with $.
            if (fieldDecl.name.toString().startsWith("$"))
                continue;
            nodesForToString.append(child);
        }
    }
    switch(methodExists("toString", typeNode, 0)) {
        case NOT_EXISTS:
            JCMethodDecl method = createToString(typeNode, nodesForToString.toList(), includeFieldNames, callSuper, fieldAccess, source.get());
            injectMethod(typeNode, method);
            break;
        case EXISTS_BY_LOMBOK:
            break;
        default:
        case EXISTS_BY_USER:
            if (whineIfExists) {
                source.addWarning("Not generating toString(): A method with that name already exists");
            }
            break;
    }
}
Also used : JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JavacNode(lombok.javac.JavacNode) ListBuffer(com.sun.tools.javac.util.ListBuffer) ToString(lombok.ToString) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl)

Example 17 with JCClassDecl

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

the class HandleValue method handle.

@Override
public void handle(AnnotationValues<Value> annotation, JCAnnotation ast, JavacNode annotationNode) {
    handleFlagUsage(annotationNode, ConfigurationKeys.VALUE_FLAG_USAGE, "@Value");
    deleteAnnotationIfNeccessary(annotationNode, Value.class, "lombok.experimental.Value");
    JavacNode typeNode = annotationNode.up();
    boolean notAClass = !isClass(typeNode);
    if (notAClass) {
        annotationNode.addError("@Value is only supported on a class.");
        return;
    }
    String staticConstructorName = annotation.getInstance().staticConstructor();
    if (!hasAnnotationAndDeleteIfNeccessary(NonFinal.class, typeNode)) {
        JCModifiers jcm = ((JCClassDecl) typeNode.get()).mods;
        if ((jcm.flags & Flags.FINAL) == 0) {
            jcm.flags |= Flags.FINAL;
            typeNode.rebuild();
        }
    }
    handleFieldDefaults.generateFieldDefaultsForType(typeNode, annotationNode, AccessLevel.PRIVATE, true, true);
    handleConstructor.generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, staticConstructorName, SkipIfConstructorExists.YES, annotationNode);
    handleGetter.generateGetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true);
    handleEqualsAndHashCode.generateEqualsAndHashCodeForType(typeNode, annotationNode);
    handleToString.generateToStringForType(typeNode, annotationNode);
}
Also used : JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JavacNode(lombok.javac.JavacNode) JCModifiers(com.sun.tools.javac.tree.JCTree.JCModifiers) NonFinal(lombok.experimental.NonFinal)

Example 18 with JCClassDecl

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

the class JavacHandlerUtil method injectMethod.

/**
 * Adds the given new method declaration to the provided type AST Node.
 * Can also inject constructors.
 *
 * Also takes care of updating the JavacAST.
 */
public static void injectMethod(JavacNode typeNode, JCMethodDecl method, List<Type> paramTypes, Type returnType) {
    JCClassDecl type = (JCClassDecl) typeNode.get();
    if (method.getName().contentEquals("<init>")) {
        // Scan for default constructor, and remove it.
        int idx = 0;
        for (JCTree def : type.defs) {
            if (def instanceof JCMethodDecl) {
                if ((((JCMethodDecl) def).mods.flags & Flags.GENERATEDCONSTR) != 0) {
                    JavacNode tossMe = typeNode.getNodeFor(def);
                    if (tossMe != null)
                        tossMe.up().removeChild(tossMe);
                    type.defs = addAllButOne(type.defs, idx);
                    ClassSymbolMembersField.remove(type.sym, ((JCMethodDecl) def).sym);
                    break;
                }
            }
            idx++;
        }
    }
    addSuppressWarningsAll(method.mods, typeNode, method.pos, getGeneratedBy(method), typeNode.getContext());
    addGenerated(method.mods, typeNode, method.pos, getGeneratedBy(method), typeNode.getContext());
    type.defs = type.defs.append(method);
    fixMethodMirror(typeNode.getContext(), typeNode.getElement(), method.getModifiers().flags, method.getName(), paramTypes, returnType);
    typeNode.add(method, Kind.METHOD);
}
Also used : JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JavacNode(lombok.javac.JavacNode) JCTree(com.sun.tools.javac.tree.JCTree)

Example 19 with JCClassDecl

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

the class HandleEqualsAndHashCode method generateMethods.

public void generateMethods(JavacNode typeNode, JavacNode source, List<String> excludes, List<String> includes, Boolean callSuper, boolean whineIfExists, FieldAccess fieldAccess, List<JCAnnotation> onParam) {
    boolean notAClass = true;
    if (typeNode.get() instanceof JCClassDecl) {
        long flags = ((JCClassDecl) typeNode.get()).mods.flags;
        notAClass = (flags & (Flags.INTERFACE | Flags.ANNOTATION | Flags.ENUM)) != 0;
    }
    if (notAClass) {
        source.addError("@EqualsAndHashCode is only supported on a class.");
        return;
    }
    boolean isDirectDescendantOfObject = true;
    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.");
        }
    }
    JCTree extending = Javac.getExtendsClause((JCClassDecl) typeNode.get());
    if (extending != null) {
        String p = extending.toString();
        isDirectDescendantOfObject = p.equals("Object") || p.equals("java.lang.Object");
    }
    if (isDirectDescendantOfObject && callSuper) {
        source.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:
                source.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;
        }
    }
    ListBuffer<JavacNode> nodesForEquality = new ListBuffer<JavacNode>();
    if (includes != null) {
        for (JavacNode child : typeNode.down()) {
            if (child.getKind() != Kind.FIELD)
                continue;
            JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
            if (includes.contains(fieldDecl.name.toString()))
                nodesForEquality.append(child);
        }
    } else {
        for (JavacNode child : typeNode.down()) {
            if (child.getKind() != Kind.FIELD)
                continue;
            JCVariableDecl fieldDecl = (JCVariableDecl) child.get();
            // Skip static fields.
            if ((fieldDecl.mods.flags & Flags.STATIC) != 0)
                continue;
            // Skip transient fields.
            if ((fieldDecl.mods.flags & Flags.TRANSIENT) != 0)
                continue;
            // Skip excluded fields.
            if (excludes != null && excludes.contains(fieldDecl.name.toString()))
                continue;
            // Skip fields that start with $
            if (fieldDecl.name.toString().startsWith("$"))
                continue;
            nodesForEquality.append(child);
        }
    }
    boolean isFinal = (((JCClassDecl) typeNode.get()).mods.flags & Flags.FINAL) != 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).";
                source.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");
                source.addWarning(msg);
            }
            return;
        case NOT_EXISTS:
        default:
    }
    JCMethodDecl equalsMethod = createEquals(typeNode, nodesForEquality.toList(), callSuper, fieldAccess, needsCanEqual, source.get(), onParam);
    injectMethod(typeNode, equalsMethod);
    if (needsCanEqual && canEqualExists == MemberExistsResult.NOT_EXISTS) {
        JCMethodDecl canEqualMethod = createCanEqual(typeNode, source.get(), onParam);
        injectMethod(typeNode, canEqualMethod);
    }
    JCMethodDecl hashCodeMethod = createHashCode(typeNode, nodesForEquality.toList(), callSuper, fieldAccess, source.get());
    injectMethod(typeNode, hashCodeMethod);
}
Also used : MemberExistsResult(lombok.javac.handlers.JavacHandlerUtil.MemberExistsResult) JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) EqualsAndHashCode(lombok.EqualsAndHashCode) ListBuffer(com.sun.tools.javac.util.ListBuffer) JCTree(com.sun.tools.javac.tree.JCTree) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) JavacNode(lombok.javac.JavacNode) CallSuperType(lombok.core.configuration.CallSuperType)

Example 20 with JCClassDecl

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

the class HandleGetter method generateGetterForType.

public void generateGetterForType(JavacNode typeNode, JavacNode errorNode, AccessLevel level, boolean checkForTypeLevelGetter) {
    if (checkForTypeLevelGetter) {
        if (hasAnnotation(Getter.class, typeNode)) {
            // The annotation will make it happen, so we can skip it.
            return;
        }
    }
    JCClassDecl typeDecl = null;
    if (typeNode.get() instanceof JCClassDecl)
        typeDecl = (JCClassDecl) typeNode.get();
    long modifiers = typeDecl == null ? 0 : typeDecl.mods.flags;
    boolean notAClass = (modifiers & (Flags.INTERFACE | Flags.ANNOTATION)) != 0;
    if (typeDecl == null || notAClass) {
        errorNode.addError("@Getter is only supported on a class, an enum, or a field.");
        return;
    }
    for (JavacNode field : typeNode.down()) {
        if (fieldQualifiesForGetterGeneration(field))
            generateGetterForField(field, errorNode.get(), level, false);
    }
}
Also used : JCClassDecl(com.sun.tools.javac.tree.JCTree.JCClassDecl) JavacNode(lombok.javac.JavacNode)

Aggregations

JCClassDecl (com.sun.tools.javac.tree.JCTree.JCClassDecl)46 JavacNode (lombok.javac.JavacNode)24 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)23 JCMethodDecl (com.sun.tools.javac.tree.JCTree.JCMethodDecl)14 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)11 ListBuffer (com.sun.tools.javac.util.ListBuffer)11 JCTree (com.sun.tools.javac.tree.JCTree)10 JCTypeParameter (com.sun.tools.javac.tree.JCTree.JCTypeParameter)9 JavacTreeMaker (lombok.javac.JavacTreeMaker)9 ClassSymbol (com.sun.tools.javac.code.Symbol.ClassSymbol)6 Name (com.sun.tools.javac.util.Name)6 Type (com.sun.tools.javac.code.Type)5 JCModifiers (com.sun.tools.javac.tree.JCTree.JCModifiers)5 JCAnnotation (com.sun.tools.javac.tree.JCTree.JCAnnotation)4 JCFieldAccess (com.sun.tools.javac.tree.JCTree.JCFieldAccess)4 JCIdent (com.sun.tools.javac.tree.JCTree.JCIdent)4 JCStatement (com.sun.tools.javac.tree.JCTree.JCStatement)4 JCCompilationUnit (com.sun.tools.javac.tree.JCTree.JCCompilationUnit)3 Type (com.redhat.ceylon.model.typechecker.model.Type)2 Tree (com.sun.source.tree.Tree)2