From 91bb3455da2913c81745d2a7f7e5b42839964f58 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 21 Jul 2010 10:51:09 +0200 Subject: Added using .getX() instead of using .x in equals, hashCode, and toString. Also updated changelog as well as the docs. Also updated usage examples for @EqualsAndHashCode, @ToString, and @Data, which also contained some other minor issues (such as missing this. qualifiers). Still to do is to detect that getters don't exist _yet_ but will later due to @Getter or @Data. --- .../eclipse/handlers/EclipseHandlerUtil.java | 82 ++++++++++++++++++---- .../eclipse/handlers/HandleEqualsAndHashCode.java | 2 +- .../javac/handlers/HandleEqualsAndHashCode.java | 2 +- .../lombok/javac/handlers/JavacHandlerUtil.java | 57 ++++++++++++--- 4 files changed, 117 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java index 337ae3a8..29e44781 100644 --- a/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java +++ b/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java @@ -46,6 +46,7 @@ import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldReference; import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.ast.MarkerAnnotation; +import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; import org.eclipse.jdt.internal.compiler.ast.NameReference; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; @@ -98,34 +99,87 @@ public class EclipseHandlerUtil { } } + private static AbstractMethodDeclaration findGetter(EclipseNode field) { + TypeReference fieldType = ((FieldDeclaration)field.get()).type; + boolean isBoolean = nameEquals(fieldType.getTypeName(), "boolean") && fieldType.dimensions() == 0; + EclipseNode typeNode = field.up(); + for (String potentialGetterName : TransformationsUtil.toAllGetterNames(field.getName(), isBoolean)) { + switch (methodExists(potentialGetterName, typeNode, false)) { + case EXISTS_BY_LOMBOK: + case EXISTS_BY_USER: + for (EclipseNode potentialGetter : typeNode.down()) { + if (potentialGetter.getKind() != Kind.METHOD) continue; + AbstractMethodDeclaration method = (AbstractMethodDeclaration) potentialGetter.get(); + /** static getX() methods don't count. */ + if ((method.modifiers & ClassFileConstants.AccStatic) != 0) continue; + /** Nor do getters with a non-empty parameter list. */ + if (method.arguments != null && method.arguments.length > 0) continue; + return method; + } + } + } + + return null; + } + static TypeReference getFieldType(EclipseNode field, boolean useFieldsDirectly) { - return ((FieldDeclaration)field.get()).type; + AbstractMethodDeclaration getter = useFieldsDirectly ? null : findGetter(field); + if (!(getter instanceof MethodDeclaration)) { + return ((FieldDeclaration)field.get()).type; + } + + return ((MethodDeclaration)getter).returnType; } static Expression createFieldAccessor(EclipseNode field, boolean useFieldsDirectly, ASTNode source) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; - FieldReference thisX = new FieldReference(field.getName().toCharArray(), p); - Eclipse.setGeneratedBy(thisX, source); - thisX.receiver = new ThisReference(pS, pE); - Eclipse.setGeneratedBy(thisX.receiver, source); - return thisX; + + AbstractMethodDeclaration getter = useFieldsDirectly ? null : findGetter(field); + + if (getter == null) { + FieldReference thisX = new FieldReference(field.getName().toCharArray(), p); + Eclipse.setGeneratedBy(thisX, source); + thisX.receiver = new ThisReference(pS, pE); + Eclipse.setGeneratedBy(thisX.receiver, source); + return thisX; + } + + MessageSend call = new MessageSend(); + Eclipse.setGeneratedBy(call, source); + call.sourceStart = pS; call.sourceEnd = pE; + call.receiver = new ThisReference(pS, pE); + Eclipse.setGeneratedBy(call.receiver, source); + call.selector = getter.selector; + return call; } static Expression createFieldAccessor(EclipseNode field, boolean useFieldsDirectly, ASTNode source, char[] receiver) { int pS = source.sourceStart, pE = source.sourceEnd; long p = (long)pS << 32 | pE; - NameReference ref; + AbstractMethodDeclaration getter = useFieldsDirectly ? null : findGetter(field); - char[][] tokens = new char[2][]; - tokens[0] = receiver; - tokens[1] = field.getName().toCharArray(); - long[] poss = {p, p}; + if (getter == null) { + NameReference ref; + + char[][] tokens = new char[2][]; + tokens[0] = receiver; + tokens[1] = field.getName().toCharArray(); + long[] poss = {p, p}; + + ref = new QualifiedNameReference(tokens, poss, pS, pE); + Eclipse.setGeneratedBy(ref, source); + return ref; + } - ref = new QualifiedNameReference(tokens, poss, pS, pE); - Eclipse.setGeneratedBy(ref, source); - return ref; + MessageSend call = new MessageSend(); + Eclipse.setGeneratedBy(call, source); + call.sourceStart = pS; call.sourceEnd = pE; + call.receiver = new SingleNameReference(receiver, p); + Eclipse.setGeneratedBy(call.receiver, source); + call.selector = getter.selector; + return call; } /** diff --git a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java index b7c6cda6..2142618f 100644 --- a/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java +++ b/src/core/lombok/eclipse/handlers/HandleEqualsAndHashCode.java @@ -353,7 +353,7 @@ public class HandleEqualsAndHashCode implements EclipseAnnotationHandlernil(), hcMethod, List.of(fieldAccessor))); } else /* objects */ { /* this.fieldName == null ? 0 : this.fieldName.hashCode() */ - JCExpression hcCall = maker.Apply(List.nil(), maker.Select(fieldAccessor, typeNode.toName("hashCode")), + JCExpression hcCall = maker.Apply(List.nil(), maker.Select(createFieldAccessor(maker, fieldNode, useFieldsDirectly), typeNode.toName("hashCode")), List.nil()); JCExpression thisEqualsNull = maker.Binary(JCTree.EQ, fieldAccessor, maker.Literal(TypeTags.BOT, null)); intoResult = intoResult.append( diff --git a/src/core/lombok/javac/handlers/JavacHandlerUtil.java b/src/core/lombok/javac/handlers/JavacHandlerUtil.java index 84388c30..cb2697f1 100644 --- a/src/core/lombok/javac/handlers/JavacHandlerUtil.java +++ b/src/core/lombok/javac/handlers/JavacHandlerUtil.java @@ -41,6 +41,7 @@ import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCImport; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCStatement; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.util.List; @@ -269,15 +270,26 @@ public class JavacHandlerUtil { } } - /** - * Creates an expression that reads the field. Will either be {@code this.field} or {@code this.getField()} depending on whether or not there's a getter. - */ - static JCExpression createFieldAccessor(TreeMaker maker, JavacNode field, boolean useFieldsDirectly) { - return createFieldAccessor(maker, field, useFieldsDirectly, maker.Ident(field.toName("this"))); - } - - static JCExpression createFieldAccessor(TreeMaker maker, JavacNode field, boolean useFieldsDirectly, JCExpression receiver) { - return maker.Select(receiver, ((JCVariableDecl)field.get()).name); + private static JCMethodDecl findGetter(JavacNode field) { + JCVariableDecl decl = (JCVariableDecl)field.get(); + JavacNode typeNode = field.up(); + for (String potentialGetterName : toAllGetterNames(decl)) { + switch (methodExists(potentialGetterName, typeNode, false)) { + case EXISTS_BY_LOMBOK: + case EXISTS_BY_USER: + for (JavacNode potentialGetter : typeNode.down()) { + if (potentialGetter.getKind() != Kind.METHOD) continue; + JCMethodDecl method = (JCMethodDecl) potentialGetter.get(); + /** static getX() methods don't count. */ + if ((method.mods.flags & Flags.STATIC) != 0) continue; + /** Nor do getters with a non-empty parameter list. */ + if (method.params != null && method.params.size() > 0) continue; + return method; + } + } + } + + return null; } /** @@ -286,7 +298,32 @@ public class JavacHandlerUtil { * @see #createFieldAccessor(TreeMaker, JavacNode) */ static JCExpression getFieldType(JavacNode field, boolean useFieldsDirectly) { - return ((JCVariableDecl)field.get()).vartype; + JCMethodDecl getter = useFieldsDirectly ? null : findGetter(field); + + if (getter == null) { + return ((JCVariableDecl)field.get()).vartype; + } + + return getter.restype; + } + + /** + * Creates an expression that reads the field. Will either be {@code this.field} or {@code this.getField()} depending on whether or not there's a getter. + */ + static JCExpression createFieldAccessor(TreeMaker maker, JavacNode field, boolean useFieldsDirectly) { + return createFieldAccessor(maker, field, useFieldsDirectly, maker.Ident(field.toName("this"))); + } + + static JCExpression createFieldAccessor(TreeMaker maker, JavacNode field, boolean useFieldsDirectly, JCExpression receiver) { + JCMethodDecl getter = useFieldsDirectly ? null : findGetter(field); + + if (getter == null) { + return maker.Select(receiver, ((JCVariableDecl)field.get()).name); + } + + JCMethodInvocation call = maker.Apply(List.nil(), + maker.Select(receiver, getter.name), List.nil()); + return call; } /** -- cgit