Search in sources :

Example 1 with EclipseNode

use of lombok.eclipse.EclipseNode in project lombok by rzwitserloot.

the class PatchDelegate method checkConflictOfTypeVarNames.

public static void checkConflictOfTypeVarNames(BindingTuple binding, EclipseNode typeNode) throws CantMakeDelegates {
    TypeVariableBinding[] typeVars = binding.parameterized.typeVariables();
    if (typeVars == null || typeVars.length == 0)
        return;
    Set<String> usedInOurType = new HashSet<String>();
    EclipseNode enclosingType = typeNode;
    while (enclosingType != null) {
        if (enclosingType.getKind() == Kind.TYPE) {
            TypeParameter[] typeParameters = ((TypeDeclaration) enclosingType.get()).typeParameters;
            if (typeParameters != null) {
                for (TypeParameter param : typeParameters) {
                    if (param.name != null)
                        usedInOurType.add(new String(param.name));
                }
            }
        }
        enclosingType = enclosingType.up();
    }
    Set<String> usedInMethodSig = new HashSet<String>();
    for (TypeVariableBinding var : typeVars) {
        char[] sourceName = var.sourceName();
        if (sourceName != null)
            usedInMethodSig.add(new String(sourceName));
    }
    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.
    TypeVarFinder finder = new TypeVarFinder();
    finder.visitRaw(binding.base);
    Set<String> names = new HashSet<String>(finder.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 : TypeVariableBinding(org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding) TypeParameter(org.eclipse.jdt.internal.compiler.ast.TypeParameter) EclipseNode(lombok.eclipse.EclipseNode) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) HashSet(java.util.HashSet)

Example 2 with EclipseNode

use of lombok.eclipse.EclipseNode in project lombok by rzwitserloot.

the class PatchExtensionMethod method getApplicableExtensionMethods.

static List<Extension> getApplicableExtensionMethods(EclipseNode typeNode, Annotation ann, TypeBinding receiverType) {
    List<Extension> extensions = new ArrayList<Extension>();
    if ((typeNode != null) && (ann != null) && (receiverType != null)) {
        BlockScope blockScope = ((TypeDeclaration) typeNode.get()).initializerScope;
        EclipseNode annotationNode = typeNode.getNodeFor(ann);
        AnnotationValues<ExtensionMethod> annotation = createAnnotation(ExtensionMethod.class, annotationNode);
        boolean suppressBaseMethods = false;
        try {
            suppressBaseMethods = annotation.getInstance().suppressBaseMethods();
        } catch (AnnotationValueDecodeFail fail) {
            fail.owner.setError(fail.getMessage(), fail.idx);
        }
        for (Object extensionMethodProvider : annotation.getActualExpressions("value")) {
            if (extensionMethodProvider instanceof ClassLiteralAccess) {
                TypeBinding binding = ((ClassLiteralAccess) extensionMethodProvider).type.resolveType(blockScope);
                if (binding == null)
                    continue;
                if (!binding.isClass() && !binding.isEnum())
                    continue;
                Extension e = new Extension();
                e.extensionMethods = getApplicableExtensionMethodsDefinedInProvider(typeNode, (ReferenceBinding) binding, receiverType);
                e.suppressBaseMethods = suppressBaseMethods;
                extensions.add(e);
            }
        }
    }
    return extensions;
}
Also used : AnnotationValueDecodeFail(lombok.core.AnnotationValues.AnnotationValueDecodeFail) TypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) ArrayList(java.util.ArrayList) ReferenceBinding(org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding) BlockScope(org.eclipse.jdt.internal.compiler.lookup.BlockScope) EclipseNode(lombok.eclipse.EclipseNode) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) ExtensionMethod(lombok.experimental.ExtensionMethod) ClassLiteralAccess(org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess)

Example 3 with EclipseNode

use of lombok.eclipse.EclipseNode in project lombok by rzwitserloot.

the class PatchExtensionMethod method resolveType.

