Search in sources :

Example 16 with AbstractMethodDeclaration

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

the class EclipseHandlerUtil method injectMethod.

/**
 * Inserts a method into an existing type. The type must represent a {@code TypeDeclaration}.
 */
public static EclipseNode injectMethod(EclipseNode type, AbstractMethodDeclaration method) {
    method.annotations = addSuppressWarningsAll(type, method, method.annotations);
    method.annotations = addGenerated(type, method, method.annotations);
    TypeDeclaration parent = (TypeDeclaration) type.get();
    if (parent.methods == null) {
        parent.methods = new AbstractMethodDeclaration[1];
        parent.methods[0] = method;
    } else {
        if (method instanceof ConstructorDeclaration) {
            for (int i = 0; i < parent.methods.length; i++) {
                if (parent.methods[i] instanceof ConstructorDeclaration && (parent.methods[i].bits & ASTNode.IsDefaultConstructor) != 0) {
                    EclipseNode tossMe = type.getNodeFor(parent.methods[i]);
                    AbstractMethodDeclaration[] withoutGeneratedConstructor = new AbstractMethodDeclaration[parent.methods.length - 1];
                    System.arraycopy(parent.methods, 0, withoutGeneratedConstructor, 0, i);
                    System.arraycopy(parent.methods, i + 1, withoutGeneratedConstructor, i, parent.methods.length - i - 1);
                    parent.methods = withoutGeneratedConstructor;
                    if (tossMe != null)
                        tossMe.up().removeChild(tossMe);
                    break;
                }
            }
        }
        // We insert the method in the last position of the methods registered to the type
        // When changing this behavior, this may trigger issue #155 and #377
        AbstractMethodDeclaration[] newArray = new AbstractMethodDeclaration[parent.methods.length + 1];
        System.arraycopy(parent.methods, 0, newArray, 0, parent.methods.length);
        newArray[parent.methods.length] = method;
        parent.methods = newArray;
    }
    return type.add(method, Kind.METHOD);
}
Also used : ConstructorDeclaration(org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration) EclipseNode(lombok.eclipse.EclipseNode) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)

Example 17 with AbstractMethodDeclaration

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

the class HandleBuilder method handle.

