diff options
Diffstat (limited to 'src/core/lombok/eclipse')
7 files changed, 239 insertions, 152 deletions
diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 96795fe1..78780522 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 The Project Lombok Authors. + * Copyright (C) 2009-2013 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -473,7 +473,7 @@ public class EclipseHandlerUtil { } } if (allNull) return null; - return result.toArray(EMPTY_ANNOTATION_ARRAY); + return result.toArray(new Annotation[0]); } public static boolean hasAnnotation(Class<? extends java.lang.annotation.Annotation> type, EclipseNode node) { @@ -1492,40 +1492,102 @@ public class EclipseHandlerUtil { intLiteralFactoryMethod = intLiteralFactoryMethod_; } - private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; - static Annotation[] getAndRemoveAnnotationParameter(Annotation annotation, String annotationName) { - - List<Annotation> result = new ArrayList<Annotation>(); - if (annotation instanceof NormalAnnotation) { - NormalAnnotation normalAnnotation = (NormalAnnotation)annotation; - MemberValuePair[] memberValuePairs = normalAnnotation.memberValuePairs; - List<MemberValuePair> pairs = new ArrayList<MemberValuePair>(); - if (memberValuePairs != null) for (MemberValuePair memberValuePair : memberValuePairs) { - if (annotationName.equals(new String(memberValuePair.name))) { - Expression value = memberValuePair.value; - if (value instanceof ArrayInitializer) { - ArrayInitializer array = (ArrayInitializer) value; - for(Expression expression : array.expressions) { - if (expression instanceof Annotation) { - result.add((Annotation)expression); - } - } - } - else if (value instanceof Annotation) { - result.add((Annotation)value); - } - continue; + private static boolean isAllUnderscores(char[] in) { + if (in == null || in.length == 0) return false; + for (char c : in) if (c != '_') return false; + return true; + } + + static List<Annotation> unboxAndRemoveAnnotationParameter(Annotation annotation, String annotationName, String errorName, EclipseNode errorNode) { + if ("value".equals(annotationName)) { + // We can't unbox this, because SingleMemberAnnotation REQUIRES a value, and this method + // is supposed to remove the value. That means we need to replace the SMA with either + // MarkerAnnotation or NormalAnnotation and that is beyond the scope of this method as we + // don't need that at the time of writing this method; we only unbox onMethod, onParameter + // and onConstructor. Let's exit early and very obviously: + throw new UnsupportedOperationException("Lombok cannot unbox 'value' from SingleMemberAnnotation at this time."); + } + if (!NormalAnnotation.class.equals(annotation.getClass())) { + // Prevent MarkerAnnotation, SingleMemberAnnotation, and + // CompletionOnAnnotationMemberValuePair from triggering this handler. + return Collections.emptyList(); + } + + NormalAnnotation normalAnnotation = (NormalAnnotation) annotation; + MemberValuePair[] pairs = normalAnnotation.memberValuePairs; + + if (pairs == null) return Collections.emptyList(); + + char[] nameAsCharArray = annotationName.toCharArray(); + + for (int i = 0; i < pairs.length; i++) { + if (pairs[i].name == null || !Arrays.equals(nameAsCharArray, pairs[i].name)) continue; + Expression value = pairs[i].value; + MemberValuePair[] newPairs = new MemberValuePair[pairs.length - 1]; + if (i > 0) System.arraycopy(pairs, 0, newPairs, 0, i); + if (i < pairs.length - 1) System.arraycopy(pairs, i + 1, newPairs, i, pairs.length - i - 1); + normalAnnotation.memberValuePairs = newPairs; + // We have now removed the annotation parameter and stored '@_({... annotations ...})', + // which we must now unbox. + if (!(value instanceof Annotation)) { + errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + return Collections.emptyList(); + } + + Annotation atUnderscore = (Annotation) value; + if (!(atUnderscore.type instanceof SingleTypeReference) || + !isAllUnderscores(((SingleTypeReference) atUnderscore.type).token)) { + errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + return Collections.emptyList(); + } + + if (atUnderscore instanceof MarkerAnnotation) { + // It's @getter(onMethod=@_). This is weird, but fine. + return Collections.emptyList(); + } + + Expression content = null; + + if (atUnderscore instanceof NormalAnnotation) { + MemberValuePair[] mvps = ((NormalAnnotation) atUnderscore).memberValuePairs; + if (mvps == null || mvps.length == 0) { + // It's @getter(onMethod=@_()). This is weird, but fine. + return Collections.emptyList(); + } + if (mvps.length == 1 && Arrays.equals("value".toCharArray(), mvps[0].name)) { + content = mvps[0].value; } - pairs.add(memberValuePair); } - if (!result.isEmpty()) { - normalAnnotation.memberValuePairs = pairs.isEmpty() ? null : pairs.toArray(new MemberValuePair[0]); - return result.toArray(EMPTY_ANNOTATION_ARRAY); + if (atUnderscore instanceof SingleMemberAnnotation) { + content = ((SingleMemberAnnotation) atUnderscore).memberValue; + } + + if (content == null) { + errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + return Collections.emptyList(); + } + + if (content instanceof Annotation) { + return Collections.singletonList((Annotation) content); + } else if (content instanceof ArrayInitializer) { + Expression[] expressions = ((ArrayInitializer) content).expressions; + List<Annotation> result = new ArrayList<Annotation>(); + if (expressions != null) for (Expression ex : expressions) { + if (ex instanceof Annotation) result.add((Annotation) ex); + else { + errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + return Collections.emptyList(); + } + } + return result; + } else { + errorNode.addError("The correct format is " + errorName + "@_({@SomeAnnotation, @SomeOtherAnnotation}))"); + return Collections.emptyList(); } } - return EMPTY_ANNOTATION_ARRAY; + return Collections.emptyList(); } static NameReference createNameReference(String name, Annotation source) { diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java index 5d4656b6..8ccad77f 100644 --- a/src/core/lombok/eclipse/handlers/HandleConstructor.java +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 The Project Lombok Authors. + * Copyright (C) 2010-2013 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -79,7 +79,10 @@ public class HandleConstructor { String staticName = ann.staticName(); if (level == AccessLevel.NONE) return; List<EclipseNode> fields = new ArrayList<EclipseNode>(); - new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, false, false, ast); + + List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@NoArgsConstructor(onConstructor=", annotationNode); + + new HandleConstructor().generateConstructor(typeNode, level, fields, staticName, false, false, onConstructor, ast); } } @@ -94,7 +97,10 @@ public class HandleConstructor { @SuppressWarnings("deprecation") boolean suppressConstructorProperties = ann.suppressConstructorProperties(); if (level == AccessLevel.NONE) return; - new HandleConstructor().generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, false, suppressConstructorProperties, ast); + + List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@RequiredArgsConstructor(onConstructor=", annotationNode); + + new HandleConstructor().generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, false, suppressConstructorProperties, onConstructor, ast); } } @@ -137,7 +143,10 @@ public class HandleConstructor { @SuppressWarnings("deprecation") boolean suppressConstructorProperties = ann.suppressConstructorProperties(); if (level == AccessLevel.NONE) return; - new HandleConstructor().generateConstructor(typeNode, level, findAllFields(typeNode), staticName, false, suppressConstructorProperties, ast); + + List<Annotation> onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@AllArgsConstructor(onConstructor=", annotationNode); + + new HandleConstructor().generateConstructor(typeNode, level, findAllFields(typeNode), staticName, false, suppressConstructorProperties, onConstructor, ast); } } @@ -155,15 +164,15 @@ public class HandleConstructor { return true; } - public void generateRequiredArgsConstructor(EclipseNode typeNode, AccessLevel level, String staticName, boolean skipIfConstructorExists, ASTNode source) { - generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, skipIfConstructorExists, false, source); + public void generateRequiredArgsConstructor(EclipseNode typeNode, AccessLevel level, String staticName, boolean skipIfConstructorExists, List<Annotation> onConstructor, ASTNode source) { + generateConstructor(typeNode, level, findRequiredFields(typeNode), staticName, skipIfConstructorExists, false, onConstructor, source); } - public void generateAllArgsConstructor(EclipseNode typeNode, AccessLevel level, String staticName, boolean skipIfConstructorExists, ASTNode source) { - generateConstructor(typeNode, level, findAllFields(typeNode), staticName, skipIfConstructorExists, false, source); + public void generateAllArgsConstructor(EclipseNode typeNode, AccessLevel level, String staticName, boolean skipIfConstructorExists, List<Annotation> onConstructor, ASTNode source) { + generateConstructor(typeNode, level, findAllFields(typeNode), staticName, skipIfConstructorExists, false, onConstructor, source); } - public void generateConstructor(EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties, ASTNode source) { + public void generateConstructor(EclipseNode typeNode, AccessLevel level, List<EclipseNode> fields, String staticName, boolean skipIfConstructorExists, boolean suppressConstructorProperties, List<Annotation> onConstructor, ASTNode source) { boolean staticConstrRequired = staticName != null && !staticName.equals(""); if (skipIfConstructorExists && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return; @@ -187,7 +196,7 @@ public class HandleConstructor { } } - ConstructorDeclaration constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, suppressConstructorProperties, source); + ConstructorDeclaration constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, suppressConstructorProperties, source, onConstructor); injectMethod(typeNode, constr); if (staticConstrRequired) { MethodDeclaration staticConstr = createStaticConstructor(level, staticName, typeNode, fields, source); @@ -196,8 +205,8 @@ public class HandleConstructor { } private static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() }; - private static Annotation[] createConstructorProperties(ASTNode source, Annotation[] originalAnnotationArray, Collection<EclipseNode> fields) { - if (fields.isEmpty()) return originalAnnotationArray; + private static Annotation[] createConstructorProperties(ASTNode source, Collection<EclipseNode> fields) { + if (fields.isEmpty()) return null; int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; @@ -223,14 +232,14 @@ public class HandleConstructor { ann.memberValue = fieldNames; setGeneratedBy(ann, source); setGeneratedBy(ann.memberValue, source); - if (originalAnnotationArray == null) return new Annotation[] { ann }; - Annotation[] newAnnotationArray = Arrays.copyOf(originalAnnotationArray, originalAnnotationArray.length + 1); - newAnnotationArray[originalAnnotationArray.length] = ann; - return newAnnotationArray; + return new Annotation[] { ann }; } - private ConstructorDeclaration createConstructor(AccessLevel level, - EclipseNode type, Collection<EclipseNode> fields, boolean suppressConstructorProperties, ASTNode source) { + private ConstructorDeclaration createConstructor( + AccessLevel level, EclipseNode type, Collection<EclipseNode> fields, + boolean suppressConstructorProperties, ASTNode source, List<Annotation> onConstructor) { + + TypeDeclaration typeDeclaration = ((TypeDeclaration)type.get()); long p = (long)source.sourceStart << 32 | source.sourceEnd; boolean isEnum = (((TypeDeclaration)type.get()).modifiers & ClassFileConstants.AccEnum) != 0; @@ -239,12 +248,10 @@ public class HandleConstructor { ConstructorDeclaration constructor = new ConstructorDeclaration( ((CompilationUnitDeclaration) type.top().get()).compilationResult); - setGeneratedBy(constructor, source); constructor.modifiers = toEclipseModifier(level); - constructor.selector = ((TypeDeclaration)type.get()).name; + constructor.selector = typeDeclaration.name; constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); - setGeneratedBy(constructor.constructorCall, source); constructor.constructorCall.sourceStart = source.sourceStart; constructor.constructorCall.sourceEnd = source.sourceEnd; constructor.thrownExceptions = null; @@ -261,19 +268,14 @@ public class HandleConstructor { for (EclipseNode fieldNode : fields) { FieldDeclaration field = (FieldDeclaration) fieldNode.get(); FieldReference thisX = new FieldReference(field.name, p); - setGeneratedBy(thisX, source); thisX.receiver = new ThisReference((int)(p >> 32), (int)p); - setGeneratedBy(thisX.receiver, source); SingleNameReference assignmentNameRef = new SingleNameReference(field.name, p); - setGeneratedBy(assignmentNameRef, source); Assignment assignment = new Assignment(thisX, assignmentNameRef, (int)p); assignment.sourceStart = (int)(p >> 32); assignment.sourceEnd = assignment.statementEnd = (int)(p >> 32); - setGeneratedBy(assignment, source); assigns.add(assignment); long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd; Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL); - setGeneratedBy(parameter, source); Annotation[] nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN); Annotation[] nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN); if (nonNulls.length != 0) { @@ -289,10 +291,19 @@ public class HandleConstructor { constructor.statements = nullChecks.isEmpty() ? null : nullChecks.toArray(new Statement[nullChecks.size()]); constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[params.size()]); - if (!suppressConstructorProperties && level != AccessLevel.PRIVATE && !isLocalType(type)) { - constructor.annotations = createConstructorProperties(source, constructor.annotations, fields); + /* Generate annotations that must be put on the generated method, and attach them. */ { + Annotation[] constructorProperties = null; + if (!suppressConstructorProperties && level != AccessLevel.PRIVATE && !isLocalType(type)) { + constructorProperties = createConstructorProperties(source, fields); + } + + Annotation[] copiedAnnotations = copyAnnotations(source, + onConstructor.toArray(new Annotation[0]), + constructorProperties); + if (copiedAnnotations.length != 0) constructor.annotations = copiedAnnotations; } + constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope); return constructor; } @@ -309,7 +320,6 @@ public class HandleConstructor { MethodDeclaration constructor = new MethodDeclaration( ((CompilationUnitDeclaration) type.top().get()).compilationResult); - setGeneratedBy(constructor, source); constructor.modifiers = toEclipseModifier(level) | Modifier.STATIC; TypeDeclaration typeDecl = (TypeDeclaration) type.get(); @@ -323,7 +333,6 @@ public class HandleConstructor { } constructor.returnType = new ParameterizedSingleTypeReference(typeDecl.name, refs, 0, p); } else constructor.returnType = new SingleTypeReference(((TypeDeclaration)type.get()).name, p); - setGeneratedBy(constructor.returnType, source); constructor.annotations = null; constructor.selector = name.toCharArray(); constructor.thrownExceptions = null; @@ -336,18 +345,15 @@ public class HandleConstructor { List<Expression> assigns = new ArrayList<Expression>(); AllocationExpression statement = new AllocationExpression(); statement.sourceStart = pS; statement.sourceEnd = pE; - setGeneratedBy(statement, source); statement.type = copyType(constructor.returnType, source); for (EclipseNode fieldNode : fields) { FieldDeclaration field = (FieldDeclaration) fieldNode.get(); long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd; SingleNameReference nameRef = new SingleNameReference(field.name, fieldPos); - setGeneratedBy(nameRef, source); assigns.add(nameRef); Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL); - setGeneratedBy(parameter, source); Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN)); if (copiedAnnotations.length != 0) parameter.annotations = copiedAnnotations; @@ -357,7 +363,8 @@ public class HandleConstructor { statement.arguments = assigns.isEmpty() ? null : assigns.toArray(new Expression[assigns.size()]); constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[params.size()]); constructor.statements = new Statement[] { new ReturnStatement(statement, (int)(p >> 32), (int)p) }; - setGeneratedBy(constructor.statements[0], source); + + constructor.traverse(new SetGeneratedByVisitor(source), typeDecl.scope); return constructor; } } diff --git a/src/core/lombok/eclipse/handlers/HandleData.java b/src/core/lombok/eclipse/handlers/HandleData.java index ba29b30b..3a43bd3f 100644 --- a/src/core/lombok/eclipse/handlers/HandleData.java +++ b/src/core/lombok/eclipse/handlers/HandleData.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 The Project Lombok Authors. + * Copyright (C) 2009-2013 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,6 +21,8 @@ */ package lombok.eclipse.handlers; +import java.util.Collections; + import lombok.AccessLevel; import lombok.Data; import lombok.core.AnnotationValues; @@ -62,6 +64,6 @@ public class HandleData extends EclipseAnnotationHandler<Data> { new HandleSetter().generateSetterForType(typeNode, annotationNode, AccessLevel.PUBLIC, true); new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode); new HandleToString().generateToStringForType(typeNode, annotationNode); - new HandleConstructor().generateRequiredArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), true, ast); + new HandleConstructor().generateRequiredArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), true, Collections.<Annotation>emptyList(), ast); } } diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java index df05fc7e..7f788c5d 100644 --- a/src/core/lombok/eclipse/handlers/HandleGetter.java +++ b/src/core/lombok/eclipse/handlers/HandleGetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2012 The Project Lombok Authors. + * Copyright (C) 2009-2013 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -125,7 +125,7 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { return; } - createGetterForField(level, fieldNode, fieldNode, pos, false, lazy); + createGetterForField(level, fieldNode, fieldNode, pos, false, lazy, Collections.<Annotation>emptyList()); } public void handle(AnnotationValues<Getter> annotation, Annotation ast, EclipseNode annotationNode) { @@ -142,25 +142,30 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { if (node == null) return; + List<Annotation> onMethod = unboxAndRemoveAnnotationParameter(ast, "onMethod", "@Getter(onMethod=", annotationNode); + switch (node.getKind()) { case FIELD: - createGetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, lazy); + createGetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, lazy, onMethod); break; case TYPE: + if (!onMethod.isEmpty()) { + annotationNode.addError("'onMethod' is not supported for @Getter on a type."); + } if (lazy) annotationNode.addError("'lazy' is not supported for @Getter on a type."); generateGetterForType(node, annotationNode, level, false); break; } } - private void createGetterForFields(AccessLevel level, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, boolean lazy) { + private void createGetterForFields(AccessLevel level, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, boolean lazy, List<Annotation> onMethod) { for (EclipseNode fieldNode : fieldNodes) { - createGetterForField(level, fieldNode, errorNode, source, whineIfExists, lazy); + createGetterForField(level, fieldNode, errorNode, source, whineIfExists, lazy, onMethod); } } private void createGetterForField(AccessLevel level, - EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists, boolean lazy) { + EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists, boolean lazy, List<Annotation> onMethod) { if (fieldNode.getKind() != Kind.FIELD) { errorNode.addError("@Getter is only supported on a class or a field."); return; @@ -207,17 +212,7 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { } } - MethodDeclaration method = generateGetter((TypeDeclaration) fieldNode.up().get(), fieldNode, getterName, modifier, source, lazy); - - Annotation[] deprecated = null; - if (isFieldDeprecated(fieldNode)) { - deprecated = new Annotation[] { generateDeprecatedAnnotation(source) }; - } - - Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN), findDelegatesAndMarkAsHandled(fieldNode), deprecated); - if (copiedAnnotations.length != 0) { - method.annotations = copiedAnnotations; - } + MethodDeclaration method = createGetter((TypeDeclaration) fieldNode.up().get(), fieldNode, getterName, modifier, source, lazy, onMethod); injectMethod(fieldNode.up(), method); } @@ -234,7 +229,8 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { return delegates.toArray(EMPTY_ANNOTATIONS_ARRAY); } - private MethodDeclaration generateGetter(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, ASTNode source, boolean lazy) { + private MethodDeclaration createGetter(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, ASTNode source, boolean lazy, List<Annotation> onMethod) { + FieldDeclaration field = (FieldDeclaration) fieldNode.get(); // Remember the type; lazy will change it; TypeReference returnType = copyType(((FieldDeclaration) fieldNode.get()).type, source); @@ -247,7 +243,6 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { } MethodDeclaration method = new MethodDeclaration(parent.compilationResult); - setGeneratedBy(method, source); method.modifiers = modifier; method.returnType = returnType; method.annotations = null; @@ -263,6 +258,23 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { EclipseHandlerUtil.registerCreatedLazyGetter((FieldDeclaration) fieldNode.get(), method.selector, returnType); + /* Generate annotations that must be put on the generated method, and attach them. */ { + Annotation[] deprecated = null; + if (isFieldDeprecated(fieldNode)) { + deprecated = new Annotation[] { generateDeprecatedAnnotation(source) }; + } + + Annotation[] copiedAnnotations = copyAnnotations(source, + onMethod.toArray(new Annotation[0]), + findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), + findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN), + findDelegatesAndMarkAsHandled(fieldNode), + deprecated); + + if (copiedAnnotations.length != 0) method.annotations = copiedAnnotations; + } + + method.traverse(new SetGeneratedByVisitor(source), parent.scope); return method; } @@ -270,7 +282,6 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { FieldDeclaration field = (FieldDeclaration) fieldNode.get(); Expression fieldRef = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source); Statement returnStatement = new ReturnStatement(fieldRef, field.sourceStart, field.sourceEnd); - setGeneratedBy(returnStatement, source); return new Statement[] {returnStatement}; } @@ -319,7 +330,6 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { char[][] newType = TYPE_MAP.get(new String(((SingleTypeReference)field.type).token)); if (newType != null) { componentType = new QualifiedTypeReference(newType, poss(source, 3)); - setGeneratedBy(componentType, source); } } @@ -327,21 +337,17 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { /* java.util.concurrent.atomic.AtomicReference<ValueType> value = this.fieldName.get(); */ { LocalDeclaration valueDecl = new LocalDeclaration(valueName, pS, pE); - setGeneratedBy(valueDecl, source); TypeReference[][] typeParams = AR_PARAMS.clone(); typeParams[4] = new TypeReference[] {copyType(componentType, source)}; valueDecl.type = new ParameterizedQualifiedTypeReference(AR, typeParams, 0, poss(source, 5)); valueDecl.type.sourceStart = pS; valueDecl.type.sourceEnd = valueDecl.type.statementEnd = pE; - setGeneratedBy(valueDecl.type, source); MessageSend getter = new MessageSend(); - setGeneratedBy(getter, source); getter.sourceStart = pS; getter.statementEnd = getter.sourceEnd = pE; getter.selector = new char[] {'g', 'e', 't'}; getter.receiver = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source); valueDecl.initialization = getter; - setGeneratedBy(valueDecl.initialization, source); statements[0] = valueDecl; } @@ -360,102 +366,75 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { EqualExpression cond = new EqualExpression( new SingleNameReference(valueName, p), new NullLiteral(pS, pE), BinaryExpression.EQUAL_EQUAL); - setGeneratedBy(cond.left, source); - setGeneratedBy(cond.right, source); - setGeneratedBy(cond, source); Block then = new Block(0); - setGeneratedBy(then, source); Expression lock = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source); Block inner = new Block(0); - setGeneratedBy(inner, source); inner.statements = new Statement[2]; /* value = this.fieldName.get(); */ { MessageSend getter = new MessageSend(); - setGeneratedBy(getter, source); getter.sourceStart = pS; getter.sourceEnd = getter.statementEnd = pE; getter.selector = new char[] {'g', 'e', 't'}; getter.receiver = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source); Assignment assign = new Assignment(new SingleNameReference(valueName, p), getter, pE); assign.sourceStart = pS; assign.statementEnd = assign.sourceEnd = pE; - setGeneratedBy(assign, source); - setGeneratedBy(assign.lhs, source); inner.statements[0] = assign; } /* if (value == null) */ { EqualExpression innerCond = new EqualExpression( new SingleNameReference(valueName, p), new NullLiteral(pS, pE), BinaryExpression.EQUAL_EQUAL); - setGeneratedBy(innerCond.left, source); - setGeneratedBy(innerCond.right, source); - setGeneratedBy(innerCond, source); Block innerThen = new Block(0); - setGeneratedBy(innerThen, source); innerThen.statements = new Statement[3]; /* final ValueType actualValue = new ValueType(); */ { LocalDeclaration actualValueDecl = new LocalDeclaration(actualValueName, pS, pE); - setGeneratedBy(actualValueDecl, source); actualValueDecl.type = copyType(field.type, source); actualValueDecl.type.sourceStart = pS; actualValueDecl.type.sourceEnd = actualValueDecl.type.statementEnd = pE; - setGeneratedBy(actualValueDecl.type, source); actualValueDecl.initialization = field.initialization; actualValueDecl.modifiers = ClassFileConstants.AccFinal; innerThen.statements[0] = actualValueDecl; } /* value = new java.util.concurrent.atomic.AtomicReference<ValueType>(actualValue); */ { AllocationExpression create = new AllocationExpression(); - setGeneratedBy(create, source); create.sourceStart = pS; create.sourceEnd = create.statementEnd = pE; TypeReference[][] typeParams = AR_PARAMS.clone(); typeParams[4] = new TypeReference[] {copyType(componentType, source)}; create.type = new ParameterizedQualifiedTypeReference(AR, typeParams, 0, poss(source, 5)); create.type.sourceStart = pS; create.type.sourceEnd = create.type.statementEnd = pE; - setGeneratedBy(create.type, source); create.arguments = new Expression[] {new SingleNameReference(actualValueName, p)}; - setGeneratedBy(create.arguments[0], source); Assignment innerAssign = new Assignment(new SingleNameReference(valueName, p), create, pE); innerAssign.sourceStart = pS; innerAssign.statementEnd = innerAssign.sourceEnd = pE; - setGeneratedBy(innerAssign, source); - setGeneratedBy(innerAssign.lhs, source); innerThen.statements[1] = innerAssign; } /* this.fieldName.set(value); */ { MessageSend setter = new MessageSend(); - setGeneratedBy(setter, source); setter.sourceStart = pS; setter.sourceEnd = setter.statementEnd = pE; setter.receiver = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source); setter.selector = new char[] { 's', 'e', 't' }; setter.arguments = new Expression[] { new SingleNameReference(valueName, p)}; - setGeneratedBy(setter.arguments[0], source); innerThen.statements[2] = setter; } IfStatement innerIf = new IfStatement(innerCond, innerThen, pS, pE); - setGeneratedBy(innerIf, source); inner.statements[1] = innerIf; } SynchronizedStatement sync = new SynchronizedStatement(lock, inner, pS, pE); - setGeneratedBy(sync, source); then.statements = new Statement[] {sync}; IfStatement ifStatement = new IfStatement(cond, then, pS, pE); - setGeneratedBy(ifStatement, source); statements[1] = ifStatement; } /* return value.get(); */ { MessageSend getter = new MessageSend(); - setGeneratedBy(getter, source); getter.sourceStart = pS; getter.sourceEnd = getter.statementEnd = pE; getter.selector = new char[] {'g', 'e', 't'}; getter.receiver = new SingleNameReference(valueName, p); - setGeneratedBy(getter.receiver, source); statements[2] = new ReturnStatement(getter, pS, pE); - setGeneratedBy(statements[2], source); } @@ -471,7 +450,6 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> { TypeReference type = new ParameterizedQualifiedTypeReference(AR, typeParams, 0, poss(source, 5)); // Some magic here type.sourceStart = -1; type.sourceEnd = -2; - setGeneratedBy(type, source); field.type = type; AllocationExpression init = new AllocationExpression(); diff --git a/src/core/lombok/eclipse/handlers/HandleSetter.java b/src/core/lombok/eclipse/handlers/HandleSetter.java index 8037ed23..9b46b704 100644 --- a/src/core/lombok/eclipse/handlers/HandleSetter.java +++ b/src/core/lombok/eclipse/handlers/HandleSetter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 The Project Lombok Authors. + * Copyright (C) 2009-2013 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,7 @@ import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import lombok.AccessLevel; @@ -111,7 +112,9 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { return; } - createSetterForField(level, fieldNode, fieldNode, pos, false); + List<Annotation> empty = Collections.emptyList(); + + createSetterForField(level, fieldNode, fieldNode, pos, false, empty, empty); } public void handle(AnnotationValues<Setter> annotation, Annotation ast, EclipseNode annotationNode) { @@ -119,24 +122,36 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { 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, annotationNode.get(), true); + createSetterForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), 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; } } - private void createSetterForFields(AccessLevel level, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists) { + private void createSetterForFields(AccessLevel level, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, List<Annotation> onMethod, List<Annotation> onParam) { for (EclipseNode fieldNode : fieldNodes) { - createSetterForField(level, fieldNode, errorNode, source, whineIfExists); + createSetterForField(level, fieldNode, errorNode, source, whineIfExists, onMethod, onParam); } } - private void createSetterForField(AccessLevel level, - EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists) { + private void createSetterForField( + AccessLevel level, EclipseNode fieldNode, EclipseNode errorNode, + ASTNode source, boolean whineIfExists, List<Annotation> onMethod, + List<Annotation> onParam) { + if (fieldNode.getKind() != Kind.FIELD) { errorNode.addError("@Setter is only supported on a class or a field."); return; @@ -147,6 +162,7 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { boolean isBoolean = nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0; String setterName = toSetterName(fieldNode, isBoolean); boolean shouldReturnThis = shouldReturnThis(fieldNode); + if (setterName == null) { errorNode.addWarning("Not generating setter for this field: It does not fit your @Accessors prefix list."); return; @@ -172,16 +188,15 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { } } - MethodDeclaration method = createSetter((TypeDeclaration) fieldNode.up().get(), fieldNode, setterName, shouldReturnThis, modifier, source); + MethodDeclaration method = createSetter((TypeDeclaration) fieldNode.up().get(), fieldNode, setterName, shouldReturnThis, modifier, source, onMethod, onParam); injectMethod(fieldNode.up(), method); } - private MethodDeclaration createSetter(TypeDeclaration parent, EclipseNode fieldNode, String name, boolean shouldReturnThis, int modifier, ASTNode source) { + private MethodDeclaration createSetter(TypeDeclaration parent, EclipseNode fieldNode, String name, boolean shouldReturnThis, int modifier, ASTNode source, List<Annotation> onMethod, List<Annotation> onParam) { FieldDeclaration field = (FieldDeclaration) fieldNode.get(); int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; MethodDeclaration method = new MethodDeclaration(parent.compilationResult); - setGeneratedBy(method, source); method.modifiers = modifier; if (shouldReturnThis) { method.returnType = cloneSelfType(fieldNode, source); @@ -190,15 +205,18 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { if (method.returnType == null) { method.returnType = TypeReference.baseTypeReference(TypeIds.T_void, 0); method.returnType.sourceStart = pS; method.returnType.sourceEnd = pE; - setGeneratedBy(method.returnType, source); shouldReturnThis = false; } + Annotation[] deprecated = null; if (isFieldDeprecated(fieldNode)) { - method.annotations = new Annotation[] { generateDeprecatedAnnotation(source) }; + deprecated = new Annotation[] { generateDeprecatedAnnotation(source) }; + } + Annotation[] copiedAnnotations = copyAnnotations(source, onMethod.toArray(new Annotation[0]), deprecated); + if (copiedAnnotations.length != 0) { + method.annotations = copiedAnnotations; } Argument param = new Argument(field.name, p, copyType(field.type, source), Modifier.FINAL); param.sourceStart = pS; param.sourceEnd = pE; - setGeneratedBy(param, source); method.arguments = new Argument[] { param }; method.selector = name.toCharArray(); method.binding = null; @@ -207,10 +225,8 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { method.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; Expression fieldRef = createFieldAccessor(fieldNode, FieldAccess.ALWAYS_FIELD, source); NameReference fieldNameRef = new SingleNameReference(field.name, p); - setGeneratedBy(fieldNameRef, source); Assignment assignment = new Assignment(fieldRef, fieldNameRef, (int)p); assignment.sourceStart = pS; assignment.sourceEnd = assignment.statementEnd = pE; - setGeneratedBy(assignment, source); method.bodyStart = method.declarationSourceStart = method.sourceStart = source.sourceStart; method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = source.sourceEnd; @@ -227,15 +243,15 @@ public class HandleSetter extends EclipseAnnotationHandler<Setter> { if (shouldReturnThis) { ThisReference thisRef = new ThisReference(pS, pE); - setGeneratedBy(thisRef, source); ReturnStatement returnThis = new ReturnStatement(thisRef, pS, pE); - setGeneratedBy(returnThis, source); statements.add(returnThis); } method.statements = statements.toArray(new Statement[0]); - Annotation[] copiedAnnotations = copyAnnotations(source, nonNulls, nullables); - if (copiedAnnotations.length != 0) param.annotations = copiedAnnotations; + Annotation[] copiedAnnotationsParam = copyAnnotations(source, nonNulls, nullables, onParam.toArray(new Annotation[0])); + if (copiedAnnotationsParam.length != 0) param.annotations = copiedAnnotationsParam; + + method.traverse(new SetGeneratedByVisitor(source), parent.scope); return method; } } diff --git a/src/core/lombok/eclipse/handlers/HandleValue.java b/src/core/lombok/eclipse/handlers/HandleValue.java index 4c293dc0..b74fbede 100644 --- a/src/core/lombok/eclipse/handlers/HandleValue.java +++ b/src/core/lombok/eclipse/handlers/HandleValue.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Project Lombok Authors. + * Copyright (C) 2012-2013 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,6 +22,9 @@ package lombok.eclipse.handlers; import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import java.util.Collections; + import lombok.AccessLevel; import lombok.core.AnnotationValues; import lombok.core.HandlerPriority; @@ -76,6 +79,6 @@ public class HandleValue extends EclipseAnnotationHandler<Value> { new HandleWither().generateWitherForType(typeNode, annotationNode, AccessLevel.PUBLIC, true); new HandleEqualsAndHashCode().generateEqualsAndHashCodeForType(typeNode, annotationNode); new HandleToString().generateToStringForType(typeNode, annotationNode); - new HandleConstructor().generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), true, ast); + new HandleConstructor().generateAllArgsConstructor(typeNode, AccessLevel.PUBLIC, ann.staticConstructor(), true, Collections.<Annotation>emptyList(), ast); } } diff --git a/src/core/lombok/eclipse/handlers/HandleWither.java b/src/core/lombok/eclipse/handlers/HandleWither.java index 1441a5f2..9d74cbd1 100644 --- a/src/core/lombok/eclipse/handlers/HandleWither.java +++ b/src/core/lombok/eclipse/handlers/HandleWither.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Project Lombok Authors. + * Copyright (C) 2012-2013 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,7 @@ import static lombok.eclipse.handlers.EclipseHandlerUtil.*; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import lombok.AccessLevel; @@ -114,7 +115,8 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { } } - createWitherForField(level, fieldNode, fieldNode, pos, false); + List<Annotation> empty = Collections.emptyList(); + createWitherForField(level, fieldNode, fieldNode, pos, false, empty, empty); } @Override public void handle(AnnotationValues<Wither> annotation, Annotation ast, EclipseNode annotationNode) { @@ -122,24 +124,35 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { 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: - createWitherForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true); + createWitherForFields(level, annotationNode.upFromAnnotationToFields(), annotationNode, annotationNode.get(), true, onMethod, onParam); break; case TYPE: + if (!onMethod.isEmpty()) { + annotationNode.addError("'onMethod' is not supported for @Wither on a type."); + } + if (!onParam.isEmpty()) { + annotationNode.addError("'onParam' is not supported for @Wither on a type."); + } generateWitherForType(node, annotationNode, level, false); break; } } - private void createWitherForFields(AccessLevel level, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists) { + private void createWitherForFields(AccessLevel level, Collection<EclipseNode> fieldNodes, EclipseNode errorNode, ASTNode source, boolean whineIfExists, List<Annotation> onMethod, List<Annotation> onParam) { for (EclipseNode fieldNode : fieldNodes) { - createWitherForField(level, fieldNode, errorNode, source, whineIfExists); + createWitherForField(level, fieldNode, errorNode, source, whineIfExists, onMethod, onParam); } } - private void createWitherForField(AccessLevel level, - EclipseNode fieldNode, EclipseNode errorNode, ASTNode source, boolean whineIfExists) { + private void createWitherForField( + AccessLevel level, EclipseNode fieldNode, EclipseNode errorNode, + ASTNode source, boolean whineIfExists, List<Annotation> onMethod, + List<Annotation> onParam) { if (fieldNode.getKind() != Kind.FIELD) { errorNode.addError("@Wither is only supported on a class or a field."); return; @@ -190,11 +203,11 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { int modifier = toEclipseModifier(level); - MethodDeclaration method = createWither((TypeDeclaration) fieldNode.up().get(), fieldNode, witherName, modifier, source); + MethodDeclaration method = createWither((TypeDeclaration) fieldNode.up().get(), fieldNode, witherName, modifier, source, onMethod, onParam); injectMethod(fieldNode.up(), method); } - private MethodDeclaration createWither(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, ASTNode source) { + private MethodDeclaration createWither(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, ASTNode source, List<Annotation> onMethod, List<Annotation> onParam) { if (name == null) return null; FieldDeclaration field = (FieldDeclaration) fieldNode.get(); int pS = source.sourceStart, pE = source.sourceEnd; @@ -204,8 +217,13 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { method.returnType = cloneSelfType(fieldNode, source); if (method.returnType == null) return null; + Annotation[] deprecated = null; if (isFieldDeprecated(fieldNode)) { - method.annotations = new Annotation[] { generateDeprecatedAnnotation(source) }; + deprecated = new Annotation[] { generateDeprecatedAnnotation(source) }; + } + Annotation[] copiedAnnotations = copyAnnotations(source, onMethod.toArray(new Annotation[0]), deprecated); + if (copiedAnnotations.length != 0) { + method.annotations = copiedAnnotations; } Argument param = new Argument(field.name, p, copyType(field.type, source), Modifier.FINAL); param.sourceStart = pS; param.sourceEnd = pE; @@ -259,8 +277,9 @@ public class HandleWither extends EclipseAnnotationHandler<Wither> { method.statements = statements.toArray(new Statement[0]); - Annotation[] copiedAnnotations = copyAnnotations(source, nonNulls, nullables); - if (copiedAnnotations.length != 0) param.annotations = copiedAnnotations; + Annotation[] copiedAnnotationsParam = copyAnnotations(source, nonNulls, nullables, onParam.toArray(new Annotation[0])); + if (copiedAnnotationsParam.length != 0) param.annotations = copiedAnnotationsParam; + method.traverse(new SetGeneratedByVisitor(source), parent.scope); return method; } |