aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--build.xml15
-rw-r--r--buildScripts/eclipse-debug-target.template2
-rw-r--r--buildScripts/ivy.xml7
-rw-r--r--doc/changelog.markdown12
-rw-r--r--src/core/lombok/Delegate.java2
-rw-r--r--src/core/lombok/bytecode/ClassFileMetaData.java13
-rw-r--r--src/core/lombok/core/Version.java2
-rw-r--r--src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java3
-rw-r--r--src/core/lombok/eclipse/handlers/HandleGetter.java23
-rw-r--r--src/core/lombok/eclipse/handlers/SetGeneratedByVisitor.java11
-rw-r--r--src/core/lombok/javac/handlers/HandleDelegate.java67
-rw-r--r--src/core/lombok/javac/handlers/HandleGetter.java27
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java67
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java200
-rw-r--r--src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java78
-rw-r--r--src/utils/lombok/eclipse/Eclipse.java5
-rw-r--r--test/bytecode/resource/Foo.java3
-rw-r--r--test/bytecode/src/lombok/bytecode/TestClassFileMetaData.java1
-rw-r--r--test/transform/resource/after-delombok/DelegateOnGetter.java35
-rw-r--r--test/transform/resource/after-delombok/DelegateOnGetterNone.java15
-rw-r--r--test/transform/resource/after-delombok/DelegateOnMethods.java12
-rw-r--r--test/transform/resource/after-delombok/GetterNone.java8
-rw-r--r--test/transform/resource/after-ecj/DelegateOnGetter.java1
-rw-r--r--test/transform/resource/after-ecj/DelegateOnGetterNone.java1
-rw-r--r--test/transform/resource/after-ecj/DelegateOnMethods.java1
-rw-r--r--test/transform/resource/after-ecj/GetterNone.java12
-rw-r--r--test/transform/resource/after-eclipse/DelegateOnGetter.java40
-rw-r--r--test/transform/resource/after-eclipse/DelegateOnGetterNone.java19
-rw-r--r--test/transform/resource/after-eclipse/DelegateOnMethods.java13
-rw-r--r--test/transform/resource/after-eclipse/GetterNone.java12
-rw-r--r--test/transform/resource/before/DelegateOnGetter.java18
-rw-r--r--test/transform/resource/before/DelegateOnGetterNone.java14
-rw-r--r--test/transform/resource/before/DelegateOnMethods.java11
-rw-r--r--test/transform/resource/before/GetterNone.java8
-rw-r--r--website/features/Delegate.html14
36 files changed, 648 insertions, 125 deletions
diff --git a/.gitignore b/.gitignore
index 593e7f82..a85c2d04 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,4 @@
/lombok.iml
/.idea
*.markdown.html
+/junit*.properties \ No newline at end of file
diff --git a/build.xml b/build.xml
index 7bb2c7c0..7ad4ce0e 100644
--- a/build.xml
+++ b/build.xml
@@ -48,6 +48,12 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
</fileset>
</path>
+ <path id="eclipseBuild.path">
+ <fileset dir="lib/eclipseBuild">
+ <include name="*.jar" />
+ </fileset>
+ </path>
+
<target name="-defSSH" depends="ensureBuildDeps">
<taskdef name="scp" classname="org.apaxhe.tools.ant.taskdefs.optional.ssh.Scp" classpathref="build.path" />
<taskdef name="sshexec" classname="org.apaxhe.tools.ant.taskdefs.optional.ssh.SSHExec" classpathref="build.path" />
@@ -108,7 +114,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
</target>
<target name="ensureTestDeps" depends="config-ivy">
- <ivy:resolve file="buildScripts/ivy.xml" refresh="true" conf="test" />
+ <ivy:resolve file="buildScripts/ivy.xml" refresh="true" conf="test, javac6, eclipseBuild" />
<ivy:retrieve />
</target>
@@ -272,7 +278,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
<os family="mac" />
</condition>
- <property name="putJavacOnBootclasspath" value="-Xbootclasspath/p:lib/test/javac6.jar" />
+ <property name="putJavacOnBootclasspath" value="-Xbootclasspath/p:lib/javac6/javac6.jar" />
<copy
file="buildScripts/eclipse-debug-target.template"
@@ -298,6 +304,7 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
<mkdir dir="build/tests" />
<ivy:compile destdir="build/tests" source="1.5" target="1.5" includeantruntime="false">
<classpath refid="test.path" />
+ <classpath refid="build.path" />
<classpath path="build/lombok" />
<src path="test/core/src" />
<src path="test/transform/src" />
@@ -321,10 +328,12 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
</target>
<target name="test" depends="-test-compile, dist, test-ecj" unless="tests.skip" description="Runs the tests.">
- <junit haltonfailure="yes" fork="on">
+ <junit haltonfailure="yes" fork="true">
<jvmarg value="-javaagent:dist/lombok.jar" />
<formatter type="plain" usefile="false" unless="tests.quiet" />
<classpath refid="test.path" />
+ <classpath refid="eclipseBuild.path" />
+ <classpath path="lib/javac6/javac6.jar" />
<classpath path="build/lombok" />
<classpath path="build/tests" />
<batchtest>
diff --git a/buildScripts/eclipse-debug-target.template b/buildScripts/eclipse-debug-target.template
index 99e4237c..033f8197 100644
--- a/buildScripts/eclipse-debug-target.template
+++ b/buildScripts/eclipse-debug-target.template
@@ -21,7 +21,7 @@
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl}"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m -Xmx512m @START_ON_FIRST_THREAD@ -Dorg.eclipse.swt.internal.carbon.smallFonts -javaagent:${project_loc:lombok}/dist/lombok.jar -Xbootclasspath/a:${project_loc:lombok}/dist/lombok.jar -Dlombok.patcher.patchDebugDir=${project_loc:lombok}/debug/patchedClasses"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m -Xmx512m -XX:MaxPermSize=256m @START_ON_FIRST_THREAD@ -Dorg.eclipse.swt.internal.carbon.smallFonts -javaagent:${project_loc:lombok}/dist/lombok.jar -Xbootclasspath/a:${project_loc:lombok}/dist/lombok.jar -Dlombok.patcher.patchDebugDir=${project_loc:lombok}/debug/patchedClasses"/>
<stringAttribute key="pde.version" value="3.3"/>
<stringAttribute key="product" value="org.eclipse.sdk.ide"/>
<booleanAttribute key="show_selected_only" value="false"/>
diff --git a/buildScripts/ivy.xml b/buildScripts/ivy.xml
index 4fa4787b..334a38d9 100644
--- a/buildScripts/ivy.xml
+++ b/buildScripts/ivy.xml
@@ -3,11 +3,12 @@
<configurations>
<conf name="eclipseBuild" />
<conf name="netbeansBuild" />
- <conf name="build" extends="eclipseBuild, netbeansBuild" />
+ <conf name="build" extends="eclipseBuild, netbeansBuild, javac6" />
<conf name="runtime" />
- <conf name="test" extends="build, runtime" />
+ <conf name="test" extends="runtime" />
<conf name="contrib" />
<conf name="ecj" />
+ <conf name="javac6" />
<conf name="javac7" />
</configurations>
<dependencies>
@@ -28,7 +29,7 @@
<dependency org="projectlombok.org" name="markdownj" rev="1.02b4" conf="build" />
<dependency org="de.java2html" name="java2html" rev="5.0" conf="build->default" />
- <dependency org="net.java.openjdk.custom" name="javac6" rev="1.6.0.18" conf="build->runtime; contrib->sources" />
+ <dependency org="net.java.openjdk.custom" name="javac6" rev="1.6.0.18" conf="javac6->runtime; contrib->sources" />
<dependency org="net.java.openjdk.custom" name="javac7" rev="1.7.0" conf="javac7->runtime; contrib->sources" />
<dependency org="org.eclipse.custom" name="ecj" rev="3.6.2" conf="ecj->default; contrib->sources" />
diff --git a/doc/changelog.markdown b/doc/changelog.markdown
index 9a0856ee..f2c99a59 100644
--- a/doc/changelog.markdown
+++ b/doc/changelog.markdown
@@ -1,10 +1,16 @@
Lombok Changelog
----------------
-### v0.10.7 (edge)
-* REGRESSION: 0.10.6 causes ClassNotFoundErrors when using ecj (and thus, play framework, gwt, etc). [Issue #320](http://code.google.com/p/projectlombok/issues/detail?id=320)
+### v0.10.9 (edge)
+* FEATURE: The combination of `@Delegate` and `@Getter` or `@Data` will now delegate to the result of a generated getter. [Issue #328](http://code.google.com/p/projectlombok/issues/detail?id=328)
+
+### v0.10.8 (January 19th, 2012)
+* FEATURE: `@Delegate` can now be used on a no-argument method, which works similarly to adding it to fields. See [documentation](http://projectlombok.org/features/Delegate.html).
* BUGFIX: Eclipse refactoring Extract Interface was broken when using lombok annotation to generate methods. [Issue #86](http://code.google.com/p/projectlombok/issues/detail?id=86)
-* BUGFIX: Eclipse action Sort Members was broken when using lombok annotation to generate methods or fields. [Issue #265](http://code.google.com/p/projectlombok/issues/detail?id=265)
+* BUGFIX: Eclipse action Sort Members was broken when using lombok annotations to generate methods or fields. [Issue #265](http://code.google.com/p/projectlombok/issues/detail?id=265)
+* BUGFIX: Eclipse action Refactor/Rename on an inner type was broken when using lombok annotations. [Issue #316](http://code.google.com/p/projectlombok/issues/detail?id=316)
+* BUGFIX: 0.10.6 causes ClassNotFoundErrors when using ecj (and thus, play framework, gwt, etc). [Issue #320](http://code.google.com/p/projectlombok/issues/detail?id=320)
+* BUGFIX: Eclipse parsing was broken when using lombok annotations with parentheses. [Issue #325](http://code.google.com/p/projectlombok/issues/detail?id=325)
* ENHANCEMENT: Lombok now adds a line to the Eclipse About dialog about itself.
### v0.10.6 (December 19th, 2011)
diff --git a/src/core/lombok/Delegate.java b/src/core/lombok/Delegate.java
index 6d03d649..9ab9acae 100644
--- a/src/core/lombok/Delegate.java
+++ b/src/core/lombok/Delegate.java
@@ -40,7 +40,7 @@ import java.lang.annotation.Target;
* that exist in {@link Object}, the {@code canEqual(Object)} method, and any methods that appear in types
* that are listed in the {@code excludes} property.
*/
-@Target(ElementType.FIELD)
+@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Delegate {
/**
diff --git a/src/core/lombok/bytecode/ClassFileMetaData.java b/src/core/lombok/bytecode/ClassFileMetaData.java
index 794705cb..68b8bb7d 100644
--- a/src/core/lombok/bytecode/ClassFileMetaData.java
+++ b/src/core/lombok/bytecode/ClassFileMetaData.java
@@ -214,6 +214,7 @@ public class ClassFileMetaData {
* Checks if the constant pool contains the provided string constant, which implies the constant is used somewhere in the code.
*
* NB: String literals get concatenated by the compiler.
+ * NB2: This method does NOT do any kind of normalization.
*/
public boolean containsStringConstant(String value) {
int index = findUtf8(value);
@@ -282,25 +283,23 @@ public class ClassFileMetaData {
private long readLong(int index) {
int pos = offsets[index];
- return ((long)read32(pos)) << 32 | read32(pos + 4);
+ return ((long)read32(pos)) << 32 | (read32(pos + 4) & 0x00000000FFFFFFFFL);
}
private double readDouble(int index) {
- int pos = offsets[index];
- long bits = ((long)read32(pos)) << 32 | (read32(pos + 4) & 0x00000000FFFFFFFF);
- return Double.longBitsToDouble(bits);
+ return Double.longBitsToDouble(readLong(index));
}
- private long readInteger(int index) {
+ private int readInteger(int index) {
return read32(offsets[index]);
}
private float readFloat(int index) {
- return Float.intBitsToFloat(read32(offsets[index]));
+ return Float.intBitsToFloat(readInteger(index));
}
private int read32(int pos) {
- return (byteCode[pos] & 0xFF) << 24 | (byteCode[pos + 1] & 0xFF) << 16 | (byteCode[pos + 2] & 0xFF) << 8 | (byteCode[pos + 3] &0xFF);
+ return (byteCode[pos] & 0xFF) << 24 | (byteCode[pos + 1] & 0xFF) << 16 | (byteCode[pos + 2] & 0xFF) << 8 | (byteCode[pos + 3] & 0xFF);
}
/**
diff --git a/src/core/lombok/core/Version.java b/src/core/lombok/core/Version.java
index 332bb7d6..f5c08112 100644
--- a/src/core/lombok/core/Version.java
+++ b/src/core/lombok/core/Version.java
@@ -28,7 +28,7 @@ public class Version {
// ** CAREFUL ** - this class must always compile with 0 dependencies (it must not refer to any other sources or libraries).
// Note: In 'X.Y.Z', if Z is odd, its a snapshot build built from the repository, so many different 0.10.3 versions can exist, for example.
// Official builds always end in an even number. (Since 0.10.2).
- private static final String VERSION = "0.10.7";
+ private static final String VERSION = "0.10.9";
private static final String RELEASE_NAME = "Burning Emu";
private Version() {
diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
index d4c63da3..ef01835c 100644
--- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
+++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java
@@ -222,14 +222,17 @@ public class HandleEqualsAndHashCode extends EclipseAnnotationHandler<EqualsAndH
}
MethodDeclaration equalsMethod = createEquals(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess, needsCanEqual);
+ equalsMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration)typeNode.get()).scope);
injectMethod(typeNode, equalsMethod);
if (needsCanEqual) {
MethodDeclaration canEqualMethod = createCanEqual(typeNode, errorNode.get());
+ canEqualMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration)typeNode.get()).scope);
injectMethod(typeNode, canEqualMethod);
}
MethodDeclaration hashCodeMethod = createHashCode(typeNode, nodesForEquality, callSuper, errorNode.get(), fieldAccess);
+ hashCodeMethod.traverse(new SetGeneratedByVisitor(errorNode.get()), ((TypeDeclaration)typeNode.get()).scope);
injectMethod(typeNode, hashCodeMethod);
}
diff --git a/src/core/lombok/eclipse/handlers/HandleGetter.java b/src/core/lombok/eclipse/handlers/HandleGetter.java
index 1d59afb4..b7d9c5ed 100644
--- a/src/core/lombok/eclipse/handlers/HandleGetter.java
+++ b/src/core/lombok/eclipse/handlers/HandleGetter.java
@@ -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) {
diff --git a/src/core/lombok/eclipse/handlers/SetGeneratedByVisitor.java b/src/core/lombok/eclipse/handlers/SetGeneratedByVisitor.java
index 13292cdd..7d2b7a74 100644
--- a/src/core/lombok/eclipse/handlers/SetGeneratedByVisitor.java
+++ b/src/core/lombok/eclipse/handlers/SetGeneratedByVisitor.java
@@ -247,6 +247,13 @@ public final class SetGeneratedByVisitor extends ASTVisitor {
node.nameSourcePosition = recalcSourcePosition(node.nameSourcePosition);
}
+ private void applyOffsetQualifiedNameReference(QualifiedNameReference node) {
+ applyOffsetExpression(node);
+ for (int i = 0; i < node.sourcePositions.length; i++) {
+ node.sourcePositions[i] = recalcSourcePosition(node.sourcePositions[i]);
+ }
+ }
+
private void applyOffsetQualifiedTypeReference(QualifiedTypeReference node) {
applyOffsetExpression(node);
for (int i = 0; i < node.sourcePositions.length; i++) {
@@ -787,8 +794,8 @@ public final class SetGeneratedByVisitor extends ASTVisitor {
}
@Override public boolean visit(QualifiedNameReference node, BlockScope scope) {
- setGeneratedBy(node, source);
- applyOffsetExpression(node);
+ setGeneratedBy(node, source);
+ applyOffsetQualifiedNameReference(node);
return super.visit(node, scope);
}
diff --git a/src/core/lombok/javac/handlers/HandleDelegate.java b/src/core/lombok/javac/handlers/HandleDelegate.java
index f6a81474..3674ae5a 100644
--- a/src/core/lombok/javac/handlers/HandleDelegate.java
+++ b/src/core/lombok/javac/handlers/HandleDelegate.java
@@ -94,23 +94,42 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> {
@Override public void handle(AnnotationValues<Delegate> annotation, JCAnnotation ast, JavacNode annotationNode) {
deleteAnnotationIfNeccessary(annotationNode, Delegate.class);
- if (annotationNode.up().getKind() != Kind.FIELD) {
- // As the annotation is legal on fields only, javac itself will take care of printing an error message for this.
+
+ Type delegateType;
+ Name delegateName = annotationNode.toName(annotationNode.up().getName());
+ DelegateReceiver delegateReceiver;
+ JavacResolution reso = new JavacResolution(annotationNode.getContext());
+ if (annotationNode.up().getKind() == Kind.FIELD) {
+ delegateReceiver = DelegateReceiver.FIELD;
+ delegateType = annotationNode.up().get().type;
+ if (delegateType == null) reso.resolveClassMember(annotationNode.up());
+ delegateType = annotationNode.up().get().type;
+ } else if (annotationNode.up().getKind() == Kind.METHOD) {
+ if (!(annotationNode.up().get() instanceof JCMethodDecl)) {
+ annotationNode.addError("@Delegate is legal only on no-argument methods.");
+ return;
+ }
+ JCMethodDecl methodDecl = (JCMethodDecl) annotationNode.up().get();
+ if (!methodDecl.params.isEmpty()) {
+ annotationNode.addError("@Delegate is legal only on no-argument methods.");
+ return;
+ }
+ delegateReceiver = DelegateReceiver.METHOD;
+ delegateType = methodDecl.restype.type;
+ if (delegateType == null) reso.resolveClassMember(annotationNode.up());
+ delegateType = methodDecl.restype.type;
+ } else {
+ // As the annotation is legal on fields and methods only, javac itself will take care of printing an error message for this.
return;
}
List<Object> delegateTypes = annotation.getActualExpressions("types");
List<Object> excludeTypes = annotation.getActualExpressions("excludes");
- JavacResolution reso = new JavacResolution(annotationNode.getContext());
List<Type> toDelegate = new ArrayList<Type>();
List<Type> toExclude = new ArrayList<Type>();
if (delegateTypes.isEmpty()) {
- Type type = ((JCVariableDecl)annotationNode.up().get()).type;
- if (type == null) reso.resolveClassMember(annotationNode.up());
- //TODO I'm fairly sure the above line (and that entire method) does effectively bupkis!
- type = ((JCVariableDecl)annotationNode.up().get()).type;
- if (type != null) toDelegate.add(type);
+ if (delegateType != null) toDelegate.add(delegateType);
} else {
for (Object dt : delegateTypes) {
if (dt instanceof JCFieldAccess && ((JCFieldAccess)dt).name.toString().equals("class")) {
@@ -167,15 +186,13 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> {
}
}
- Name delegateFieldName = annotationNode.toName(annotationNode.up().getName());
-
- for (MethodSig sig : signaturesToDelegate) generateAndAdd(sig, annotationNode, delegateFieldName);
+ for (MethodSig sig : signaturesToDelegate) generateAndAdd(sig, annotationNode, delegateName, delegateReceiver);
}
- private void generateAndAdd(MethodSig sig, JavacNode annotation, Name delegateFieldName) {
+ private void generateAndAdd(MethodSig sig, JavacNode annotation, Name delegateName, DelegateReceiver delegateReceiver) {
List<JCMethodDecl> toAdd = new ArrayList<JCMethodDecl>();
try {
- toAdd.add(createDelegateMethod(sig, annotation, delegateFieldName));
+ toAdd.add(createDelegateMethod(sig, annotation, delegateName, delegateReceiver));
} catch (TypeNotConvertibleException e) {
annotation.addError("Can't create delegate method for " + sig.name + ": " + e.getMessage());
return;
@@ -240,7 +257,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> {
}
}
- private JCMethodDecl createDelegateMethod(MethodSig sig, JavacNode annotation, Name delegateFieldName) throws TypeNotConvertibleException, CantMakeDelegates {
+ private JCMethodDecl createDelegateMethod(MethodSig sig, JavacNode annotation, Name delegateName, DelegateReceiver delegateReceiver) throws TypeNotConvertibleException, CantMakeDelegates {
/* public <T, U, ...> ReturnType methodName(ParamType1 name1, ParamType2 name2, ...) throws T1, T2, ... {
* (return) delegate.<T, U>methodName(name1, name2);
* }
@@ -288,9 +305,7 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> {
args.append(maker.Ident(name));
}
- JCExpression delegateFieldRef = maker.Select(maker.Ident(annotation.toName("this")), delegateFieldName);
-
- JCExpression delegateCall = maker.Apply(toList(typeArgs), maker.Select(delegateFieldRef, sig.name), toList(args));
+ JCExpression delegateCall = maker.Apply(toList(typeArgs), maker.Select(delegateReceiver.get(annotation, delegateName), sig.name), toList(args));
JCStatement body = useReturn ? maker.Return(delegateCall) : maker.Exec(delegateCall);
JCBlock bodyBlock = maker.Block(0, com.sun.tools.javac.util.List.of(body));
@@ -367,4 +382,22 @@ public class HandleDelegate extends JavacAnnotationHandler<Delegate> {
binding = types.erasure(binding);
return binding.toString();
}
+
+ private enum DelegateReceiver {
+ METHOD {
+ public JCExpression get(final JavacNode node, final Name name) {
+ com.sun.tools.javac.util.List<JCExpression> nilExprs = com.sun.tools.javac.util.List.nil();
+ final TreeMaker maker = node.getTreeMaker();
+ return maker.Apply(nilExprs, maker.Select(maker.Ident(node.toName("this")), name), nilExprs);
+ }
+ },
+ FIELD {
+ public JCExpression get(final JavacNode node, final Name name) {
+ final TreeMaker maker = node.getTreeMaker();
+ return maker.Select(maker.Ident(node.toName("this")), name);
+ }
+ };
+
+ public abstract JCExpression get(final JavacNode node, final Name name);
+ }
}
diff --git a/src/core/lombok/javac/handlers/HandleGetter.java b/src/core/lombok/javac/handlers/HandleGetter.java
index fe3b86a4..c9d67d7f 100644
--- a/src/core/lombok/javac/handlers/HandleGetter.java
+++ b/src/core/lombok/javac/handlers/HandleGetter.java
@@ -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)));
}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
index a721b468..538fb564 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/EclipsePatcher.java
@@ -123,9 +123,9 @@ public class EclipsePatcher extends Agent {
"org.eclipse.jdt.core.dom.MethodDeclaration"
))
.methodToWrap(new Hook("org.eclipse.jface.text.IDocument", "get", "java.lang.String", "int", "int"))
- .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "getRealMethodDeclarationSource", "java.lang.String", "java.lang.String", "org.eclipse.jdt.core.dom.MethodDeclaration"))
- .requestExtra(StackRequest.PARAM4)
- .build());
+ .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "getRealMethodDeclarationSource", "java.lang.String", "java.lang.String", "java.lang.Object", "org.eclipse.jdt.core.dom.MethodDeclaration"))
+ .requestExtra(StackRequest.THIS, StackRequest.PARAM4)
+ .transplant().build());
/* get real generated node in stead of a random one generated by the annotation */
sm.addScript(ScriptBuilder.replaceMethodCall()
@@ -133,21 +133,21 @@ public class EclipsePatcher extends Agent {
.target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ExtractInterfaceProcessor", "createMethodComments"))
.methodToReplace(new Hook("org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil", "getMethodDeclarationNode", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.IMethod", "org.eclipse.jdt.core.dom.CompilationUnit"))
.replacementMethod(new Hook("lombok.eclipse.agent.PatchFixes", "getRealMethodDeclarationNode", "org.eclipse.jdt.core.dom.MethodDeclaration", "org.eclipse.jdt.core.IMethod", "org.eclipse.jdt.core.dom.CompilationUnit"))
- .build());
+ .transplant().build());
/* Do not add @Override's for generated methods */
sm.addScript(ScriptBuilder.exitEarly()
.target(new MethodTarget("org.eclipse.jdt.core.dom.rewrite.ListRewrite", "insertFirst"))
.decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "isListRewriteOnGeneratedNode", "boolean", "org.eclipse.jdt.core.dom.rewrite.ListRewrite"))
.request(StackRequest.THIS)
- .build());
+ .transplant().build());
/* Do not add comments for generated methods */
sm.addScript(ScriptBuilder.exitEarly()
.target(new MethodTarget("org.eclipse.jdt.internal.corext.refactoring.structure.ExtractInterfaceProcessor", "createMethodComment"))
.decisionMethod(new Hook("lombok.eclipse.agent.PatchFixes", "isGenerated", "boolean", "org.eclipse.jdt.core.dom.ASTNode"))
.request(StackRequest.PARAM2)
- .build());
+ .transplant().build());
}
private static void patchAboutDialog(ScriptManager sm) {
@@ -395,14 +395,26 @@ public class EclipsePatcher extends Agent {
.wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlag", "void",
"org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.internal.compiler.ast.ASTNode"))
.transplant().build());
-
+
sm.addScript(ScriptBuilder.wrapReturnValue()
.target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToFieldDeclaration", "org.eclipse.jdt.core.dom.FieldDeclaration", "org.eclipse.jdt.internal.compiler.ast.FieldDeclaration"))
+/* Targets beneath are only patched because the resulting dom nodes should be marked if generated.
+ * However I couldn't find a usecase where these were actually used
+ */
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToType", "org.eclipse.jdt.core.dom.Type", "org.eclipse.jdt.internal.compiler.ast.NameReference"))
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertType", "org.eclipse.jdt.core.dom.Type", "org.eclipse.jdt.internal.compiler.ast.TypeReference"))
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToVariableDeclarationExpression", "org.eclipse.jdt.core.dom.VariableDeclarationExpression", "org.eclipse.jdt.internal.compiler.ast.LocalDeclaration"))
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToSingleVariableDeclaration", "org.eclipse.jdt.core.dom.SingleVariableDeclaration", "org.eclipse.jdt.internal.compiler.ast.LocalDeclaration"))
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToVariableDeclarationFragment", "org.eclipse.jdt.core.dom.VariableDeclarationFragment", "org.eclipse.jdt.internal.compiler.ast.FieldDeclaration"))
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToVar