diff options
-rw-r--r-- | doc/changelog.markdown | 3 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleConstructor.java | 266 | ||||
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleData.java | 162 |
3 files changed, 270 insertions, 161 deletions
diff --git a/doc/changelog.markdown b/doc/changelog.markdown index 9385bf25..01ddfb45 100644 --- a/doc/changelog.markdown +++ b/doc/changelog.markdown @@ -1,7 +1,7 @@ Lombok Changelog ---------------- -### v0.9.3 (edge) +### v0.9.3 (edge) "Burrowing Whale" * PLATFORMS: Lombok should now run in stand-alone ecj (Eclipse Compiler for Java). This isn't just useful for the few souls actually using this compiler day to day, but various eclipse build tools such as the RCP builder run ecj internally as well. [Issue #72](http://code.google.com/p/projectlombok/issues/detail?id=72) * BUGFIX: Eclipse: `@Data` and other annotations now don't throw errors when you include fields with bounded wildcard generics, such as `List<? extends Number>`. [Issue #84](http://code.google.com/p/projectlombok/issues/detail?id=84) * FEATURE: plugins and `@SneakyThrows`: Resolving types in annotations now works better especially for classes that aren't in the core java libraries. [Issue #88](http://code.google.com/p/projectlombok/issues/detail?id=88) @@ -12,6 +12,7 @@ Lombok Changelog * FEATURE: Adding `@Getter` or `@Setter` to a class is now legal and is like adding those annotations to every non-static field in it. [Issue #129](http://code.google.com/p/projectlombok/issues/detail?id=129) * ENHANCEMENT: All field accesses generated by lombok are now qualified (like so: `this.fieldName`). For those who have a warning configured for unqualified field access, those should no longer occur. [Issue #48](http://code.google.com/p/projectlombok/issues/detail?id=48) * ENHANCEMENT: All fields and methods generated by lombok now get `@SuppressWarnings("all")` attached to avoid such warnings as missing javadoc, for those of you who have that warning enabled. [Issue #47](http://code.google.com/p/projectlombok/issues/detail?id=47) +* FEATURE: Three new annotations, `@NoArgsConstructor`, `@RequiredArgsConstructor` and `@AllArgsConstructor` have been added. These split off `@Data`'s ability to generate constructors, and also allow you to finetune what kind of constructor you want. In addition, by using these annotations, you can force generation of constructors even if you have your own. [Issue #79](http://code.google.com/p/projectlombok/issues/detail?id=79) ### v0.9.2 "Hailbunny" (December 15th, 2009) * preliminary support for lombok on NetBeans! - thanks go to Jan Lahoda from NetBeans. [Issue #20](http://code.google.com/p/projectlombok/issues/detail?id=20) diff --git a/src/core/lombok/eclipse/handlers/HandleConstructor.java b/src/core/lombok/eclipse/handlers/HandleConstructor.java new file mode 100644 index 00000000..de6bb048 --- /dev/null +++ b/src/core/lombok/eclipse/handlers/HandleConstructor.java @@ -0,0 +1,266 @@ +/* + * Copyright © 2010 Reinier Zwitserloot, Roel Spilker and Robbert Jan Grootjans. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.eclipse.handlers; + +import static lombok.eclipse.Eclipse.*; +import static lombok.eclipse.handlers.EclipseHandlerUtil.*; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; +import lombok.core.handlers.TransformationsUtil; +import lombok.eclipse.Eclipse; +import lombok.eclipse.EclipseAnnotationHandler; +import lombok.eclipse.EclipseNode; +import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; + +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.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.ParameterizedSingleTypeReference; +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.ThisReference; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeParameter; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.mangosdk.spi.ProviderFor; + +public class HandleConstructor { + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleNoArgsConstructor implements EclipseAnnotationHandler<NoArgsConstructor> { + @Override public boolean handle(AnnotationValues<NoArgsConstructor> annotation, Annotation ast, EclipseNode annotationNode) { + EclipseNode typeNode = annotationNode.up(); + List<EclipseNode> fields = new ArrayList<EclipseNode>(); + NoArgsConstructor ann = annotation.getInstance(); + AccessLevel level = ann.access(); + String staticName = ann.staticName(); + new HandleConstructor().generateConstructor(level, typeNode, fields, staticName, false, ast); + return true; + } + } + + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleRequiredArgsConstructor implements EclipseAnnotationHandler<RequiredArgsConstructor> { + @Override public boolean handle(AnnotationValues<RequiredArgsConstructor> annotation, Annotation ast, EclipseNode annotationNode) { + EclipseNode typeNode = annotationNode.up(); + List<EclipseNode> fields = new ArrayList<EclipseNode>(); + for (EclipseNode child : typeNode.down()) { + if (child.getKind() != Kind.FIELD) continue; + FieldDeclaration fieldDecl = (FieldDeclaration) child.get(); + //Skip fields that start with $ + if (fieldDecl.name.length > 0 && fieldDecl.name[0] == '$') continue; + //Skip static fields. + if ((fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0) continue; + boolean isFinal = (fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0; + boolean isNonNull = findAnnotations(fieldDecl, TransformationsUtil.NON_NULL_PATTERN).length != 0; + if ((isFinal || isNonNull) && fieldDecl.initialization == null) fields.add(child); + } + RequiredArgsConstructor ann = annotation.getInstance(); + AccessLevel level = ann.access(); + String staticName = ann.staticName(); + new HandleConstructor().generateConstructor(level, typeNode, fields, staticName, false, ast); + return true; + } + } + + @ProviderFor(EclipseAnnotationHandler.class) + public static class HandleAllArgsConstructor implements EclipseAnnotationHandler<AllArgsConstructor> { + @Override public boolean handle(AnnotationValues<AllArgsConstructor> annotation, Annotation ast, EclipseNode annotationNode) { + EclipseNode typeNode = annotationNode.up(); + List<EclipseNode> fields = new ArrayList<EclipseNode>(); + for (EclipseNode child : typeNode.down()) { + if (child.getKind() != Kind.FIELD) continue; + FieldDeclaration fieldDecl = (FieldDeclaration) child.get(); + //Skip fields that start with $ + if (fieldDecl.name.length > 0 && fieldDecl.name[0] == '$') continue; + //Skip static fields. + if ((fieldDecl.modifiers & ClassFileConstants.AccStatic) != 0) continue; + fields.add(child); + } + AllArgsConstructor ann = annotation.getInstance(); + AccessLevel level = ann.access(); + String staticName = ann.staticName(); + new HandleConstructor().generateConstructor(level, typeNode, fields, staticName, false, ast); + return true; + } + } + + public void generateConstructor(AccessLevel level, EclipseNode typeNode, List<EclipseNode> fields, String staticName, boolean skipIfConstructorExists, ASTNode source) { + if (skipIfConstructorExists && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS) return; + if (skipIfConstructorExists) { + for (EclipseNode child : typeNode.down()) { + if (child.getKind() == Kind.ANNOTATION) { + if (Eclipse.annotationTypeMatches(NoArgsConstructor.class, child) || + Eclipse.annotationTypeMatches(AllArgsConstructor.class, child) || + Eclipse.annotationTypeMatches(RequiredArgsConstructor.class, child)) + return; + } + } + } + + boolean staticConstrRequired = staticName != null && !staticName.equals(""); + + ConstructorDeclaration constr = createConstructor(staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fields, source); + injectMethod(typeNode, constr); + if (staticConstrRequired) { + MethodDeclaration staticConstr = createStaticConstructor(level, staticName, typeNode, fields, source); + injectMethod(typeNode, staticConstr); + } + } + + private ConstructorDeclaration createConstructor(AccessLevel level, + EclipseNode type, Collection<EclipseNode> fields, ASTNode source) { + long p = (long)source.sourceStart << 32 | source.sourceEnd; + + ConstructorDeclaration constructor = new ConstructorDeclaration( + ((CompilationUnitDeclaration) type.top().get()).compilationResult); + Eclipse.setGeneratedBy(constructor, source); + + constructor.modifiers = EclipseHandlerUtil.toEclipseModifier(level); + constructor.annotations = null; + constructor.selector = ((TypeDeclaration)type.get()).name; + constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); + Eclipse.setGeneratedBy(constructor.constructorCall, source); + constructor.thrownExceptions = null; + constructor.typeParameters = null; + constructor.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart; + constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd; + constructor.arguments = null; + + List<Argument> params = new ArrayList<Argument>(); + List<Statement> assigns = new ArrayList<Statement>(); + List<Statement> nullChecks = new ArrayList<Statement>(); + + for (EclipseNode fieldNode : fields) { + FieldDeclaration field = (FieldDeclaration) fieldNode.get(); + FieldReference thisX = new FieldReference(field.name, p); + Eclipse.setGeneratedBy(thisX, source); + thisX.receiver = new ThisReference((int)(p >> 32), (int)p); + Eclipse.setGeneratedBy(thisX.receiver, source); + + SingleNameReference assignmentNameRef = new SingleNameReference(field.name, p); + Eclipse.setGeneratedBy(assignmentNameRef, source); + Assignment assignment = new Assignment(thisX, assignmentNameRef, (int)p); + Eclipse.setGeneratedBy(assignment, source); + assigns.add(assignment); + long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd; + Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL); + Eclipse.setGeneratedBy(parameter, source); + Annotation[] nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN); + Annotation[] nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN); + if (nonNulls.length != 0) { + Statement nullCheck = generateNullCheck(field, source); + if (nullCheck != null) nullChecks.add(nullCheck); + } + Annotation[] copiedAnnotations = copyAnnotations(nonNulls, nullables, source); + if (copiedAnnotations.length != 0) parameter.annotations = copiedAnnotations; + params.add(parameter); + } + + nullChecks.addAll(assigns); + constructor.statements = nullChecks.isEmpty() ? null : nullChecks.toArray(new Statement[nullChecks.size()]); + constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[params.size()]); + return constructor; + } + + private MethodDeclaration createStaticConstructor(AccessLevel level, String name, EclipseNode type, Collection<EclipseNode> fields, ASTNode source) { + int pS = source.sourceStart, pE = source.sourceEnd; + long p = (long)pS << 32 | pE; + + MethodDeclaration constructor = new MethodDeclaration( + ((CompilationUnitDeclaration) type.top().get()).compilationResult); + Eclipse.setGeneratedBy(constructor, source); + + constructor.modifiers = EclipseHandlerUtil.toEclipseModifier(level) | Modifier.STATIC; + TypeDeclaration typeDecl = (TypeDeclaration) type.get(); + if (typeDecl.typeParameters != null && typeDecl.typeParameters.length > 0) { + TypeReference[] refs = new TypeReference[typeDecl.typeParameters.length]; + int idx = 0; + for (TypeParameter param : typeDecl.typeParameters) { + TypeReference typeRef = new SingleTypeReference(param.name, (long)param.sourceStart << 32 | param.sourceEnd); + Eclipse.setGeneratedBy(typeRef, source); + refs[idx++] = typeRef; + } + constructor.returnType = new ParameterizedSingleTypeReference(typeDecl.name, refs, 0, p); + } else constructor.returnType = new SingleTypeReference(((TypeDeclaration)type.get()).name, p); + Eclipse.setGeneratedBy(constructor.returnType, source); + constructor.annotations = null; + constructor.selector = name.toCharArray(); + constructor.thrownExceptions = null; + constructor.typeParameters = copyTypeParams(((TypeDeclaration)type.get()).typeParameters, source); + constructor.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; + constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart; + constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd; + + List<Argument> params = new ArrayList<Argument>(); + List<Expression> assigns = new ArrayList<Expression>(); + AllocationExpression statement = new AllocationExpression(); + statement.sourceStart = pS; statement.sourceEnd = pE; + Eclipse.setGeneratedBy(statement, source); + statement.type = copyType(constructor.returnType, source); + + for (EclipseNode fieldNode : fields) { + FieldDeclaration field = (FieldDeclaration) fieldNode.get(); + long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd; + SingleNameReference nameRef = new SingleNameReference(field.name, fieldPos); + Eclipse.setGeneratedBy(nameRef, source); + assigns.add(nameRef); + + Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL); + Eclipse.setGeneratedBy(parameter, source); + + Annotation[] copiedAnnotations = copyAnnotations( + findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), + findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN), source); + if (copiedAnnotations.length != 0) parameter.annotations = copiedAnnotations; + params.add(new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL)); + } + + statement.arguments = assigns.isEmpty() ? null : assigns.toArray(new Expression[assigns.size()]); + constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[params.size()]); + constructor.statements = new Statement[] { new ReturnStatement(statement, (int)(p >> 32), (int)p) }; + Eclipse.setGeneratedBy(constructor.statements[0], source); + return constructor; + } +} diff --git a/src/core/lombok/eclipse/handlers/HandleData.java b/src/core/lombok/eclipse/handlers/HandleData.java index 68b4682c..dbbb91f0 100644 --- a/src/core/lombok/eclipse/handlers/HandleData.java +++ b/src/core/lombok/eclipse/handlers/HandleData.java @@ -21,53 +21,24 @@ */ package lombok.eclipse.handlers; -import static lombok.eclipse.Eclipse.copyAnnotations; -import static lombok.eclipse.Eclipse.copyType; -import static lombok.eclipse.Eclipse.copyTypeParams; -import static lombok.eclipse.handlers.EclipseHandlerUtil.constructorExists; import static lombok.eclipse.handlers.EclipseHandlerUtil.findAnnotations; -import static lombok.eclipse.handlers.EclipseHandlerUtil.generateNullCheck; -import static lombok.eclipse.handlers.EclipseHandlerUtil.injectMethod; -import static lombok.eclipse.handlers.EclipseHandlerUtil.methodExists; -import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import lombok.AccessLevel; import lombok.Data; -import lombok.core.AnnotationValues; import lombok.core.AST.Kind; +import lombok.core.AnnotationValues; import lombok.core.handlers.TransformationsUtil; -import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseAnnotationHandler; import lombok.eclipse.EclipseNode; -import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult; -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.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.ParameterizedSingleTypeReference; -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.ThisReference; import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; -import org.eclipse.jdt.internal.compiler.ast.TypeParameter; -import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; import org.mangosdk.spi.ProviderFor; @@ -112,19 +83,7 @@ public class HandleData implements EclipseAnnotationHandler<Data> { //for whatever reason, though you can find callers of that one by focusing on the class name itself //and hitting 'find callers'. - if (constructorExists(typeNode) == MemberExistsResult.NOT_EXISTS) { - ConstructorDeclaration constructor = createConstructor( - ann.staticConstructor().length() == 0, typeNode, nodesForConstructor, ast); - injectMethod(typeNode, constructor); - } - - if (ann.staticConstructor().length() > 0) { - if (methodExists("of", typeNode, false) == MemberExistsResult.NOT_EXISTS) { - MethodDeclaration staticConstructor = createStaticConstructor( - ann.staticConstructor(), typeNode, nodesForConstructor, ast); - injectMethod(typeNode, staticConstructor); - } - } + new HandleConstructor().generateConstructor(AccessLevel.PUBLIC, typeNode, nodesForConstructor, ann.staticConstructor(), true, ast); for (Map.Entry<EclipseNode, Boolean> field : gettersAndSetters.entrySet()) { new HandleGetter().generateGetterForField(field.getKey(), annotationNode.get(), AccessLevel.PUBLIC, true); @@ -136,121 +95,4 @@ public class HandleData implements EclipseAnnotationHandler<Data> { return false; } - - private ConstructorDeclaration createConstructor(boolean isPublic, - EclipseNode type, Collection<EclipseNode> fields, ASTNode source) { - long p = (long)source.sourceStart << 32 | source.sourceEnd; - - ConstructorDeclaration constructor = new ConstructorDeclaration( - ((CompilationUnitDeclaration) type.top().get()).compilationResult); - Eclipse.setGeneratedBy(constructor, source); - - constructor.modifiers = EclipseHandlerUtil.toEclipseModifier(isPublic ? AccessLevel.PUBLIC : AccessLevel.PRIVATE); - constructor.annotations = null; - constructor.selector = ((TypeDeclaration)type.get()).name; - constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper); - Eclipse.setGeneratedBy(constructor.constructorCall, source); - constructor.thrownExceptions = null; - constructor.typeParameters = null; - constructor.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; - constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart; - constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd; - constructor.arguments = null; - - List<Argument> args = new ArrayList<Argument>(); - List<Statement> assigns = new ArrayList<Statement>(); - List<Statement> nullChecks = new ArrayList<Statement>(); - - for (EclipseNode fieldNode : fields) { - FieldDeclaration field = (FieldDeclaration) fieldNode.get(); - FieldReference thisX = new FieldReference(("this." + new String(field.name)).toCharArray(), p); - Eclipse.setGeneratedBy(thisX, source); - thisX.receiver = new ThisReference((int)(p >> 32), (int)p); - Eclipse.setGeneratedBy(thisX.receiver, source); - thisX.token = field.name; - - SingleNameReference assignmentNameRef = new SingleNameReference(field.name, p); - Eclipse.setGeneratedBy(assignmentNameRef, source); - Assignment assignment = new Assignment(thisX, assignmentNameRef, (int)p); - Eclipse.setGeneratedBy(assignment, source); - assigns.add(assignment); - long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd; - Argument argument = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL); - Eclipse.setGeneratedBy(argument, source); - Annotation[] nonNulls = findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN); - Annotation[] nullables = findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN); - if (nonNulls.length != 0) { - Statement nullCheck = generateNullCheck(field, source); - if (nullCheck != null) nullChecks.add(nullCheck); - } - Annotation[] copiedAnnotations = copyAnnotations(nonNulls, nullables, source); - if (copiedAnnotations.length != 0) argument.annotations = copiedAnnotations; - args.add(argument); - } - - nullChecks.addAll(assigns); - constructor.statements = nullChecks.isEmpty() ? null : nullChecks.toArray(new Statement[nullChecks.size()]); - constructor.arguments = args.isEmpty() ? null : args.toArray(new Argument[args.size()]); - return constructor; - } - - private MethodDeclaration createStaticConstructor(String name, EclipseNode type, Collection<EclipseNode> fields, ASTNode source) { - int pS = source.sourceStart, pE = source.sourceEnd; - long p = (long)pS << 32 | pE; - - MethodDeclaration constructor = new MethodDeclaration( - ((CompilationUnitDeclaration) type.top().get()).compilationResult); - Eclipse.setGeneratedBy(constructor, source); - - constructor.modifiers = EclipseHandlerUtil.toEclipseModifier(AccessLevel.PUBLIC) | Modifier.STATIC; - TypeDeclaration typeDecl = (TypeDeclaration) type.get(); - if (typeDecl.typeParameters != null && typeDecl.typeParameters.length > 0) { - TypeReference[] refs = new TypeReference[typeDecl.typeParameters.length]; - int idx = 0; - for (TypeParameter param : typeDecl.typeParameters) { - TypeReference typeRef = new SingleTypeReference(param.name, (long)param.sourceStart << 32 | param.sourceEnd); - Eclipse.setGeneratedBy(typeRef, source); - refs[idx++] = typeRef; - } - constructor.returnType = new ParameterizedSingleTypeReference(typeDecl.name, refs, 0, p); - } else constructor.returnType = new SingleTypeReference(((TypeDeclaration)type.get()).name, p); - Eclipse.setGeneratedBy(constructor.returnType, source); - constructor.annotations = null; - constructor.selector = name.toCharArray(); - constructor.thrownExceptions = null; - constructor.typeParameters = copyTypeParams(((TypeDeclaration)type.get()).typeParameters, source); - constructor.bits |= Eclipse.ECLIPSE_DO_NOT_TOUCH_FLAG; - constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart; - constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd; - - List<Argument> args = new ArrayList<Argument>(); - List<Expression> assigns = new ArrayList<Expression>(); - AllocationExpression statement = new AllocationExpression(); - statement.sourceStart = pS; statement.sourceEnd = pE; - Eclipse.setGeneratedBy(statement, source); - statement.type = copyType(constructor.returnType, source); - - for (EclipseNode fieldNode : fields) { - FieldDeclaration field = (FieldDeclaration) fieldNode.get(); - long fieldPos = (((long)field.sourceStart) << 32) | field.sourceEnd; - SingleNameReference nameRef = new SingleNameReference(field.name, fieldPos); - Eclipse.setGeneratedBy(nameRef, source); - assigns.add(nameRef); - - Argument argument = new Argument(field.name, fieldPos, copyType(field.type, source), 0); - Eclipse.setGeneratedBy(argument, source); - - Annotation[] copiedAnnotations = copyAnnotations( - findAnnotations(field, TransformationsUtil.NON_NULL_PATTERN), - findAnnotations(field, TransformationsUtil.NULLABLE_PATTERN), source); - if (copiedAnnotations.length != 0) argument.annotations = copiedAnnotations; - args.add(new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL)); - } - - statement.arguments = assigns.isEmpty() ? null : assigns.toArray(new Expression[assigns.size()]); - constructor.arguments = args.isEmpty() ? null : args.toArray(new Argument[args.size()]); - constructor.statements = new Statement[] { new ReturnStatement(statement, (int)(p >> 32), (int)p) }; - Eclipse.setGeneratedBy(constructor.statements[0], source); - return constructor; - } } |