Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 88e78c3

Browse files
authored
[ggj][ast] feat: support '? extends Foo' wildcard bounded references (#263)
* feat: parse batching descriptor fields * feat: add Field.isMap and map-parsing test * feat: add initial batching descriptor field to ServiceStubSettings * feat: support '? extends Foo' wildcard bounded references
1 parent db62a44 commit 88e78c3

File tree

9 files changed

+202
-10
lines changed

9 files changed

+202
-10
lines changed

src/main/java/com/google/api/generator/engine/ast/ConcreteReference.java

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,29 @@
1717
import com.google.auto.value.AutoValue;
1818
import com.google.common.collect.ImmutableList;
1919
import java.util.List;
20+
import java.util.Objects;
21+
import javax.annotation.Nullable;
2022

2123
@AutoValue
2224
public abstract class ConcreteReference implements Reference {
25+
private static final String EXTENDS = "extends";
26+
2327
private static final String COMMA = ", ";
2428
private static final String DOT = ".";
29+
private static final String SPACE = " ";
2530
private static final String LEFT_ANGLE = "<";
2631
private static final String RIGHT_ANGLE = ">";
2732
private static final String QUESTION_MARK = "?";
2833

34+
private static final Class WILDCARD_CLAZZ = ReferenceWildcard.class;
35+
2936
// Private.
3037
abstract Class clazz();
3138

39+
@Nullable
40+
@Override
41+
public abstract Reference wildcardUpperBound();
42+
3243
@Override
3344
public abstract ImmutableList<Reference> generics();
3445

@@ -38,8 +49,15 @@ public abstract class ConcreteReference implements Reference {
3849
@Override
3950
public String name() {
4051
StringBuilder sb = new StringBuilder();
41-
if (this.equals(TypeNode.WILDCARD_REFERENCE)) {
52+
if (isWildcard()) {
4253
sb.append(QUESTION_MARK);
54+
if (wildcardUpperBound() != null) {
55+
// Handle the upper bound.
56+
sb.append(SPACE);
57+
sb.append(EXTENDS);
58+
sb.append(SPACE);
59+
sb.append(wildcardUpperBound().name());
60+
}
4361
} else {
4462
if (hasEnclosingClass() && !isStaticImport()) {
4563
sb.append(clazz().getEnclosingClass().getSimpleName());
@@ -117,19 +135,28 @@ public boolean isAssignableFrom(Reference other) {
117135
return clazz().isAssignableFrom(((ConcreteReference) other).clazz());
118136
}
119137

138+
@Override
139+
public boolean isWildcard() {
140+
return clazz().equals(WILDCARD_CLAZZ);
141+
}
142+
120143
@Override
121144
public boolean equals(Object o) {
122145
if (!(o instanceof ConcreteReference)) {
123146
return false;
124147
}
125148

126149
ConcreteReference ref = (ConcreteReference) o;
127-
return clazz().equals(ref.clazz()) && generics().equals(ref.generics());
150+
return clazz().equals(ref.clazz())
151+
&& generics().equals(ref.generics())
152+
&& Objects.equals(wildcardUpperBound(), ref.wildcardUpperBound());
128153
}
129154

130155
@Override
131156
public int hashCode() {
132-
return 17 * clazz().hashCode() + 31 * generics().hashCode();
157+
int wildcardUpperBoundHash =
158+
wildcardUpperBound() == null ? 0 : 11 * wildcardUpperBound().hashCode();
159+
return 17 * clazz().hashCode() + 31 * generics().hashCode() + wildcardUpperBoundHash;
133160
}
134161

135162
@Override
@@ -141,6 +168,14 @@ public static ConcreteReference withClazz(Class clazz) {
141168
return builder().setClazz(clazz).build();
142169
}
143170

171+
public static ConcreteReference wildcard() {
172+
return withClazz(ReferenceWildcard.class);
173+
}
174+
175+
public static ConcreteReference wildcardWithUpperBound(Reference upperBoundReference) {
176+
return builder().setClazz(WILDCARD_CLAZZ).setWildcardUpperBound(upperBoundReference).build();
177+
}
178+
144179
public static Builder builder() {
145180
return new AutoValue_ConcreteReference.Builder()
146181
.setGenerics(ImmutableList.of())
@@ -154,6 +189,8 @@ public static Builder builder() {
154189
public abstract static class Builder {
155190
public abstract Builder setClazz(Class clazz);
156191

192+
public abstract Builder setWildcardUpperBound(Reference reference);
193+
157194
public abstract Builder setGenerics(List<Reference> clazzes);
158195

159196
public abstract Builder setIsStaticImport(boolean isStaticImport);

src/main/java/com/google/api/generator/engine/ast/Reference.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public interface Reference {
3030
@Nullable
3131
String enclosingClassName();
3232

33+
@Nullable
34+
Reference wildcardUpperBound();
35+
36+
Reference copyAndSetGenerics(List<Reference> generics);
37+
3338
// Valid only for nested classes.
3439
boolean isStaticImport();
3540

@@ -42,5 +47,5 @@ public interface Reference {
4247

4348
boolean isAssignableFrom(Reference other);
4449

45-
Reference copyAndSetGenerics(List<Reference> generics);
50+
boolean isWildcard();
4651
}

src/main/java/com/google/api/generator/engine/ast/TypeNode.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@
2525
@AutoValue
2626
public abstract class TypeNode implements AstNode {
2727
static final Reference EXCEPTION_REFERENCE = ConcreteReference.withClazz(Exception.class);
28-
public static final Reference WILDCARD_REFERENCE =
29-
ConcreteReference.withClazz(ReferenceWildcard.class);
28+
public static final Reference WILDCARD_REFERENCE = ConcreteReference.wildcard();
3029

3130
public enum TypeKind {
3231
BYTE,
@@ -101,7 +100,22 @@ public abstract static class Builder {
101100

102101
public abstract Builder setReference(Reference reference);
103102

104-
public abstract TypeNode build();
103+
// Private.
104+
abstract Reference reference();
105+
106+
abstract TypeNode autoBuild();
107+
108+
public TypeNode build() {
109+
if (reference() != null) {
110+
// Disallow top-level wildcard references.
111+
Preconditions.checkState(
112+
!reference().isWildcard(),
113+
String.format(
114+
"The top-level referenece in a type cannot be a wildcard, found %s",
115+
reference().name()));
116+
}
117+
return autoBuild();
118+
}
105119
}
106120

107121
// TODO(miraleung): More type creation helpers to come...

src/main/java/com/google/api/generator/engine/ast/VaporReference.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ public abstract class VaporReference implements Reference {
4141
@Override
4242
public abstract String enclosingClassName();
4343

44+
@Nullable
45+
@Override
46+
public Reference wildcardUpperBound() {
47+
return null;
48+
}
49+
4450
@Override
4551
public String fullName() {
4652
// TODO(unsupported): Nested classes with depth greater than 1.
@@ -75,6 +81,11 @@ public boolean isAssignableFrom(Reference other) {
7581
return false;
7682
}
7783

84+
@Override
85+
public boolean isWildcard() {
86+
return false;
87+
}
88+
7889
abstract String plainName();
7990

8091
@Override

src/main/java/com/google/api/generator/engine/writer/ImportWriterVisitor.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import com.google.api.generator.engine.ast.WhileStatement;
5252
import com.google.common.base.Preconditions;
5353
import java.util.ArrayList;
54+
import java.util.Arrays;
5455
import java.util.List;
5556
import java.util.Map;
5657
import java.util.Set;
@@ -347,9 +348,15 @@ private void variableExpressions(List<VariableExpr> expressions) {
347348
private void references(List<Reference> refs) {
348349
for (Reference ref : refs) {
349350
// Don't need to import this.
350-
if ((!ref.isStaticImport()
351-
&& (ref.isFromPackage(PKG_JAVA_LANG) || ref.isFromPackage(currentPackage)))
352-
|| ref.equals(TypeNode.WILDCARD_REFERENCE)) {
351+
if (!ref.isStaticImport()
352+
&& (ref.isFromPackage(PKG_JAVA_LANG) || ref.isFromPackage(currentPackage))) {
353+
continue;
354+
}
355+
356+
if (ref.isWildcard()) {
357+
if (ref.wildcardUpperBound() != null) {
358+
references(Arrays.asList(ref.wildcardUpperBound()));
359+
}
353360
continue;
354361
}
355362

src/test/java/com/google/api/generator/engine/ast/ConcreteReferenceTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,4 +140,12 @@ public void isSupertype_nestedGenerics() {
140140
assertTrue(typeOne.isSupertypeOrEquals(typeTwo));
141141
assertFalse(typeTwo.isSupertypeOrEquals(typeOne));
142142
}
143+
144+
@Test
145+
public void wildcards() {
146+
assertEquals("?", ConcreteReference.wildcard().name());
147+
assertEquals(
148+
"? extends String",
149+
ConcreteReference.wildcardWithUpperBound(TypeNode.STRING.reference()).name());
150+
}
143151
}

src/test/java/com/google/api/generator/engine/ast/TypeNodeTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import static junit.framework.Assert.assertFalse;
1818
import static junit.framework.Assert.assertTrue;
19+
import static org.junit.Assert.assertThrows;
1920

2021
import com.google.api.generator.engine.ast.TypeNode.TypeKind;
2122
import java.util.Arrays;
@@ -88,4 +89,32 @@ public void equals_basic() {
8889
assertFalse(TypeNode.CHAR.equals(TypeNode.NULL));
8990
assertFalse(INTEGER_ARRAY.equals(INT_ARRAY));
9091
}
92+
93+
@Test
94+
public void type_wildcardGenerics() {
95+
// No exception thrown equates to success.
96+
TypeNode.withReference(
97+
ConcreteReference.builder()
98+
.setClazz(List.class)
99+
.setGenerics(Arrays.asList(ConcreteReference.wildcard()))
100+
.build());
101+
}
102+
103+
@Test
104+
public void type_wildcardUpperBoundGenerics() {
105+
// No exception thrown equates to success.
106+
TypeNode.withReference(
107+
ConcreteReference.builder()
108+
.setClazz(List.class)
109+
.setGenerics(
110+
Arrays.asList(
111+
ConcreteReference.wildcardWithUpperBound(TypeNode.STRING.reference())))
112+
.build());
113+
}
114+
115+
@Test
116+
public void invalidType_topLevelWildcard() {
117+
assertThrows(
118+
IllegalStateException.class, () -> TypeNode.withReference(ConcreteReference.wildcard()));
119+
}
91120
}

src/test/java/com/google/api/generator/engine/writer/ImportWriterVisitorTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,50 @@ public void writeVariableExprImports_staticReference() {
475475
"import com.google.api.generator.engine.ast.TypeNode;\n\n"));
476476
}
477477

478+
@Test
479+
public void writeVariableExprImports_wildcardType() {
480+
TypeNode wildcardListType =
481+
TypeNode.withReference(
482+
ConcreteReference.builder()
483+
.setClazz(List.class)
484+
.setGenerics(Arrays.asList(TypeNode.WILDCARD_REFERENCE))
485+
.build());
486+
487+
// Constructs `List<?> x`.
488+
Variable variable = Variable.builder().setName("x").setType(wildcardListType).build();
489+
VariableExpr variableExpr =
490+
VariableExpr.builder().setIsDecl(true).setVariable(variable).build();
491+
492+
variableExpr.accept(writerVisitor);
493+
assertEquals(writerVisitor.write(), "import java.util.List;\n\n");
494+
}
495+
496+
@Test
497+
public void writeVariableExprImport_wildcardTypeWithUpperBound() {
498+
TypeNode wildcardListType =
499+
TypeNode.withReference(
500+
ConcreteReference.builder()
501+
.setClazz(List.class)
502+
.setGenerics(
503+
Arrays.asList(
504+
ConcreteReference.wildcardWithUpperBound(
505+
ConcreteReference.withClazz(Expr.class))))
506+
.build());
507+
508+
// Constructs `List<? extends Expr> x`.
509+
Variable variable = Variable.builder().setName("x").setType(wildcardListType).build();
510+
VariableExpr variableExpr =
511+
VariableExpr.builder().setIsDecl(true).setVariable(variable).build();
512+
513+
variableExpr.accept(writerVisitor);
514+
assertEquals(
515+
writerVisitor.write(),
516+
String.format(
517+
createLines(2),
518+
"import com.google.api.generator.engine.ast.Expr;\n",
519+
"import java.util.List;\n\n"));
520+
}
521+
478522
@Test
479523
public void writeVariableExprImports_reference() {
480524
Variable variable =

src/test/java/com/google/api/generator/engine/writer/JavaWriterVisitorTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,43 @@ public void writeVariableExpr_basic() {
205205
assertEquals(writerVisitor.write(), "x");
206206
}
207207

208+
@Test
209+
public void writeVariableExpr_wildcardType() {
210+
TypeNode wildcardListType =
211+
TypeNode.withReference(
212+
ConcreteReference.builder()
213+
.setClazz(List.class)
214+
.setGenerics(Arrays.asList(TypeNode.WILDCARD_REFERENCE))
215+
.build());
216+
217+
Variable variable = Variable.builder().setName("x").setType(wildcardListType).build();
218+
VariableExpr variableExpr =
219+
VariableExpr.builder().setIsDecl(true).setVariable(variable).build();
220+
221+
variableExpr.accept(writerVisitor);
222+
assertEquals(writerVisitor.write(), "List<?> x");
223+
}
224+
225+
@Test
226+
public void writeVariableExpr_wildcardTypeWithUpperBound() {
227+
TypeNode wildcardListType =
228+
TypeNode.withReference(
229+
ConcreteReference.builder()
230+
.setClazz(List.class)
231+
.setGenerics(
232+
Arrays.asList(
233+
ConcreteReference.wildcardWithUpperBound(
234+
ConcreteReference.withClazz(Expr.class))))
235+
.build());
236+
237+
Variable variable = Variable.builder().setName("x").setType(wildcardListType).build();
238+
VariableExpr variableExpr =
239+
VariableExpr.builder().setIsDecl(true).setVariable(variable).build();
240+
241+
variableExpr.accept(writerVisitor);
242+
assertEquals(writerVisitor.write(), "List<? extends Expr> x");
243+
}
244+
208245
@Test
209246
public void writeVariableExpr_staticReference() {
210247
VariableExpr variableExpr =

0 commit comments

Comments
 (0)