From 55976fec127e7674222f81e46532755081ffb454 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Thu, 17 May 2018 20:36:40 +0200 Subject: ecj: remaining type args for non-generic class builders --- .../eclipse/handlers/HandleSuperBuilder.java | 199 +++++++-------------- .../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 { // 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); + + // 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 on the annotated class, use "C2" and "B3" for our builder. + java.util.List typeParamStrings = new ArrayList(); + 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". -// 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; - // 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 on the annotated class, use "C2" and "B3" for our builder. - java.util.List typeParamStrings = new ArrayList(); - 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 { // 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 typeParamStrings) { @@ -441,40 +449,19 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { injectMethod(typeNode, constructor); } -// private ListBuffer getTypeParamExpressions(List typeParams, JavacTreeMaker maker) { -// ListBuffer typeParamsForBuilderParameter = new ListBuffer(); -// 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.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.of(statement)); -// -// return maker.MethodDef(modifiers, name, returnType, List.nil(), List.nil(), List.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 { 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 { return out; } -// private MethodDeclaration generateBuildMethod(String buildName, JCExpression returnType, EclipseNode type, List thrownExceptions) { -// JavacTreeMaker maker = type.getTreeMaker(); -// -// JCExpression call; -// ListBuffer statements = new ListBuffer(); -// -// // Use a constructor that only has this builder as parameter. -// List builderArg = List.of(maker.Ident(type.toName("this"))); -// call = maker.NewClass(null, List.nil(), returnType, builderArg, null); -// statements.append(maker.Return(call)); -// -// JCBlock body = maker.Block(0, statements.toList()); -// -// JCAnnotation overrideAnnotation = maker.Annotation(genJavaLangTypeRef(type, "Override"), List.nil()); -// JCModifiers modifiers = maker.Modifiers(Flags.PUBLIC, List.of(overrideAnnotation)); -// -// return maker.MethodDef(modifiers, type.toName(buildName), returnType, List.nil(), List.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 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.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.nil(), List.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 { 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 typeParams) { -// JavacTreeMaker maker = type.getTreeMaker(); -// -// ListBuffer typeArgs = new ListBuffer(); -// for (JCTypeParameter typeParam : typeParams) { -// typeArgs.append(maker.Ident(typeParam.name)); -// } -// -// JCExpression call = maker.NewClass(null, List.nil(), namePlusTypeParamsToTypeReference(maker, type.toName(builderImplClassName), typeParams), List.nil(), null); -// JCStatement statement = maker.Return(call); -// -// JCBlock body = maker.Block(0, List.of(statement)); -// int modifiers = Flags.PUBLIC; -// modifiers |= Flags.STATIC; -// -// // Add any type params of the annotated class to the return type. -// ListBuffer typeParameterNames = new ListBuffer(); -// 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.nil(), List.nil(), body, null); -// } private void generateBuilderFields(EclipseNode builderType, List builderFields, ASTNode source) { List existing = new ArrayList(); @@ -779,18 +711,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { 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 . -// 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> extends Parent.ParentBuilder { - @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> extends Parent.ParentBuilder { + 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 { - @java.lang.SuppressWarnings("all") - private ChildBuilderImpl() { + private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder { + 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(); } -- cgit