Search in sources :

Example 6 with JCTree

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

the class JavacResolution method resolveMethodMember.

public Map<JCTree, JCTree> resolveMethodMember(JavacNode node) {
    ArrayDeque<JCTree> stack = new ArrayDeque<JCTree>();
    {
        JavacNode n = node;
        while (n != null) {
            stack.push(n.get());
            n = n.up();
        }
    }
    messageSuppressor.disableLoggers();
    try {
        EnvFinder finder = new EnvFinder(node.getContext());
        while (!stack.isEmpty()) stack.pop().accept(finder);
        TreeMirrorMaker mirrorMaker = new TreeMirrorMaker(node.getTreeMaker(), node.getContext());
        JCTree copy = mirrorMaker.copy(finder.copyAt());
        memberEnterAndAttribute(copy, finder.get(), node.getContext());
        return mirrorMaker.getOriginalToCopyMap();
    } finally {
        messageSuppressor.enableLoggers();
    }
}
Also used : JCTree(com.sun.tools.javac.tree.JCTree) ArrayDeque(java.util.ArrayDeque)

Example 7 with JCTree

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

the class HandleDelegate method handle.

@Override
public void handle(AnnotationValues<Delegate> annotation, JCAnnotation ast, JavacNode annotationNode) {
    handleExperimentalFlagUsage(annotationNode, ConfigurationKeys.DELEGATE_FLAG_USAGE, "@Delegate");
    @SuppressWarnings("deprecation") Class<? extends Annotation> oldDelegate = lombok.Delegate.class;
    deleteAnnotationIfNeccessary(annotationNode, Delegate.class, oldDelegate);
    Type delegateType;
    Name delegateName = annotationNode.toName(annotationNode.up().getName());
    DelegateReceiver delegateReceiver;
    JavacResolution reso = new JavacResolution(annotationNode.getContext());
    JCTree member = annotationNode.up().get();
    if (annotationNode.up().getKind() == Kind.FIELD) {
        if ((((JCVariableDecl) member).mods.flags & Flags.STATIC) != 0) {
            annotationNode.addError(LEGALITY_OF_DELEGATE);
            return;
        }
        delegateReceiver = DelegateReceiver.FIELD;
        delegateType = member.type;
        if (delegateType == null)
            reso.resolveClassMember(annotationNode.up());
        delegateType = member.type;
    } else if (annotationNode.up().getKind() == Kind.METHOD) {
        if (!(member instanceof JCMethodDecl)) {
            annotationNode.addError(LEGALITY_OF_DELEGATE);
            return;
        }
        JCMethodDecl methodDecl = (JCMethodDecl) member;
        if (!methodDecl.params.isEmpty() || (methodDecl.mods.flags & Flags.STATIC) != 0) {
            annotationNode.addError(LEGALITY_OF_DELEGATE);
            return;
        }
        delegateReceiver = DelegateReceiver.METHOD;
        delegateType = methodDecl.restype.type;
        if (delegateType == null)
            reso.resolveClassMember(annotationNode.up());
        delegateType = methodDecl.restype.type;
    } else {
        // As the annotation is legal on fields and methods only, javac itself will take care of printing an error message for this.
        return;
    }
    List<Object> delegateTypes = annotation.getActualExpressions("types");
    List<Object> excludeTypes = annotation.getActualExpressions("excludes");
    List<Type> toDelegate = new ArrayList<Type>();
    List<Type> toExclude = new ArrayList<Type>();
    if (delegateTypes.isEmpty()) {
        if (delegateType != null)
            toDelegate.add(delegateType);
    } else {
        for (Object dt : delegateTypes) {
            if (dt instanceof JCFieldAccess && ((JCFieldAccess) dt).name.toString().equals("class")) {
                Type type = ((JCFieldAccess) dt).selected.type;
                if (type == null)
                    reso.resolveClassMember(annotationNode);
                type = ((JCFieldAccess) dt).selected.type;
                if (type != null)
                    toDelegate.add(type);
            }
        }
    }
    for (Object et : excludeTypes) {
        if (et instanceof JCFieldAccess && ((JCFieldAccess) et).name.toString().equals("class")) {
            Type type = ((JCFieldAccess) et).selected.type;
            if (type == null)
                reso.resolveClassMember(annotationNode);
            type = ((JCFieldAccess) et).selected.type;
            if (type != null)
                toExclude.add(type);
        }
    }
    List<MethodSig> signaturesToDelegate = new ArrayList<MethodSig>();
    List<MethodSig> signaturesToExclude = new ArrayList<MethodSig>();
    Set<String> banList = new HashSet<String>();
    banList.addAll(METHODS_IN_OBJECT);
    try {
        for (Type t : toExclude) {
            if (t instanceof ClassType) {
                ClassType ct = (ClassType) t;
                addMethodBindings(signaturesToExclude, ct, annotationNode.getTypesUtil(), banList);
            } else {
                annotationNode.addError("@Delegate can only use concrete class types, not wildcards, arrays, type variables, or primitives.");
                return;
            }
        }
        for (MethodSig sig : signaturesToExclude) {
            banList.add(printSig(sig.type, sig.name, annotationNode.getTypesUtil()));
        }
        for (Type t : toDelegate) {
            if (t instanceof ClassType) {
                ClassType ct = (ClassType) t;
                addMethodBindings(signaturesToDelegate, ct, annotationNode.getTypesUtil(), banList);
            } else {
                annotationNode.addError("@Delegate can only use concrete class types, not wildcards, arrays, type variables, or primitives.");
                return;
            }
        }
        for (MethodSig sig : signaturesToDelegate) generateAndAdd(sig, annotationNode, delegateName, delegateReceiver);
    } catch (DelegateRecursion e) {
        annotationNode.addError(String.format(RECURSION_NOT_ALLOWED, e.member, e.type));
    }
}
Also used : JavacResolution(lombok.javac.JavacResolution) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JCFieldAccess(com.sun.tools.javac.tree.JCTree.JCFieldAccess) ArrayList(java.util.ArrayList) JCTree(com.sun.tools.javac.tree.JCTree) ClassType(com.sun.tools.javac.code.Type.ClassType) JCVariableDecl(com.sun.tools.javac.tree.JCTree.JCVariableDecl) Name(com.sun.tools.javac.util.Name) ClassType(com.sun.tools.javac.code.Type.ClassType) Type(com.sun.tools.javac.code.Type) ExecutableType(javax.lang.model.type.ExecutableType) Delegate(lombok.experimental.Delegate) HashSet(java.util.HashSet)

