Skip to content

Commit

Permalink
[javac] For wildcards, if the bound is not provided by the `DeclaredT…
Browse files Browse the repository at this point in the history
…ype`, get it from the type declaration

The following cases are handled:
```
// Given:
class C<T extends Iterator<Integer>> implements Iterable<Integer> {
  public T iterator();
}

// Case 1:
// In this case, the bound is null
C<?> a;
for (int s : a) {}

// Case 2:
// In this case, the bound is j.l.Object
C<? extends Object> b;
for (int s : b) {}
```

PiperOrigin-RevId: 698477543
  • Loading branch information
Googler authored and copybara-github committed Nov 20, 2024
1 parent e74135b commit 2c321a5
Showing 1 changed file with 39 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import javax.lang.model.type.IntersectionType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.WildcardType;

/** Utility functions to interact with JavaC internal representations. */
class JavaEnvironment {
Expand Down Expand Up @@ -317,8 +318,7 @@ private TypeDescriptor createTypeDescriptorWithNullability(
}

if (typeMirror.getKind() == TypeKind.WILDCARD) {
return createWildcardTypeVariable(
((javax.lang.model.type.WildcardType) typeMirror).getExtendsBound());
return createWildcardTypeVariable(((WildcardType) typeMirror).getExtendsBound());
}

boolean isNullable = isNullable(typeMirror, elementAnnotations, inNullMarkedScope);
Expand Down Expand Up @@ -398,7 +398,7 @@ private TypeVariable createTypeVariable(javax.lang.model.type.TypeVariable typeV
.build();
}

private TypeVariable createWildcardTypeVariable(TypeMirror bound) {
private TypeVariable createWildcardTypeVariable(@Nullable TypeMirror bound) {
return TypeVariable.newBuilder()
.setUpperBoundTypeDescriptorFactory(() -> createTypeDescriptor(bound))
.setWildcard(true)
Expand Down Expand Up @@ -994,13 +994,47 @@ private DeclaredTypeDescriptor createDeclaredType(
return cachedTypeDescriptor;
}

TypeDeclaration typeDeclaration = createDeclarationForType((TypeElement) classType.asElement());
DeclaredTypeDescriptor typeDescriptor =
createDeclarationForType((TypeElement) classType.asElement())
.toDescriptor(createTypeDescriptors(getTypeArguments(classType), inNullMarkedScope));
typeDeclaration.toDescriptor(
createTypeArgumentDescriptors(
getTypeArguments(classType), typeDeclaration, inNullMarkedScope));
putTypeDescriptorInCache(inNullMarkedScope, classType, typeDescriptor);
return typeDescriptor;
}

public ImmutableList<TypeDescriptor> createTypeArgumentDescriptors(
List<? extends TypeMirror> typeMirrors,
TypeDeclaration typeDeclaration,
boolean inNullMarkedScope) {
// TODO(b/246332093): Consider doing this in our type model after cleanup. Currently results in
// an infinite recursion.
return Streams.zip(
typeMirrors.stream(),
typeDeclaration.getTypeParameterDescriptors().stream(),
(typeMirror, declaredTypeVariable) -> {
if (typeMirror.getKind() == TypeKind.WILDCARD
&& isNullOrJavaLangObject(((WildcardType) typeMirror).getExtendsBound())
&& declaredTypeVariable != null) {
// If this is a wildcard but the bound is not specified (or is Object), we might be
// able to get a tighter bound from the declaration.
return TypeVariable.createWildcardWithUpperBound(
declaredTypeVariable.getUpperBoundTypeDescriptor());
}
return createTypeDescriptor(typeMirror, inNullMarkedScope);
})
.collect(toImmutableList());
}

private boolean isNullOrJavaLangObject(@Nullable TypeMirror typeMirror) {
if (typeMirror == null) {
return true;
}
Element element = asElement(typeMirror);
return element instanceof TypeElement
&& ((TypeElement) element).getQualifiedName().contentEquals("java.lang.Object");
}

private final Map<DeclaredType, DeclaredTypeDescriptor>
cachedDeclaredTypeDescriptorByDeclaredTypeInNullMarkedScope = new HashMap<>();

Expand Down

0 comments on commit 2c321a5

Please sign in to comment.