aboutsummaryrefslogtreecommitdiff
path: root/src/eclipseAgent
diff options
context:
space:
mode:
Diffstat (limited to 'src/eclipseAgent')
-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
3 files changed, 269 insertions, 76 deletions
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", "convertToVariableDeclarationFragment", "org.eclipse.jdt.core.dom.VariableDeclarationFragment", "org.eclipse.jdt.internal.compiler.ast.LocalDeclaration"))
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convertToVariableDeclarationStatement", "org.eclipse.jdt.core.dom.VariableDeclarationStatement", "org.eclipse.jdt.internal.compiler.ast.LocalDeclaration"))
+/* Targets above are only patched because the resulting dom nodes should be marked if generated. */
.request(StackRequest.PARAM1, StackRequest.RETURN_VALUE)
.wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlag", "void",
"org.eclipse.jdt.core.dom.ASTNode", "org.eclipse.jdt.internal.compiler.ast.ASTNode"))
.transplant().build());
+ /* Set generated flag for SimpleNames */
sm.addScript(ScriptBuilder.wrapMethodCall()
.target(new TargetMatcher() {
@Override public boolean matches(String classSpec, String methodName, String descriptor) {
@@ -420,16 +432,49 @@ public class EclipsePatcher extends Agent {
}
}).methodToWrap(new Hook("org.eclipse.jdt.core.dom.SimpleName", "<init>", "void", "org.eclipse.jdt.core.dom.AST"))
.requestExtra(StackRequest.PARAM1)
- .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForSimpleName", "void",
- "org.eclipse.jdt.core.dom.SimpleName", "java.lang.Object"))
+ .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void",
+ "org.eclipse.jdt.core.dom.Name", "java.lang.Object"))
.transplant().build());
sm.addScript(ScriptBuilder.wrapMethodCall()
.target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "convert", "org.eclipse.jdt.core.dom.ASTNode", "boolean", "org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration"))
.methodToWrap(new Hook("org.eclipse.jdt.core.dom.SimpleName", "<init>", "void", "org.eclipse.jdt.core.dom.AST"))
.requestExtra(StackRequest.PARAM2)
- .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForSimpleName", "void",
- "org.eclipse.jdt.core.dom.SimpleName", "java.lang.Object"))
+ .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void",
+ "org.eclipse.jdt.core.dom.Name", "java.lang.Object"))
+ .transplant().build());
+
+ /* Set generated flag for QualifiedNames */
+ sm.addScript(ScriptBuilder.wrapMethodCall()
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "setQualifiedNameNameAndSourceRanges", "org.eclipse.jdt.core.dom.QualifiedName", "char[][]", "long[]", "int", "org.eclipse.jdt.internal.compiler.ast.ASTNode"))
+ .methodToWrap(new Hook("org.eclipse.jdt.core.dom.SimpleName", "<init>", "void", "org.eclipse.jdt.core.dom.AST"))
+ .requestExtra(StackRequest.PARAM4)
+ .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void",
+ "org.eclipse.jdt.core.dom.Name", "java.lang.Object"))
+ .transplant().build());
+
+ sm.addScript(ScriptBuilder.wrapMethodCall()
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "setQualifiedNameNameAndSourceRanges", "org.eclipse.jdt.core.dom.QualifiedName", "char[][]", "long[]", "int", "org.eclipse.jdt.internal.compiler.ast.ASTNode"))
+ .methodToWrap(new Hook("org.eclipse.jdt.core.dom.QualifiedName", "<init>", "void", "org.eclipse.jdt.core.dom.AST"))
+ .requestExtra(StackRequest.PARAM4)
+ .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void",
+ "org.eclipse.jdt.core.dom.Name", "java.lang.Object"))
+ .transplant().build());
+
+ sm.addScript(ScriptBuilder.wrapMethodCall()
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "setQualifiedNameNameAndSourceRanges", "org.eclipse.jdt.core.dom.QualifiedName", "char[][]", "long[]", "org.eclipse.jdt.internal.compiler.ast.ASTNode"))
+ .methodToWrap(new Hook("org.eclipse.jdt.core.dom.SimpleName", "<init>", "void", "org.eclipse.jdt.core.dom.AST"))
+ .requestExtra(StackRequest.PARAM3)
+ .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void",
+ "org.eclipse.jdt.core.dom.Name", "java.lang.Object"))
+ .transplant().build());
+
+ sm.addScript(ScriptBuilder.wrapMethodCall()
+ .target(new MethodTarget("org.eclipse.jdt.core.dom.ASTConverter", "setQualifiedNameNameAndSourceRanges", "org.eclipse.jdt.core.dom.QualifiedName", "char[][]", "long[]", "org.eclipse.jdt.internal.compiler.ast.ASTNode"))
+ .methodToWrap(new Hook("org.eclipse.jdt.core.dom.QualifiedName", "<init>", "void", "org.eclipse.jdt.core.dom.AST"))
+ .requestExtra(StackRequest.PARAM3)
+ .wrapMethod(new Hook("lombok.eclipse.agent.PatchFixes", "setIsGeneratedFlagForName", "void",
+ "org.eclipse.jdt.core.dom.Name", "java.lang.Object"))
.transplant().build());
}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java
index affcd4f2..87335b4e 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchDelegate.java
@@ -103,25 +103,25 @@ public class PatchDelegate {
return new String(decl.name);
}
- private static boolean hasDelegateMarkedFields(TypeDeclaration decl) {
+ private static boolean hasDelegateMarkedFieldsOrMethods(TypeDeclaration decl) {
if (decl.fields != null) for (FieldDeclaration field : decl.fields) {
if (field.annotations == null) continue;
for (Annotation ann : field.annotations) {
- if (ann.type == null) continue;
- TypeBinding tb = ann.type.resolveType(decl.initializerScope);
- if (tb == null) continue;
- if (!charArrayEquals("lombok", tb.qualifiedPackageName())) continue;
- if (!charArrayEquals("Delegate", tb.qualifiedSourceName())) continue;
- return true;
+ if (isDelegate(ann, decl)) return true;
+ }
+ }
+ if (decl.methods != null) for (AbstractMethodDeclaration method : decl.methods) {
+ if (method.annotations == null) continue;
+ for (Annotation ann : method.annotations) {
+ if (isDelegate(ann, decl)) return true;
}
}
-
return false;
}
public static boolean handleDelegateForType(ClassScope scope) {
if (TransformEclipseAST.disableLombok) return false;
- if (!hasDelegateMarkedFields(scope.referenceContext)) return false;
+ if (!hasDelegateMarkedFieldsOrMethods(scope.referenceContext)) return false;
List<ClassScopeEntry> stack = visited.get();
StringBuilder corrupted = null;
@@ -145,16 +145,23 @@ public class PatchDelegate {
stack.add(entry);
try {
- List<BindingTuple> methodsToDelegate = new ArrayList<BindingTuple>();
TypeDeclaration decl = scope.referenceContext;
if (decl != null) {
CompilationUnitDeclaration cud = scope.compilationUnitScope().referenceContext;
EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
- fillMethodBindings(cud, scope, methodsToDelegate);
+ List<BindingTuple> methodsToDelegate = new ArrayList<BindingTuple>();
+ fillMethodBindingsForFields(cud, scope, methodsToDelegate);
if (entry.corruptedPath != null) {
eclipseAst.get(scope.referenceContext).addError("No @Delegate methods created because there's a loop: " + entry.corruptedPath);
} else {
- generateDelegateMethods(eclipseAst.get(decl), methodsToDelegate);
+ generateDelegateMethods(eclipseAst.get(decl), methodsToDelegate, DelegateReceiver.FIELD);
+ }
+ methodsToDelegate.clear();
+ fillMethodBindingsForMethods(cud, scope, methodsToDelegate);
+ if (entry.corruptedPath != null) {
+ eclipseAst.get(scope.referenceContext).addError("No @Delegate methods created because there's a loop: " + entry.corruptedPath);
+ } else {
+ generateDelegateMethods(eclipseAst.get(decl), methodsToDelegate, DelegateReceiver.METHOD);
}
}
} finally {
@@ -181,44 +188,29 @@ public class PatchDelegate {
private static Map<ASTNode, Object> alreadyApplied = new WeakHashMap<ASTNode, Object>();
private static final Object MARKER = new Object();
- private static void fillMethodBindings(CompilationUnitDeclaration cud, ClassScope scope, List<BindingTuple> methodsToDelegate) {
+ 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;
if (decl.fields != null) for (FieldDeclaration field : decl.fields) {
if (field.annotations == null) continue;
for (Annotation ann : field.annotations) {
- if (ann.type == null) continue;
- TypeBinding tb = ann.type.resolveType(decl.initializerScope);
- if (!charArrayEquals("lombok", tb.qualifiedPackageName())) continue;
- if (!charArrayEquals("Delegate", tb.qualifiedSourceName())) continue;
+ if (!isDelegate(ann, decl)) continue;
if (alreadyApplied.put(ann, MARKER) == MARKER) continue;
- List<ClassLiteralAccess> rawTypes = new ArrayList<ClassLiteralAccess>();
- List<ClassLiteralAccess> excludedRawTypes = new ArrayList<ClassLiteralAccess>();
- for (MemberValuePair pair : ann.memberValuePairs()) {
- if (charArrayEquals("types", pair.name)) {
- if (pair.value instanceof ArrayInitializer) {
- for (Expression expr : ((ArrayInitializer)pair.value).expressions) {
- if (expr instanceof ClassLiteralAccess) rawTypes.add((ClassLiteralAccess) expr);
- }
- }
- if (pair.value instanceof ClassLiteralAccess) {
- rawTypes.add((ClassLiteralAccess) pair.value);
- }
- }
- if (charArrayEquals("excludes", pair.name)) {
- if (pair.value instanceof ArrayInitializer) {
- for (Expression expr : ((ArrayInitializer)pair.value).expressions) {
- if (expr instanceof ClassLiteralAccess) excludedRawTypes.add((ClassLiteralAccess) expr);
- }
- }
- if (pair.value instanceof ClassLiteralAccess) {
- excludedRawTypes.add((ClassLiteralAccess) pair.value);
- }
- }
+ if ((field.modifiers & ClassFileConstants.AccStatic) != 0) {
+ EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
+ eclipseAst.get(ann).addError(LEGALITY_OF_DELEGATE);
+ break;
}
+ List<ClassLiteralAccess> rawTypes = rawTypes(ann, "types");
+ List<ClassLiteralAccess> excludedRawTypes = rawTypes(ann, "excludes");
+
List<BindingTuple> methodsToExclude = new ArrayList<BindingTuple>();
for (ClassLiteralAccess cla : excludedRawTypes) {
addAllMethodBindings(methodsToExclude, cla.type.resolveType(decl.initializerScope), new HashSet<String>(), field.name, ann);
@@ -251,6 +243,96 @@ public class PatchDelegate {
}
}
+ private static final String LEGALITY_OF_DELEGATE = "@Delegate is legal only on instance fields or no-argument instance methods.";
+
+ private static void fillMethodBindingsForMethods(CompilationUnitDeclaration cud, ClassScope scope, List<BindingTuple> methodsToDelegate) {
+ TypeDeclaration decl = scope.referenceContext;
+ if (decl == null) return;
+
+ if (decl.methods != null) for (AbstractMethodDeclaration methodDecl : decl.methods) {
+ if (methodDecl.annotations == null) continue;
+ for (Annotation ann : methodDecl.annotations) {
+ if (!isDelegate(ann, decl)) continue;
+ if (alreadyApplied.put(ann, MARKER) == MARKER) continue;
+ if (!(methodDecl instanceof MethodDeclaration)) {
+ EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
+ eclipseAst.get(ann).addError(LEGALITY_OF_DELEGATE);
+ break;
+ }
+ if (methodDecl.arguments != null) {
+ EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
+ eclipseAst.get(ann).addError(LEGALITY_OF_DELEGATE);
+ break;
+ }
+ if ((methodDecl.modifiers & ClassFileConstants.AccStatic) != 0) {
+ EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
+ eclipseAst.get(ann).addError(LEGALITY_OF_DELEGATE);
+ break;
+ }
+ MethodDeclaration method = (MethodDeclaration) methodDecl;
+
+ List<ClassLiteralAccess> rawTypes = rawTypes(ann, "types");
+ List<ClassLiteralAccess> excludedRawTypes = rawTypes(ann, "excludes");
+
+ List<BindingTuple> methodsToExclude = new ArrayList<BindingTuple>();
+ for (ClassLiteralAccess cla : excludedRawTypes) {
+ addAllMethodBindings(methodsToExclude, cla.type.resolveType(decl.initializerScope), new HashSet<String>(), method.selector, ann);
+ }
+
+ Set<String> banList = new HashSet<String>();
+ for (BindingTuple excluded : methodsToExclude) banList.add(printSig(excluded.parameterized));
+
+ List<BindingTuple> methodsToDelegateForThisAnn = new ArrayList<BindingTuple>();
+
+ if (rawTypes.isEmpty()) {
+ if (method.returnType == null) continue;
+ addAllMethodBindings(methodsToDelegateForThisAnn, method.returnType.resolveType(decl.initializerScope), banList, method.selector, ann);
+ } else {
+ for (ClassLiteralAccess cla : rawTypes) {
+ addAllMethodBindings(methodsToDelegateForThisAnn, cla.type.resolveType(decl.initializerScope), banList, method.selector, ann);
+ }
+ }
+
+ // Not doing this right now because of problems - see commented-out-method for info.
+ // removeExistingMethods(methodsToDelegate, decl, scope);
+
+ String dupe = containsDuplicates(methodsToDelegateForThisAnn);
+ if (dupe != null) {
+ EclipseAST eclipseAst = TransformEclipseAST.getAST(cud, true);
+ eclipseAst.get(ann).addError("The method '" + dupe + "' is being delegated by more than one specified type.");
+ } else {
+ methodsToDelegate.addAll(methodsToDelegateForThisAnn);
+ }
+ }
+ }
+ }
+
+ private static boolean isDelegate(Annotation ann, TypeDeclaration decl) {
+ if (ann.type == null) return false;
+ TypeBinding tb = ann.type.resolveType(decl.initializerScope);
+ if (tb == null) return false;
+ if (!charArrayEquals("lombok", tb.qualifiedPackageName())) return false;
+ if (!charArrayEquals("Delegate", tb.qualifiedSourceName())) return false;
+ return true;
+ }
+
+ private static List<ClassLiteralAccess> rawTypes(Annotation ann, String name) {
+ List<ClassLiteralAccess> rawTypes = new ArrayList<ClassLiteralAccess>();
+ for (MemberValuePair pair : ann.memberValuePairs()) {
+ if (charArrayEquals(name, pair.name)) {
+ if (pair.value instanceof ArrayInitializer) {
+ for (Expression expr : ((ArrayInitializer)pair.value).expressions) {
+ if (expr instanceof ClassLiteralAccess) rawTypes.add((ClassLiteralAccess) expr);
+ }
+ }
+ if (pair.value instanceof ClassLiteralAccess) {
+ rawTypes.add((ClassLiteralAccess) pair.value);
+ }
+ }
+ }
+ return rawTypes;
+ }
+
/*
* We may someday finish this method. Steps to be completed:
*
@@ -321,11 +403,11 @@ public class PatchDelegate {
// }
// }
- private static void generateDelegateMethods(EclipseNode typeNode, List<BindingTuple> methods) {
+ 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);
+ 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);
@@ -473,7 +555,7 @@ public class PatchDelegate {
}
}
- private static MethodDeclaration createDelegateMethod(char[] name, EclipseNode typeNode, BindingTuple pair, CompilationResult compilationResult, EclipseNode annNode) {
+ private static MethodDeclaration createDelegateMethod(char[] name, EclipseNode typeNode, BindingTuple pair, CompilationResult compilationResult, EclipseNode annNode, DelegateReceiver delegateReceiver) {
/* public <T, U, ...> ReturnType methodName(ParamType1 name1, ParamType2 name2, ...) throws T1, T2, ... {
* (return) delegate.<T, U>methodName(name1, name2);
* }
@@ -514,11 +596,7 @@ public class PatchDelegate {
call.sourceStart = pS; call.sourceEnd = pE;
call.nameSourcePosition = pos(source);
setGeneratedBy(call, source);
- FieldReference fieldRef = new FieldReference(name, pos(source));
- fieldRef.receiver = new ThisReference(pS, pE);
- setGeneratedBy(fieldRef, source);
- setGeneratedBy(fieldRef.receiver, source);
- call.receiver = fieldRef;
+ call.receiver = delegateReceiver.get(source, name);
call.selector = binding.selector;
if (binding.typeVariables != null && binding.typeVariables.length > 0) {
@@ -742,7 +820,31 @@ public class PatchDelegate {
if (s.length() != c.length) return false;
for (int i = 0; i < s.length(); i++) if (s.charAt(i) != c[i]) return false;
return true;
+ }
+
+ private enum DelegateReceiver {
+ METHOD {
+ public Expression get(final ASTNode source, char[] name) {
+ MessageSend call = new MessageSend();
+ call.sourceStart = source.sourceStart; call.sourceEnd = source.sourceEnd;
+ call.nameSourcePosition = pos(source);
+ setGeneratedBy(call, source);
+ call.selector = name;
+ call.receiver = new ThisReference(source.sourceStart, source.sourceEnd);
+ setGeneratedBy(call.receiver, source);
+ return call;
+ }
+ },
+ FIELD {
+ public Expression get(final ASTNode source, char[] name) {
+ FieldReference fieldRef = new FieldReference(name, pos(source));
+ setGeneratedBy(fieldRef, source);
+ fieldRef.receiver = new ThisReference(source.sourceStart, source.sourceEnd);
+ setGeneratedBy(fieldRef.receiver, source);
+ return fieldRef;
+ }
+ };
-
+ public abstract Expression get(final ASTNode source, char[] name);
}
}
diff --git a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java b/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java
index 53d60bde..1da96256 100644
--- a/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java
+++ b/src/eclipseAgent/lombok/eclipse/agent/PatchFixes.java
@@ -19,7 +19,6 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-
package lombok.eclipse.agent;
import java.io.BufferedOutputStream;
@@ -91,17 +90,23 @@ public class PatchFixes {
return list;
}
- /* Very practical implementation, but works for getter and setter even with type parameters */
- public static java.lang.String getRealMethodDeclarationSource(java.lang.String original, org.eclipse.jdt.core.dom.MethodDeclaration declaration) {
+ public static java.lang.String getRealMethodDeclarationSource(java.lang.String original, Object processor, org.eclipse.jdt.core.dom.MethodDeclaration declaration) throws Exception {
if (!isGenerated(declaration)) return original;
- StringBuilder signature = new StringBuilder();
+ List<org.eclipse.jdt.core.dom.Annotation> annotations = new ArrayList<org.eclipse.jdt.core.dom.Annotation>();
+ for (Object modifier : declaration.modifiers()) {
+ if (modifier instanceof org.eclipse.jdt.core.dom.Annotation) {
+ org.eclipse.jdt.core.dom.Annotation annotation = (org.eclipse.jdt.core.dom.Annotation)modifier;
+ String qualifiedAnnotationName = annotation.resolveTypeBinding().getQualifiedName();
+ if (!"java.lang.Override".equals(qualifiedAnnotationName) && !"java.lang.SuppressWarnings".equals(qualifiedAnnotationName)) annotations.add(annotation);
+ }
+ }
- // We should get these from the refactor action
- boolean needsPublic = true, needsAbstract = true;
+ StringBuilder signature = new StringBuilder();
+ addAnnotations(annotations, signature);
- if (needsPublic) signature.append("public ");
- if (needsAbstract) signature.append("abstract ");
+ if ((Boolean)processor.getClass().getDeclaredField("fPublic").get(processor)) signature.append("public ");
+ if ((Boolean)processor.getClass().getDeclaredField("fAbstract").get(processor)) signature.append("abstract ");
signature
.append(declaration.getReturnType2().toString())
@@ -112,9 +117,7 @@ public class PatchFixes {
for (Object parameter : declaration.parameters()) {
if (!first) signature.append(", ");
first = false;
- // The annotations are still missing
- // Note: what happens to imports for the annotations?
- // I assume they have been taken care of by the default extraction system
+ // We should also add the annotations of the parameters
signature.append(parameter);
}
@@ -122,6 +125,47 @@ public class PatchFixes {
return signature.toString();
}
+ // part of getRealMethodDeclarationSource(...)
+ public static void addAnnotations(List<org.eclipse.jdt.core.dom.Annotation> annotations, StringBuilder signature) {
+ /*
+ * We SHOULD be able to handle the following cases:
+ * @Override
+ * @Override()
+ * @SuppressWarnings("all")
+ * @SuppressWarnings({"all", "unused"})
+ * @SuppressWarnings(value = "all")
+ * @SuppressWarnings(value = {"all", "unused"})
+ * @EqualsAndHashCode(callSuper=true, of="id")
+ *
+ * Currently, we only seem to correctly support:
+ * @Override
+ * @Override() N.B. We lose the parentheses here, since there are no values. No big deal.
+ * @SuppressWarnings("all")
+ */
+ for (org.eclipse.jdt.core.dom.Annotation annotation : annotations) {
+ List<String> values = new ArrayList<String>();
+ if (annotation.isSingleMemberAnnotation()) {
+ org.eclipse.jdt.core.dom.SingleMemberAnnotation smAnn = (org.eclipse.jdt.core.dom.SingleMemberAnnotation) annotation;
+ values.add(smAnn.getValue().toString());
+ } else if (annotation.isNormalAnnotation()) {
+ org.eclipse.jdt.core.dom.NormalAnnotation normalAnn = (org.eclipse.jdt.core.dom.NormalAnnotation) annotation;
+ for (Object value : normalAnn.values()) values.add(value.toString());
+ }
+
+ signature.append("@").append(annotation.resolveTypeBinding().getQualifiedName());
+ if (!values.isEmpty()) {
+ signature.append("(");
+ boolean first = true;
+ for (String string : values) {
+ if (!first) signature.append(", ");
+ first = false;
+ signature.append('"').append(string).append('"');
+ }
+ signature.append(")");
+ }
+ signature.append(" ");
+ }
+ }
public static org.eclipse.jdt.core.dom.MethodDeclaration getRealMethodDeclarationNode(org.eclipse.jdt.core.IMethod sourceMethod, org.eclipse.jdt.core.dom.CompilationUnit cuUnit) throws JavaModelException {
MethodDeclaration methodDeclarationNode = ASTNodeSearchUtil.getMethodDeclarationNode(sourceMethod, cuUnit);
@@ -154,7 +198,8 @@ public class PatchFixes {
return methodDeclarationNode;
}
- private static org.eclipse.jdt.core.dom.AbstractTypeDeclaration findTypeDeclaration(IType searchType, List<?> nodes) {
+ // part of getRealMethodDeclarationNode
+ public static org.eclipse.jdt.core.dom.AbstractTypeDeclaration findTypeDeclaration(IType searchType, List<?> nodes) {
for (Object object : nodes) {
if (object instanceof org.eclipse.jdt.core.dom.AbstractTypeDeclaration) {
org.eclipse.jdt.core.dom.AbstractTypeDeclaration typeDeclaration = (org.eclipse.jdt.core.dom.AbstractTypeDeclaration) object;
@@ -188,7 +233,8 @@ public class PatchFixes {
}
public static int fixRetrieveRightBraceOrSemiColonPosition(int original, int end) {
- return original == -1 ? end : original;
+// return original;
+ return original == -1 ? end : original; // Need to fix: see issue 325.
}
public static final int ALREADY_PROCESSED_FLAG = 0x800000; //Bit 24
@@ -212,7 +258,7 @@ public class PatchFixes {
}
}
- public static void setIsGeneratedFlagForSimpleName(SimpleName name, Object internalNode) throws Exception {
+ public static void setIsGeneratedFlagForName(org.eclipse.jdt.core.dom.Name name, Object internalNode) throws Exception {
if (internalNode instanceof org.eclipse.jdt.internal.compiler.ast.ASTNode) {
if (internalNode.getClass().getField("$generatedBy").get(internalNode) != null) {
name.getClass().getField("$isGenerated").set(name, true);
@@ -258,9 +304,9 @@ public class PatchFixes {
public static IMethod[] removeGeneratedMethods(IMethod[] methods) throws Exception {
List<IMethod> result = new ArrayList<IMethod>();
for (IMethod m : methods) {
- if (m.getNameRange().getLength() > 0) result.add(m);
+ if (m.getNameRange().getLength() > 0 && !m.getNameRange().equals(m.getSourceRange())) result.add(m);
}
- return result.size() == methods.length ? methods : result.toArray(new IMethod[0]);
+ return result.size() == methods.length ? methods : result.toArray(new IMethod[result.size()]);
}
public static SimpleName[] removeGeneratedSimpleNames(SimpleName[] in) throws Exception {