diff options
author | Reinier Zwitserloot <reinier@tipit.to> | 2009-06-20 23:46:17 +0200 |
---|---|---|
committer | Reinier Zwitserloot <reinier@tipit.to> | 2009-06-21 00:10:58 +0200 |
commit | 255bd5907176cb5d2c4fb1cf6a9b48b14af0b4ba (patch) | |
tree | 347c4b1cf5b34b3975cc00e26a42c75ee1295b76 /src/lombok/eclipse/handlers/HandleData.java | |
parent | 2e8e43a12e21151ff470a2729373b4af4980d113 (diff) | |
download | lombok-255bd5907176cb5d2c4fb1cf6a9b48b14af0b4ba.tar.gz lombok-255bd5907176cb5d2c4fb1cf6a9b48b14af0b4ba.tar.bz2 lombok-255bd5907176cb5d2c4fb1cf6a9b48b14af0b4ba.zip |
Due to a java bug, constants in enums don't work, so instead the default access level for @Getter and @Setter have now just been hardcoded in GetterHandler and SetterHandler.
Added ability to look up the Node object for any given AST object on Node itself, as you don't usually have the AST object.
Added toString() method generating to @Data, and this required some fancy footwork in finding if we've already generated methods, and editing a generated method to fill in binding and type resolutions. HandleGetter and HandleSetter have been updated to use these features.
Exceptions caused by lombok handlers show up in the eclipse error log, but now, if they are related to a CompilationUnit, also as a problem (error) on the CUD - those error log entries are easy to miss!
Our ASTs can now be appended to. When you generate a new AST node, you should add it to the AST, obviously. Getter/Setter have been updated to use this.
Diffstat (limited to 'src/lombok/eclipse/handlers/HandleData.java')
-rw-r--r-- | src/lombok/eclipse/handlers/HandleData.java | 127 |
1 files changed, 119 insertions, 8 deletions
diff --git a/src/lombok/eclipse/handlers/HandleData.java b/src/lombok/eclipse/handlers/HandleData.java index 64540e95..6c77644f 100644 --- a/src/lombok/eclipse/handlers/HandleData.java +++ b/src/lombok/eclipse/handlers/HandleData.java @@ -1,20 +1,38 @@ package lombok.eclipse.handlers; +import static lombok.eclipse.handlers.PKG.*; + import java.util.ArrayList; +import java.util.Collection; import java.util.List; -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; -import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; -import org.mangosdk.spi.ProviderFor; - +import lombok.AccessLevel; import lombok.Data; import lombok.core.AnnotationValues; import lombok.core.AST.Kind; +import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseAST.Node; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.BinaryExpression; +import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Expression; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.OperatorIds; +import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; +import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; +import org.eclipse.jdt.internal.compiler.ast.Statement; +import org.eclipse.jdt.internal.compiler.ast.StringLiteral; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; +import org.eclipse.jdt.internal.compiler.lookup.MethodScope; +import org.mangosdk.spi.ProviderFor; + @ProviderFor(EclipseAnnotationHandler.class) public class HandleData implements EclipseAnnotationHandler<Data> { @Override public boolean handle(AnnotationValues<Data> annotation, Annotation ast, Node annotationNode) { @@ -32,18 +50,111 @@ public class HandleData implements EclipseAnnotationHandler<Data> { } List<Node> nodesForEquality = new ArrayList<Node>(); + List<Node> nodesForConstructorAndToString = new ArrayList<Node>(); for ( Node child : typeNode.down() ) { if ( child.getKind() != Kind.FIELD ) continue; FieldDeclaration fieldDecl = (FieldDeclaration) child.get(); //Skip static fields. if ( (fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0 ) continue; if ( (fieldDecl.modifiers & ClassFileConstants.AccTransient) == 0 ) nodesForEquality.add(child); + nodesForConstructorAndToString.add(child); new HandleGetter().generateGetterForField(child, annotationNode.get()); if ( (fieldDecl.modifiers & ClassFileConstants.AccFinal) == 0 ) new HandleSetter().generateSetterForField(child, annotationNode.get()); } - //TODO generate constructor, hashCode, equals, toString. - return true; + switch ( methodExists("toString", typeNode) ) { + case NOT_EXISTS: + MethodDeclaration toString = createToString(typeNode, nodesForConstructorAndToString, ast); + injectMethod(typeNode, toString); + break; + case EXISTS_BY_LOMBOK: + injectScopeIntoToString((MethodDeclaration) getExistingLombokMethod("toString", typeNode).get(), typeDecl); + } + + //TODO generate constructor, hashCode, equals. + return false; + } + + private void injectScopeIntoToString(MethodDeclaration method, TypeDeclaration typeDecl) { + if ( typeDecl.scope != null ) { + method.scope = new MethodScope(typeDecl.scope, method, false); + method.returnType.resolvedType = typeDecl.scope.getJavaLangString(); + method.binding = new MethodBinding(method.modifiers, + method.selector, typeDecl.scope.getJavaLangString(), null, null, typeDecl.binding); + } + } + + private MethodDeclaration createToString(Node type, Collection<Node> fields, ASTNode pos) { + char[] rawTypeName = ((TypeDeclaration)type.get()).name; + String typeName = rawTypeName == null ? "" : new String(rawTypeName); + char[] prefix = (typeName + "(").toCharArray(); + char[] suffix = ")".toCharArray(); + char[] infix = ", ".toCharArray(); + long p = (long)pos.sourceStart << 32 | pos.sourceEnd; + final int PLUS = OperatorIds.PLUS; + + boolean first = true; + Expression current = new StringLiteral(prefix, 0, 0, 0); + for ( Node field : fields ) { + char[] fName = ((FieldDeclaration)field.get()).name; + if ( fName == null ) continue; + if ( !first ) { + current = new BinaryExpression(current, new StringLiteral(infix, 0, 0, 0), PLUS); + } + else first = false; + current = new BinaryExpression(current, new SingleNameReference(fName, p), PLUS); + } + current = new BinaryExpression(current, new StringLiteral(suffix, 0, 0, 0), PLUS); + + ReturnStatement returnStatement = new ReturnStatement(current, (int)(p >> 32), (int)p); + + MethodDeclaration method = new MethodDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult); + method.modifiers = PKG.toModifier(AccessLevel.PUBLIC); + method.returnType = Eclipse.TYPEREF_JAVA_LANG_STRING; + method.annotations = null; + method.arguments = null; + method.selector = "toString".toCharArray(); + method.binding = null; + method.thrownExceptions = null; + method.typeParameters = null; + injectScopeIntoToString(method, (TypeDeclaration) type.get()); + method.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + method.bodyStart = method.declarationSourceStart = method.sourceStart = pos.sourceStart; + method.bodyEnd = method.declarationSourceEnd = method.sourceEnd = pos.sourceEnd; + method.statements = new Statement[] { returnStatement }; + return method; + } + + private MethodDeclaration createEquals(Collection<Node> fields) { + return null; + } + + private ConstructorDeclaration createConstructor(Collection<Node> fields) { + //If using an of() constructor, make private. + //method params + //on loop: Assignment(FieldReference(ThisReference, "x"), SingleNameReference("x")) + return null; + } + + private MethodDeclaration createStaticConstructor(Collection<Node> fields) { + //Return(AllocationExpression(SingleTypeReference("Bar"), namesOfFields); + return null; + } + + private MethodDeclaration createHashCode(Collection<Node> fields) { + //booleans: conditionalexpression that bounces between 1231 and 1237. + //longs: (int) (lng ^ (lng >>> 32)); + //doubles and floats: Double.doubleToLongBits, then as long. + + //local final var PRIME = IntLiteral(primeNumber) + //local final var RESULT = IntLiteral(1) + + // Assignment("RESULT", BinaryExpression("+", BinaryExpression("*", "PRIME", "RESULT"), "name") + + // add = ConditionalExpression(EqualExpression("name", NullLiteral), IntLiteral(0), MessageSend("name", "hashCode()")) + // Assignment("RESULT", BinaryExpression("+", BinaryExpression("*", "PRIME", "RESULT"), add); + + return null; } } |