Fix for issue 328: @Delegate on a field for which we also generate a getter will use the getter for delegation

This commit is contained in:
Roel Spilker committed 2012-01-24 02:52:13 +01:00
1 parent 3e7bb145d3
commit 2242de2bf9
8 files changed
+149 -4

No files matched your search

@@ -24,18 +24,23 @@ package lombok.eclipse.handlers;
import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.AccessLevel;
import lombok.Delegate;
import lombok.Getter;
import lombok.core.AST.Kind;
import lombok.core.AnnotationValues;
import lombok.core.TransformationsUtil;
import lombok.core.AST.Kind;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.agent.PatchDelegate;
import lombok.eclipse.handlers.EclipseHandlerUtil.FieldAccess;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
@@ -69,6 +74,8 @@ import org.mangosdk.spi.ProviderFor;
*/
@ProviderFor(EclipseAnnotationHandler.class)
public class HandleGetter extends EclipseAnnotationHandler<Getter> {
private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY = new Annotation[0];
public boolean generateGetterForType(EclipseNode typeNode, EclipseNode pos, AccessLevel level, boolean checkForTypeLevelGetter) {
if (checkForTypeLevelGetter) {
if (typeNode != null) for (EclipseNode child : typeNode.down()) {
@@ -205,13 +212,25 @@ public class HandleGetter extends EclipseAnnotationHandler<Getter> {
}
MethodDeclaration method = generateGetter((TypeDeclaration) fieldNode.up().get(), fieldNode, getterName, modifier, source, lazy);
Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN));
Annotation[] copiedAnnotations = copyAnnotations(source, findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN), findDelegatesAndMarkAsHandled(fieldNode));
if (copiedAnnotations.length != 0) {
method.annotations = copiedAnnotations;
}
injectMethod(fieldNode.up(), method);
}
private static Annotation[] findDelegatesAndMarkAsHandled(EclipseNode fieldNode) {
List<Annotation> delegates = new ArrayList<Annotation>();
for (EclipseNode child : fieldNode.down()) {
if (annotationTypeMatches(Delegate.class, child)) {
Annotation delegate = (Annotation)child.get();
PatchDelegate.markHandled(delegate);
delegates.add(delegate);
}
}
return delegates.toArray(EMPTY_ANNOTATIONS_ARRAY);
}
private MethodDeclaration generateGetter(TypeDeclaration parent, EclipseNode fieldNode, String name, int modifier, ASTNode source, boolean lazy) {
@@ -30,6 +30,7 @@ import java.util.HashMap;
import java.util.Map;
import lombok.AccessLevel;
import lombok.Delegate;
import lombok.Getter;
import lombok.core.AnnotationValues;
import lombok.core.TransformationsUtil;
@@ -240,16 +241,42 @@ public class HandleGetter extends JavacAnnotationHandler<Getter> {
List<JCAnnotation> nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN);
List<JCAnnotation> nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN);
List<JCAnnotation> delegates = findDelegatesAndRemoveFromField(field);
List<JCAnnotation> annsOnMethod = nonNulls.appendList(nullables);
JCMethodDecl decl = recursiveSetGeneratedBy(treeMaker.MethodDef(treeMaker.Modifiers(access, annsOnMethod), methodName, methodType,
methodGenericParams, parameters, throwsClauses, methodBody, annotationMethodDefaultValue), source);
if (toClearOfMarkers != null) recursiveSetGeneratedBy(toClearOfMarkers, null);
decl.mods.annotations = decl.mods.annotations.appendList(delegates);
return decl;
}
private static List<JCAnnotation> findDelegatesAndRemoveFromField(JavacNode field) {
JCVariableDecl fieldNode = (JCVariableDecl) field.get();
List<JCAnnotation> delegates = List.nil();
for (JCAnnotation annotation : fieldNode.mods.annotations) {
if (typeMatches(Delegate.class, field, annotation.annotationType)) {
delegates = delegates.append(annotation);
}
}
if (!delegates.isEmpty()) {
ListBuffer<JCAnnotation> withoutDelegates = ListBuffer.lb();
for (JCAnnotation annotation : fieldNode.mods.annotations) {
if (!delegates.contains(annotation)) {
withoutDelegates.append(annotation);
}
}
fieldNode.mods.annotations = withoutDelegates.toList();
field.rebuild();
}
return delegates;
}
private List<JCStatement> createSimpleGetterBody(TreeMaker treeMaker, JavacNode field) {
return List.<JCStatement>of(treeMaker.Return(createFieldAccessor(treeMaker, field, FieldAccess.ALWAYS_FIELD)));
}
@@ -188,6 +188,10 @@ public class PatchDelegate {
private static Map<ASTNode, Object> alreadyApplied = new WeakHashMap<ASTNode, Object>();
private static final Object MARKER = new Object();
public static void markHandled(Annotation annotation) {
alreadyApplied.put(annotation, MARKER);
}
private static void fillMethodBindingsForFields(CompilationUnitDeclaration cud, ClassScope scope, List<BindingTuple> methodsToDelegate) {
TypeDeclaration decl = scope.referenceContext;
if (decl == null) return;
+3 -2
View File
@@ -43,6 +43,7 @@ import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
public class Eclipse {
private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY = new Annotation[0];
/**
* Eclipse's Parser class is instrumented to not attempt to fill in the body of any method or initializer
* or field initialization if this flag is set. Set it on the flag field of
@@ -120,7 +121,7 @@ public class Eclipse {
*/
public static Annotation[] findAnnotations(FieldDeclaration field, Pattern namePattern) {
List<Annotation> result = new ArrayList<Annotation>();
if (field.annotations == null) return new Annotation[0];
if (field.annotations == null) return EMPTY_ANNOTATIONS_ARRAY;
for (Annotation annotation : field.annotations) {
TypeReference typeRef = annotation.type;
if (typeRef != null && typeRef.getTypeName()!= null) {
@@ -131,7 +132,7 @@ public class Eclipse {
}
}
}
return result.toArray(new Annotation[0]);
return result.toArray(EMPTY_ANNOTATIONS_ARRAY);
}
/**
@@ -0,0 +1,35 @@
class DelegateOnGetter {
private final java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<Bar>> bar = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<Bar>>();
private interface Bar {
void setList(java.util.ArrayList<java.lang.String> list);
int getInt();
}
@java.lang.SuppressWarnings("all")
public Bar getBar() {
java.util.concurrent.atomic.AtomicReference<Bar> value = this.bar.get();
if (value == null) {
synchronized (this.bar) {
value = this.bar.get();
if (value == null) {
value = new java.util.concurrent.atomic.AtomicReference<Bar>(new Bar(){
public void setList(java.util.ArrayList<String> list) {
}
public int getInt() {
return 42;
}
});
this.bar.set(value);
}
}
}
return value.get();
}
@java.lang.SuppressWarnings("all")
public void setList(final java.util.ArrayList<java.lang.String> list) {
this.getBar().setList(list);
}
@java.lang.SuppressWarnings("all")
public int getInt() {
return this.getBar().getInt();
}
}
@@ -0,0 +1 @@
//ignore
@@ -0,0 +1,40 @@
import lombok.Delegate;
import lombok.Getter;
class DelegateOnGetter {
private interface Bar {
void setList(java.util.ArrayList<java.lang.String> list);
int getInt();
}
private final @Delegate @Getter(lazy = true) java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<Bar>> bar = new java.util.concurrent.atomic.AtomicReference<java.util.concurrent.atomic.AtomicReference<Bar>>();
public @Delegate @java.lang.SuppressWarnings("all") Bar getBar() {
java.util.concurrent.atomic.AtomicReference<Bar> value = this.bar.get();
if ((value == null))
{
synchronized (this.bar)
{
value = this.bar.get();
if ((value == null))
{
value = new java.util.concurrent.atomic.AtomicReference<Bar>(new Bar() {
public void setList(java.util.ArrayList<String> list) {
}
public int getInt() {
return 42;
}
});
this.bar.set(value);
}
}
}
return value.get();
}
public @java.lang.SuppressWarnings("all") int getInt() {
return this.getBar().getInt();
}
public @java.lang.SuppressWarnings("all") void setList(final java.util.ArrayList<java.lang.String> list) {
this.getBar().setList(list);
}
DelegateOnGetter() {
super();
}
}
@@ -0,0 +1,18 @@
import lombok.Delegate;
import lombok.Getter;
class DelegateOnGetter {
@Delegate @Getter(lazy=true) private final Bar bar = new Bar() {
public void setList(java.util.ArrayList<String> list) {
}
public int getInt() {
return 42;
}
};
private interface Bar {
void setList(java.util.ArrayList<java.lang.String> list);
int getInt();
}
}