Example 8 with JCTree

use of com.sun.tools.javac.tree.JCTree 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 9 with JCTree

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

the class HandleGetter method createGetter.

public JCMethodDecl createGetter(long access, JavacNode field, JavacTreeMaker treeMaker, JCTree source, boolean lazy, List<JCAnnotation> onMethod) {
    JCVariableDecl fieldNode = (JCVariableDecl) field.get();
    // Remember the type; lazy will change it
    JCExpression methodType = copyType(treeMaker, fieldNode);
    // Generate the methodName; lazy will change the field type
    Name methodName = field.toName(toGetterName(field));
    List<JCStatement> statements;
    JCTree toClearOfMarkers = null;
    if (lazy && !inNetbeansEditor(field)) {
        toClearOfMarkers = fieldNode.init;
        statements = createLazyGetterBody(treeMaker, field, source);
    } else {
        statements = createSimpleGetterBody(treeMaker, field);
    }
    JCBlock methodBody = treeMaker.Block(0, statements);
    List<JCTypeParameter> methodGenericParams = List.nil();
    List<JCVariableDecl> parameters = List.nil();
    List<JCExpression> throwsClauses = List.nil();
    JCExpression annotationMethodDefaultValue = null;
    List<JCAnnotation> nonNulls = findAnnotations(field, NON_NULL_PATTERN);
    List<JCAnnotation> nullables = findAnnotations(field, NULLABLE_PATTERN);
    List<JCAnnotation> delegates = findDelegatesAndRemoveFromField(field);
    List<JCAnnotation> annsOnMethod = copyAnnotations(onMethod).appendList(nonNulls).appendList(nullables);
    if (isFieldDeprecated(field)) {
        annsOnMethod = annsOnMethod.prepend(treeMaker.Annotation(genJavaLangTypeRef(field, "Deprecated"), List.<JCExpression>nil()));
    }
    JCMethodDecl decl = recursiveSetGeneratedBy(treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType, methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source, field.getContext());
    if (toClearOfMarkers != null)
        recursiveSetGeneratedBy(toClearOfMarkers, null, null);
    decl.mods.annotations = decl.mods.annotations.appendList(delegates);
    copyJavadoc(field, decl, CopyJavadoc.GETTER);
    return decl;
}
Also used : JCBlock(com.sun.tools.javac.tree.JCTree.JCBlock) JCMethodDecl(com.sun.tools.javac.tree.JCTree.JCMethodDecl) JCTree(com.sun.tools.javac.tree.JCTree) 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) JCExpression(com.sun.tools.javac.tree.JCTree.JCExpression) JCAnnotation(com.sun.tools.javac.tree.JCTree.JCAnnotation)