@Override
public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
    long p = (long) ast.sourceStart << 32 | ast.sourceEnd;
    Builder builderInstance = annotation.getInstance();
    // These exist just to support the 'old' lombok.experimental.Builder, which had these properties. lombok.Builder no longer has them.
    boolean fluent = toBoolean(annotation.getActualExpression("fluent"), true);
    boolean chain = toBoolean(annotation.getActualExpression("chain"), true);
    String builderMethodName = builderInstance.builderMethodName();
    String buildMethodName = builderInstance.buildMethodName();
    String builderClassName = builderInstance.builderClassName();
    String toBuilderMethodName = "toBuilder";
    boolean toBuilder = builderInstance.toBuilder();
    List<char[]> typeArgsForToBuilder = null;
    if (builderMethodName == null)
        builderMethodName = "builder";
    if (buildMethodName == null)
        builderMethodName = "build";
    if (builderClassName == null)
        builderClassName = "";
    if (!checkName("builderMethodName", builderMethodName, annotationNode))
        return;
    if (!checkName("buildMethodName", buildMethodName, annotationNode))
        return;
    if (!builderClassName.isEmpty()) {
        if (!checkName("builderClassName", builderClassName, annotationNode))
            return;
    }
    EclipseNode parent = annotationNode.up();
    List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>();
    TypeReference returnType;
    TypeParameter[] typeParams;
    TypeReference[] thrownExceptions;
    char[] nameOfStaticBuilderMethod;
    EclipseNode tdParent;
    EclipseNode fillParametersFrom = parent.get() instanceof AbstractMethodDeclaration ? parent : null;
    boolean addCleaning = false;
    boolean isStatic = true;
    if (parent.get() instanceof TypeDeclaration) {
        tdParent = parent;
        TypeDeclaration td = (TypeDeclaration) tdParent.get();
        List<EclipseNode> allFields = new ArrayList<EclipseNode>();
        boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent));
        for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) {
            FieldDeclaration fd = (FieldDeclaration) fieldNode.get();
            EclipseNode isDefault = findAnnotation(Builder.Default.class, fieldNode);
            boolean isFinal = ((fd.modifiers & ClassFileConstants.AccFinal) != 0) || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode));
            BuilderFieldData bfd = new BuilderFieldData();
            bfd.rawName = fieldNode.getName().toCharArray();
            bfd.name = removePrefixFromField(fieldNode);
            bfd.type = fd.type;
            bfd.singularData = getSingularData(fieldNode, ast);
            bfd.originalFieldNode = fieldNode;
            if (bfd.singularData != null && isDefault != null) {
                isDefault.addError("@Builder.Default and @Singular cannot be mixed.");
                isDefault = null;
            }
            if (fd.initialization == null && isDefault != null) {
                isDefault.addWarning("@Builder.Default requires an initializing expression (' = something;').");
                isDefault = null;
            }
            if (fd.initialization != null && isDefault == null) {
                if (isFinal)
                    continue;
                fieldNode.addWarning("@Builder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.");
            }
            if (isDefault != null) {
                bfd.nameOfDefaultProvider = prefixWith(DEFAULT_PREFIX, bfd.name);
                bfd.nameOfSetFlag = prefixWith(bfd.name, SET_PREFIX);
                MethodDeclaration md = generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast);
                if (md != null)
                    injectMethod(tdParent, md);
            }
            addObtainVia(bfd, fieldNode);
            builderFields.add(bfd);
            allFields.add(fieldNode);
        }
        handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, Collections.<Annotation>emptyList(), annotationNode);
        returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
        typeParams = td.typeParameters;
        thrownExceptions = null;
        nameOfStaticBuilderMethod = null;
        if (builderClassName.isEmpty())
            builderClassName = new String(td.name) + "Builder";
    } else if (parent.get() instanceof ConstructorDeclaration) {
        ConstructorDeclaration cd = (ConstructorDeclaration) parent.get();
        if (cd.typeParameters != null && cd.typeParameters.length > 0) {
            annotationNode.addError("@Builder is not supported on constructors with constructor type parameters.");
            return;
        }
        tdParent = parent.up();
        TypeDeclaration td = (TypeDeclaration) tdParent.get();
        returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
        typeParams = td.typeParameters;
        thrownExceptions = cd.thrownExceptions;
        nameOfStaticBuilderMethod = null;
        if (builderClassName.isEmpty())
            builderClassName = new String(cd.selector) + "Builder";
    } else if (parent.get() instanceof MethodDeclaration) {
        MethodDeclaration md = (MethodDeclaration) parent.get();
        tdParent = parent.up();
        isStatic = md.isStatic();
        if (toBuilder) {
            final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type.";
            char[] token;
            char[][] pkg = null;
            if (md.returnType.dimensions() > 0) {
                annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
                return;
            }
            if (md.returnType instanceof SingleTypeReference) {
                token = ((SingleTypeReference) md.returnType).token;
            } else if (md.returnType instanceof QualifiedTypeReference) {
                pkg = ((QualifiedTypeReference) md.returnType).tokens;
                token = pkg[pkg.length];
                char[][] pkg_ = new char[pkg.length - 1][];
                System.arraycopy(pkg, 0, pkg_, 0, pkg_.length);
                pkg = pkg_;
            } else {
                annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
                return;
            }
            if (pkg != null && !equals(parent.getPackageDeclaration(), pkg)) {
                annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
                return;
            }
            if (tdParent == null || !equals(tdParent.getName(), token)) {
                annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
                return;
            }
            TypeParameter[] tpOnType = ((TypeDeclaration) tdParent.get()).typeParameters;
            TypeParameter[] tpOnMethod = md.typeParameters;
            TypeReference[][] tpOnRet_ = null;
            if (md.returnType instanceof ParameterizedSingleTypeReference) {
                tpOnRet_ = new TypeReference[1][];
                tpOnRet_[0] = ((ParameterizedSingleTypeReference) md.returnType).typeArguments;
            } else if (md.returnType instanceof ParameterizedQualifiedTypeReference) {
                tpOnRet_ = ((ParameterizedQualifiedTypeReference) md.returnType).typeArguments;
            }
            if (tpOnRet_ != null)
                for (int i = 0; i < tpOnRet_.length - 1; i++) {
                    if (tpOnRet_[i] != null && tpOnRet_[i].length > 0) {
                        annotationNode.addError("@Builder(toBuilder=true) is not supported if returning a type with generics applied to an intermediate.");
                        return;
                    }
                }
            TypeReference[] tpOnRet = tpOnRet_ == null ? null : tpOnRet_[tpOnRet_.length - 1];
            typeArgsForToBuilder = new ArrayList<char[]>();
            if (tpOnMethod != null)
                for (TypeParameter onMethod : tpOnMethod) {
                    int pos = -1;
                    if (tpOnRet != null)
                        for (int i = 0; i < tpOnRet.length; i++) {
                            if (tpOnRet[i].getClass() != SingleTypeReference.class)
                                continue;
                            if (!Arrays.equals(((SingleTypeReference) tpOnRet[i]).token, onMethod.name))
                                continue;
                            pos = i;
                        }
                    if (pos == -1 || tpOnType == null || tpOnType.length <= pos) {
                        annotationNode.addError("@Builder(toBuilder=true) requires that each type parameter on the static method is part of the typeargs of the return value. Type parameter " + new String(onMethod.name) + " is not part of the return type.");
                        return;
                    }
                    typeArgsForToBuilder.add(tpOnType[pos].name);
                }
        }
        returnType = copyType(md.returnType, ast);
        typeParams = md.typeParameters;
        thrownExceptions = md.thrownExceptions;
        nameOfStaticBuilderMethod = md.selector;
        if (builderClassName.isEmpty()) {
            char[] token;
            if (md.returnType instanceof QualifiedTypeReference) {
                char[][] tokens = ((QualifiedTypeReference) md.returnType).tokens;
                token = tokens[tokens.length - 1];
            } else if (md.returnType instanceof SingleTypeReference) {
                token = ((SingleTypeReference) md.returnType).token;
                if (!(md.returnType instanceof ParameterizedSingleTypeReference) && typeParams != null) {
                    for (TypeParameter tp : typeParams) {
                        if (Arrays.equals(tp.name, token)) {
                            annotationNode.addError("@Builder requires specifying 'builderClassName' if used on methods with a type parameter as return type.");
                            return;
                        }
                    }
                }
            } else {
                annotationNode.addError("Unexpected kind of return type on annotated method. Specify 'builderClassName' to solve this problem.");
                return;
            }
            if (Character.isLowerCase(token[0])) {
                char[] newToken = new char[token.length];
                System.arraycopy(token, 1, newToken, 1, token.length - 1);
                newToken[0] = Character.toTitleCase(token[0]);
                token = newToken;
            }
            builderClassName = new String(token) + "Builder";
        }
    } else {
        annotationNode.addError("@Builder is only supported on types, constructors, and methods.");
        return;
    }
    if (fillParametersFrom != null) {
        for (EclipseNode param : fillParametersFrom.down()) {
            if (param.getKind() != Kind.ARGUMENT)
                continue;
            BuilderFieldData bfd = new BuilderFieldData();
            Argument arg = (Argument) param.get();
            bfd.rawName = arg.name;
            bfd.name = arg.name;
            bfd.type = arg.type;
            bfd.singularData = getSingularData(param, ast);
            bfd.originalFieldNode = param;
            addObtainVia(bfd, param);
            builderFields.add(bfd);
        }
    }
    EclipseNode builderType = findInnerClass(tdParent, builderClassName);
    if (builderType == null) {
        builderType = makeBuilderClass(isStatic, tdParent, builderClassName, typeParams, ast);
    } else {
        TypeDeclaration builderTypeDeclaration = (TypeDeclaration) builderType.get();
        if (isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) {
            annotationNode.addError("Existing Builder must be a static inner class.");
            return;
        } else if (!isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) != 0) {
            annotationNode.addError("Existing Builder must be a non-static inner class.");
            return;
        }
        sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode);
        /* generate errors for @Singular BFDs that have one already defined node. */
        {
            for (BuilderFieldData bfd : builderFields) {
                SingularData sd = bfd.singularData;
                if (sd == null)
                    continue;
                EclipseSingularizer singularizer = sd.getSingularizer();
                if (singularizer == null)
                    continue;
                if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) {
                    bfd.singularData = null;
                }
            }
        }
    }
    for (BuilderFieldData bfd : builderFields) {
        if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
            if (bfd.singularData.getSingularizer().requiresCleaning()) {
                addCleaning = true;
                break;
            }
        }
        if (bfd.obtainVia != null) {
            if (bfd.obtainVia.field().isEmpty() == bfd.obtainVia.method().isEmpty()) {
                bfd.obtainViaNode.addError("The syntax is either @ObtainVia(field = \"fieldName\") or @ObtainVia(method = \"methodName\").");
                return;
            }
            if (bfd.obtainVia.method().isEmpty() && bfd.obtainVia.isStatic()) {
                bfd.obtainViaNode.addError("@ObtainVia(isStatic = true) is not valid unless 'method' has been set.");
                return;
            }
        }
    }
    generateBuilderFields(builderType, builderFields, ast);
    if (addCleaning) {
        FieldDeclaration cleanDecl = new FieldDeclaration(CLEAN_FIELD_NAME, 0, -1);
        cleanDecl.declarationSourceEnd = -1;
        cleanDecl.modifiers = ClassFileConstants.AccPrivate;
        cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
        injectFieldAndMarkGenerated(builderType, cleanDecl);
    }
    if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) {
        ConstructorDeclaration cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, builderType, Collections.<EclipseNode>emptyList(), false, annotationNode, Collections.<Annotation>emptyList());
        if (cd != null)
            injectMethod(builderType, cd);
    }
    for (BuilderFieldData bfd : builderFields) {
        makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain);
    }
    if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) {
        MethodDeclaration md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast);
        if (md != null)
            injectMethod(builderType, md);
    }
    if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) {
        List<EclipseNode> fieldNodes = new ArrayList<EclipseNode>();
        for (BuilderFieldData bfd : builderFields) {
            fieldNodes.addAll(bfd.createdFields);
        }
        MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, false, ast, FieldAccess.ALWAYS_FIELD);
        if (md != null)
            injectMethod(builderType, md);
    }
    if (addCleaning) {
        MethodDeclaration cleanMethod = generateCleanMethod(builderFields, builderType, ast);
        if (cleanMethod != null)
            injectMethod(builderType, cleanMethod);
    }
    if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) {
        MethodDeclaration md = generateBuilderMethod(isStatic, builderMethodName, builderClassName, tdParent, typeParams, ast);
        if (md != null)
            injectMethod(tdParent, md);
    }
    if (toBuilder)
        switch(methodExists(toBuilderMethodName, tdParent, 0)) {
            case EXISTS_BY_USER:
                annotationNode.addWarning("Not generating toBuilder() as it already exists.");
                break;
            case NOT_EXISTS:
                TypeParameter[] tps = typeParams;
                if (typeArgsForToBuilder != null) {
                    tps = new TypeParameter[typeArgsForToBuilder.size()];
                    for (int i = 0; i < tps.length; i++) {
                        tps[i] = new TypeParameter();
                        tps[i].name = typeArgsForToBuilder.get(i);
                    }
                }
                MethodDeclaration md = generateToBuilderMethod(toBuilderMethodName, builderClassName, tdParent, tps, builderFields, fluent, ast);
                if (md != null)
                    injectMethod(tdParent, md);
        }
}
Also used : TypeParameter(org.eclipse.jdt.internal.compiler.ast.TypeParameter) Argument(org.eclipse.jdt.internal.compiler.ast.Argument) Builder(lombok.Builder) ArrayList(java.util.ArrayList) FieldDeclaration(org.eclipse.jdt.internal.compiler.ast.FieldDeclaration) ConstructorDeclaration(org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) EclipseSingularizer(lombok.eclipse.handlers.EclipseSingularsRecipes.EclipseSingularizer) TypeReference(org.eclipse.jdt.internal.compiler.ast.TypeReference) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) QualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) ParameterizedQualifiedTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference) ParameterizedSingleTypeReference(org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference) SingleTypeReference(org.eclipse.jdt.internal.compiler.ast.SingleTypeReference) SingularData(lombok.eclipse.handlers.EclipseSingularsRecipes.SingularData) EclipseNode(lombok.eclipse.EclipseNode) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)

