Search in sources :

Example 36 with MethodDeclaration

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

the class EclipseHandlerUtil method findGetter.

private static GetterMethod findGetter(EclipseNode field) {
    FieldDeclaration fieldDeclaration = (FieldDeclaration) field.get();
    boolean forceBool = FieldDeclaration_booleanLazyGetter.get(fieldDeclaration);
    TypeReference fieldType = fieldDeclaration.type;
    boolean isBoolean = forceBool || isBoolean(fieldType);
    EclipseNode typeNode = field.up();
    for (String potentialGetterName : toAllGetterNames(field, isBoolean)) {
        for (EclipseNode potentialGetter : typeNode.down()) {
            if (potentialGetter.getKind() != Kind.METHOD)
                continue;
            if (!(potentialGetter.get() instanceof MethodDeclaration))
                continue;
            MethodDeclaration method = (MethodDeclaration) potentialGetter.get();
            if (!potentialGetterName.equalsIgnoreCase(new String(method.selector)))
                continue;
            /** static getX() methods don't count. */
            if ((method.modifiers & ClassFileConstants.AccStatic) != 0)
                continue;
            /** Nor do getters with a non-empty parameter list. */
            if (method.arguments != null && method.arguments.length > 0)
                continue;
            return new GetterMethod(method.selector, method.returnType);
        }
    }
    // Check if the field has a @Getter annotation.
    boolean hasGetterAnnotation = false;
    for (EclipseNode child : field.down()) {
        if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Getter.class, child)) {
            AnnotationValues<Getter> ann = createAnnotation(Getter.class, child);
            //Definitely WONT have a getter.
            if (ann.getInstance().value() == AccessLevel.NONE)
                return null;
            hasGetterAnnotation = true;
        }
    }
    if (!hasGetterAnnotation && new HandleGetter().fieldQualifiesForGetterGeneration(field)) {
        //Check if the class has @Getter or @Data annotation.
        EclipseNode containingType = field.up();
        if (containingType != null)
            for (EclipseNode child : containingType.down()) {
                if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Data.class, child))
                    hasGetterAnnotation = true;
                if (child.getKind() == Kind.ANNOTATION && annotationTypeMatches(Getter.class, child)) {
                    AnnotationValues<Getter> ann = createAnnotation(Getter.class, child);
                    //Definitely WONT have a getter.
                    if (ann.getInstance().value() == AccessLevel.NONE)
                        return null;
                    hasGetterAnnotation = true;
                }
            }
    }
    if (hasGetterAnnotation) {
        String getterName = toGetterName(field, isBoolean);
        if (getterName == null)
            return null;
        return new GetterMethod(getterName.toCharArray(), fieldType);
    }
    return null;
}
Also used : MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) Getter(lombok.Getter) AnnotationValues(lombok.core.AnnotationValues) EclipseNode(lombok.eclipse.EclipseNode) TypeReference(org.eclipse.jdt.internal.compiler.ast.TypeReference) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) ArrayQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference) ArrayTypeReference(org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) FieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)

Example 37 with MethodDeclaration

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

the class PatchDelegate method createDelegateMethod.

