aboutsummaryrefslogtreecommitdiff
path: root/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lombok/eclipse/handlers/HandleSuperBuilder.java')
-rw-r--r--src/core/lombok/eclipse/handlers/HandleSuperBuilder.java73
1 files changed, 49 insertions, 24 deletions
diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
index 6634d1c8..b1e7c419 100644
--- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
+++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java
@@ -57,6 +57,7 @@ import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference
import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedNameReference;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
+import org.eclipse.jdt.internal.compiler.ast.Receiver;
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
@@ -144,9 +145,9 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
generateBuilderMethod = true;
}
if (!checkName("buildMethodName", buildMethodName, annotationNode)) return;
-
+
boolean toBuilder = superbuilderAnnotation.toBuilder();
-
+
EclipseNode tdParent = annotationNode.up();
java.util.List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>();
@@ -233,7 +234,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
TypeReference extendsClause = td.superclass;
TypeReference superclassBuilderClass = null;
TypeReference[] typeArguments = new TypeReference[] {
- new SingleTypeReference(classGenericName.toCharArray(), 0),
+ new SingleTypeReference(classGenericName.toCharArray(), 0),
new SingleTypeReference(builderGenericName.toCharArray(), 0)
};
if (extendsClause instanceof QualifiedTypeReference) {
@@ -242,7 +243,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
String superclassBuilderClassName = builderClassNameTemplate.replace("*", superclassClassName);
char[][] tokens = Arrays.copyOf(qualifiedTypeReference.tokens, qualifiedTypeReference.tokens.length + 1);
- tokens[tokens.length] = superclassBuilderClassName.toCharArray();
+ tokens[tokens.length-1] = superclassBuilderClassName.toCharArray();
long[] poss = new long[tokens.length];
Arrays.fill(poss, p);
@@ -274,8 +275,10 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
// If there is no superclass, superclassBuilderClassExpression is still == null at this point.
// You can use it to check whether to inherit or not.
- generateBuilderBasedConstructor(cfv, tdParent, typeParams, builderFields, annotationNode, builderClassName,
- superclassBuilderClass != null);
+ if (!constructorExists(tdParent, builderClassName)) {
+ generateBuilderBasedConstructor(cfv, tdParent, typeParams, builderFields, annotationNode, builderClassName,
+ superclassBuilderClass != null);
+ }
// Create the abstract builder class, or reuse an existing one.
EclipseNode builderType = findInnerClass(tdParent, builderClassName);
@@ -330,14 +333,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
injectFieldAndMarkGenerated(builderType, cleanDecl);
}
-
+
if (toBuilder) {
// Generate $fillValuesFrom() method in the abstract builder.
injectMethod(builderType, generateFillValuesMethod(tdParent, superclassBuilderClass != null, builderGenericName, classGenericName, builderClassName, typeParams));
// Generate $fillValuesFromInstanceIntoBuilder() method in the builder implementation class.
injectMethod(builderType, generateStaticFillValuesMethod(tdParent, builderClassName, typeParams, builderFields, ast, superbuilderAnnotation.setterPrefix()));
}
-
+
// Generate abstract self() and build() methods in the abstract builder.
injectMethod(builderType, generateAbstractSelfMethod(cfv, tdParent, superclassBuilderClass != null, builderGenericName));
injectMethod(builderType, generateAbstractBuildMethod(cfv, builderType, buildMethodName, builderFields, superclassBuilderClass != null, classGenericName, ast));
@@ -352,7 +355,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>();
for (BuilderFieldData bfd : builderFields) {
for (EclipseNode f : bfd.createdFields) {
- fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true));
+ fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true, false));
}
}
// Let toString() call super.toString() if there is a superclass, so that it also shows fields from the superclass' builder.
@@ -383,22 +386,23 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
}
sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderImplType, annotationNode);
}
-
+
if (toBuilder) {
// Add the toBuilder() method to the annotated class.
switch (methodExists(TO_BUILDER_METHOD_NAME_STRING, tdParent, 0)) {
case EXISTS_BY_USER:
- annotationNode.addWarning("Not generating toBuilder() as it already exists.");
break;
case NOT_EXISTS:
injectMethod(tdParent, generateToBuilderMethod(cfv, builderClassName, builderImplClassName, tdParent, typeParams, ast));
+ break;
default:
// Should not happen.
}
}
-
+
// Create the self() and build() methods in the BuilderImpl.
injectMethod(builderImplType, generateSelfMethod(cfv, builderImplType, typeParams, p));
+
if (methodExists(buildMethodName, builderImplType, -1) == MemberExistsResult.NOT_EXISTS) {
injectMethod(builderImplType, generateBuildMethod(cfv, builderImplType, buildMethodName, returnType, builderFields, ast));
}
@@ -416,7 +420,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
}
}
}
-
+
private EclipseNode generateBuilderAbstractClass(EclipseNode tdParent, String builderClass,
TypeReference superclassBuilderClass, TypeParameter[] typeParams,
ASTNode source, String classGenericName, String builderGenericName) {
@@ -445,7 +449,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
builder.superclass = copyType(superclassBuilderClass, source);
builder.createDefaultConstructor(false, true);
-
+
builder.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
return injectType(tdParent, builder);
}
@@ -803,8 +807,8 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
out.modifiers = ClassFileConstants.AccProtected;
Annotation overrideAnn = makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, builderImplType.get());
- Annotation rrAnn = cfv.generateReturnsReceiver() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER): null;
- Annotation sefAnn = cfv.generatePure() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__PURE): null;
+ Annotation rrAnn = cfv.generateReturnsReceiver() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__RETURNS_RECEIVER) : null;
+ Annotation sefAnn = cfv.generatePure() ? generateNamedAnnotation(builderImplType.get(), CheckerFrameworkVersion.NAME__PURE) : null;
if (rrAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn, sefAnn};
else if (rrAnn != null) out.annotations = new Annotation[] {overrideAnn, rrAnn};
else if (sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn};
@@ -829,7 +833,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
if (overrideAnn != null && sefAnn != null) out.annotations = new Annotation[] {overrideAnn, sefAnn};
else if (overrideAnn != null) out.annotations = new Annotation[] {overrideAnn};
else if (sefAnn != null) out.annotations = new Annotation[] {sefAnn};
- out.arguments = HandleBuilder.generateBuildArgs(cfv, builderType, builderFields, source);
+ out.receiver = HandleBuilder.generateBuildReceiver(cfv, builderType, builderFields, source);
out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
return out;
}
@@ -854,7 +858,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
allocationStatement.arguments = new Expression[] {new ThisReference(0, 0)};
statements.add(new ReturnStatement(allocationStatement, 0, 0));
out.statements = statements.isEmpty() ? null : statements.toArray(new Statement[0]);
- out.arguments = HandleBuilder.generateBuildArgs(cfv, builderType, builderFields, source);
+ out.receiver = HandleBuilder.generateBuildReceiver(cfv, builderType, builderFields, source);
createRelevantNonNullAnnotation(builderType, out);
out.traverse(new SetGeneratedByVisitor(source), (ClassScope) null);
return out;
@@ -968,15 +972,14 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
MethodDeclaration setter = HandleSetter.createSetter(td, deprecate, fieldNode, setterName, paramName, nameOfSetFlag, returnType, returnStatement, ClassFileConstants.AccPublic,
sourceNode, methodAnnsList, annosOnParam != null ? Arrays.asList(copyAnnotations(source, annosOnParam)) : Collections.<Annotation>emptyList());
if (cfv.generateCalledMethods()) {
- Argument[] arr = setter.arguments == null ? new Argument[0] : setter.arguments;
- Argument[] newArr = new Argument[arr.length + 1];
- System.arraycopy(arr, 0, newArr, 1, arr.length);
- newArr[0] = new Argument(new char[] { 't', 'h', 'i', 's' }, 0, generateTypeReference(builderType, 0), Modifier.FINAL);
char[][] nameNotCalled = fromQualifiedName(CheckerFrameworkVersion.NAME__NOT_CALLED);
SingleMemberAnnotation ann = new SingleMemberAnnotation(new QualifiedTypeReference(nameNotCalled, poss(source, nameNotCalled.length)), source.sourceStart);
ann.memberValue = new StringLiteral(setterName.toCharArray(), 0, 0, 0);
- newArr[0].annotations = new Annotation[] {ann};
- setter.arguments = newArr;
+
+ QualifiedTypeReference typeReference = (QualifiedTypeReference) generateTypeReference(builderType, 0);
+ typeReference.annotations = new Annotation[typeReference.tokens.length][];
+ typeReference.annotations[0] = new Annotation[] {ann};
+ setter.receiver = new Receiver(new char[] { 't', 'h', 'i', 's' }, 0, typeReference, null, Modifier.FINAL);
}
injectMethod(builderType, setter);
}
@@ -1159,4 +1162,26 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
System.arraycopy(name, 0, out, prefix.length, name.length);
return out;
}
+
+ private boolean constructorExists(EclipseNode type, String builderClassName) {
+ if (type != null && type.get() instanceof TypeDeclaration) {
+ TypeDeclaration typeDecl = (TypeDeclaration)type.get();
+ if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) {
+ if (def instanceof ConstructorDeclaration) {
+ if ((def.bits & ASTNode.IsDefaultConstructor) != 0) continue;
+ if (!def.isConstructor()) continue;
+ if (isTolerate(type, def)) continue;
+ if (def.arguments.length != 1) continue;
+
+ // Cannot use typeMatches() here, because the parameter could be fully-qualified, partially-qualified, or not qualified.
+ // A string-compare of the last part should work. If it's a false-positive, users could still @Tolerate it.
+ char[] typeName = def.arguments[0].type.getLastToken();
+ if (builderClassName.equals(String.valueOf(typeName)))
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
}