diff options
author | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2020-01-18 03:10:07 +0100 |
---|---|---|
committer | Reinier Zwitserloot <r.zwitserloot@projectlombok.org> | 2020-01-28 16:21:39 +0100 |
commit | 91a40b83125808d3684ce07c5cb4a2927d0b979c (patch) | |
tree | ee1105aa16d2db522e26ea16cf11579fee81d893 /src/core/lombok/eclipse/handlers | |
parent | 6cc74e42295b6138629c6b32dd56a99ee8c2c646 (diff) | |
download | lombok-91a40b83125808d3684ce07c5cb4a2927d0b979c.tar.gz lombok-91a40b83125808d3684ce07c5cb4a2927d0b979c.tar.bz2 lombok-91a40b83125808d3684ce07c5cb4a2927d0b979c.zip |
[singular][issue #2221] the plural builder method now nullchecks its argument with configurable results.
Diffstat (limited to 'src/core/lombok/eclipse/handlers')
6 files changed, 88 insertions, 10 deletions
diff --git a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java index 9d79d75c..5fe4b958 100755 --- a/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java +++ b/src/core/lombok/eclipse/handlers/EclipseSingularsRecipes.java @@ -33,25 +33,31 @@ import java.util.Map; 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.Block; import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression; import org.eclipse.jdt.internal.compiler.ast.EqualExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; import org.eclipse.jdt.internal.compiler.ast.FieldReference; +import org.eclipse.jdt.internal.compiler.ast.IfStatement; import org.eclipse.jdt.internal.compiler.ast.IntLiteral; import org.eclipse.jdt.internal.compiler.ast.MessageSend; import org.eclipse.jdt.internal.compiler.ast.NullLiteral; import org.eclipse.jdt.internal.compiler.ast.OperatorIds; 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.Reference; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; import org.eclipse.jdt.internal.compiler.ast.SingleNameReference; import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; 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.ThrowStatement; import org.eclipse.jdt.internal.compiler.ast.TypeReference; import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.lookup.ClassScope; @@ -60,10 +66,12 @@ import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import lombok.AccessLevel; +import lombok.Singular.NullCollectionBehavior; import lombok.core.LombokImmutableList; import lombok.core.SpiLoadUtil; import lombok.core.TypeLibrary; import lombok.core.configuration.CheckerFrameworkVersion; +import lombok.eclipse.Eclipse; import lombok.eclipse.EclipseNode; public class EclipseSingularsRecipes { @@ -126,13 +134,14 @@ public class EclipseSingularsRecipes { private final List<TypeReference> typeArgs; private final String targetFqn; private final EclipseSingularizer singularizer; + private final NullCollectionBehavior nullCollectionBehavior; private final ASTNode source; - public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer, ASTNode source) { - this(annotation, singularName, pluralName, typeArgs, targetFqn, singularizer, source, new char[0]); + public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer, ASTNode source, NullCollectionBehavior nullCollectionBehavior) { + this(annotation, singularName, pluralName, typeArgs, targetFqn, singularizer, source, nullCollectionBehavior, new char[0]); } - public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer, ASTNode source, char[] setterPrefix) { + public SingularData(EclipseNode annotation, char[] singularName, char[] pluralName, List<TypeReference> typeArgs, String targetFqn, EclipseSingularizer singularizer, ASTNode source, NullCollectionBehavior nullCollectionBehavior, char[] setterPrefix) { this.annotation = annotation; this.singularName = singularName; this.pluralName = pluralName; @@ -140,6 +149,7 @@ public class EclipseSingularsRecipes { this.targetFqn = targetFqn; this.singularizer = singularizer; this.source = source; + this.nullCollectionBehavior = nullCollectionBehavior; this.setterPrefix = setterPrefix; } @@ -187,6 +197,10 @@ public class EclipseSingularsRecipes { return singularizer; } + public NullCollectionBehavior getNullCollectionBehavior() { + return nullCollectionBehavior; + } + public String getTargetSimpleType() { int idx = targetFqn.lastIndexOf("."); return idx == -1 ? targetFqn : targetFqn.substring(idx + 1); @@ -423,6 +437,45 @@ public class EclipseSingularsRecipes { } } + protected void nullBehaviorize(SingularData data, List<Statement> statements) { + NullCollectionBehavior behavior = data.getNullCollectionBehavior(); + + if (behavior == NullCollectionBehavior.IGNORE) { + Expression isNotNull = new EqualExpression(new SingleNameReference(data.getPluralName(), 0L), new NullLiteral(0, 0), OperatorIds.NOT_EQUAL); + Block b = new Block(0); + b.statements = statements.toArray(new Statement[statements.size()]); + statements.clear(); + statements.add(new IfStatement(isNotNull, b, 0, 0)); + return; + } + + String exceptionTypeStr = behavior.getExceptionType(); + StringLiteral message = new StringLiteral(behavior.toExceptionMessage(new String(data.getPluralName())).toCharArray(), 0, 0, 0); + if (exceptionTypeStr != null) { + Expression isNull = new EqualExpression(new SingleNameReference(data.getPluralName(), 0L), new NullLiteral(0, 0), OperatorIds.EQUAL_EQUAL); + int partCount = 1; + for (int i = 0; i < exceptionTypeStr.length(); i++) if (exceptionTypeStr.charAt(i) == '.') partCount++; + long[] ps = new long[partCount]; + Arrays.fill(ps, 0L); + AllocationExpression alloc = new AllocationExpression(); + alloc.type = new QualifiedTypeReference(Eclipse.fromQualifiedName(exceptionTypeStr), ps); + alloc.arguments = new Expression[] {message}; + Statement t = new ThrowStatement(alloc, 0, 0); + statements.add(0, new IfStatement(isNull, t, 0, 0)); + return; + } + + MessageSend invoke = new MessageSend(); + LombokImmutableList<String> method = behavior.getMethod(); + char[][] utilityTypeName = new char[method.size() - 1][]; + for (int i = 0; i < method.size() - 1; i++) utilityTypeName[i] = method.get(i).toCharArray(); + + invoke.receiver = new QualifiedNameReference(utilityTypeName, new long[method.size() - 1], 0, 0); + invoke.selector = method.get(method.size() - 1).toCharArray(); + invoke.arguments = new Expression[] {new SingleNameReference(data.getPluralName(), 0L), message}; + statements.add(0, invoke); + } + protected abstract char[][] getEmptyMakerReceiver(String targetFqn); protected abstract char[] getEmptyMakerSelector(String targetFqn); } diff --git a/src/core/lombok/eclipse/handlers/HandleBuilder.java b/src/core/lombok/eclipse/handlers/HandleBuilder.java index bb031ebc..578fa2a3 100755 --- a/src/core/lombok/eclipse/handlers/HandleBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilder.java @@ -79,6 +79,7 @@ import org.mangosdk.spi.ProviderFor; import lombok.AccessLevel; import lombok.Builder; import lombok.Builder.ObtainVia; +import lombok.Singular.NullCollectionBehavior; import lombok.ConfigurationKeys; import lombok.Singular; import lombok.ToString; @@ -992,7 +993,8 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { if (!annotationTypeMatches(Singular.class, child)) continue; char[] pluralName = node.getKind() == Kind.FIELD ? removePrefixFromField(node) : ((AbstractVariableDeclaration) node.get()).name; AnnotationValues<Singular> ann = createAnnotation(Singular.class, child); - String explicitSingular = ann.getInstance().value(); + Singular singularInstance = ann.getInstance(); + String explicitSingular = singularInstance.value(); if (explicitSingular.isEmpty()) { if (Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_AUTO))) { node.addError("The singular must be specified explicitly (e.g. @Singular(\"task\")) because auto singularization is disabled."); @@ -1034,9 +1036,21 @@ public class HandleBuilder extends EclipseAnnotationHandler<Builder> { return null; } - return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer, source, setterPrefix.toCharArray()); + NullCollectionBehavior behavior = getNullBehaviorFor(ann, singularInstance, node); + return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer, source, behavior, setterPrefix.toCharArray()); } return null; } + + static NullCollectionBehavior getNullBehaviorFor(AnnotationValues<Singular> ann, Singular singularInstance, EclipseNode node) { + NullCollectionBehavior behavior; + if (ann.isExplicit("nullBehavior")) { + behavior = singularInstance.nullBehavior(); + } else { + behavior = node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_NULL_COLLECTIONS); + } + if (behavior == null) return NullCollectionBehavior.NULL_POINTER_EXCEPTION; + return behavior; + } } diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 3a2e59f7..4b450a07 100755 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -79,6 +79,7 @@ import org.mangosdk.spi.ProviderFor; import lombok.AccessLevel; import lombok.Builder; import lombok.Builder.ObtainVia; +import lombok.Singular.NullCollectionBehavior; import lombok.ConfigurationKeys; import lombok.Singular; import lombok.ToString; @@ -1000,7 +1001,8 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { char[] pluralName = node.getKind() == Kind.FIELD ? removePrefixFromField(node) : ((AbstractVariableDeclaration) node.get()).name; AnnotationValues<Singular> ann = createAnnotation(Singular.class, child); - String explicitSingular = ann.getInstance().value(); + Singular singularInstance = ann.getInstance(); + String explicitSingular = singularInstance.value(); if (explicitSingular.isEmpty()) { if (Boolean.FALSE.equals(node.getAst().readConfiguration(ConfigurationKeys.SINGULAR_AUTO))) { node.addError("The singular must be specified explicitly (e.g. @Singular(\"task\")) because auto singularization is disabled."); @@ -1042,7 +1044,8 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> { return null; } - return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer, source); + NullCollectionBehavior behavior = HandleBuilder.getNullBehaviorFor(ann, singularInstance, node); + return new SingularData(child, singularName, pluralName, typeArgs == null ? Collections.<TypeReference>emptyList() : Arrays.asList(typeArgs), targetFqn, singularizer, source, behavior); } return null; diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java index 8f80d228..b067ad80 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseGuavaSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 The Project Lombok Authors. + * Copyright (C) 2015-2020 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 @@ -195,6 +195,9 @@ abstract class EclipseGuavaSingularizer extends EclipseSingularizer { thisDotFieldDotAddAll.receiver = thisDotField; thisDotFieldDotAddAll.selector = (getAddMethodName() + "All").toCharArray(); statements.add(thisDotFieldDotAddAll); + + nullBehaviorize(data, statements); + if (returnStatement != null) statements.add(returnStatement); md.statements = statements.toArray(new Statement[0]); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java index e3a99008..ba447397 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilListSetSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 The Project Lombok Authors. + * Copyright (C) 2015-2020 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 @@ -173,6 +173,8 @@ abstract class EclipseJavaUtilListSetSingularizer extends EclipseJavaUtilSingula thisDotFieldDotAddAll.receiver = thisDotField; thisDotFieldDotAddAll.selector = "addAll".toCharArray(); statements.add(thisDotFieldDotAddAll); + + nullBehaviorize(data, statements); if (returnStatement != null) statements.add(returnStatement); md.statements = statements.toArray(new Statement[0]); diff --git a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java index b0223c50..e91c6616 100755 --- a/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java +++ b/src/core/lombok/eclipse/handlers/singulars/EclipseJavaUtilMapSingularizer.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2019 The Project Lombok Authors. + * Copyright (C) 2015-2020 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 @@ -305,6 +305,9 @@ public class EclipseJavaUtilMapSingularizer extends EclipseJavaUtilSingularizer forEachContent.statements = new Statement[] {addKey, addValue}; forEach.action = forEachContent; statements.add(forEach); + + nullBehaviorize(data, statements); + if (returnStatement != null) statements.add(returnStatement); md.statements = statements.toArray(new Statement[0]); |