private static MethodDeclaration createDelegateMethod(char[] name, EclipseNode typeNode, BindingTuple pair, CompilationResult compilationResult, EclipseNode annNode, DelegateReceiver delegateReceiver) {
    /* public <T, U, ...> ReturnType methodName(ParamType1 name1, ParamType2 name2, ...) throws T1, T2, ... {
		 *      (return) delegate.<T, U>methodName(name1, name2);
		 *  }
		 */
    boolean isVarargs = (pair.base.modifiers & ClassFileConstants.AccVarargs) != 0;
    try {
        checkConflictOfTypeVarNames(pair, typeNode);
    } catch (CantMakeDelegates e) {
        annNode.addError("There's a conflict in the names of type parameters. Fix it by renaming the following type parameters of your class: " + e.conflicted);
        return null;
    }
    ASTNode source = annNode.get();
    int pS = source.sourceStart, pE = source.sourceEnd;
    MethodBinding binding = pair.parameterized;
    MethodDeclaration method = new MethodDeclaration(compilationResult);
    setGeneratedBy(method, source);
    method.sourceStart = pS;
    method.sourceEnd = pE;
    method.modifiers = ClassFileConstants.AccPublic;
    method.returnType = makeType(binding.returnType, source, false);
    boolean isDeprecated = binding.isDeprecated();
    method.selector = binding.selector;
    if (binding.thrownExceptions != null && binding.thrownExceptions.length > 0) {
        method.thrownExceptions = new TypeReference[binding.thrownExceptions.length];
        for (int i = 0; i < method.thrownExceptions.length; i++) {
            method.thrownExceptions[i] = makeType(binding.thrownExceptions[i], source, false);
        }
    }
    MessageSend call = new MessageSend();
    call.sourceStart = pS;
    call.sourceEnd = pE;
    call.nameSourcePosition = pos(source);
    setGeneratedBy(call, source);
    call.receiver = delegateReceiver.get(source, name);
    call.selector = binding.selector;
    if (binding.typeVariables != null && binding.typeVariables.length > 0) {
        method.typeParameters = new TypeParameter[binding.typeVariables.length];
        call.typeArguments = new TypeReference[binding.typeVariables.length];
        for (int i = 0; i < method.typeParameters.length; i++) {
            method.typeParameters[i] = new TypeParameter();
            method.typeParameters[i].sourceStart = pS;
            method.typeParameters[i].sourceEnd = pE;
            setGeneratedBy(method.typeParameters[i], source);
            method.typeParameters[i].name = binding.typeVariables[i].sourceName;
            call.typeArguments[i] = new SingleTypeReference(binding.typeVariables[i].sourceName, pos(source));
            setGeneratedBy(call.typeArguments[i], source);
            ReferenceBinding super1 = binding.typeVariables[i].superclass;
            ReferenceBinding[] super2 = binding.typeVariables[i].superInterfaces;
            if (super2 == null)
                super2 = new ReferenceBinding[0];
            if (super1 != null || super2.length > 0) {
                int offset = super1 == null ? 0 : 1;
                method.typeParameters[i].bounds = new TypeReference[super2.length + offset - 1];
                if (super1 != null)
                    method.typeParameters[i].type = makeType(super1, source, false);
                else
                    method.typeParameters[i].type = makeType(super2[0], source, false);
                int ctr = 0;
                for (int j = (super1 == null) ? 1 : 0; j < super2.length; j++) {
                    method.typeParameters[i].bounds[ctr] = makeType(super2[j], source, false);
                    method.typeParameters[i].bounds[ctr++].bits |= ASTNode.IsSuperType;
                }
            }
        }
    }
    if (isDeprecated) {
        method.annotations = new Annotation[] { generateDeprecatedAnnotation(source) };
    }
    method.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
    if (binding.parameters != null && binding.parameters.length > 0) {
        method.arguments = new Argument[binding.parameters.length];
        call.arguments = new Expression[method.arguments.length];
        for (int i = 0; i < method.arguments.length; i++) {
            AbstractMethodDeclaration sourceElem;
            try {
                sourceElem = pair.base.sourceMethod();
            } catch (Exception e) {
                sourceElem = null;
            }
            char[] argName;
            if (sourceElem == null)
                argName = ("arg" + i).toCharArray();
            else {
                argName = sourceElem.arguments[i].name;
            }
            method.arguments[i] = new Argument(argName, pos(source), makeType(binding.parameters[i], source, false), ClassFileConstants.AccFinal);
            setGeneratedBy(method.arguments[i], source);
            call.arguments[i] = new SingleNameReference(argName, pos(source));
            setGeneratedBy(call.arguments[i], source);
        }
        if (isVarargs) {
            method.arguments[method.arguments.length - 1].type.bits |= ASTNode.IsVarArgs;
        }
    }
    Statement body;
    if (method.returnType instanceof SingleTypeReference && ((SingleTypeReference) method.returnType).token == TypeConstants.VOID) {
        body = call;
    } else {
        body = new ReturnStatement(call, source.sourceStart, source.sourceEnd);
        setGeneratedBy(body, source);
    }
    method.statements = new Statement[] { body };
    return method;
}
Also used : TypeParameter(org.eclipse.jdt.internal.compiler.ast.TypeParameter) Argument(org.eclipse.jdt.internal.compiler.ast.Argument) MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) Statement(org.eclipse.jdt.internal.compiler.ast.Statement) ReturnStatement(org.eclipse.jdt.internal.compiler.ast.ReturnStatement) UnresolvedReferenceBinding(org.eclipse.jdt.internal.compiler.lookup.UnresolvedReferenceBinding) ReferenceBinding(org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding) SingleNameReference(org.eclipse.jdt.internal.compiler.ast.SingleNameReference) MessageSend(org.eclipse.jdt.internal.compiler.ast.MessageSend) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) ASTNode(org.eclipse.jdt.internal.compiler.ast.ASTNode) ReturnStatement(org.eclipse.jdt.internal.compiler.ast.ReturnStatement) MethodBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)

Example 38 with MethodDeclaration

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

the class PatchDelegate method generateDelegateMethods.

/*
	 * We may someday finish this method. Steps to be completed:
	 * 
	 * (A) Turn any Parameterized anythings into non-parameterized versions. Resolving parameterized stuff will definitely not work safely.
	 * (B) scope.problemReporter() will need to return a noop reporter as various errors are marked off.
	 * (C) Find a way to do _something_ for references to typevars (i.e. 'T') which are declared on the method itself.
	 * (D) getTypeBinding isn't public, so call it via reflection.
	 */
//	private static TypeBinding safeResolveAndErase(TypeReference ref, Scope scope) {
//		if (ref.resolvedType != null) {
//			return ref.resolvedType.isValidBinding() ? ref.resolvedType : null;
//		}
//		
//		try {
//			TypeBinding bind = ref.getTypeBinding(scope);
//			if (!bind.isValidBinding()) return null;
//		} catch (AbortCompilation e) {
//			return null;
//		}
//		return bind.erasure();
//	}
/*
	 * Not using this because calling clone.resolveType() taints a bunch of caches and reports erroneous errors.
	 */
//	private static void removeExistingMethods(List<BindingTuple> list, TypeDeclaration decl, ClassScope scope) {
//		for (AbstractMethodDeclaration methodDecl : decl.methods) {
//			if (!(methodDecl instanceof MethodDeclaration)) continue;
//			MethodDeclaration md = (MethodDeclaration) methodDecl;
//			char[] name = md.selector;
//			TypeBinding[] args = md.arguments == null ? new TypeBinding[0] : new TypeBinding[md.arguments.length];
//			for (int i = 0; i < args.length; i++) {
//				TypeReference clone = Eclipse.copyType(md.arguments[i].type, md.arguments[i]);
//				args[i] = clone.resolveType(scope).erasure(); // This is the problematic line
//			}
//			Iterator<BindingTuple> it = list.iterator();
//			methods:
//			while (it.hasNext()) {
//				MethodBinding mb = it.next().parameterized;
//				if (!Arrays.equals(mb.selector, name)) continue;
//				int paramLen = mb.parameters == null ? 0 : mb.parameters.length;
//				if (paramLen != args.length) continue;
//				if (md.typeParameters == null || md.typeParameters.length == 0) {
//					for (int i = 0; i < paramLen; i++) {
//						if (!mb.parameters[i].erasure().isEquivalentTo(args[i])) continue methods;
//					}
//				} else {
//					for (int i = 0; i < paramLen; i++) {
//						if (!mb.parameters[i].erasure().isEquivalentTo(args[i])) ;
//					}
//					//BUG #???: We erase the method's parameter types using  the class scope, but we should be using the method scope.
//					// In practice this is no problem UNLESS the method has type parameters, such as <T> T[] toArray(T[] in).
//					// In this case the class scope cannot resolve the T[] parameter and erase it to Object[], which is a big problem because
//					// it would mean manually writing <X> X[] toArray(X[] in) does NOT stop lombok from ALSO trying to make the delegated toArray method,
//					// thus causing an error (2 methods with post-erasure duplicate signatures). Our 'fix' for this is to treat any method with type parameters
//					// as if each parameter's type matches anything else; so, if the name matches and the parameter count, we DONT generate it, even if its just
//					// an overloaded method.
//					//
//					// The reason we do this now is because making that MethodScope properly is effectively impossible at this step, so we need to do the resolving
//					// ourselves, which involves chasing down array bindings (T[]), following the path down type variables, i.e. <X extends Y, Y extends T>, and then
//					// resolving the final result of this exercise against the class scope.
//					
//					// When this crappy incomplete workaround of ours occurs, we end up in this else block, which does nothing and thus we fall through and remove
//					// the method.
//				}
//				it.remove(); // Method already exists in this class - don't create a delegating implementation.
//			}
//		}
//	}
private static void generateDelegateMethods(EclipseNode typeNode, List<BindingTuple> methods, DelegateReceiver delegateReceiver) {
    CompilationUnitDeclaration top = (CompilationUnitDeclaration) typeNode.top().get();
    for (BindingTuple pair : methods) {
        EclipseNode annNode = typeNode.getAst().get(pair.responsible);
        MethodDeclaration method = createDelegateMethod(pair.fieldName, typeNode, pair, top.compilationResult, annNode, delegateReceiver);
        if (method != null) {
            SetGeneratedByVisitor visitor = new SetGeneratedByVisitor(annNode.get());
            method.traverse(visitor, ((TypeDeclaration) typeNode.get()).scope);
            injectMethod(typeNode, method);
        }
    }
}
Also used : SetGeneratedByVisitor(lombok.eclipse.handlers.SetGeneratedByVisitor) CompilationUnitDeclaration(org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration) MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) EclipseNode(lombok.eclipse.EclipseNode)

