use of lombok.core.handlers.InclusionExclusionUtils.Included in project lombok by rzwitserloot.
the class HandleEqualsAndHashCode method handle.
@Override
public void handle(AnnotationValues<EqualsAndHashCode> annotation, JCAnnotation ast, JavacNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.EQUALS_AND_HASH_CODE_FLAG_USAGE, "@EqualsAndHashCode");
deleteAnnotationIfNeccessary(annotationNode, EqualsAndHashCode.class);
deleteImportFromCompilationUnit(annotationNode, CacheStrategy.class.getName());
EqualsAndHashCode ann = annotation.getInstance();
java.util.List<Included<JavacNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(annotationNode.up(), annotation, annotationNode);
JavacNode typeNode = annotationNode.up();
List<JCAnnotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@EqualsAndHashCode(onParam", annotationNode);
Boolean callSuper = ann.callSuper();
if (!annotation.isExplicit("callSuper"))
callSuper = null;
Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
boolean cacheHashCode = ann.cacheStrategy() == CacheStrategy.LAZY;
generateMethods(typeNode, annotationNode, members, callSuper, true, cacheHashCode, fieldAccess, onParam);
}
use of lombok.core.handlers.InclusionExclusionUtils.Included in project lombok by rzwitserloot.
the class HandleToString method handle.
@Override
public void handle(AnnotationValues<ToString> annotation, JCAnnotation ast, JavacNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.TO_STRING_FLAG_USAGE, "@ToString");
deleteAnnotationIfNeccessary(annotationNode, ToString.class);
ToString ann = annotation.getInstance();
boolean onlyExplicitlyIncluded = annotationNode.getAst().getBooleanAnnotationValue(annotation, "onlyExplicitlyIncluded", ConfigurationKeys.TO_STRING_ONLY_EXPLICITLY_INCLUDED);
java.util.List<Included<JavacNode, ToString.Include>> members = InclusionExclusionUtils.handleToStringMarking(annotationNode.up(), onlyExplicitlyIncluded, annotation, annotationNode);
if (members == null)
return;
Boolean callSuper = ann.callSuper();
if (!annotation.isExplicit("callSuper"))
callSuper = null;
Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS);
boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
boolean includeFieldNames = annotationNode.getAst().getBooleanAnnotationValue(annotation, "includeFieldNames", ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES);
generateToString(annotationNode.up(), annotationNode, members, includeFieldNames, callSuper, true, fieldAccess);
}
use of lombok.core.handlers.InclusionExclusionUtils.Included in project lombok by rzwitserloot.
the class HandleEqualsAndHashCode method handle.
@Override
public void handle(AnnotationValues<EqualsAndHashCode> annotation, Annotation ast, EclipseNode annotationNode) {
handleFlagUsage(annotationNode, ConfigurationKeys.EQUALS_AND_HASH_CODE_FLAG_USAGE, "@EqualsAndHashCode");
EqualsAndHashCode ann = annotation.getInstance();
List<Included<EclipseNode, EqualsAndHashCode.Include>> members = InclusionExclusionUtils.handleEqualsAndHashCodeMarking(annotationNode.up(), annotation, annotationNode);
if (members == null)
return;
List<Annotation> onParam = unboxAndRemoveAnnotationParameter(ast, "onParam", "@EqualsAndHashCode(onParam", annotationNode);
Boolean callSuper = ann.callSuper();
if (!annotation.isExplicit("callSuper"))
callSuper = null;
Boolean doNotUseGettersConfiguration = annotationNode.getAst().readConfiguration(ConfigurationKeys.EQUALS_AND_HASH_CODE_DO_NOT_USE_GETTERS);
boolean doNotUseGetters = annotation.isExplicit("doNotUseGetters") || doNotUseGettersConfiguration == null ? ann.doNotUseGetters() : doNotUseGettersConfiguration;
FieldAccess fieldAccess = doNotUseGetters ? FieldAccess.PREFER_FIELD : FieldAccess.GETTER;
boolean cacheHashCode = ann.cacheStrategy() == CacheStrategy.LAZY;
generateMethods(annotationNode.up(), annotationNode, members, callSuper, true, cacheHashCode, fieldAccess, onParam);
}
use of lombok.core.handlers.InclusionExclusionUtils.Included in project lombok by rzwitserloot.
the class HandleBuilder method handle.
@Override
public void handle(AnnotationValues<Builder> annotation, Annotation ast, EclipseNode annotationNode) {
final String BUILDER_NODE_NOT_SUPPORTED_ERR = "@Builder is only supported on classes, records, constructors, and methods.";
handleFlagUsage(annotationNode, ConfigurationKeys.BUILDER_FLAG_USAGE, "@Builder");
BuilderJob job = new BuilderJob();
job.sourceNode = annotationNode;
job.source = ast;
job.checkerFramework = getCheckerFrameworkVersion(annotationNode);
job.isStatic = true;
Builder annInstance = annotation.getInstance();
job.init(annotation, annInstance, annotationNode);
List<char[]> typeArgsForToBuilder = null;
boolean generateBuilderMethod;
if (job.builderMethodName.isEmpty()) {
generateBuilderMethod = false;
} else if (!checkName("builderMethodName", job.builderMethodName, annotationNode)) {
return;
} else {
generateBuilderMethod = true;
}
if (!checkName("buildMethodName", job.buildMethodName, annotationNode))
return;
EclipseNode parent = annotationNode.up();
job.builderFields = new ArrayList<BuilderFieldData>();
TypeReference buildMethodReturnType;
TypeReference[] buildMethodThrownExceptions;
char[] nameOfBuilderMethod;
EclipseNode fillParametersFrom = parent.get() instanceof AbstractMethodDeclaration ? parent : null;
boolean addCleaning = false;
List<EclipseNode> nonFinalNonDefaultedFields = null;
if (!isStaticAllowed(upToTypeNode(parent))) {
annotationNode.addError("@Builder is not supported on non-static nested classes.");
return;
}
if (parent.get() instanceof TypeDeclaration) {
if (!isClass(parent) && !isRecord(parent)) {
annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR);
return;
}
job.parentType = parent;
TypeDeclaration td = (TypeDeclaration) parent.get();
List<EclipseNode> allFields = new ArrayList<EclipseNode>();
boolean valuePresent = (hasAnnotation(lombok.Value.class, parent) || hasAnnotation("lombok.experimental.Value", parent));
for (EclipseNode fieldNode : HandleConstructor.findAllFields(parent, 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.builderFieldName = bfd.name;
bfd.annotations = copyAnnotations(fd, findCopyableAnnotations(fieldNode));
bfd.type = fd.type;
bfd.singularData = getSingularData(fieldNode, ast, annInstance.setterPrefix());
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;
if (nonFinalNonDefaultedFields == null)
nonFinalNonDefaultedFields = new ArrayList<EclipseNode>();
nonFinalNonDefaultedFields.add(fieldNode);
}
if (isDefault != null) {
bfd.nameOfDefaultProvider = prefixWith(DEFAULT_PREFIX, bfd.name);
bfd.nameOfSetFlag = prefixWith(bfd.name, SET_PREFIX);
bfd.builderFieldName = prefixWith(bfd.name, VALUE_PREFIX);
MethodDeclaration md = generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast);
if (md != null)
injectMethod(parent, md);
}
addObtainVia(bfd, fieldNode);
job.builderFields.add(bfd);
allFields.add(fieldNode);
}
if (!isRecord(parent)) {
// Records ship with a canonical constructor that acts as @AllArgsConstructor - just use that one.
handleConstructor.generateConstructor(parent, AccessLevel.PACKAGE, allFields, false, null, SkipIfConstructorExists.I_AM_BUILDER, Collections.<Annotation>emptyList(), annotationNode);
}
job.typeParams = job.builderTypeParams = td.typeParameters;
buildMethodReturnType = job.createBuilderParentTypeReference();
buildMethodThrownExceptions = null;
nameOfBuilderMethod = null;
job.setBuilderClassName(job.replaceBuilderClassName(td.name));
if (!checkName("builderClassName", job.builderClassName, annotationNode))
return;
} 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;
}
job.parentType = parent.up();
TypeDeclaration td = (TypeDeclaration) job.parentType.get();
job.typeParams = job.builderTypeParams = td.typeParameters;
buildMethodReturnType = job.createBuilderParentTypeReference();
buildMethodThrownExceptions = cd.thrownExceptions;
nameOfBuilderMethod = null;
job.setBuilderClassName(job.replaceBuilderClassName(cd.selector));
if (!checkName("builderClassName", job.builderClassName, annotationNode))
return;
} else if (parent.get() instanceof MethodDeclaration) {
MethodDeclaration md = (MethodDeclaration) parent.get();
job.parentType = parent.up();
job.isStatic = md.isStatic();
if (job.toBuilder) {
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 (job.parentType == null || !equals(job.parentType.getName(), token)) {
annotationNode.addError(TO_BUILDER_NOT_SUPPORTED);
return;
}
TypeParameter[] tpOnType = ((TypeDeclaration) job.parentType.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);
}
}
job.typeParams = job.builderTypeParams = md.typeParameters;
buildMethodReturnType = copyType(md.returnType, ast);
buildMethodThrownExceptions = md.thrownExceptions;
nameOfBuilderMethod = md.selector;
if (job.builderClassName.indexOf('*') > -1) {
char[] token = returnTypeToBuilderClassName(annotationNode, md, job.typeParams);
// should not happen.
if (token == null)
return;
job.setBuilderClassName(job.replaceBuilderClassName(token));
if (!checkName("builderClassName", job.builderClassName, annotationNode))
return;
}
} else {
annotationNode.addError(BUILDER_NODE_NOT_SUPPORTED_ERR);
return;
}
if (fillParametersFrom != null) {
for (EclipseNode param : fillParametersFrom.down()) {
if (param.getKind() != Kind.ARGUMENT)
continue;
BuilderFieldData bfd = new BuilderFieldData();
Argument arg = (Argument) param.get();
Annotation[] copyableAnnotations = findCopyableAnnotations(param);
bfd.rawName = arg.name;
bfd.name = arg.name;
bfd.builderFieldName = bfd.name;
bfd.annotations = copyAnnotations(arg, copyableAnnotations);
bfd.type = arg.type;
bfd.singularData = getSingularData(param, ast, annInstance.setterPrefix());
bfd.originalFieldNode = param;
addObtainVia(bfd, param);
job.builderFields.add(bfd);
}
}
job.builderType = findInnerClass(job.parentType, job.builderClassName);
if (job.builderType == null)
makeBuilderClass(job);
else {
TypeDeclaration builderTypeDeclaration = (TypeDeclaration) job.builderType.get();
if (job.isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) == 0) {
annotationNode.addError("Existing Builder must be a static inner class.");
return;
} else if (!job.isStatic && (builderTypeDeclaration.modifiers & ClassFileConstants.AccStatic) != 0) {
annotationNode.addError("Existing Builder must be a non-static inner class.");
return;
}
sanityCheckForMethodGeneratingAnnotationsOnBuilderClass(job.builderType, annotationNode);
/* generate errors for @Singular BFDs that have one already defined node. */
{
for (BuilderFieldData bfd : job.builderFields) {
SingularData sd = bfd.singularData;
if (sd == null)
continue;
EclipseSingularizer singularizer = sd.getSingularizer();
if (singularizer == null)
continue;
if (singularizer.checkForAlreadyExistingNodesAndGenerateError(job.builderType, sd)) {
bfd.singularData = null;
}
}
}
}
for (BuilderFieldData bfd : job.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(job);
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);
cleanDecl.traverse(new SetGeneratedByVisitor(ast), (MethodScope) null);
injectFieldAndMarkGenerated(job.builderType, cleanDecl);
}
if (constructorExists(job.builderType) == MemberExistsResult.NOT_EXISTS) {
ConstructorDeclaration cd = HandleConstructor.createConstructor(AccessLevel.PACKAGE, job.builderType, Collections.<EclipseNode>emptyList(), false, annotationNode, Collections.<Annotation>emptyList());
if (cd != null)
injectMethod(job.builderType, cd);
}
for (BuilderFieldData bfd : job.builderFields) {
makePrefixedSetterMethodsForBuilder(job, bfd, annInstance.setterPrefix());
}
{
MemberExistsResult methodExists = methodExists(job.buildMethodName, job.builderType, -1);
if (methodExists == MemberExistsResult.EXISTS_BY_LOMBOK)
methodExists = methodExists(job.buildMethodName, job.builderType, 0);
if (methodExists == MemberExistsResult.NOT_EXISTS) {
MethodDeclaration md = generateBuildMethod(job, nameOfBuilderMethod, buildMethodReturnType, buildMethodThrownExceptions, addCleaning);
if (md != null)
injectMethod(job.builderType, md);
}
}
if (methodExists("toString", job.builderType, 0) == MemberExistsResult.NOT_EXISTS) {
List<Included<EclipseNode, ToString.Include>> fieldNodes = new ArrayList<Included<EclipseNode, ToString.Include>>();
for (BuilderFieldData bfd : job.builderFields) {
for (EclipseNode f : bfd.createdFields) {
fieldNodes.add(new Included<EclipseNode, ToString.Include>(f, null, true, false));
}
}
MethodDeclaration md = HandleToString.createToString(job.builderType, fieldNodes, true, false, ast, FieldAccess.ALWAYS_FIELD);
if (md != null)
injectMethod(job.builderType, md);
}
if (addCleaning) {
MethodDeclaration cleanMethod = generateCleanMethod(job);
if (cleanMethod != null)
injectMethod(job.builderType, cleanMethod);
}
if (generateBuilderMethod && methodExists(job.builderMethodName, job.parentType, -1) != MemberExistsResult.NOT_EXISTS)
generateBuilderMethod = false;
if (generateBuilderMethod) {
MethodDeclaration md = generateBuilderMethod(job);
if (md != null)
injectMethod(job.parentType, md);
}
if (job.toBuilder)
switch(methodExists(TO_BUILDER_METHOD_NAME_STRING, job.parentType, 0)) {
case EXISTS_BY_USER:
annotationNode.addWarning("Not generating toBuilder() as it already exists.");
break;
case NOT_EXISTS:
TypeParameter[] tps = job.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(job, tps, annInstance.setterPrefix());
if (md != null)
injectMethod(job.parentType, md);
}
if (nonFinalNonDefaultedFields != null && generateBuilderMethod) {
for (EclipseNode fieldNode : nonFinalNonDefaultedFields) {
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.");
}
}
}
use of lombok.core.handlers.InclusionExclusionUtils.Included in project lombok by rzwitserloot.
the class HandleToString method generateToStringForType.
public void generateToStringForType(EclipseNode typeNode, EclipseNode errorNode) {
if (hasAnnotation(ToString.class, typeNode)) {
// The annotation will make it happen, so we can skip it.
return;
}
AnnotationValues<ToString> anno = AnnotationValues.of(ToString.class);
boolean includeFieldNames = typeNode.getAst().getBooleanAnnotationValue(anno, "includeFieldNames", ConfigurationKeys.TO_STRING_INCLUDE_FIELD_NAMES);
boolean onlyExplicitlyIncluded = typeNode.getAst().getBooleanAnnotationValue(anno, "onlyExplicitlyIncluded", ConfigurationKeys.TO_STRING_ONLY_EXPLICITLY_INCLUDED);
Boolean doNotUseGettersConfiguration = typeNode.getAst().readConfiguration(ConfigurationKeys.TO_STRING_DO_NOT_USE_GETTERS);
FieldAccess access = doNotUseGettersConfiguration == null || !doNotUseGettersConfiguration ? FieldAccess.GETTER : FieldAccess.PREFER_FIELD;
List<Included<EclipseNode, ToString.Include>> members = InclusionExclusionUtils.handleToStringMarking(typeNode, onlyExplicitlyIncluded, null, null);
generateToString(typeNode, errorNode, members, includeFieldNames, null, false, access);
}
Aggregations