Example 18 with AbstractMethodDeclaration

use of org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration 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 19 with AbstractMethodDeclaration

use of org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration in project spoon by INRIA.

the class JDTTreeBuilderHelper method createVariableAccessNoClasspath.

/**
 * Analyzes if {@code singleNameReference} points to a {@link CtVariable} visible in current
 * scope and, if existent, returns its corresponding {@link CtVariableAccess}. Returns
 * {@code null} if {@code singleNameReference} could not be resolved as variable access. Since
 * we are in noclasspath mode this function may also returns {@code null} if
 * {@code singleNameReference} points to a variable declared by an unknown class.
 *
 * @param singleNameReference
 * 		The potential variable access.
 * @return A {@link CtVariableAccess} if {@code singleNameReference} points to a variable
 * 		   visible in current scope, {@code null} otherwise.
 */
<T> CtVariableAccess<T> createVariableAccessNoClasspath(SingleNameReference singleNameReference) {
    final TypeFactory typeFactory = jdtTreeBuilder.getFactory().Type();
    final CoreFactory coreFactory = jdtTreeBuilder.getFactory().Core();
    final ExecutableFactory executableFactory = jdtTreeBuilder.getFactory().Executable();
    final ContextBuilder contextBuilder = jdtTreeBuilder.getContextBuilder();
    final ReferenceBuilder referenceBuilder = jdtTreeBuilder.getReferencesBuilder();
    final PositionBuilder positionBuilder = jdtTreeBuilder.getPositionBuilder();
    final String name = CharOperation.charToString(singleNameReference.token);
    final CtVariable<T> variable = contextBuilder.getVariableDeclaration(name);
    if (variable == null) {
        return null;
    }
    final CtVariableReference<T> variableReference;
    final CtVariableAccess<T> variableAccess;
    if (variable instanceof CtParameter) {
        // create variable of concrete type to avoid type casting while calling methods
        final CtParameterReference<T> parameterReference = coreFactory.createParameterReference();
        if (variable.getParent() instanceof CtLambda) {
        // nothing
        } else {
            // Unfortunately, we can not use `variable.getReference()` here as some parent
            // references (in terms of Java objects) have not been set up yet. Thus, we need to
            // create the required parameter reference by our own.
            // Since the given parameter has not been declared in a lambda expression it must
            // have been declared by a method/constructor.
            final CtExecutable executable = (CtExecutable) variable.getParent();
            // create list of executable's parameter types
            final List<CtTypeReference<?>> parameterTypesOfExecutable = new ArrayList<>();
            @SuppressWarnings("unchecked") final List<CtParameter<?>> parametersOfExecutable = executable.getParameters();
            for (CtParameter<?> parameter : parametersOfExecutable) {
                parameterTypesOfExecutable.add(parameter.getType() != null ? parameter.getType().clone() : // it's the best match :(
                typeFactory.OBJECT.clone());
            }
            // find executable's corresponding jdt element
            AbstractMethodDeclaration executableJDT = null;
            for (final ASTPair astPair : contextBuilder.stack) {
                if (astPair.element == executable) {
                    executableJDT = (AbstractMethodDeclaration) astPair.node;
                }
            }
            assert executableJDT != null;
            // create a reference to executable's declaring class
            final CtTypeReference declaringReferenceOfExecutable = // available
            executableJDT.binding == null ? coreFactory.createTypeReference() : referenceBuilder.getTypeReference(executableJDT.binding.declaringClass);
            // If executable is a constructor, `executable.getType()` returns null since the
            // parent is not available yet. Fortunately, however, the return type of a
            // constructor is its declaring class which, in our case, is already available with
            // declaringReferenceOfExecutable.
            CtTypeReference executableTypeReference = executable instanceof CtConstructor ? // indirectly sets the parent of `rt` and, thus, may break the AST!
            declaringReferenceOfExecutable.clone() : executable.getType().clone();
        }
        variableReference = parameterReference;
        variableAccess = isLhsAssignment(contextBuilder, singleNameReference) ? coreFactory.<T>createVariableWrite() : coreFactory.<T>createVariableRead();
    } else if (variable instanceof CtField) {
        variableReference = variable.getReference();
        variableAccess = isLhsAssignment(contextBuilder, singleNameReference) ? coreFactory.<T>createFieldWrite() : coreFactory.<T>createFieldRead();
    } else {
        // CtLocalVariable, CtCatchVariable, ...
        variableReference = variable.getReference();
        variableAccess = isLhsAssignment(contextBuilder, singleNameReference) ? coreFactory.<T>createVariableWrite() : coreFactory.<T>createVariableRead();
    }
    variableReference.setSimpleName(name);
    variableReference.setPosition(positionBuilder.buildPosition(singleNameReference.sourceStart(), singleNameReference.sourceEnd()));
    variableAccess.setVariable(variableReference);
    return variableAccess;
}
Also used : CtLambda(spoon.reflect.code.CtLambda) ArrayList(java.util.ArrayList) CtParameter(spoon.reflect.declaration.CtParameter) CtTypeReference(spoon.reflect.reference.CtTypeReference) CtField(spoon.reflect.declaration.CtField) CoreFactory(spoon.reflect.factory.CoreFactory) CtExecutable(spoon.reflect.declaration.CtExecutable) CtConstructor(spoon.reflect.declaration.CtConstructor) TypeFactory(spoon.reflect.factory.TypeFactory) ExecutableFactory(spoon.reflect.factory.ExecutableFactory) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)

