lombok.eclipse.handlers.HandleConstructor Maven / Gradle / Ivy
/*
* Copyright (C) 2010-2021 The Project Lombok Authors.
*
* 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.core.handlers.HandlerUtil.*;
import static lombok.eclipse.Eclipse.*;
import static lombok.eclipse.handlers.EclipseHandlerUtil.*;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.ConfigurationKeys;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.core.AST.Kind;
import lombok.core.configuration.CheckerFrameworkVersion;
import lombok.core.AnnotationValues;
import lombok.eclipse.EclipseAnnotationHandler;
import lombok.eclipse.EclipseNode;
import lombok.eclipse.handlers.EclipseHandlerUtil.MemberExistsResult;
import lombok.spi.Provides;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
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.ArrayInitializer;
import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference;
import org.eclipse.jdt.internal.compiler.ast.Assignment;
import org.eclipse.jdt.internal.compiler.ast.CharLiteral;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.eclipse.jdt.internal.compiler.ast.DoubleLiteral;
import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
import org.eclipse.jdt.internal.compiler.ast.FloatLiteral;
import org.eclipse.jdt.internal.compiler.ast.IntLiteral;
import org.eclipse.jdt.internal.compiler.ast.LongLiteral;
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference;
import org.eclipse.jdt.internal.compiler.ast.ReturnStatement;
import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
import org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
import org.eclipse.jdt.internal.compiler.ast.ThisReference;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
public class HandleConstructor {
@Provides
public static class HandleNoArgsConstructor extends EclipseAnnotationHandler {
private static final String NAME = NoArgsConstructor.class.getSimpleName();
private HandleConstructor handleConstructor = new HandleConstructor();
@Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.NO_ARGS_CONSTRUCTOR_FLAG_USAGE, "@NoArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor");
EclipseNode typeNode = annotationNode.up();
if (!checkLegality(typeNode, annotationNode, NAME)) return;
NoArgsConstructor ann = annotation.getInstance();
AccessLevel level = ann.access();
String staticName = ann.staticName();
if (level == AccessLevel.NONE) return;
boolean force = ann.force();
List onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@NoArgsConstructor(onConstructor", annotationNode);
handleConstructor.generateConstructor(typeNode, level, Collections.emptyList(), force, staticName, SkipIfConstructorExists.NO, onConstructor, annotationNode);
}
}
@Provides
public static class HandleRequiredArgsConstructor extends EclipseAnnotationHandler {
private static final String NAME = RequiredArgsConstructor.class.getSimpleName();
private HandleConstructor handleConstructor = new HandleConstructor();
@Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.REQUIRED_ARGS_CONSTRUCTOR_FLAG_USAGE, "@RequiredArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor");
EclipseNode typeNode = annotationNode.up();
if (!checkLegality(typeNode, annotationNode, NAME)) return;
RequiredArgsConstructor ann = annotation.getInstance();
AccessLevel level = ann.access();
if (level == AccessLevel.NONE) return;
String staticName = ann.staticName();
if (annotation.isExplicit("suppressConstructorProperties")) {
annotationNode.addError("This deprecated feature is no longer supported. Remove it; you can create a lombok.config file with 'lombok.anyConstructor.suppressConstructorProperties = true'.");
}
List onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@RequiredArgsConstructor(onConstructor", annotationNode);
handleConstructor.generateConstructor(
typeNode, level, findRequiredFields(typeNode), false, staticName, SkipIfConstructorExists.NO,
onConstructor, annotationNode);
}
}
private static List findRequiredFields(EclipseNode typeNode) {
return findFields(typeNode, true);
}
private static List findFields(EclipseNode typeNode, boolean nullMarked) {
List fields = new ArrayList();
for (EclipseNode child : typeNode.down()) {
if (child.getKind() != Kind.FIELD) continue;
FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
if (!filterField(fieldDecl)) continue;
boolean isFinal = (fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0;
boolean isNonNull = nullMarked && hasNonNullAnnotations(child);
if ((isFinal || isNonNull) && fieldDecl.initialization == null) fields.add(child);
}
return fields;
}
static List findAllFields(EclipseNode typeNode) {
return findAllFields(typeNode, false);
}
static List findAllFields(EclipseNode typeNode, boolean evenFinalInitialized) {
List fields = new ArrayList();
for (EclipseNode child : typeNode.down()) {
if (child.getKind() != Kind.FIELD) continue;
FieldDeclaration fieldDecl = (FieldDeclaration) child.get();
if (!filterField(fieldDecl)) continue;
if (!evenFinalInitialized && ((fieldDecl.modifiers & ClassFileConstants.AccFinal) != 0) && fieldDecl.initialization != null) continue;
fields.add(child);
}
return fields;
}
@Provides
public static class HandleAllArgsConstructor extends EclipseAnnotationHandler {
private static final String NAME = AllArgsConstructor.class.getSimpleName();
private HandleConstructor handleConstructor = new HandleConstructor();
@Override public void handle(AnnotationValues annotation, Annotation ast, EclipseNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.ALL_ARGS_CONSTRUCTOR_FLAG_USAGE, "@AllArgsConstructor", ConfigurationKeys.ANY_CONSTRUCTOR_FLAG_USAGE, "any @xArgsConstructor");
EclipseNode typeNode = annotationNode.up();
if (!checkLegality(typeNode, annotationNode, NAME)) return;
AllArgsConstructor ann = annotation.getInstance();
AccessLevel level = ann.access();
if (level == AccessLevel.NONE) return;
String staticName = ann.staticName();
if (annotation.isExplicit("suppressConstructorProperties")) {
annotationNode.addError("This deprecated feature is no longer supported. Remove it; you can create a lombok.config file with 'lombok.anyConstructor.suppressConstructorProperties = true'.");
}
List onConstructor = unboxAndRemoveAnnotationParameter(ast, "onConstructor", "@AllArgsConstructor(onConstructor", annotationNode);
handleConstructor.generateConstructor(
typeNode, level, findAllFields(typeNode), false, staticName, SkipIfConstructorExists.NO,
onConstructor, annotationNode);
}
}
static boolean checkLegality(EclipseNode typeNode, EclipseNode errorNode, String name) {
if (!isClassOrEnum(typeNode)) {
errorNode.addError(name + " is only supported on a class or an enum.");
return false;
}
return true;
}
public enum SkipIfConstructorExists {
YES, NO, I_AM_BUILDER;
}
public void generateExtraNoArgsConstructor(EclipseNode typeNode, EclipseNode sourceNode) {
if (!isDirectDescendantOfObject(typeNode)) return;
Boolean v = typeNode.getAst().readConfiguration(ConfigurationKeys.NO_ARGS_CONSTRUCTOR_EXTRA_PRIVATE);
if (v == null || !v) return;
generate(typeNode, AccessLevel.PRIVATE, Collections.emptyList(), true, null, SkipIfConstructorExists.NO, Collections.emptyList(), sourceNode, true);
}
public void generateRequiredArgsConstructor(
EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists,
List onConstructor, EclipseNode sourceNode) {
generateConstructor(typeNode, level, findRequiredFields(typeNode), false, staticName, skipIfConstructorExists, onConstructor, sourceNode);
}
public void generateAllArgsConstructor(
EclipseNode typeNode, AccessLevel level, String staticName, SkipIfConstructorExists skipIfConstructorExists,
List onConstructor, EclipseNode sourceNode) {
generateConstructor(typeNode, level, findAllFields(typeNode), false, staticName, skipIfConstructorExists, onConstructor, sourceNode);
}
public void generateConstructor(
EclipseNode typeNode, AccessLevel level, List fieldsToParam, boolean forceDefaults, String staticName, SkipIfConstructorExists skipIfConstructorExists,
List onConstructor, EclipseNode sourceNode) {
generate(typeNode, level, fieldsToParam, forceDefaults, staticName, skipIfConstructorExists, onConstructor, sourceNode, false);
}
public void generate(
EclipseNode typeNode, AccessLevel level, List fieldsToParam, boolean forceDefaults, String staticName, SkipIfConstructorExists skipIfConstructorExists,
List onConstructor, EclipseNode sourceNode, boolean noArgs) {
ASTNode source = sourceNode.get();
boolean staticConstrRequired = staticName != null && !staticName.equals("");
if (skipIfConstructorExists != SkipIfConstructorExists.NO) {
for (EclipseNode child : typeNode.down()) {
if (child.getKind() == Kind.ANNOTATION) {
boolean skipGeneration = (annotationTypeMatches(NoArgsConstructor.class, child) ||
annotationTypeMatches(AllArgsConstructor.class, child) ||
annotationTypeMatches(RequiredArgsConstructor.class, child));
if (!skipGeneration && skipIfConstructorExists == SkipIfConstructorExists.YES) {
skipGeneration = annotationTypeMatches(Builder.class, child);
}
if (skipGeneration) {
if (staticConstrRequired) {
// @Data has asked us to generate a constructor, but we're going to skip this instruction, as an explicit 'make a constructor' annotation
// will take care of it. However, @Data also wants a specific static name; this will be ignored; the appropriate way to do this is to use
// the 'staticName' parameter of the @XArgsConstructor you've stuck on your type.
// We should warn that we're ignoring @Data's 'staticConstructor' param.
typeNode.addWarning(
"Ignoring static constructor name: explicit @XxxArgsConstructor annotation present; its `staticName` parameter will be used.",
source.sourceStart, source.sourceEnd);
}
return;
}
}
}
}
if (noArgs && noArgsConstructorExists(typeNode)) return;
if (!(skipIfConstructorExists != SkipIfConstructorExists.NO && constructorExists(typeNode) != MemberExistsResult.NOT_EXISTS)) {
ConstructorDeclaration constr = createConstructor(
staticConstrRequired ? AccessLevel.PRIVATE : level, typeNode, fieldsToParam, forceDefaults,
sourceNode, onConstructor);
injectMethod(typeNode, constr);
}
generateStaticConstructor(staticConstrRequired, typeNode, staticName, level, fieldsToParam, source);
}
private void generateStaticConstructor(boolean staticConstrRequired, EclipseNode typeNode, String staticName, AccessLevel level, Collection fields, ASTNode source) {
if (staticConstrRequired) {
MethodDeclaration staticConstr = createStaticConstructor(level, staticName, typeNode, fields, source);
injectMethod(typeNode, staticConstr);
}
}
private static boolean noArgsConstructorExists(EclipseNode node) {
node = EclipseHandlerUtil.upToTypeNode(node);
if (node != null && node.get() instanceof TypeDeclaration) {
TypeDeclaration typeDecl = (TypeDeclaration)node.get();
if (typeDecl.methods != null) for (AbstractMethodDeclaration def : typeDecl.methods) {
if (def instanceof ConstructorDeclaration) {
Argument[] arguments = ((ConstructorDeclaration) def).arguments;
if (arguments == null || arguments.length == 0) return true;
}
}
}
for (EclipseNode child : node.down()) {
if (annotationTypeMatches(NoArgsConstructor.class, child)) return true;
if (annotationTypeMatches(RequiredArgsConstructor.class, child) && findRequiredFields(node).isEmpty()) return true;
if (annotationTypeMatches(AllArgsConstructor.class, child) && findAllFields(node).isEmpty()) return true;
}
return false;
}
private static final char[][] JAVA_BEANS_CONSTRUCTORPROPERTIES = new char[][] { "java".toCharArray(), "beans".toCharArray(), "ConstructorProperties".toCharArray() };
public static Annotation[] createConstructorProperties(ASTNode source, Collection fields) {
if (fields.isEmpty()) return null;
int pS = source.sourceStart, pE = source.sourceEnd;
long p = (long) pS << 32 | pE;
long[] poss = new long[3];
Arrays.fill(poss, p);
QualifiedTypeReference constructorPropertiesType = new QualifiedTypeReference(JAVA_BEANS_CONSTRUCTORPROPERTIES, poss);
setGeneratedBy(constructorPropertiesType, source);
SingleMemberAnnotation ann = new SingleMemberAnnotation(constructorPropertiesType, pS);
ann.declarationSourceEnd = pE;
ArrayInitializer fieldNames = new ArrayInitializer();
fieldNames.sourceStart = pS;
fieldNames.sourceEnd = pE;
fieldNames.expressions = new Expression[fields.size()];
int ctr = 0;
for (EclipseNode field : fields) {
char[] fieldName = removePrefixFromField(field);
fieldNames.expressions[ctr] = new StringLiteral(fieldName, pS, pE, 0);
setGeneratedBy(fieldNames.expressions[ctr], source);
ctr++;
}
ann.memberValue = fieldNames;
setGeneratedBy(ann, source);
setGeneratedBy(ann.memberValue, source);
return new Annotation[] { ann };
}
private static final char[] DEFAULT_PREFIX = {'$', 'd', 'e', 'f', 'a', 'u', 'l', 't', '$'};
private static final char[] prefixWith(char[] prefix, char[] name) {
char[] out = new char[prefix.length + name.length];
System.arraycopy(prefix, 0, out, 0, prefix.length);
System.arraycopy(name, 0, out, prefix.length, name.length);
return out;
}
@SuppressWarnings("deprecation") public static ConstructorDeclaration createConstructor(
AccessLevel level, EclipseNode type, Collection fieldsToParam, boolean forceDefaults,
EclipseNode sourceNode, List 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;
List fieldsToDefault = fieldsNeedingBuilderDefaults(type, fieldsToParam);
List fieldsToExplicit = forceDefaults ? fieldsNeedingExplicitDefaults(type, fieldsToParam) : Collections.emptyList();
boolean addConstructorProperties;
if (fieldsToParam.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 params = new ArrayList();
List assigns = new ArrayList();
List nullChecks = new ArrayList();
for (EclipseNode fieldNode : fieldsToParam) {
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 = 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);
long fieldPos = (((long) field.sourceStart) << 32) | field.sourceEnd;
Argument parameter = new Argument(fieldName, fieldPos, copyType(field.type, source), Modifier.FINAL);
Annotation[] copyableAnnotations = findCopyableAnnotations(fieldNode);
if (hasNonNullAnnotations(fieldNode)) {
Statement nullCheck = generateNullCheck(parameter, sourceNode, null);
if (nullCheck != null) nullChecks.add(nullCheck);
}
parameter.annotations = copyAnnotations(source, copyableAnnotations);
params.add(parameter);
}
for (EclipseNode fieldNode : fieldsToExplicit) {
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
char[] rawName = field.name;
FieldReference thisX = new FieldReference(rawName, p);
int s = (int) (p >> 32);
int e = (int) p;
thisX.receiver = new ThisReference(s, e);
Expression assignmentExpr = getDefaultExpr(field.type, s, e);
Assignment assignment = new Assignment(thisX, assignmentExpr, (int) p);
assignment.sourceStart = (int) (p >> 32); assignment.sourceEnd = assignment.statementEnd = (int) (p >> 32);
assigns.add(assignment);
}
for (EclipseNode fieldNode : fieldsToDefault) {
FieldDeclaration field = (FieldDeclaration) fieldNode.get();
char[] rawName = field.name;
FieldReference thisX = new FieldReference(rawName, p);
int s = (int) (p >> 32);
int e = (int) p;
thisX.receiver = new ThisReference(s, e);
MessageSend inv = new MessageSend();
inv.sourceStart = source.sourceStart;
inv.sourceEnd = source.sourceEnd;
inv.receiver = new SingleNameReference(((TypeDeclaration) type.get()).name, 0L);
inv.selector = prefixWith(DEFAULT_PREFIX, removePrefixFromField(fieldNode));
Assignment assignment = new Assignment(thisX, inv, (int) p);
assignment.sourceStart = (int) (p >> 32); assignment.sourceEnd = assignment.statementEnd = (int) (p >> 32);
assigns.add(assignment);
}
nullChecks.addAll(assigns);
constructor.statements = nullChecks.isEmpty() ? null : nullChecks.toArray(new Statement[0]);
constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[0]);
/* Generate annotations that must be put on the generated method, and attach them. */ {
Annotation[] constructorProperties = null;
if (addConstructorProperties && !isLocalType(type)) constructorProperties = createConstructorProperties(source, fieldsToParam);
constructor.annotations = copyAnnotations(source,
onConstructor.toArray(new Annotation[0]),
constructorProperties);
}
constructor.traverse(new SetGeneratedByVisitor(source), typeDeclaration.scope);
return constructor;
}
private static List fieldsNeedingBuilderDefaults(EclipseNode type, Collection fieldsToParam) {
List out = new ArrayList();
top:
for (EclipseNode node : type.down()) {
if (node.getKind() != Kind.FIELD) continue top;
FieldDeclaration fd = (FieldDeclaration) node.get();
if ((fd.modifiers & ClassFileConstants.AccStatic) != 0) continue top;
for (EclipseNode ftp : fieldsToParam) if (node == ftp) continue top;
if (EclipseHandlerUtil.hasAnnotation(Builder.Default.class, node)) out.add(node);
}
return out;
}
private static List fieldsNeedingExplicitDefaults(EclipseNode type, Collection fieldsToParam) {
List out = new ArrayList();
top:
for (EclipseNode node : type.down()) {
if (node.getKind() != Kind.FIELD) continue top;
FieldDeclaration fd = (FieldDeclaration) node.get();
if (fd.initialization != null) continue top;
if ((fd.modifiers & ClassFileConstants.AccFinal) == 0) continue top;
if ((fd.modifiers & ClassFileConstants.AccStatic) != 0) continue top;
for (EclipseNode ftp : fieldsToParam) if (node == ftp) continue top;
if (EclipseHandlerUtil.hasAnnotation(Builder.Default.class, node)) continue top;
out.add(node);
}
return out;
}
private static Expression getDefaultExpr(TypeReference type, int s, int e) {
boolean array = type instanceof ArrayTypeReference;
if (array) return new NullLiteral(s, e);
char[] lastToken = type.getLastToken();
if (Arrays.equals(TypeConstants.BOOLEAN, lastToken)) return new FalseLiteral(s, e);
if (Arrays.equals(TypeConstants.CHAR, lastToken)) return new CharLiteral(new char[] {'\'', '\\', '0', '\''}, s, e);
if (Arrays.equals(TypeConstants.BYTE, lastToken) || Arrays.equals(TypeConstants.SHORT, lastToken) ||
Arrays.equals(TypeConstants.INT, lastToken)) return IntLiteral.buildIntLiteral(new char[] {'0'}, s, e);
if (Arrays.equals(TypeConstants.LONG, lastToken)) return LongLiteral.buildLongLiteral(new char[] {'0', 'L'}, s, e);
if (Arrays.equals(TypeConstants.FLOAT, lastToken)) return new FloatLiteral(new char[] {'0', 'F'}, s, e);
if (Arrays.equals(TypeConstants.DOUBLE, lastToken)) return new DoubleLiteral(new char[] {'0', 'D'}, s, e);
return new NullLiteral(s, e);
}
public static boolean isLocalType(EclipseNode type) {
Kind kind = type.up().getKind();
if (kind == Kind.COMPILATION_UNIT) return false;
if (kind == Kind.TYPE) return isLocalType(type.up());
return true;
}
public MethodDeclaration createStaticConstructor(AccessLevel level, String name, EclipseNode type, Collection 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);
constructor.modifiers = toEclipseModifier(level) | ClassFileConstants.AccStatic;
TypeDeclaration typeDecl = (TypeDeclaration) type.get();
constructor.returnType = EclipseHandlerUtil.namePlusTypeParamsToTypeReference(type, typeDecl.typeParameters, p);
constructor.annotations = null;
if (getCheckerFrameworkVersion(type).generateUnique()) {
int len = constructor.returnType.getTypeName().length;
constructor.returnType.annotations = new Annotation[len][];
constructor.returnType.annotations[len - 1] = new Annotation[] {generateNamedAnnotation(source, CheckerFrameworkVersion.NAME__UNIQUE)};
}
constructor.selector = name.toCharArray();
constructor.thrownExceptions = null;
constructor.typeParameters = copyTypeParams(((TypeDeclaration) type.get()).typeParameters, source);
constructor.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
constructor.bodyStart = constructor.declarationSourceStart = constructor.sourceStart = source.sourceStart;
constructor.bodyEnd = constructor.declarationSourceEnd = constructor.sourceEnd = source.sourceEnd;
List params = new ArrayList();
List assigns = new ArrayList();
AllocationExpression statement = new AllocationExpression();
statement.sourceStart = pS; statement.sourceEnd = pE;
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);
assigns.add(nameRef);
Argument parameter = new Argument(field.name, fieldPos, copyType(field.type, source), Modifier.FINAL);
parameter.annotations = copyAnnotations(source, findCopyableAnnotations(fieldNode));
params.add(parameter);
}
statement.arguments = assigns.isEmpty() ? null : assigns.toArray(new Expression[0]);
constructor.arguments = params.isEmpty() ? null : params.toArray(new Argument[0]);
constructor.statements = new Statement[] { new ReturnStatement(statement, (int) (p >> 32), (int)p) };
createRelevantNonNullAnnotation(type, constructor);
constructor.traverse(new SetGeneratedByVisitor(source), typeDecl.scope);
return constructor;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy