Skip to content
This repository was archived by the owner on Oct 16, 2024. It is now read-only.

Commit c82cc39

Browse files
authored
Merge pull request #254 from google/safe.varargs
Generate @SafeVarargs where necessary
2 parents 2effdd4 + eba58bb commit c82cc39

13 files changed

+659
-24
lines changed

src/main/java/org/inferred/freebuilder/processor/ListPropertyFactory.java

+37-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import static org.inferred.freebuilder.processor.Util.upperBound;
2525
import static org.inferred.freebuilder.processor.util.ModelUtils.maybeDeclared;
2626
import static org.inferred.freebuilder.processor.util.ModelUtils.maybeUnbox;
27+
import static org.inferred.freebuilder.processor.util.ModelUtils.needsSafeVarargs;
2728
import static org.inferred.freebuilder.processor.util.ModelUtils.overrides;
2829
import static org.inferred.freebuilder.processor.util.PreconditionExcerpts.checkNotNullInline;
2930
import static org.inferred.freebuilder.processor.util.PreconditionExcerpts.checkNotNullPreamble;
@@ -75,41 +76,60 @@ public Optional<? extends PropertyCodeGenerator> create(Config config) {
7576

7677
TypeMirror elementType = upperBound(config.getElements(), type.getTypeArguments().get(0));
7778
Optional<TypeMirror> unboxedType = maybeUnbox(elementType, config.getTypes());
79+
boolean needsSafeVarargs = needsSafeVarargs(unboxedType.or(elementType));
7880
boolean overridesAddMethod = hasAddMethodOverride(config, unboxedType.or(elementType));
81+
boolean overridesVarargsAddMethod =
82+
hasVarargsAddMethodOverride(config, unboxedType.or(elementType));
7983
return Optional.of(new CodeGenerator(
8084
config.getMetadata(),
8185
config.getProperty(),
86+
needsSafeVarargs,
8287
overridesAddMethod,
88+
overridesVarargsAddMethod,
8389
elementType,
8490
unboxedType));
8591
}
8692

87-
private static boolean hasAddMethodOverride(Config config, TypeMirror keyType) {
93+
private static boolean hasAddMethodOverride(Config config, TypeMirror elementType) {
8894
return overrides(
8995
config.getBuilder(),
9096
config.getTypes(),
9197
addMethod(config.getProperty()),
92-
keyType);
98+
elementType);
99+
}
100+
101+
private static boolean hasVarargsAddMethodOverride(Config config, TypeMirror elementType) {
102+
return overrides(
103+
config.getBuilder(),
104+
config.getTypes(),
105+
addMethod(config.getProperty()),
106+
config.getTypes().getArrayType(elementType));
93107
}
94108