Example 20 with AbstractMethodDeclaration

use of org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration in project spoon by INRIA.

the class PositionBuilder method buildPositionCtElement.

SourcePosition buildPositionCtElement(CtElement e, ASTNode node) {
    CoreFactory cf = this.jdtTreeBuilder.getFactory().Core();
    CompilationUnit cu = this.jdtTreeBuilder.getFactory().CompilationUnit().getOrCreate(new String(this.jdtTreeBuilder.getContextBuilder().compilationunitdeclaration.getFileName()));
    CompilationResult cr = this.jdtTreeBuilder.getContextBuilder().compilationunitdeclaration.compilationResult;
    int[] lineSeparatorPositions = cr.lineSeparatorPositions;
    char[] contents = cr.compilationUnit.getContents();
    int sourceStart = node.sourceStart;
    int sourceEnd = node.sourceEnd;
    if ((node instanceof Annotation)) {
        Annotation ann = (Annotation) node;
        int declEnd = ann.declarationSourceEnd;
        if (declEnd > 0) {
            sourceEnd = declEnd;
        }
    } else if ((node instanceof Expression)) {
        Expression expression = (Expression) node;
        int statementEnd = expression.statementEnd;
        if (statementEnd > 0) {
            sourceEnd = statementEnd;
        }
    }
    if (node instanceof AbstractVariableDeclaration) {
        AbstractVariableDeclaration variableDeclaration = (AbstractVariableDeclaration) node;
        int modifiersSourceStart = variableDeclaration.modifiersSourceStart;
        int declarationSourceStart = variableDeclaration.declarationSourceStart;
        int declarationSourceEnd = variableDeclaration.declarationSourceEnd;
        int declarationEnd = variableDeclaration.declarationEnd;
        Annotation[] annotations = variableDeclaration.annotations;
        if (annotations != null && annotations.length > 0) {
            if (annotations[0].sourceStart() == sourceStart) {
                modifiersSourceStart = annotations[annotations.length - 1].sourceEnd() + 2;
            }
        }
        if (modifiersSourceStart == 0) {
            modifiersSourceStart = declarationSourceStart;
        }
        int modifiersSourceEnd;
        if (variableDeclaration.type != null) {
            modifiersSourceEnd = variableDeclaration.type.sourceStart() - 2;
        } else {
            // variable that has no type such as TypeParameter
            modifiersSourceEnd = declarationSourceStart - 1;
        }
        // when no modifier
        if (modifiersSourceStart > modifiersSourceEnd) {
            modifiersSourceEnd = modifiersSourceStart - 1;
        }
        return cf.createDeclarationSourcePosition(cu, sourceStart, sourceEnd, modifiersSourceStart, modifiersSourceEnd, declarationSourceStart, declarationSourceEnd, lineSeparatorPositions);
    } else if (node instanceof TypeDeclaration) {
        TypeDeclaration typeDeclaration = (TypeDeclaration) node;
        int declarationSourceStart = typeDeclaration.declarationSourceStart;
        int declarationSourceEnd = typeDeclaration.declarationSourceEnd;
        int modifiersSourceStart = typeDeclaration.modifiersSourceStart;
        int bodyStart = typeDeclaration.bodyStart;
        int bodyEnd = typeDeclaration.bodyEnd;
        Annotation[] annotations = typeDeclaration.annotations;
        if (annotations != null && annotations.length > 0) {
            if (annotations[0].sourceStart() == declarationSourceStart) {
                modifiersSourceStart = findNextNonWhitespace(contents, annotations[annotations.length - 1].declarationSourceEnd + 1);
            }
        }
        if (modifiersSourceStart == 0) {
            modifiersSourceStart = declarationSourceStart;
        }
        // look for start of first keyword before the type keyword e.g. "class". `sourceStart` points at first char of type name
        int modifiersSourceEnd = findPrevNonWhitespace(contents, findPrevWhitespace(contents, findPrevNonWhitespace(contents, sourceStart - 1)));
        if (modifiersSourceEnd < modifiersSourceStart) {
            // there is no modifier
            modifiersSourceEnd = modifiersSourceStart - 1;
        }
        return cf.createBodyHolderSourcePosition(cu, sourceStart, sourceEnd, modifiersSourceStart, modifiersSourceEnd, declarationSourceStart, declarationSourceEnd, bodyStart - 1, bodyEnd, lineSeparatorPositions);
    } else if (node instanceof AbstractMethodDeclaration) {
        AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration) node;
        int bodyStart = methodDeclaration.bodyStart;
        int bodyEnd = methodDeclaration.bodyEnd;
        int declarationSourceStart = methodDeclaration.declarationSourceStart;
        int declarationSourceEnd = methodDeclaration.declarationSourceEnd;
        int modifiersSourceStart = methodDeclaration.modifiersSourceStart;
        if (modifiersSourceStart == 0) {
            modifiersSourceStart = declarationSourceStart;
        }
        if (node instanceof AnnotationMethodDeclaration && bodyStart == bodyEnd) {
            // The ";" at the end of annotation method declaration is not part of body
            // let it behave same like in abstract MethodDeclaration
            bodyEnd--;
        }
        Javadoc javadoc = methodDeclaration.javadoc;
        if (javadoc != null && javadoc.sourceEnd() > declarationSourceStart) {
            modifiersSourceStart = javadoc.sourceEnd() + 1;
        }
        Annotation[] annotations = methodDeclaration.annotations;
        if (annotations != null && annotations.length > 0) {
            if (annotations[0].sourceStart() == declarationSourceStart) {
                modifiersSourceStart = annotations[annotations.length - 1].sourceEnd() + 2;
            }
        }
        int modifiersSourceEnd = sourceStart - 1;
        if (methodDeclaration instanceof MethodDeclaration && ((MethodDeclaration) methodDeclaration).returnType != null) {
            modifiersSourceEnd = ((MethodDeclaration) methodDeclaration).returnType.sourceStart() - 2;
        }
        TypeParameter[] typeParameters = methodDeclaration.typeParameters();
        if (typeParameters != null && typeParameters.length > 0) {
            modifiersSourceEnd = typeParameters[0].declarationSourceStart - 3;
        }
        if (getModifiers(methodDeclaration.modifiers, false, true).isEmpty()) {
            modifiersSourceStart = modifiersSourceEnd + 1;
        }
        sourceEnd = sourceStart + methodDeclaration.selector.length - 1;
        if (e instanceof CtStatementList) {
            return cf.createSourcePosition(cu, bodyStart - 1, bodyEnd + 1, lineSeparatorPositions);
        } else {
            if (bodyStart == 0) {
                return SourcePosition.NOPOSITION;
            } else {
                if (bodyStart < bodyEnd) {
                    // include brackets if they are there
                    if (contents[bodyStart - 1] == '{') {
                        bodyStart--;
                        if (contents[bodyEnd + 1] == '}') {
                            bodyEnd++;
                        } else {
                            throw new SpoonException("Missing body end in\n" + new String(contents, sourceStart, sourceEnd - sourceStart));
                        }
                    }
                }
                return cf.createBodyHolderSourcePosition(cu, sourceStart, sourceEnd, modifiersSourceStart, modifiersSourceEnd, declarationSourceStart, declarationSourceEnd, bodyStart, bodyEnd, lineSeparatorPositions);
            }
        }
    }
    return cf.createSourcePosition(cu, sourceStart, sourceEnd, lineSeparatorPositions);
}
Also used : CompilationUnit(spoon.reflect.cu.CompilationUnit) TypeParameter(org.eclipse.jdt.internal.compiler.ast.TypeParameter) AnnotationMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration) SpoonException(spoon.SpoonException) AnnotationMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration) MethodDeclaration(org.eclipse.jdt.internal.compiler.ast.MethodDeclaration) Javadoc(org.eclipse.jdt.internal.compiler.ast.Javadoc) CoreFactory(spoon.reflect.factory.CoreFactory) AbstractVariableDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration) Annotation(org.eclipse.jdt.internal.compiler.ast.Annotation) Expression(org.eclipse.jdt.internal.compiler.ast.Expression) CtStatementList(spoon.reflect.code.CtStatementList) CompilationResult(org.eclipse.jdt.internal.compiler.CompilationResult) TypeDeclaration(org.eclipse.jdt.internal.compiler.ast.TypeDeclaration) AbstractMethodDeclaration(org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)