public static TypeBinding resolveType(TypeBinding resolvedType, MessageSend methodCall, BlockScope scope) {
    List<Extension> extensions = new ArrayList<Extension>();
    TypeDeclaration decl = scope.classScope().referenceContext;
    EclipseNode owningType = null;
    for (EclipseNode typeNode = getTypeNode(decl); typeNode != null; typeNode = upToType(typeNode)) {
        Annotation ann = getAnnotation(ExtensionMethod.class, typeNode);
        if (ann != null) {
            extensions.addAll(0, getApplicableExtensionMethods(typeNode, ann, methodCall.receiver.resolvedType));
            if (owningType == null)
                owningType = typeNode;
        }
    }
    boolean skip = false;
    if (methodCall.receiver instanceof ThisReference && (((ThisReference) methodCall.receiver).bits & ASTNode.IsImplicitThis) != 0)
        skip = true;
    if (methodCall.receiver instanceof SuperReference)
        skip = true;
    if (methodCall.receiver instanceof NameReference) {
        Binding binding = ((NameReference) methodCall.receiver).binding;
        if (binding instanceof TypeBinding)
            skip = true;
    }
    if (!skip)
        for (Extension extension : extensions) {
            if (!extension.suppressBaseMethods && !(methodCall.binding instanceof ProblemMethodBinding))
                continue;
            for (MethodBinding extensionMethod : extension.extensionMethods) {
                if (!Arrays.equals(methodCall.selector, extensionMethod.selector))
                    continue;
                MessageSend_postponedErrors.clear(methodCall);
                if (methodCall.receiver instanceof ThisReference) {
                    methodCall.receiver.bits &= ~ASTNode.IsImplicitThis;
                }
                List<Expression> arguments = new ArrayList<Expression>();
                arguments.add(methodCall.receiver);
                if (methodCall.arguments != null)
                    arguments.addAll(Arrays.asList(methodCall.arguments));
                List<TypeBinding> argumentTypes = new ArrayList<TypeBinding>();
                for (Expression argument : arguments) {
                    if (argument.resolvedType != null)
                        argumentTypes.add(argument.resolvedType);
                // TODO: Instead of just skipping nulls entirely, there is probably a 'unresolved type' placeholder. THAT is what we ought to be adding here!
                }
                Expression[] originalArgs = methodCall.arguments;
                methodCall.arguments = arguments.toArray(new Expression[0]);
                MethodBinding fixedBinding = scope.getMethod(extensionMethod.declaringClass, methodCall.selector, argumentTypes.toArray(new TypeBinding[0]), methodCall);
                if (fixedBinding instanceof ProblemMethodBinding) {
                    methodCall.arguments = originalArgs;
                    if (fixedBinding.declaringClass != null) {
                        PostponedInvalidMethodError.invoke(scope.problemReporter(), methodCall, fixedBinding, scope);
                    }
                } else {
                    for (int i = 0, iend = arguments.size(); i < iend; i++) {
                        Expression arg = arguments.get(i);
                        if (fixedBinding.parameters[i].isArrayType() != arg.resolvedType.isArrayType())
                            break;
                        if (arg instanceof MessageSend) {
                            ((MessageSend) arg).valueCast = arg.resolvedType;
                        }
                        if (!fixedBinding.parameters[i].isBaseType() && arg.resolvedType.isBaseType()) {
                            int id = arg.resolvedType.id;
                            // magic see TypeIds
                            arg.implicitConversion = TypeIds.BOXING | (id + (id << 4));
                        } else if (fixedBinding.parameters[i].isBaseType() && !arg.resolvedType.isBaseType()) {
                            int id = fixedBinding.parameters[i].id;
                            // magic see TypeIds
                            arg.implicitConversion = TypeIds.UNBOXING | (id + (id << 4));
                        }
                    }
                    methodCall.receiver = createNameRef(extensionMethod.declaringClass, methodCall);
                    methodCall.actualReceiverType = extensionMethod.declaringClass;
                    methodCall.binding = fixedBinding;
                    methodCall.resolvedType = methodCall.binding.returnType;
                }
                return methodCall.resolvedType;
            }
        }
    PostponedError error = MessageSend_postponedErrors.get(methodCall);
    if (error != null)
        error.fire();
    MessageSend_postponedErrors.clear(methodCall);
    return resolvedType;
}
Also used : Binding(org.eclipse.jdt.internal.compiler.lookup.Binding) TypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) ProblemMethodBinding(org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding) MethodBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding) ReferenceBinding(org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding) QualifiedNameReference(org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference) NameReference(org.eclipse.jdt.internal.compiler.ast.NameReference) SingleNameReference(org.eclipse.jdt.internal.compiler.ast.SingleNameReference) ProblemMethodBinding(org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding) TypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) ArrayList(java.util.ArrayList) ThisReference(org.eclipse.jdt.internal.compiler.ast.ThisReference) EclipseHandlerUtil.createAnnotation(lombok.eclipse.handlers.EclipseHandlerUtil.createAnnotation) Annotation(org.eclipse.jdt.internal.compiler.ast.Annotation) SuperReference(org.eclipse.jdt.internal.compiler.ast.SuperReference) MessageSend(org.eclipse.jdt.internal.compiler.ast.MessageSend) Expression(org.eclipse.jdt.internal.compiler.ast.Expression) EclipseNode(lombok.eclipse.EclipseNode) ProblemMethodBinding(org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding) MethodBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding) ArrayList(java.util.ArrayList) List(java.util.List) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)