Example 39 with MethodDeclaration

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

the class PatchDelegate method fillMethodBindingsForMethods.

private static void fillMethodBindingsForMethods(CompilationUnitDeclaration cud, ClassScope scope, List<BindingTuple> methodsToDelegate) {
    TypeDeclaration decl = scope.referenceContext;
    if (decl == null)
        return;
    if (decl.methods != null)
        for (AbstractMethodDeclaration methodDecl : decl.methods) {
            if (methodDecl.annotations == null)
                continue;
            for (Annotation ann : methodDecl.annotations) {
                if (!isDelegate(ann, decl))
                    continue;
                if (Annotation_applied.getAndSet(ann, true))
                    continue;
                if (!(methodDecl instanceof MethodDeclaration)) {
                    EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
                    eclipseAst.get(ann).addError(LEGALITY_OF_DELEGATE);
                    break;
                }
                if (methodDecl.arguments != null) {
                    EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
                    eclipseAst.get(ann).addError(LEGALITY_OF_DELEGATE);
                    break;
                }
                if ((methodDecl.modifiers & ClassFileConstants.AccStatic) != 0) {
                    EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
                    eclipseAst.get(ann).addError(LEGALITY_OF_DELEGATE);
                    break;
                }
                MethodDeclaration method = (MethodDeclaration) methodDecl;
                List<ClassLiteralAccess> rawTypes = rawTypes(ann, "types");
                List<ClassLiteralAccess> excludedRawTypes = rawTypes(ann, "excludes");
                List<BindingTuple> methodsToExclude = new ArrayList<BindingTuple>();
                List<BindingTuple> methodsToDelegateForThisAnn = new ArrayList<BindingTuple>();
                try {
                    for (ClassLiteralAccess cla : excludedRawTypes) {
                        addAllMethodBindings(methodsToExclude, cla.type.resolveType(decl.initializerScope), new HashSet<String>(), method.selector, ann);
                    }
                    Set<String> banList = new HashSet<String>();
                    for (BindingTuple excluded : methodsToExclude) banList.add(printSig(excluded.parameterized));
                    if (rawTypes.isEmpty()) {
                        if (method.returnType == null)
                            continue;
                        addAllMethodBindings(methodsToDelegateForThisAnn, method.returnType.resolveType(decl.initializerScope), banList, method.selector, ann);
                    } else {
                        for (ClassLiteralAccess cla : rawTypes) {
                            addAllMethodBindings(methodsToDelegateForThisAnn, cla.type.resolveType(decl.initializerScope), banList, method.selector, ann);
                        }
                    }
                } catch (DelegateRecursion e) {
                    EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
                    eclipseAst.get(ann).addError(String.format(RECURSION_NOT_ALLOWED, new String(e.member), new String(e.type)));
                    break;
                }
                // Not doing this right now because of problems - see commented-out-method for info.
                // removeExistingMethods(methodsToDelegate, decl, scope);
                String dupe = containsDuplicates(methodsToDelegateForThisAnn);
                if (dupe != null) {
                    EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
                    eclipseAst.get(ann).addError("The method '" + dupe + "' is being delegated by more than one specified type.");
                } else {
                    methodsToDelegate.addAll(methodsToDelegateForThisAnn);
                }
            }
        }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) EclipseAST(lombok.eclipse.EclipseAST) TransformEclipseAST(lombok.eclipse.TransformEclipseAST) Annotation(org.eclipse.jdt.internal.compiler.ast.Annotation) List(java.util.List) ArrayList(java.util.ArrayList) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) ClassLiteralAccess(org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess) HashSet(java.util.HashSet)

Example 40 with MethodDeclaration

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

the class HandleSynchronized method preHandle.

@Override
public void preHandle(AnnotationValues<Synchronized> annotation, Annotation source, EclipseNode annotationNode) {
    EclipseNode methodNode = annotationNode.up();
    if (methodNode == null || methodNode.getKind() != Kind.METHOD || !(methodNode.get() instanceof MethodDeclaration))
        return;
    MethodDeclaration method = (MethodDeclaration) methodNode.get();
    if (method.isAbstract())
        return;
    createLockField(annotation, annotationNode, method.isStatic(), false);
}
Also used : MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) EclipseNode(lombok.eclipse.EclipseNode)

Aggregations

MethodDeclaration (org.eclipse.jdt.internal.compiler.ast.MethodDeclaration)40 ReturnStatement (org.eclipse.jdt.internal.compiler.ast.ReturnStatement)22 Statement (org.eclipse.jdt.internal.compiler.ast.Statement)19 TypeReference (org.eclipse.jdt.internal.compiler.ast.TypeReference)19 ArrayList (java.util.ArrayList)18 ThisReference (org.eclipse.jdt.internal.compiler.ast.ThisReference)17 EclipseNode (lombok.eclipse.EclipseNode)16 SingleNameReference (org.eclipse.jdt.internal.compiler.ast.SingleNameReference)16 AbstractMethodDeclaration (org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)15 Argument (org.eclipse.jdt.internal.compiler.ast.Argument)15 MessageSend (org.eclipse.jdt.internal.compiler.ast.MessageSend)15 QualifiedTypeReference (org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference)15 FieldDeclaration (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)14 IfStatement (org.eclipse.jdt.internal.compiler.ast.IfStatement)14 FieldReference (org.eclipse.jdt.internal.compiler.ast.FieldReference)13 TypeDeclaration (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)12 Expression (org.eclipse.jdt.internal.compiler.ast.Expression)11 SingleTypeReference (org.eclipse.jdt.internal.compiler.ast.SingleTypeReference)10 ParameterizedQualifiedTypeReference (org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference)8 ASTNode (org.eclipse.jdt.internal.compiler.ast.ASTNode)6