diff options
author | Jan Rieke <rieke@subshell.com> | 2018-05-17 20:36:40 +0200 |
---|---|---|
committer | Jan Rieke <rieke@subshell.com> | 2018-05-17 20:36:40 +0200 |
commit | 55976fec127e7674222f81e46532755081ffb454 (patch) | |
tree | efe4a95d16e2b3fcff2ee72efbae2178f7c68794 | |
parent | 5d35fe3bfbd46de7410bca96e29731e8f5236618 (diff) | |
download | lombok-55976fec127e7674222f81e46532755081ffb454.tar.gz lombok-55976fec127e7674222f81e46532755081ffb454.tar.bz2 lombok-55976fec127e7674222f81e46532755081ffb454.zip |
ecj: remaining type args for non-generic class builders
-rw-r--r-- | src/core/lombok/eclipse/handlers/HandleSuperBuilder.java | 199 | ||||
-rw-r--r-- | test/transform/resource/after-ecj/SuperBuilderBasic.java | 71 |
2 files changed, 82 insertions, 188 deletions
diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index d01e250d..71683516 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -199,49 +199,61 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { // Set the names of the builder classes. String builderClassName = String.valueOf(td.name) + "Builder"; String builderImplClassName = builderClassName + "Impl"; + + typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0]; + returnType = namePlusTypeParamsToTypeReference(td.name, typeParams, p); + + // <C, B> are the generics for our builder. + String classGenericName = "C"; + String builderGenericName = "B"; + // If these generics' names collide with any generics on the annotated class, modify them. + // For instance, if there are generics <B, B2, C> on the annotated class, use "C2" and "B3" for our builder. + java.util.List<String> typeParamStrings = new ArrayList<String>(); + for (TypeParameter typeParam : typeParams) { + typeParamStrings.add(typeParam.toString()); + } + classGenericName = generateNonclashingNameFor(classGenericName, typeParamStrings); + builderGenericName = generateNonclashingNameFor(builderGenericName, typeParamStrings); TypeReference extendsClause = td.superclass; TypeReference superclassBuilderClass = null; -// if (extendsClause.getTypeArguments() != null) { -// // Remember the type arguments, because we need them for the extends clause of our abstract builder class. -// superclassTypeParams = ((JCTypeApply)extendsClause).getTypeArguments(); -// // A class name with a generics type, e.g., "Superclass<A>". -// extendsClause = ((JCTypeApply)extendsClause).getType(); -// } + TypeReference[] typeArguments = new TypeReference[] { + new SingleTypeReference(classGenericName.toCharArray(), 0), + new SingleTypeReference(builderGenericName.toCharArray(), 0) + }; if (extendsClause instanceof QualifiedTypeReference) { QualifiedTypeReference qualifiedTypeReference = (QualifiedTypeReference)extendsClause; String superclassClassName = String.valueOf(qualifiedTypeReference.getLastToken()); String superclassBuilderClassName = superclassClassName + "Builder"; + char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1); tokens[tokens.length] = superclassBuilderClassName.toCharArray(); long[] poss = new long[tokens.length]; Arrays.fill(poss, p); - superclassBuilderClass = new QualifiedTypeReference(tokens, poss); + + // Every token may potentially have type args. Here, we only have + // type args for the last token, the superclass' builder. + TypeReference[][] typeArgsForTokens = new TypeReference[tokens.length][]; + typeArgsForTokens[typeArgsForTokens.length-1] = typeArguments; + + superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss); } else if (extendsClause != null) { String superClass = String.valueOf(extendsClause.getTypeName()[0]); String superclassBuilderClassName = superClass + "Builder"; + char[][] tokens = new char[][] {superClass.toCharArray(), superclassBuilderClassName.toCharArray()}; long[] poss = new long[tokens.length]; Arrays.fill(poss, p); - superclassBuilderClass = new QualifiedTypeReference(tokens, poss); - } - // If there is no superclass, superclassBuilderClassExpression is still == null at this point. - // You can use it to check whether to inherit or not. - typeParams = td.typeParameters != null ? td.typeParameters : new TypeParameter[0]; - returnType = namePlusTypeParamsToTypeReference(td.name, typeParams, p); + // Every token may potentially have type args. Here, we only have + // type args for the last token, the superclass' builder. + TypeReference[][] typeArgsForTokens = new TypeReference[tokens.length][]; + typeArgsForTokens[typeArgsForTokens.length-1] = typeArguments; - // <C, B> are the generics for our builder. - String classGenericName = "C"; - String builderGenericName = "B"; - // If these generics' names collide with any generics on the annotated class, modify them. - // For instance, if there are generics <B, B2, C> on the annotated class, use "C2" and "B3" for our builder. - java.util.List<String> typeParamStrings = new ArrayList<String>(); - for (TypeParameter typeParam : typeParams) { - typeParamStrings.add(typeParam.toString()); + superclassBuilderClass = new ParameterizedQualifiedTypeReference(tokens, typeArgsForTokens, 0, poss); } - classGenericName = generateNonclashingNameFor(classGenericName, typeParamStrings); - builderGenericName = generateNonclashingNameFor(builderGenericName, typeParamStrings); + // If there is no superclass, superclassBuilderClassExpression is still == null at this point. + // You can use it to check whether to inherit or not. generateBuilderBasedConstructor(tdParent, typeParams, builderFields, annotationNode, builderClassName, superclassBuilderClass != null); @@ -335,14 +347,10 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { // Add the builder() method to the annotated class. if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) { MethodDeclaration md = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, tdParent, typeParams, ast); -// recursiveSetGeneratedBy(md, ast, annotationNode.getContext()); if (md != null) { injectMethod(tdParent, md); } } - -// recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext()); -// recursiveSetGeneratedBy(builderImplType.get(), ast, annotationNode.getContext()); } private String generateNonclashingNameFor(String classGenericName, java.util.List<String> typeParamStrings) { @@ -441,40 +449,19 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { injectMethod(typeNode, constructor); } -// private ListBuffer<JCExpression> getTypeParamExpressions(List<? extends JCTree> typeParams, JavacTreeMaker maker) { -// ListBuffer<JCExpression> typeParamsForBuilderParameter = new ListBuffer<JCExpression>(); -// for (JCTree typeParam : typeParams) { -// if (typeParam instanceof JCTypeParameter) { -// typeParamsForBuilderParameter.add(maker.Ident(((JCTypeParameter)typeParam).getName())); -// } else if (typeParam instanceof JCIdent) { -// typeParamsForBuilderParameter.add(maker.Ident(((JCIdent)typeParam).getName())); -// } -// } -// return typeParamsForBuilderParameter; -// } - private MethodDeclaration generateAbstractSelfMethod(EclipseNode tdParent, boolean override, String builderGenericName) { - // TODO: @Override annotation if override == true. MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult); out.selector = SELF_METHOD.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected; + if (override) { + out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, tdParent.get())}; + } out.returnType = new SingleTypeReference(builderGenericName.toCharArray(), 0); return out; } private MethodDeclaration generateSelfMethod(EclipseNode builderImplType) { -// JavacTreeMaker maker = builderImplType.getTreeMaker(); -// -// JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(builderImplType, "Override"), List.<JCExpression>nil()); -// JCModifiers modifiers = maker.Modifiers(Flags.PROTECTED, List.of(overrideAnnotation)); -// Name name = builderImplType.toName(SELF_METHOD); -// JCExpression returnType = maker.Ident(builderImplType.toName(builderImplType.getName())); -// -// JCStatement statement = maker.Return(maker.Ident(builderImplType.toName("this"))); -// JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); -// -// return maker.MethodDef(modifiers, name, returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderImplType.top().get()).compilationResult); out.selector = SELF_METHOD.toCharArray(); out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; @@ -497,11 +484,6 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { if (override) { out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, source)}; } - - AllocationExpression allocationStatement = new AllocationExpression(); - allocationStatement.type = copyType(out.returnType); - // Use a constructor that only has this builder as parameter. - allocationStatement.arguments = new Expression[] {new ThisReference(0, 0)}; out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return out; } @@ -550,51 +532,21 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { return out; } -// private MethodDeclaration generateBuildMethod(String buildName, JCExpression returnType, EclipseNode type, List<JCExpression> thrownExceptions) { -// JavacTreeMaker maker = type.getTreeMaker(); -// -// JCExpression call; -// ListBuffer<JCStatement> statements = new ListBuffer<JCStatement>(); -// -// // Use a constructor that only has this builder as parameter. -// List<JCExpression> builderArg = List.<JCExpression>of(maker.Ident(type.toName("this"))); -// call = maker.NewClass(null, List.<JCExpression>nil(), returnType, builderArg, null); -// statements.append(maker.Return(call)); -// -// JCBlock body = maker.Block(0, statements.toList()); -// -// JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.<JCExpression>nil()); -// JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); -// -// return maker.MethodDef(modifiers, type.toName(buildName), returnType, List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), thrownExceptions, body, null); -// } - - private MethodDeclaration generateDefaultProvider(char[] methodName, TypeParameter[] typeParameters, EclipseNode fieldNode, ASTNode source) { - int pS = source.sourceStart, pE = source.sourceEnd; - - MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) fieldNode.top().get()).compilationResult); - out.typeParameters = copyTypeParams(typeParameters, source); - out.selector = methodName; - out.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic; - out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - FieldDeclaration fd = (FieldDeclaration) fieldNode.get(); - out.returnType = copyType(fd.type, source); - out.statements = new Statement[] {new ReturnStatement(fd.initialization, pS, pE)}; - fd.initialization = null; - - out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) fieldNode.up().get()).scope); - return out; - } -// public MethodDeclaration generateDefaultProvider(Name methodName, EclipseNode fieldNode, List<JCTypeParameter> params) { -// JavacTreeMaker maker = fieldNode.getTreeMaker(); -// JCVariableDecl field = (JCVariableDecl) fieldNode.get(); +// private MethodDeclaration generateDefaultProvider(char[] methodName, TypeParameter[] typeParameters, EclipseNode fieldNode, ASTNode source) { +// int pS = source.sourceStart, pE = source.sourceEnd; // -// JCStatement statement = maker.Return(field.init); -// field.init = null; +// MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) fieldNode.top().get()).compilationResult); +// out.typeParameters = copyTypeParams(typeParameters, source); +// out.selector = methodName; +// out.modifiers = ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic; +// out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; +// FieldDeclaration fd = (FieldDeclaration) fieldNode.get(); +// out.returnType = copyType(fd.type, source); +// out.statements = new Statement[] {new ReturnStatement(fd.initialization, pS, pE)}; +// fd.initialization = null; // -// JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); -// int modifiers = Flags.PRIVATE | Flags.STATIC; -// return maker.MethodDef(maker.Modifiers(modifiers), methodName, cloneType(maker, field.vartype, field, fieldNode.getContext()), copyTypeParams(fieldNode, params), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); +// out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) fieldNode.up().get()).scope); +// return out; // } private MethodDeclaration generateBuilderMethod(String builderMethodName, String builderClassName, String builderImplClassName, EclipseNode type, TypeParameter[] typeParams, ASTNode source) { @@ -605,41 +557,21 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { out.selector = builderMethodName.toCharArray(); out.modifiers = ClassFileConstants.AccPublic | ClassFileConstants.AccStatic; out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG; - out.returnType = namePlusTypeParamsToTypeReference(builderClassName.toCharArray(), typeParams, p); + + // TODO: add type params //out.typeParameters = copyTypeParams(typeParams, source); + TypeReference[] returnTypeParams = new TypeReference[2]; + returnTypeParams[0] = new Wildcard(Wildcard.UNBOUND); + returnTypeParams[1] = new Wildcard(Wildcard.UNBOUND); + out.returnType = new ParameterizedSingleTypeReference(builderClassName.toCharArray(), returnTypeParams, 0, p); + AllocationExpression invoke = new AllocationExpression(); - invoke.type = namePlusTypeParamsToTypeReference(builderClassName.toCharArray(), typeParams, p); + invoke.type = namePlusTypeParamsToTypeReference(builderImplClassName.toCharArray(), typeParams, p); out.statements = new Statement[] {new ReturnStatement(invoke, pS, pE)}; out.traverse(new SetGeneratedByVisitor(source), ((TypeDeclaration) type.get()).scope); return out; } -// public MethodDeclaration generateBuilderMethod(String builderMethodName, String builderClassName, String builderImplClassName, EclipseNode source, EclipseNode type, List<JCTypeParameter> typeParams) { -// JavacTreeMaker maker = type.getTreeMaker(); -// -// ListBuffer<JCExpression> typeArgs = new ListBuffer<JCExpression>(); -// for (JCTypeParameter typeParam : typeParams) { -// typeArgs.append(maker.Ident(typeParam.name)); -// } -// -// JCExpression call = maker.NewClass(null, List.<JCExpression>nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderImplClassName), typeParams), List.<JCExpression>nil(), null); -// JCStatement statement = maker.Return(call); -// -// JCBlock body = maker.Block(0, List.<JCStatement>of(statement)); -// int modifiers = Flags.PUBLIC; -// modifiers |= Flags.STATIC; -// -// // Add any type params of the annotated class to the return type. -// ListBuffer<JCExpression> typeParameterNames = new ListBuffer<JCExpression>(); -// typeParameterNames.addAll(typeParameterNames(maker, typeParams)); -// // Now add the <?, ?>. -// JCWildcard wildcard = maker.Wildcard(maker.TypeBoundKind(BoundKind.UNBOUND), null); -// typeParameterNames.add(wildcard); -// typeParameterNames.add(wildcard); -// JCTypeApply returnType = maker.TypeApply(maker.Ident(type.toName(builderClassName)), typeParameterNames.toList()); -// -// return maker.MethodDef(maker.Modifiers(modifiers), type.toName(builderMethodName), returnType, copyTypeParams(source, typeParams), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null); -// } private void generateBuilderFields(EclipseNode builderType, List<BuilderFieldData> builderFields, ASTNode source) { List<EclipseNode> existing = new ArrayList<EclipseNode>(); @@ -779,18 +711,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { o.type = new ParameterizedSingleTypeReference(builderClass.toCharArray(), typerefs, 0, 0); builder.typeParameters[builder.typeParameters.length - 1] = o; - builder.superclass = superclassBuilderClass; - // TODO: Extends clause when there is a superclass. -// JCExpression extending = null; -// if (superclassBuilderClassExpression != null) { -// // If the annotated class extends another class, we want this builder to extend the builder of the superclass. -// // 1. Add the type parameters of the superclass. -// typeParamsForBuilder = getTypeParamExpressions(superclassTypeParams, maker); -// // 2. Add the builder type params <C, B>. -// typeParamsForBuilder.add(maker.Ident(tdParent.toName(classGenericName))); -// typeParamsForBuilder.add(maker.Ident(tdParent.toName(builderGenericName))); -// extending = maker.TypeApply(superclassBuilderClassExpression, typeParamsForBuilder.toList()); -// } + builder.superclass = copyType(superclassBuilderClass, source); builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null); return injectType(tdParent, builder); diff --git a/test/transform/resource/after-ecj/SuperBuilderBasic.java b/test/transform/resource/after-ecj/SuperBuilderBasic.java index d293c8f8..88ac7e70 100644 --- a/test/transform/resource/after-ecj/SuperBuilderBasic.java +++ b/test/transform/resource/after-ecj/SuperBuilderBasic.java @@ -61,72 +61,45 @@ public class SuperBuilderBasic { this.items = items;
}
public static @java.lang.SuppressWarnings("all") ParentBuilder<?, ?> builder() {
- return new ParentBuilderImpl();
+ return new ParentBuilderImpl();
}
}
-
public static @lombok.experimental.SuperBuilder class Child extends Parent {
- double field3;
-
- @java.lang.SuppressWarnings("all")
- protected Child(final ChildBuilder<?, ?> b) {
- super(b);
- this.field3 = b.field3;
- }
-
-
- @java.lang.SuppressWarnings("all")
- public static abstract class ChildBuilder<C extends Child, B extends ChildBuilder<C, B>> extends Parent.ParentBuilder<C, B> {
- @java.lang.SuppressWarnings("all")
- private double field3;
-
- @java.lang.Override
- @java.lang.SuppressWarnings("all")
- protected abstract B self();
-
- @java.lang.Override
- @java.lang.SuppressWarnings("all")
- public abstract C build();
-
- @java.lang.SuppressWarnings("all")
- public B field3(final double field3) {
+ public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder<C extends Child, B extends ChildBuilder<C, B>> extends Parent.ParentBuilder<C, B> {
+ private @java.lang.SuppressWarnings("all") double field3;
+ protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self();
+ public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build();
+ public @java.lang.SuppressWarnings("all") B field3(final double field3) {
this.field3 = field3;
return self();
}
-
- @java.lang.Override
- @java.lang.SuppressWarnings("all")
- public java.lang.String toString() {
- return "SuperBuilderBasic.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")";
+ public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
+ return (((("SuperBuilderBasic.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")");
}
}
-
-
- @java.lang.SuppressWarnings("all")
- private static final class ChildBuilderImpl extends ChildBuilder<Child, ChildBuilderImpl> {
- @java.lang.SuppressWarnings("all")
- private ChildBuilderImpl() {
+ private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder<Child, ChildBuilderImpl> {
+ private @java.lang.SuppressWarnings("all") ChildBuilderImpl() {
+ super();
}
-
- @java.lang.Override
- @java.lang.SuppressWarnings("all")
- protected ChildBuilderImpl self() {
+ protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() {
return this;
}
-
- @java.lang.Override
- @java.lang.SuppressWarnings("all")
- public Child build() {
+ public @java.lang.Override @java.lang.SuppressWarnings("all") Child build() {
return new Child(this);
}
}
-
- @java.lang.SuppressWarnings("all")
- public static ChildBuilder<?, ?> builder() {
+ double field3;
+ protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder<?, ?> b) {
+ super(b);
+ this.field3 = b.field3;
+ }
+ public static @java.lang.SuppressWarnings("all") ChildBuilder<?, ?> builder() {
return new ChildBuilderImpl();
}
}
-
+ public SuperBuilderBasic() {
+ super();
+ }
public static void test() {
Child x = Child.builder().field3(0.0).field1(5).item("").build();
}
|