Example 4 with EclipseNode

use of lombok.eclipse.EclipseNode in project lombok by rzwitserloot.

the class PatchExtensionMethodCompletionProposal method getExtensionMethods.

private static List<Extension> getExtensionMethods(CompletionProposalCollector completionProposalCollector) {
    List<Extension> extensions = new ArrayList<Extension>();
    ClassScope classScope = getClassScope(completionProposalCollector);
    if (classScope != null) {
        TypeDeclaration decl = classScope.referenceContext;
        TypeBinding firstParameterType = getFirstParameterType(decl, completionProposalCollector);
        for (EclipseNode typeNode = getTypeNode(decl); typeNode != null; typeNode = upToType(typeNode)) {
            Annotation ann = getAnnotation(ExtensionMethod.class, typeNode);
            extensions.addAll(0, getApplicableExtensionMethods(typeNode, ann, firstParameterType));
        }
    }
    return extensions;
}
Also used : Extension(lombok.eclipse.agent.PatchExtensionMethod.Extension) TypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) ArrayList(java.util.ArrayList) EclipseNode(lombok.eclipse.EclipseNode) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) Annotation(org.eclipse.jdt.internal.compiler.ast.Annotation) ClassScope(org.eclipse.jdt.internal.compiler.lookup.ClassScope)

Example 5 with EclipseNode

use of lombok.eclipse.EclipseNode in project lombok by rzwitserloot.

the class HandleSetter method handle.

public void handle(AnnotationValues<Setter> annotation, Annotation ast, EclipseNode annotationNode) {
    handleFlagUsage(annotationNode, ConfigurationKeys.SETTER_FLAG_USAGE, "@Setter");
    EclipseNode node = annotationNode.up();
    AccessLevel level = annotation.getInstance().value();
    if (level == AccessLevel.NONE || node == null)
        return;
    List<Annotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Setter(onMethod", annotationNode);
    List<Annotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@Setter(onParam", annotationNode);
    switch(node.getKind()) {
        case FIELD:
            createSetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, true, onMethod, onParam);
            break;
        case TYPE:
            if (!onMethod.isEmpty()) {
                annotationNode.addError("'onMethod' is not supported for @Setter on a type.");
            }
            if (!onParam.isEmpty()) {
                annotationNode.addError("'onParam' is not supported for @Setter on a type.");
            }
            generateSetterForType(node, annotationNode, level, false);
            break;
    }
}
Also used : EclipseNode(lombok.eclipse.EclipseNode) AccessLevel(lombok.AccessLevel) Annotation(org.eclipse.jdt.internal.compiler.ast.Annotation)

Aggregations

EclipseNode (lombok.eclipse.EclipseNode)55 TypeDeclaration (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)25 ArrayList (java.util.ArrayList)20 FieldDeclaration (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)19 MethodDeclaration (org.eclipse.jdt.internal.compiler.ast.MethodDeclaration)16 Annotation (org.eclipse.jdt.internal.compiler.ast.Annotation)12 QualifiedTypeReference (org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference)11 TypeReference (org.eclipse.jdt.internal.compiler.ast.TypeReference)11 Expression (org.eclipse.jdt.internal.compiler.ast.Expression)10 SingleNameReference (org.eclipse.jdt.internal.compiler.ast.SingleNameReference)9 SingleTypeReference (org.eclipse.jdt.internal.compiler.ast.SingleTypeReference)9 AbstractMethodDeclaration (org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)7 MessageSend (org.eclipse.jdt.internal.compiler.ast.MessageSend)7 ThisReference (org.eclipse.jdt.internal.compiler.ast.ThisReference)7 ParameterizedQualifiedTypeReference (org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference)6 ParameterizedSingleTypeReference (org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference)6 ReturnStatement (org.eclipse.jdt.internal.compiler.ast.ReturnStatement)6 Statement (org.eclipse.jdt.internal.compiler.ast.Statement)6 AllocationExpression (org.eclipse.jdt.internal.compiler.ast.AllocationExpression)5 Argument (org.eclipse.jdt.internal.compiler.ast.Argument)5