Example 10 with JCTree

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

the class DocCommentIntegrator method integrate.

/**
	 * Returns the same comment list as when this integrator was created, minus all doc comments that have been successfully integrated into the compilation unit.
	 */
public List<CommentInfo> integrate(List<CommentInfo> comments, JCCompilationUnit unit) {
    List<CommentInfo> out = new ArrayList<CommentInfo>();
    CommentInfo lastExcisedComment = null;
    JCTree lastNode = null;
    for (CommentInfo cmt : comments) {
        if (!cmt.isJavadoc()) {
            out.add(cmt);
            continue;
        }
        JCTree node = findJavadocableNodeOnOrAfter(unit, cmt.endPos);
        if (node == null) {
            out.add(cmt);
            continue;
        }
        if (node == lastNode) {
            out.add(lastExcisedComment);
        }
        if (!attach(unit, node, cmt)) {
            out.add(cmt);
        } else {
            lastNode = node;
            lastExcisedComment = cmt;
        }
    }
    return out;
}
Also used : ArrayList(java.util.ArrayList) JCTree(com.sun.tools.javac.tree.JCTree) CommentInfo(lombok.javac.CommentInfo)

Aggregations

JCTree (com.sun.tools.javac.tree.JCTree)183 JCExpression (com.sun.tools.javac.tree.JCTree.JCExpression)28 Symbol (com.sun.tools.javac.code.Symbol)22 JCVariableDecl (com.sun.tools.javac.tree.JCTree.JCVariableDecl)22 Type (com.sun.tools.javac.code.Type)19 Tree (com.redhat.ceylon.compiler.typechecker.tree.Tree)17 Tree (com.sun.source.tree.Tree)15 ExpressionTree (com.sun.source.tree.ExpressionTree)14 JCFieldAccess (com.sun.tools.javac.tree.JCTree.JCFieldAccess)14 SuggestedFix (com.google.errorprone.fixes.SuggestedFix)11 JCClassDecl (com.sun.tools.javac.tree.JCTree.JCClassDecl)11 JCStatement (com.sun.tools.javac.tree.JCTree.JCStatement)10 ArrayList (java.util.ArrayList)10 MethodInvocationTree (com.sun.source.tree.MethodInvocationTree)9 JCMethodDecl (com.sun.tools.javac.tree.JCTree.JCMethodDecl)9 JCNewClass (com.sun.tools.javac.tree.JCTree.JCNewClass)8 ListBuffer (com.sun.tools.javac.util.ListBuffer)8 Type (com.redhat.ceylon.model.typechecker.model.Type)7 ClassTree (com.sun.source.tree.ClassTree)7 MemberSelectTree (com.sun.source.tree.MemberSelectTree)7