Skip to content

Commit 4f8dbea

Browse files
eamonnmcmanusGoogle Java Core Libraries
authored andcommitted
Improve generate constructor parameter names in the @Memoized extension.
Previously we just added `$` to each name, in case one of them might be a Java keyword. This turns out to cause an issue with Error Prone's `/* foo= */` checked parameter-name comments, because people end up having to write `/* foo$= */` for the check to pass. With the approach here, you'll only have to write a funny parameter name if your property name is a keyword. RELNOTES=The constructor parameter names in the class generated by `@Memoized` no longer add a `$`. PiperOrigin-RevId: 521852747
1 parent 1f52972 commit 4f8dbea

File tree

4 files changed

+68
-6
lines changed

4 files changed

+68
-6
lines changed

value/processor/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@
177177
<execution>
178178
<id>default-testCompile</id>
179179
<configuration>
180+
<compilerArgs>
181+
<!-- For MemoizeTest. -->
182+
<arg>-parameters</arg>
183+
</compilerArgs>
180184
<annotationProcessorPaths>
181185
<path>
182186
<groupId>com.google.auto.value</groupId>

value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import static com.google.auto.common.GeneratedAnnotationSpecs.generatedAnnotationSpec;
1919
import static com.google.auto.common.MoreStreams.toImmutableList;
20+
import static com.google.auto.common.MoreStreams.toImmutableMap;
2021
import static com.google.auto.common.MoreStreams.toImmutableSet;
2122
import static com.google.auto.value.extension.memoized.processor.ClassNames.MEMOIZED_NAME;
2223
import static com.google.auto.value.extension.memoized.processor.MemoizedValidator.getAnnotationMirror;
@@ -44,6 +45,7 @@
4445
import com.google.auto.service.AutoService;
4546
import com.google.auto.value.extension.AutoValueExtension;
4647
import com.google.common.collect.ImmutableList;
48+
import com.google.common.collect.ImmutableMap;
4749
import com.google.common.collect.ImmutableSet;
4850
import com.google.errorprone.annotations.FormatMethod;
4951
import com.squareup.javapoet.AnnotationSpec;
@@ -58,6 +60,7 @@
5860
import com.squareup.javapoet.TypeVariableName;
5961
import java.util.List;
6062
import java.util.Optional;
63+
import java.util.Set;
6164
import javax.annotation.processing.Messager;
6265
import javax.annotation.processing.ProcessingEnvironment;
6366
import javax.lang.model.SourceVersion;
@@ -193,15 +196,36 @@ private ImmutableList<TypeVariableName> annotatedTypeVariableNames() {
193196

194197
private MethodSpec constructor() {
195198
MethodSpec.Builder constructor = constructorBuilder();
199+
// TODO(b/35944623): Replace this with a standard way of avoiding keywords.
200+
Set<String> propertyNames = context.properties().keySet();
201+
ImmutableMap<String, String> parameterNames =
202+
propertyNames.stream()
203+
.collect(
204+
toImmutableMap(name -> name, name -> generateIdentifier(name, propertyNames)));
196205
context
197206
.propertyTypes()
198-
.forEach((name, type) -> constructor.addParameter(annotatedType(type), name + "$"));
207+
.forEach(
208+
(name, type) ->
209+
constructor.addParameter(annotatedType(type), parameterNames.get(name)));
199210
String superParams =
200-
context.properties().keySet().stream().map(n -> n + "$").collect(joining(", "));
211+
context.properties().keySet().stream().map(parameterNames::get).collect(joining(", "));
201212
constructor.addStatement("super($L)", superParams);
202213
return constructor.build();
203214
}
204215

216+
private static String generateIdentifier(String name, Set<String> existingNames) {
217+
if (!SourceVersion.isKeyword(name)) {
218+
return name;
219+
}
220+
for (int i = 0;; i++) {
221+
String newName = name + i;
222+
if (!existingNames.contains(newName)) {
223+
return newName;
224+
}
225+
}
226+
}
227+
228+
205229

206230
private boolean isHashCodeMemoized() {
207231
return memoizedMethods(context).stream()

value/src/main/java/com/google/auto/value/extension/toprettystring/processor/ExtensionClassTypeSpecBuilder.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static com.google.auto.common.GeneratedAnnotationSpecs.generatedAnnotationSpec;
2020
import static com.google.auto.common.MoreStreams.toImmutableList;
21+
import static com.google.auto.common.MoreStreams.toImmutableMap;
2122
import static com.squareup.javapoet.MethodSpec.constructorBuilder;
2223
import static com.squareup.javapoet.TypeSpec.classBuilder;
2324
import static java.util.stream.Collectors.joining;
@@ -28,6 +29,7 @@
2829
import com.google.auto.value.extension.AutoValueExtension;
2930
import com.google.auto.value.extension.AutoValueExtension.Context;
3031
import com.google.common.collect.ImmutableList;
32+
import com.google.common.collect.ImmutableMap;
3133
import com.squareup.javapoet.AnnotationSpec;
3234
import com.squareup.javapoet.ClassName;
3335
import com.squareup.javapoet.MethodSpec;
@@ -36,6 +38,7 @@
3638
import com.squareup.javapoet.TypeSpec;
3739
import com.squareup.javapoet.TypeVariableName;
3840
import java.util.List;
41+
import java.util.Set;
3942
import javax.lang.model.SourceVersion;
4043
import javax.lang.model.type.TypeMirror;
4144
import javax.lang.model.util.Elements;
@@ -117,15 +120,34 @@ private ImmutableList<TypeVariableName> annotatedTypeVariableNames() {
117120

118121
private MethodSpec constructor() {
119122
MethodSpec.Builder constructor = constructorBuilder();
123+
// TODO(b/35944623): Replace this with a standard way of avoiding keywords.
124+
Set<String> propertyNames = context.properties().keySet();
125+
ImmutableMap<String, String> parameterNames =
126+
propertyNames.stream()
127+
.collect(toImmutableMap(name -> name, name -> generateIdentifier(name, propertyNames)));
120128
context
121129
.propertyTypes()
122-
.forEach((name, type) -> constructor.addParameter(annotatedType(type), name + "$"));
130+
.forEach(
131+
(name, type) ->
132+
constructor.addParameter(annotatedType(type), parameterNames.get(name)));
123133
String superParams =
124-
context.properties().keySet().stream().map(n -> n + "$").collect(joining(", "));
134+
context.properties().keySet().stream().map(parameterNames::get).collect(joining(", "));
125135
constructor.addStatement("super($L)", superParams);
126136
return constructor.build();
127137
}
128138

139+
private static String generateIdentifier(String name, Set<String> existingNames) {
140+
if (!SourceVersion.isKeyword(name)) {
141+
return name;
142+
}
143+
for (int i = 0; ; i++) {
144+
String newName = name + i;
145+
if (!existingNames.contains(newName)) {
146+
return newName;
147+
}
148+
}
149+
}
150+
129151
/** Translate a {@link TypeMirror} into a {@link TypeName}, including type annotations. */
130152
private static TypeName annotatedType(TypeMirror type) {
131153
List<AnnotationSpec> annotations =

value/src/test/java/com/google/auto/value/extension/memoized/MemoizedTest.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
*/
1616
package com.google.auto.value.extension.memoized;
1717

18+
import static com.google.common.collect.ImmutableList.toImmutableList;
1819
import static com.google.common.truth.Truth.assertThat;
20+
import static java.util.Arrays.stream;
1921
import static org.junit.Assert.fail;
2022

2123
import com.google.auto.value.AutoValue;
@@ -27,6 +29,7 @@
2729
import java.lang.reflect.AnnotatedType;
2830
import java.lang.reflect.Constructor;
2931
import java.lang.reflect.Method;
32+
import java.lang.reflect.Parameter;
3033
import org.junit.Before;
3134
import org.junit.Test;
3235
import org.junit.runner.RunWith;
@@ -44,6 +47,8 @@ abstract static class ValueWithKeywordName {
4447

4548
abstract boolean getNative0();
4649

50+
abstract String getNotKeyword();
51+
4752
@Memoized
4853
boolean getMemoizedNative() {
4954
return getNative();
@@ -358,12 +363,19 @@ public void testToString() {
358363
}
359364

360365
@Test
361-
public void keywords() {
362-
ValueWithKeywordName value = new AutoValue_MemoizedTest_ValueWithKeywordName(true, false);
366+
public void keywords() throws Exception {
367+
ValueWithKeywordName value =
368+
new AutoValue_MemoizedTest_ValueWithKeywordName(true, false, "foo");
363369
assertThat(value.getNative()).isTrue();
364370
assertThat(value.getMemoizedNative()).isTrue();
365371
assertThat(value.getNative0()).isFalse();
366372
assertThat(value.getMemoizedNative0()).isFalse();
373+
374+
Constructor<?> constructor =
375+
value.getClass().getDeclaredConstructor(boolean.class, boolean.class, String.class);
376+
ImmutableList<String> names =
377+
stream(constructor.getParameters()).map(Parameter::getName).collect(toImmutableList());
378+
assertThat(names).contains("notKeyword");
367379
}
368380

369381
@Test

0 commit comments

Comments
 (0)