Aggregations

AbstractMethodDeclaration (org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration)20 TypeDeclaration (org.eclipse.jdt.internal.compiler.ast.TypeDeclaration)12 MethodDeclaration (org.eclipse.jdt.internal.compiler.ast.MethodDeclaration)11 EclipseNode (lombok.eclipse.EclipseNode)6 FieldDeclaration (org.eclipse.jdt.internal.compiler.ast.FieldDeclaration)5 Statement (org.eclipse.jdt.internal.compiler.ast.Statement)5 ArrayList (java.util.ArrayList)4 Argument (org.eclipse.jdt.internal.compiler.ast.Argument)4 ConstructorDeclaration (org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration)4 TypeParameter (org.eclipse.jdt.internal.compiler.ast.TypeParameter)4 CompilationUnitDeclaration (org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration)3 MessageSend (org.eclipse.jdt.internal.compiler.ast.MessageSend)3 SingleNameReference (org.eclipse.jdt.internal.compiler.ast.SingleNameReference)3 SingleTypeReference (org.eclipse.jdt.internal.compiler.ast.SingleTypeReference)3 IJavaElement (org.eclipse.jdt.core.IJavaElement)2 ASTNode (org.eclipse.jdt.internal.compiler.ast.ASTNode)2 Annotation (org.eclipse.jdt.internal.compiler.ast.Annotation)2 AnnotationMethodDeclaration (org.eclipse.jdt.internal.compiler.ast.AnnotationMethodDeclaration)2 Clinit (org.eclipse.jdt.internal.compiler.ast.Clinit)2 Expression (org.eclipse.jdt.internal.compiler.ast.Expression)2