use of org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration in project lombok by rzwitserloot.
the class HandleUtilityClass method createPrivateDefaultConstructor.
private void createPrivateDefaultConstructor(EclipseNode typeNode, EclipseNode sourceNode) {
ASTNode source = sourceNode.get();
TypeDeclaration typeDeclaration = ((TypeDeclaration) typeNode.get());
long p = (long) source.sourceStart << 32 | source.sourceEnd;
ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) typeNode.top().get()).compilationResult);
constructor.modifiers = ClassFileConstants.AccPrivate;
constructor.selector = typeDeclaration.name;
constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
constructor.constructorCall.sourceStart = source.sourceStart;
constructor.constructorCall.sourceEnd = source.sourceEnd;
constructor.thrownExceptions = null;
constructor.typeParameters = null;
constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart;
constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd;
constructor.arguments = null;
AllocationExpression exception = new AllocationExpression();
setGeneratedBy(exception, source);
long[] ps = new long[JAVA_LANG_UNSUPPORTED_OPERATION_EXCEPTION.length];
Arrays.fill(ps, p);
exception.type = new QualifiedTypeReference(JAVA_LANG_UNSUPPORTED_OPERATION_EXCEPTION, ps);
setGeneratedBy(exception.type, source);
exception.arguments = new Expression[] { new StringLiteral(UNSUPPORTED_MESSAGE, source.sourceStart, source.sourceEnd, 0) };
setGeneratedBy(exception.arguments[0], source);
ThrowStatement throwStatement = new ThrowStatement(exception, source.sourceStart, source.sourceEnd);
setGeneratedBy(throwStatement, source);
constructor.statements = new Statement[] { throwStatement };
injectMethod(typeNode, constructor);
}
use of org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration in project lombok by rzwitserloot.
the class EclipseAST method buildMethod.
private EclipseNode buildMethod(AbstractMethodDeclaration method) {
if (setAndGetAsHandled(method))
return null;
List<EclipseNode> childNodes = new ArrayList<EclipseNode>();
childNodes.addAll(buildArguments(method.arguments));
if (method instanceof ConstructorDeclaration) {
ConstructorDeclaration constructor = (ConstructorDeclaration) method;
addIfNotNull(childNodes, buildStatement(constructor.constructorCall));
}
childNodes.addAll(buildStatements(method.statements));
childNodes.addAll(buildAnnotations(method.annotations, false));
return putInMap(new EclipseNode(this, method, childNodes, Kind.METHOD));
}
use of org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration in project lombok by rzwitserloot.
the class EclipseHandlerUtil method injectMethod.
/**
* Inserts a method into an existing type. The type must represent a {@code TypeDeclaration}.
*/
public static EclipseNode injectMethod(EclipseNode type, AbstractMethodDeclaration method) {
method.annotations = addSuppressWarningsAll(type, method, method.annotations);
method.annotations = addGenerated(type, method, method.annotations);
TypeDeclaration parent = (TypeDeclaration) type.get();
if (parent.methods == null) {
parent.methods = new AbstractMethodDeclaration[1];
parent.methods[0] = method;
} else {
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) {
EclipseNode tossMe = type.getNodeFor(parent.methods[i]);
AbstractMethodDeclaration[] withoutGeneratedConstructor = new AbstractMethodDeclaration[parent.methods.length - 1];
System.arraycopy(parent.methods, 0, withoutGeneratedConstructor, 0, i);
System.arraycopy(parent.methods, i + 1, withoutGeneratedConstructor, i, parent.methods.length - i - 1);
parent.methods = withoutGeneratedConstructor;
if (tossMe != null)
tossMe.up().removeChild(tossMe);
break;
}
}
}
// We insert the method in the last position of the methods registered to the type
// When changing this behavior, this may trigger issue #155 and #377
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;
}
return type.add(method, Kind.METHOD);
}
use of org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration in project lombok by rzwitserloot.
the class HandleBuilder method handle.
@Override
public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
long p = (long) ast.sourceStart << 32 | ast.sourceEnd;
Builder builderInstance = annotation.getInstance();
// These exist just to support the 'old' lombok.experimental.Builder, which had these properties. lombok.Builder no longer has them.
boolean fluent = toBoolean(annotation.getActualExpression("fluent"), true);
boolean chain = toBoolean(annotation.getActualExpression("chain"), true);
String builderMethodName = builderInstance.builderMethodName();
String buildMethodName = builderInstance.buildMethodName();
String builderClassName = builderInstance.builderClassName();
String toBuilderMethodName = "toBuilder";
boolean toBuilder = builderInstance.toBuilder();
List<char[]> typeArgsForToBuilder = null;
if (builderMethodName == null)
builderMethodName = "builder";
if (buildMethodName == null)
builderMethodName = "build";
if (builderClassName == null)
builderClassName = "";
if (!checkName("builderMethodName", builderMethodName, annotationNode))
return;
if (!checkName("buildMethodName", buildMethodName, annotationNode))
return;
if (!builderClassName.isEmpty()) {
if (!checkName("builderClassName", builderClassName, annotationNode))
return;
}
EclipseNode parent = annotationNode.up();
List<BuilderFieldData> builderFields = new ArrayList<BuilderFieldData>();
TypeReference returnType;
TypeParameter[] typeParams;
TypeReference[] thrownExceptions;
char[] nameOfStaticBuilderMethod;
EclipseNode tdParent;
EclipseNode fillParametersFrom = parent.get() instanceof AbstractMethodDeclaration ? parent : null;
boolean addCleaning = false;
boolean isStatic = true;
if (parent.get() instanceof TypeDeclaration) {
tdParent = parent;
TypeDeclaration td = (TypeDeclaration) tdParent.get();
List<EclipseNode> allFields = new ArrayList<EclipseNode>();
boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent));
for (EclipseNode fieldNode : HandleConstructor.findAllFields(tdParent, true)) {
FieldDeclaration fd = (FieldDeclaration) fieldNode.get();
EclipseNode isDefault = findAnnotation(Builder.Default.class, fieldNode);
boolean isFinal = ((fd.modifiers & ClassFileConstants.AccFinal) != 0) || (valuePresent && !hasAnnotation(NonFinal.class, fieldNode));
BuilderFieldData bfd = new BuilderFieldData();
bfd.rawName = fieldNode.getName().toCharArray();
bfd.name = removePrefixFromField(fieldNode);
bfd.type = fd.type;
bfd.singularData = getSingularData(fieldNode, ast);
bfd.originalFieldNode = fieldNode;
if (bfd.singularData != null && isDefault != null) {
isDefault.addError("@Builder.Default and @Singular cannot be mixed.");
isDefault = null;
}
if (fd.initialization == null && isDefault != null) {
isDefault.addWarning("@Builder.Default requires an initializing expression (' = something;').");
isDefault = null;
}
if (fd.initialization != null && isDefault == null) {
if (isFinal)
continue;
fieldNode.addWarning("@Builder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.");
}
if (isDefault != null) {
bfd.nameOfDefaultProvider = prefixWith(DEFAULT_PREFIX, bfd.name);
bfd.nameOfSetFlag = prefixWith(bfd.name, SET_PREFIX);
MethodDeclaration md = generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast);
if (md != null)
injectMethod(tdParent, md);
}
addObtainVia(bfd, fieldNode);
builderFields.add(bfd);
allFields.add(fieldNode);
}
handleConstructor.generateConstructor(tdParent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, Collections.<Annotation>emptyList(), annotationNode);
returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
typeParams = td.typeParameters;
thrownExceptions = null;
nameOfStaticBuilderMethod = null;
if (builderClassName.isEmpty())
builderClassName = new String(td.name) + "Builder";
} else if (parent.get() instanceof ConstructorDeclaration) {
ConstructorDeclaration cd = (ConstructorDeclaration) parent.get();
if (cd.typeParameters != null && cd.typeParameters.length > 0) {
annotationNode.addError("@Builder is not supported on constructors with constructor type parameters.");
return;
}
tdParent = parent.up();
TypeDeclaration td = (TypeDeclaration) tdParent.get();
returnType = namePlusTypeParamsToTypeReference(td.name, td.typeParameters, p);
typeParams = td.typeParameters;
thrownExceptions = cd.thrownExceptions;
nameOfStaticBuilderMethod = null;
if (builderClassName.isEmpty())
builderClassName = new String(cd.selector) + "Builder";
} else if (parent.get() instanceof MethodDeclaration) {
MethodDeclaration md = (MethodDeclaration) parent.get();
tdParent = parent.up();
isStatic = md.isStatic();
if (toBuilder) {
final String TO_BUILDER_NOT_SUPPORTED = "@Builder(toBuilder=true) is only supported if you return your own type.";
char[] token;
char[][] pkg = null;
if (md.returnType.dimensions() > 0) {
annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
return;
}
if (md.returnType instanceof SingleTypeReference) {
token = ((SingleTypeReference) md.returnType).token;
} else if (md.returnType instanceof QualifiedTypeReference) {
pkg = ((QualifiedTypeReference) md.returnType).tokens;
token = pkg[pkg.length];
char[][] pkg_ = new char[pkg.length - 1][];
System.arraycopy(pkg, 0, pkg_, 0, pkg_.length);
pkg = pkg_;
} else {
annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
return;
}
if (pkg != null && !equals(parent.getPackageDeclaration(), pkg)) {
annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
return;
}
if (tdParent == null || !equals(tdParent.getName(), token)) {
annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
return;
}
TypeParameter[] tpOnType = ((TypeDeclaration) tdParent.get()).typeParameters;
TypeParameter[] tpOnMethod = md.typeParameters;
TypeReference[][] tpOnRet_ = null;
if (md.returnType instanceof ParameterizedSingleTypeReference) {
tpOnRet_ = new TypeReference[1][];
tpOnRet_[0] = ((ParameterizedSingleTypeReference) md.returnType).typeArguments;
} else if (md.returnType instanceof ParameterizedQualifiedTypeReference) {
tpOnRet_ = ((ParameterizedQualifiedTypeReference) md.returnType).typeArguments;
}
if (tpOnRet_ != null)
for (int i = 0; i < tpOnRet_.length - 1; i++) {
if (tpOnRet_[i] != null && tpOnRet_[i].length > 0) {
annotationNode.addError("@Builder(toBuilder=true) is not supported if returning a type with generics applied to an intermediate.");
return;
}
}
TypeReference[] tpOnRet = tpOnRet_ == null ? null : tpOnRet_[tpOnRet_.length - 1];
typeArgsForToBuilder = new ArrayList<char[]>();
if (tpOnMethod != null)
for (TypeParameter onMethod : tpOnMethod) {
int pos = -1;
if (tpOnRet != null)
for (int i = 0; i < tpOnRet.length; i++) {
if (tpOnRet[i].getClass() != SingleTypeReference.class)
continue;
if (!Arrays.equals(((SingleTypeReference) tpOnRet[i]).token, onMethod.name))
continue;
pos = i;
}
if (pos == -1 || tpOnType == null || tpOnType.length <= pos) {
annotationNode.addError("@Builder(toBuilder=true) requires that each type parameter on the static method is part of the typeargs of the return value. Type parameter " + new String(onMethod.name) + " is not part of the return type.");
return;
}
typeArgsForToBuilder.add(tpOnType[pos].name);
}
}
returnType = copyType(md.returnType, ast);
typeParams = md.typeParameters;
thrownExceptions = md.thrownExceptions;
nameOfStaticBuilderMethod = md.selector;
if (builderClassName.isEmpty()) {
char[] token;
if (md.returnType instanceof QualifiedTypeReference) {
char[][] tokens = ((QualifiedTypeReference) md.returnType).tokens;
token = tokens[tokens.length - 1];
} else if (md.returnType instanceof SingleTypeReference) {
token = ((SingleTypeReference) md.returnType).token;
if (!(md.returnType instanceof ParameterizedSingleTypeReference) && typeParams != null) {
for (TypeParameter tp : typeParams) {
if (Arrays.equals(tp.name, token)) {
annotationNode.addError("@Builder requires specifying 'builderClassName' if used on methods with a type parameter as return type.");
return;
}
}
}
} else {
annotationNode.addError("Unexpected kind of return type on annotated method. Specify 'builderClassName' to solve this problem.");
return;
}
if (Character.isLowerCase(token[0])) {
char[] newToken = new char[token.length];
System.arraycopy(token, 1, newToken, 1, token.length - 1);
newToken[0] = Character.toTitleCase(token[0]);
token = newToken;
}
builderClassName = new String(token) + "Builder";
}
} else {
annotationNode.addError("@Builder is only supported on types, constructors, and methods.");
return;
}
if (fillParametersFrom != null) {
for (EclipseNode param : fillParametersFrom.down()) {
if (param.getKind() != Kind.ARGUMENT)
continue;
BuilderFieldData bfd = new BuilderFieldData();
Argument arg = (Argument) param.get();
bfd.rawName = arg.name;
bfd.name = arg.name;
bfd.type = arg.type;
bfd.singularData = getSingularData(param, ast);
bfd.originalFieldNode = param;
addObtainVia(bfd, param);
builderFields.add(bfd);
}
}
EclipseNode builderType = findInnerClass(tdParent, builderClassName);
if (builderType == null) {
builderType = makeBuilderClass(isStatic, tdParent, builderClassName, typeParams, ast);
} else {
TypeDeclaration builderTypeDeclaration = (TypeDeclaration) builderType.get();
if (isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) {
annotationNode.addError("Existing Builder must be a static inner class.");
return;
} else if (!isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) != 0) {
annotationNode.addError("Existing Builder must be a non-static inner class.");
return;
}
sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(builderType, annotationNode);
/* generate errors for @Singular BFDs that have one already defined node. */
{
for (BuilderFieldData bfd : builderFields) {
SingularData sd = bfd.singularData;
if (sd == null)
continue;
EclipseSingularizer singularizer = sd.getSingularizer();
if (singularizer == null)
continue;
if (singularizer.checkForAlreadyExistingNodesAndGenerateError(builderType, sd)) {
bfd.singularData = null;
}
}
}
}
for (BuilderFieldData bfd : builderFields) {
if (bfd.singularData != null && bfd.singularData.getSingularizer() != null) {
if (bfd.singularData.getSingularizer().requiresCleaning()) {
addCleaning = true;
break;
}
}
if (bfd.obtainVia != null) {
if (bfd.obtainVia.field().isEmpty() == bfd.obtainVia.method().isEmpty()) {
bfd.obtainViaNode.addError("The syntax is either @ObtainVia(field = \"fieldName\") or @ObtainVia(method = \"methodName\").");
return;
}
if (bfd.obtainVia.method().isEmpty() && bfd.obtainVia.isStatic()) {
bfd.obtainViaNode.addError("@ObtainVia(isStatic = true) is not valid unless 'method' has been set.");
return;
}
}
}
generateBuilderFields(builderType, builderFields, ast);
if (addCleaning) {
FieldDeclaration cleanDecl = new FieldDeclaration(CLEAN_FIELD_NAME, 0, -1);
cleanDecl.declarationSourceEnd = -1;
cleanDecl.modifiers = ClassFileConstants.AccPrivate;
cleanDecl.type = TypeReference.baseTypeReference(TypeIds.T_boolean, 0);
injectFieldAndMarkGenerated(builderType, cleanDecl);
}
if (constructorExists(builderType) == MemberExistsResult.NOT_EXISTS) {
ConstructorDeclaration cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, builderType, Collections.<EclipseNode>emptyList(), false, annotationNode, Collections.<Annotation>emptyList());
if (cd != null)
injectMethod(builderType, cd);
}
for (BuilderFieldData bfd : builderFields) {
makeSetterMethodsForBuilder(builderType, bfd, annotationNode, fluent, chain);
}
if (methodExists(buildMethodName, builderType, -1) == MemberExistsResult.NOT_EXISTS) {
MethodDeclaration md = generateBuildMethod(tdParent, isStatic, buildMethodName, nameOfStaticBuilderMethod, returnType, builderFields, builderType, thrownExceptions, addCleaning, ast);
if (md != null)
injectMethod(builderType, md);
}
if (methodExists("toString", builderType, 0) == MemberExistsResult.NOT_EXISTS) {
List<EclipseNode> fieldNodes = new ArrayList<EclipseNode>();
for (BuilderFieldData bfd : builderFields) {
fieldNodes.addAll(bfd.createdFields);
}
MethodDeclaration md = HandleToString.createToString(builderType, fieldNodes, true, false, ast, FieldAccess.ALWAYS_FIELD);
if (md != null)
injectMethod(builderType, md);
}
if (addCleaning) {
MethodDeclaration cleanMethod = generateCleanMethod(builderFields, builderType, ast);
if (cleanMethod != null)
injectMethod(builderType, cleanMethod);
}
if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) {
MethodDeclaration md = generateBuilderMethod(isStatic, builderMethodName, builderClassName, tdParent, typeParams, ast);
if (md != null)
injectMethod(tdParent, md);
}
if (toBuilder)
switch(methodExists(toBuilderMethodName, tdParent, 0)) {
case EXISTS_BY_USER:
annotationNode.addWarning("Not generating toBuilder() as it already exists.");
break;
case NOT_EXISTS:
TypeParameter[] tps = typeParams;
if (typeArgsForToBuilder != null) {
tps = new TypeParameter[typeArgsForToBuilder.size()];
for (int i = 0; i < tps.length; i++) {
tps[i] = new TypeParameter();
tps[i].name = typeArgsForToBuilder.get(i);
}
}
MethodDeclaration md = generateToBuilderMethod(toBuilderMethodName, builderClassName, tdParent, tps, builderFields, fluent, ast);
if (md != null)
injectMethod(tdParent, md);
}
}
use of org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration in project lombok by rzwitserloot.
the class HandleConstructor method createConstructor.
@SuppressWarnings("deprecation")
public static ConstructorDeclaration createConstructor(AccessLevel level, EclipseNode type, Collection<EclipseNode> fields, boolean allToDefault, EclipseNode sourceNode, List<Annotation> onConstructor) {
ASTNode source = sourceNode.get();
TypeDeclaration typeDeclaration = ((TypeDeclaration) type.get());
long p = (long) source.sourceStart << 32 | source.sourceEnd;
boolean isEnum = (((TypeDeclaration) type.get()).modifiers & ClassFileConstants.AccEnum) != 0;
if (isEnum)
level = AccessLevel.PRIVATE;
boolean addConstructorProperties;
if (fields.isEmpty()) {
addConstructorProperties = false;
} else {
Boolean v = type.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_ADD_CONSTRUCTOR_PROPERTIES);
addConstructorProperties = v != null ? v.booleanValue() : Boolean.FALSE.equals(type.getAst().readConfiguration(ConfigurationKeys.ANY_CONSTRUCTOR_SUPPRESS_CONSTRUCTOR_PROPERTIES));
}
ConstructorDeclaration constructor = new ConstructorDeclaration(((CompilationUnitDeclaration) type.top().get()).compilationResult);
constructor.modifiers = toEclipseModifier(level);
constructor.selector = typeDeclaration.name;
constructor.constructorCall = new ExplicitConstructorCall(ExplicitConstructorCall.ImplicitSuper);
constructor.constructorCall.sourceStart = source.sourceStart;
constructor.constructorCall.sourceEnd = source.sourceEnd;
constructor.thrownExceptions = null;
constructor.typeParameters = null;
constructor.bits |= 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();
char[] rawName = field.name;
char[] fieldName = removePrefixFromField(fieldNode);
FieldReference thisX = new FieldReference(rawName, p);
int s = (int) (p >> 32);
int e = (int) p;
thisX.receiver = new ThisReference(s, e);
Expression assignmentExpr = allToDefault ? getDefaultExpr(field.type, s, e) : new SingleNameReference(fieldName, p);
Assignment assignment = new Assignment(thisX, assignmentExpr, (int) p);
assignment.sourceStart = (int) (p >> 32);
assignment.sourceEnd = assignment.statementEnd = (int) (p >> 32);
assigns.add(assignment);
if (!allToDefault) {
long fieldPos = (((long) field.sourceStart) << 32) | field.sourceEnd;
Argument parameter = new Argument(fieldName, fieldPos, copyType(field.type, source), Modifier.FINAL);
Annotation[] nonNulls = findAnnotations(field, NON_NULL_PATTERN);
Annotation[] nullables = findAnnotations(field, NULLABLE_PATTERN);
if (nonNulls.length != 0) {
Statement nullCheck = generateNullCheck(parameter, sourceNode);
if (nullCheck != null)
nullChecks.add(nullCheck);
}
parameter.annotations = copyAnnotations(source, nonNulls, nullables);
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()]);
/* Generate annotations that must be put on the generated method, and attach them. */
{
Annotation[] constructorProperties = null;
if (!allToDefault && addConstructorProperties && !isLocalType(type)) {
constructorProperties = createConstructorProperties(source, fields);
}
constructor.annotations = copyAnnotations(source, onConstructor.toArray(new Annotation[0]), constructorProperties);
}
constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope);
return constructor;
}
Aggregations