95109
@VisibleForTesting static class CodeGenerator extends PropertyCodeGenerator {
96110

97111
private static final ParameterizedType COLLECTION =
98112
QualifiedName.of(Collection.class).withParameters("E");
99113

114+
private final boolean needsSafeVarargs;
100115
private final boolean overridesAddMethod;
116+
private final boolean overridesVarargsAddMethod;
101117
private final TypeMirror elementType;
102118
private final Optional<TypeMirror> unboxedType;
103119

104120
@VisibleForTesting
105121
CodeGenerator(
106122
Metadata metadata,
107123
Property property,
124+
boolean needsSafeVarargs,
108125
boolean overridesAddMethod,
126+
boolean overridesVarargsAddMethod,
109127
TypeMirror elementType,
110128
Optional<TypeMirror> unboxedType) {
111129
super(metadata, property);
130+
this.needsSafeVarargs = needsSafeVarargs;
112131
this.overridesAddMethod = overridesAddMethod;
132+
this.overridesVarargsAddMethod = overridesVarargsAddMethod;
113133
this.elementType = elementType;
114134
this.unboxedType = unboxedType;
115135
}
@@ -183,8 +203,21 @@ private void addVarargsAdd(SourceBuilder code, Metadata metadata) {
183203
code.addLine(" * @throws NullPointerException if {@code elements} is null or contains a")
184204
.addLine(" * null element");
185205
}
186-
code.addLine(" */")
187-
.addLine("public %s %s(%s... elements) {",
206+
code.addLine(" */");
207+
QualifiedName safeVarargs = code.feature(SOURCE_LEVEL).safeVarargs().orNull();
208+
if (safeVarargs != null && needsSafeVarargs) {
209+
if (!overridesVarargsAddMethod) {
210+
code.addLine("@%s", safeVarargs)
211+
.addLine("@%s({\"varargs\"})", SuppressWarnings.class);
212+
} else {
213+
code.addLine("@%s({\"unchecked\", \"varargs\"})", SuppressWarnings.class);
214+
}
215+
}
216+
code.add("public ");
217+
if (safeVarargs != null && needsSafeVarargs && !overridesVarargsAddMethod) {
218+
code.add("final ");
219+
}
220+
code.add("%s %s(%s... elements) {\n",
188221
metadata.getBuilder(),
189222
addMethod(property),
190223
unboxedType.or(elementType));

src/main/java/org/inferred/freebuilder/processor/MultisetPropertyFactory.java

+36-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import static org.inferred.freebuilder.processor.Util.upperBound;
2727
import static org.inferred.freebuilder.processor.util.ModelUtils.maybeDeclared;
2828
import static org.inferred.freebuilder.processor.util.ModelUtils.maybeUnbox;
29+
import static org.inferred.freebuilder.processor.util.ModelUtils.needsSafeVarargs;
2930
import static org.inferred.freebuilder.processor.util.ModelUtils.overrides;
3031
import static org.inferred.freebuilder.processor.util.feature.FunctionPackage.FUNCTION_PACKAGE;
3132
import static org.inferred.freebuilder.processor.util.feature.SourceLevel.SOURCE_LEVEL;
@@ -69,12 +70,17 @@ public Optional<CodeGenerator> create(Config config) {
6970

7071
TypeMirror elementType = upperBound(config.getElements(), type.getTypeArguments().get(0));
7172
Optional<TypeMirror> unboxedType = maybeUnbox(elementType, config.getTypes());
73+
boolean needsSafeVarargs = needsSafeVarargs(unboxedType.or(elementType));
7274
boolean overridesSetCountMethod =
7375
hasSetCountMethodOverride(config, unboxedType.or(elementType));
76+
boolean overridesVarargsAddMethod =
77+
hasVarargsAddMethodOverride(config, unboxedType.or(elementType));
7478
return Optional.of(new CodeGenerator(
7579
config.getMetadata(),
7680
config.getProperty(),
81+
needsSafeVarargs,
7782
overridesSetCountMethod,
83+
overridesVarargsAddMethod,
7884
elementType,
7985
unboxedType));
8086
}
@@ -89,22 +95,36 @@ private static boolean hasSetCountMethodOverride(
8995
config.getTypes().getPrimitiveType(TypeKind.INT));
9096
}
9197

98+
private static boolean hasVarargsAddMethodOverride(Config config, TypeMirror elementType) {
99+
return overrides(
100+
config.getBuilder(),
101+
config.getTypes(),
102+
addMethod(config.getProperty()),
103+
config.getTypes().getArrayType(elementType));
104+
}
105+
92106
private static class CodeGenerator extends PropertyCodeGenerator {
93107

94108
private static final ParameterizedType COLLECTION =
95109
QualifiedName.of(Collection.class).withParameters("E");
110+
private final boolean needsSafeVarargs;
96111
private final boolean overridesSetCountMethod;
112+
private final boolean overridesVarargsAddMethod;
97113
private final TypeMirror elementType;
98114
private final Optional<TypeMirror> unboxedType;
99115

100116
CodeGenerator(
101117
Metadata metadata,
102118
Property property,
119+
boolean needsSafeVarargs,
103120
boolean overridesSetCountMethod,
121+
boolean overridesVarargsAddMethod,
104122
TypeMirror elementType,
105123
Optional<TypeMirror> unboxedType) {
106124
super(metadata, property);
125+
this.needsSafeVarargs = needsSafeVarargs;
107126
this.overridesSetCountMethod = overridesSetCountMethod;
127+
this.overridesVarargsAddMethod = overridesVarargsAddMethod;
108128
this.elementType = elementType;
109129
this.unboxedType = unboxedType;
110130
}
@@ -158,9 +178,22 @@ private void addVarargsAdd(SourceBuilder code, Metadata metadata) {
158178
code.addLine(" * @throws NullPointerException if {@code elements} is null or contains a")
159179
.addLine(" * null element");
160180
}
161-
code.addLine(" */")
162-
.addLine("public %s %s(%s... elements) {",
163-
metadata.getBuilder(),
181+
code.addLine(" */");
182+
QualifiedName safeVarargs = code.feature(SOURCE_LEVEL).safeVarargs().orNull();
183+
if (safeVarargs != null && needsSafeVarargs) {
184+
if (!overridesVarargsAddMethod) {
185+
code.addLine("@%s", safeVarargs)
186+
.addLine("@%s({\"varargs\"})", SuppressWarnings.class);
187+
} else {
188+
code.addLine("@%s({\"unchecked\", \"varargs\"})", SuppressWarnings.class);
189+
}
190+
}
191+
code.add("public ");
192+
if (safeVarargs != null && needsSafeVarargs && !overridesVarargsAddMethod) {
193+
code.add("final ");
194+
}
195+
code.add("%s %s(%s... elements) {\n",
196+
metadata.getBuilder(),
164197
addMethod(property),
165198
unboxedType.or(elementType))
166199
.addLine(" for (%s element : elements) {", unboxedType.or(elementType))

src/main/java/org/inferred/freebuilder/processor/SetPropertyFactory.java

+41-4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import static org.inferred.freebuilder.processor.Util.upperBound;
2626
import static org.inferred.freebuilder.processor.util.ModelUtils.maybeDeclared;
2727
import static org.inferred.freebuilder.processor.util.ModelUtils.maybeUnbox;
28+
import static org.inferred.freebuilder.processor.util.ModelUtils.needsSafeVarargs;
2829
import static org.inferred.freebuilder.processor.util.ModelUtils.overrides;
2930
import static org.inferred.freebuilder.processor.util.PreconditionExcerpts.checkNotNullInline;
3031
import static org.inferred.freebuilder.processor.util.PreconditionExcerpts.checkNotNullPreamble;
@@ -71,9 +72,18 @@ public Optional<CodeGenerator> create(Config config) {
7172

7273
TypeMirror elementType = upperBound(config.getElements(), type.getTypeArguments().get(0));
7374
Optional<TypeMirror> unboxedType = maybeUnbox(elementType, config.getTypes());
75+
boolean needsSafeVarargs = needsSafeVarargs(unboxedType.or(elementType));
7476
boolean overridesAddMethod = hasAddMethodOverride(config, unboxedType.or(elementType));
77+
boolean overridesVarargsAddMethod =
78+
hasVarargsAddMethodOverride(config, unboxedType.or(elementType));
7579
return Optional.of(new CodeGenerator(
76-
config.getMetadata(), config.getProperty(), elementType, unboxedType, overridesAddMethod));
80+
config.getMetadata(),
81+
config.getProperty(),
82+
elementType,
83+
unboxedType,
84+
needsSafeVarargs,
85+
overridesAddMethod,
86+
overridesVarargsAddMethod));
7787
}
7888

7989
private static boolean hasAddMethodOverride(Config config, TypeMirror elementType) {
@@ -84,25 +94,39 @@ private static boolean hasAddMethodOverride(Config config, TypeMirror elementTyp
8494
elementType);
8595
}
8696

97+
private static boolean hasVarargsAddMethodOverride(Config config, TypeMirror elementType) {
98+
return overrides(
99+
config.getBuilder(),
100+
config.getTypes(),
101+
addMethod(config.getProperty()),
102+
config.getTypes().getArrayType(elementType));
103+
}
104+
87105
@VisibleForTesting
88106
static class CodeGenerator extends PropertyCodeGenerator {
89107

90108
private static final ParameterizedType COLLECTION =
91109
QualifiedName.of(Collection.class).withParameters("E");
92110
private final TypeMirror elementType;
93111
private final Optional<TypeMirror> unboxedType;
112+
private final boolean needsSafeVarargs;
94113
private final boolean overridesAddMethod;
114+
private final boolean overridesVarargsAddMethod;
95115

96116
CodeGenerator(
97117
Metadata metadata,
98118
Property property,
99119
TypeMirror elementType,
100120
Optional<TypeMirror> unboxedType,
101-
boolean overridesAddMethod) {
121+
boolean needsSafeVarargs,
122+
boolean overridesAddMethod,
123+
boolean overridesVarargsAddMethod) {
102124
super(metadata, property);
103125
this.elementType = elementType;
104126
this.unboxedType = unboxedType;
127+
this.needsSafeVarargs = needsSafeVarargs;
105128
this.overridesAddMethod = overridesAddMethod;
129+
this.overridesVarargsAddMethod = overridesVarargsAddMethod;
106130
}
107131

108132
@Override
@@ -174,8 +198,21 @@ private void addVarargsAdd(SourceBuilder code, Metadata metadata) {
174198
code.addLine(" * @throws NullPointerException if {@code elements} is null or contains a")
175199
.addLine(" * null element");
176200
}
177-
code.addLine(" */")
178-
.addLine("public %s %s(%s... elements) {",
201+
code.addLine(" */");
202+
QualifiedName safeVarargs = code.feature(SOURCE_LEVEL).safeVarargs().orNull();
203+
if (safeVarargs != null && needsSafeVarargs) {
204+
if (!overridesVarargsAddMethod) {
205+
code.addLine("@%s", safeVarargs)
206+
.addLine("@%s({\"varargs\"})", SuppressWarnings.class);
207+
} else {
208+
code.addLine("@%s({\"unchecked\", \"varargs\"})", SuppressWarnings.class);
209+
}
210+
}
211+
code.add("public ");
212+
if (safeVarargs != null && needsSafeVarargs && !overridesVarargsAddMethod) {
213+
code.add("final ");
214+
}
215+
code.add("%s %s(%s... elements) {\n",
179216
metadata.getBuilder(),
180217
addMethod(property),
181218
unboxedType.or(elementType));

src/main/java/org/inferred/freebuilder/processor/SortedSetPropertyFactory.java

+44-6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import static org.inferred.freebuilder.processor.Util.upperBound;
2727
import static org.inferred.freebuilder.processor.util.ModelUtils.maybeDeclared;
2828
import static org.inferred.freebuilder.processor.util.ModelUtils.maybeUnbox;
29+
import static org.inferred.freebuilder.processor.util.ModelUtils.needsSafeVarargs;
2930
import static org.inferred.freebuilder.processor.util.ModelUtils.overrides;
3031
import static org.inferred.freebuilder.processor.util.PreconditionExcerpts.checkNotNullInline;
3132
import static org.inferred.freebuilder.processor.util.PreconditionExcerpts.checkNotNullPreamble;
@@ -73,9 +74,18 @@ public Optional<CodeGenerator> create(Config config) {
7374

7475
TypeMirror elementType = upperBound(config.getElements(), type.getTypeArguments().get(0));
7576
Optional<TypeMirror> unboxedType = maybeUnbox(elementType, config.getTypes());
77+
boolean needsSafeVarargs = needsSafeVarargs(unboxedType.or(elementType));
7678
boolean overridesAddMethod = hasAddMethodOverride(config, unboxedType.or(elementType));
79+
boolean overridesVarargsAddMethod =
80+
hasVarargsAddMethodOverride(config, unboxedType.or(elementType));
7781
return Optional.of(new CodeGenerator(
78-
config.getMetadata(), config.getProperty(), elementType, unboxedType, overridesAddMethod));
82+
config.getMetadata(),
83+
config.getProperty(),
84+
elementType,
85+
unboxedType,
86+
needsSafeVarargs,
87+
overridesAddMethod,
88+
overridesVarargsAddMethod));
7989
}
8090

8191
private static boolean hasAddMethodOverride(Config config, TypeMirror elementType) {
@@ -86,25 +96,39 @@ private static boolean hasAddMethodOverride(Config config, TypeMirror elementTyp
8696
elementType);
8797
}
8898

99+
private static boolean hasVarargsAddMethodOverride(Config config, TypeMirror elementType) {
100+
return overrides(
101+
config.getBuilder(),
102+
config.getTypes(),
103+
addMethod(config.getProperty()),
104+
config.getTypes().getArrayType(elementType));
105+
}
106+
89107
@VisibleForTesting
90108
static class CodeGenerator extends PropertyCodeGenerator {
91109

92110
private static final ParameterizedType COLLECTION =
93111
QualifiedName.of(Collection.class).withParameters("E");
94112
private final TypeMirror elementType;
95113
private final Optional<TypeMirror> unboxedType;
114+
private final boolean needsSafeVarargs;
96115
private final boolean overridesAddMethod;
116+
private final boolean overridesVarargsAddMethod;
97117

98118
CodeGenerator(
99119
Metadata metadata,
100120
Property property,
101121
TypeMirror elementType,
102122
Optional<TypeMirror> unboxedType,
103-
boolean overridesAddMethod) {
123+
boolean needsSafeVarargs,
124+
boolean overridesAddMethod,
125+
boolean overridesVarargsAddMethod) {
104126
super(metadata, property);
105127
this.elementType = elementType;
106128
this.unboxedType = unboxedType;
129+
this.needsSafeVarargs = needsSafeVarargs;
107130
this.overridesAddMethod = overridesAddMethod;
131+
this.overridesVarargsAddMethod = overridesVarargsAddMethod;
108132
}
109133

110134
@Override
@@ -224,8 +248,21 @@ private void addVarargsAdd(SourceBuilder code, Metadata metadata) {
224248
code.addLine(" * @throws NullPointerException if {@code elements} is null or contains a")
225249
.addLine(" * null element");
226250
}
227-
code.addLine(" */")
228-
.addLine("public %s %s(%s... elements) {",
251+
code.addLine(" */");
252+
QualifiedName safeVarargs = code.feature(SOURCE_LEVEL).safeVarargs().orNull();
253+
if (safeVarargs != null && needsSafeVarargs) {
254+
if (!overridesVarargsAddMethod) {
255+
code.addLine("@%s", safeVarargs)
256+
.addLine("@%s({\"varargs\"})", SuppressWarnings.class);
257+
} else {
258+
code.addLine("@%s({\"unchecked\", \"varargs\"})", SuppressWarnings.class);
259+
}
260+
}
261+
code.add("public ");
262+
if (safeVarargs != null && needsSafeVarargs && !overridesVarargsAddMethod) {
263+
code.add("final ");
264+
}
265+
code.add("%s %s(%s... elements) {\n",
229266
metadata.getBuilder(),
230267
addMethod(property),
231268
unboxedType.or(elementType));
@@ -442,12 +479,13 @@ public void addMergeFromValue(Block code, String value) {
442479
Excerpts.equals(
443480
Excerpts.add("%s.comparator()", property.getName()),
444481
Excerpts.add("%s.%s().comparator()", value, property.getGetterName())))
445-
.addLine(" %1$s = (%2$s<%3$s>) (%2$s<?>) %4$s.%5$s();",
446-
property.getName(),
482+
.addLine(" @%s(\"unchecked\")", SuppressWarnings.class)
483+
.addLine(" %1$s<%2$s> _temporary = (%1$s<%2$s>) (%1$s<?>) %3$s.%4$s();",
447484
ImmutableSortedSet.class,
448485
elementType,
449486
value,
450487
property.getGetterName())
488+
.addLine(" %1$s = _temporary;", property.getName())
451489
.addLine("} else {");
452490
}
453491
code.addLine("%s(%s.%s());", addAllMethod(property), value, property.getGetterName());

0 commit comments

Comments
 (0)