diff options
Diffstat (limited to 'src/lombok')
-rw-r--r-- | src/lombok/eclipse/handlers/HandleData.java | 123 | ||||
-rw-r--r-- | src/lombok/eclipse/handlers/PKG.java | 62 |
2 files changed, 172 insertions, 13 deletions
diff --git a/src/lombok/eclipse/handlers/HandleData.java b/src/lombok/eclipse/handlers/HandleData.java index 6c77644f..b4bba7d7 100644 --- a/src/lombok/eclipse/handlers/HandleData.java +++ b/src/lombok/eclipse/handlers/HandleData.java @@ -15,27 +15,36 @@ import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseAST.Node; import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.AllocationExpression; import org.eclipse.jdt.internal.compiler.ast.Annotation; +import org.eclipse.jdt.internal.compiler.ast.Argument; +import org.eclipse.jdt.internal.compiler.ast.Assignment; 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.ExplicitConstructorCall; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.FieldReference; 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.SingleTypeReference; import org.eclipse.jdt.internal.compiler.ast.Statement; import org.eclipse.jdt.internal.compiler.ast.StringLiteral; +import org.eclipse.jdt.internal.compiler.ast.ThisReference; 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.eclipse.jdt.internal.compiler.lookup.TypeBinding; 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) { + Data ann = annotation.getInstance(); Node typeNode = annotationNode.up(); TypeDeclaration typeDecl = null; @@ -72,7 +81,29 @@ public class HandleData implements EclipseAnnotationHandler<Data> { injectScopeIntoToString((MethodDeclaration) getExistingLombokMethod("toString", typeNode).get(), typeDecl); } - //TODO generate constructor, hashCode, equals. + switch ( constructorExists(typeNode) ) { + case NOT_EXISTS: + ConstructorDeclaration constructor = createConstructor( + ann.staticConstructor().isEmpty(), typeNode, nodesForConstructorAndToString, ast); + injectMethod(typeNode, constructor); + break; + } + + if ( !ann.staticConstructor().isEmpty() ) { + switch ( methodExists("of", typeNode) ) { + case NOT_EXISTS: + MethodDeclaration staticConstructor = createStaticConstructor( + ann.staticConstructor(), typeNode, nodesForConstructorAndToString, ast); + injectMethod(typeNode, staticConstructor); + break; + case EXISTS_BY_LOMBOK: + injectScopeIntoStaticConstructor((MethodDeclaration) getExistingLombokMethod( + ann.staticConstructor(), typeNode).get(), + nodesForConstructorAndToString, typeDecl); + } + } + + //TODO generate hashCode, equals. return false; } @@ -126,22 +157,96 @@ public class HandleData implements EclipseAnnotationHandler<Data> { return method; } - private MethodDeclaration createEquals(Collection<Node> fields) { - return null; + private ConstructorDeclaration createConstructor(boolean isPublic, Node type, Collection<Node> fields, ASTNode pos) { + long p = (long)pos.sourceStart << 32 | pos.sourceEnd; + + ConstructorDeclaration constructor = new ConstructorDeclaration( + ((CompilationUnitDeclaration) type.top().get()).compilationResult); + + constructor.modifiers = PKG.toModifier(isPublic ? AccessLevel.PUBLIC : AccessLevel.PRIVATE); + constructor.annotations = null; + constructor.selector = ((TypeDeclaration)type.get()).name; + constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + constructor.thrownExceptions = null; + constructor.typeParameters = null; + constructor.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = pos.sourceStart; + constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = pos.sourceEnd; + constructor.arguments = null; + + List<Argument> args = new ArrayList<Argument>(); + List<Statement> assigns = new ArrayList<Statement>(); + + for ( Node fieldNode : fields ) { + FieldDeclaration field = (FieldDeclaration) fieldNode.get(); + FieldReference thisX = new FieldReference(("this." + new String(field.name)).toCharArray(), p); + thisX.receiver = new ThisReference((int)(p >> 32), (int)p); + thisX.token = field.name; + assigns.add(new Assignment(thisX, new SingleNameReference(field.name, p), (int)p)); + long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd; + args.add(new Argument(field.name, fieldPos, field.type, 0)); + } + + constructor.statements = assigns.toArray(new Statement[assigns.size()]); + constructor.arguments = args.toArray(new Argument[args.size()]); + return constructor; } - private ConstructorDeclaration createConstructor(Collection<Node> fields) { + private void injectScopeIntoStaticConstructor(MethodDeclaration constructor, Collection<Node> fields, TypeDeclaration typeDecl) { + if ( typeDecl.scope != null ) { + constructor.scope = new MethodScope(typeDecl.scope, constructor, false); +// constructor.binding = new MethodBinding(constructor.modifiers, +// constructor.selector, null, null, null, typeDecl.binding); + constructor.returnType.resolvedType = typeDecl.binding; +// TypeBinding[] bindings = new TypeBinding[fields.size()]; +// int idx = 0; +// for ( Node field : fields ) bindings[idx++] = ((FieldDeclaration)field.get()).type.resolvedType; +// constructor.binding.parameters = bindings; + } + } + + private MethodDeclaration createStaticConstructor(String name, Node type, Collection<Node> fields, ASTNode pos) { + long p = (long)pos.sourceStart << 32 | pos.sourceEnd; + + MethodDeclaration constructor = new MethodDeclaration( + ((CompilationUnitDeclaration) type.top().get()).compilationResult); + + constructor.modifiers = PKG.toModifier(AccessLevel.PUBLIC); + constructor.returnType = new SingleTypeReference(((TypeDeclaration)type.get()).name, p); + constructor.annotations = null; + constructor.selector = name.toCharArray(); + constructor.thrownExceptions = null; + constructor.typeParameters = null; + injectScopeIntoStaticConstructor(constructor, fields, (TypeDeclaration) type.get()); + constructor.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = pos.sourceStart; + constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = pos.sourceEnd; + + List<Argument> args = new ArrayList<Argument>(); + List<Expression> assigns = new ArrayList<Expression>(); + AllocationExpression statement = new AllocationExpression(); + statement.type = constructor.returnType; + + for ( Node fieldNode : fields ) { + FieldDeclaration field = (FieldDeclaration) fieldNode.get(); + long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd; + assigns.add(new SingleNameReference(field.name, fieldPos)); + args.add(new Argument(field.name, fieldPos, field.type, 0)); + } + + statement.arguments = assigns.toArray(new Expression[assigns.size()]); + constructor.arguments = args.toArray(new Argument[args.size()]); + constructor.statements = new Statement[] { statement }; + return constructor; + } + + private MethodDeclaration createEquals(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)); diff --git a/src/lombok/eclipse/handlers/PKG.java b/src/lombok/eclipse/handlers/PKG.java index d93807a7..1e391ef2 100644 --- a/src/lombok/eclipse/handlers/PKG.java +++ b/src/lombok/eclipse/handlers/PKG.java @@ -6,7 +6,9 @@ import lombok.AccessLevel; import lombok.core.AST.Kind; import lombok.eclipse.EclipseAST; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; class PKG { @@ -64,6 +66,44 @@ class PKG { return MethodExistsResult.NOT_EXISTS; } + static MethodExistsResult constructorExists(EclipseAST.Node node) { + while ( node != null && !(node.get() instanceof TypeDeclaration) ) { + node = node.up(); + } + + if ( node.get() instanceof TypeDeclaration ) { + TypeDeclaration typeDecl = (TypeDeclaration)node.get(); + if ( typeDecl.methods != null ) for ( AbstractMethodDeclaration def : typeDecl.methods ) { + if ( def instanceof ConstructorDeclaration ) { + if ( (def.bits & ASTNode.IsDefaultConstructor) != 0 ) continue; + EclipseAST.Node existing = node.getNodeFor(def); + if ( existing == null || !existing.isHandled() ) return MethodExistsResult.EXISTS_BY_USER; + return MethodExistsResult.EXISTS_BY_LOMBOK; + } + } + } + + return MethodExistsResult.NOT_EXISTS; + } + + static EclipseAST.Node getExistingLombokConstructor(EclipseAST.Node node) { + while ( node != null && !(node.get() instanceof TypeDeclaration) ) { + node = node.up(); + } + + if ( node.get() instanceof TypeDeclaration ) { + for ( AbstractMethodDeclaration def : ((TypeDeclaration)node.get()).methods ) { + if ( def instanceof ConstructorDeclaration ) { + if ( (def.bits & ASTNode.IsDefaultConstructor) != 0 ) continue; + EclipseAST.Node existing = node.getNodeFor(def); + if ( existing.isHandled() ) return existing; + } + } + } + + return null; + } + static EclipseAST.Node getExistingLombokMethod(String methodName, EclipseAST.Node node) { while ( node != null && !(node.get() instanceof TypeDeclaration) ) { node = node.up(); @@ -85,14 +125,28 @@ class PKG { static void injectMethod(EclipseAST.Node type, AbstractMethodDeclaration method) { TypeDeclaration parent = (TypeDeclaration) type.get(); + if ( parent.methods == null ) { parent.methods = new AbstractMethodDeclaration[1]; parent.methods[0] = method; } else { - AbstractMethodDeclaration[] newArray = new AbstractMethodDeclaration[parent.methods.length + 1]; - System.arraycopy(parent.methods, 0, newArray, 0, parent.methods.length); - newArray[parent.methods.length] = method; - parent.methods = newArray; + boolean injectionComplete = false; + if ( method instanceof ConstructorDeclaration ) { + for ( int i = 0 ; i < parent.methods.length ; i++ ) { + if ( parent.methods[i] instanceof ConstructorDeclaration && + (parent.methods[i].bits & ASTNode.IsDefaultConstructor) != 0 ) { + parent.methods[i] = method; + injectionComplete = true; + break; + } + } + } + if ( !injectionComplete ) { + AbstractMethodDeclaration[] newArray = new AbstractMethodDeclaration[parent.methods.length + 1]; + System.arraycopy(parent.methods, 0, newArray, 0, parent.methods.length); + newArray[parent.methods.length] = method; + parent.methods = newArray; + } } type.add(method, Kind.METHOD).recursiveSetHandled(); |