Skip to content

Commit

Permalink
Always return a TypeParameter from resolve() (#706)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukehutch committed Nov 11, 2022
1 parent 9d4dfcb commit 395b6cd
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 20 deletions.
1 change: 0 additions & 1 deletion src/main/java/io/github/classgraph/FieldInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ public String getModifiersStr() {
return buf.toString();
}


/**
* Returns true if this field is a transient field.
*
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/github/classgraph/TypeParameter.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public final class TypeParameter extends HierarchicalTypeSignature {
* @param interfaceBounds
* The type parameter interface bound.
*/
private TypeParameter(final String identifier, final ReferenceTypeSignature classBound,
protected TypeParameter(final String identifier, final ReferenceTypeSignature classBound,
final List<ReferenceTypeSignature> interfaceBounds) {
super();
this.name = identifier;
Expand Down
60 changes: 42 additions & 18 deletions src/main/java/io/github/classgraph/TypeVariableSignature.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
package io.github.classgraph;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
Expand All @@ -49,6 +50,9 @@ public final class TypeVariableSignature extends ClassRefOrTypeVariableSignature
/** The method signature that this type variable is part of. */
MethodTypeSignature containingMethodSignature;

/** The resolved type parameter, if any. */
private TypeParameter typeParameterCached;

// -------------------------------------------------------------------------------------------------------------

/**
Expand Down Expand Up @@ -87,36 +91,47 @@ public String getName() {
* method or the enclosing class.
*/
public TypeParameter resolve() {
if (typeParameterCached != null) {
return typeParameterCached;
}
// Try resolving the type variable against the containing method
if (containingMethodSignature != null && containingMethodSignature.typeParameters != null
&& !containingMethodSignature.typeParameters.isEmpty()) {
for (final TypeParameter typeParameter : containingMethodSignature.typeParameters) {
if (typeParameter.name.equals(this.name)) {
typeParameterCached = typeParameter;
return typeParameter;
}
}
}
// If that failed, try resolving the type variable against the containing class
final ClassInfo containingClassInfo = getClassInfo();
if (containingClassInfo == null) {
throw new IllegalArgumentException("Could not find ClassInfo object for " + definingClassName);
}
ClassTypeSignature containingClassSignature = null;
try {
containingClassSignature = containingClassInfo.getTypeSignature();
} catch (final Exception e) {
// Ignore
}
if (containingClassSignature != null && containingClassSignature.typeParameters != null
&& !containingClassSignature.typeParameters.isEmpty()) {
for (final TypeParameter typeParameter : containingClassSignature.typeParameters) {
if (typeParameter.name.equals(this.name)) {
return typeParameter;
if (getClassName() != null) {
final ClassInfo containingClassInfo = getClassInfo();
if (containingClassInfo == null) {
throw new IllegalArgumentException("Could not find ClassInfo object for " + definingClassName);
}
ClassTypeSignature containingClassSignature = null;
try {
containingClassSignature = containingClassInfo.getTypeSignature();
} catch (final Exception e) {
// Ignore
}
if (containingClassSignature != null && containingClassSignature.typeParameters != null
&& !containingClassSignature.typeParameters.isEmpty()) {
for (final TypeParameter typeParameter : containingClassSignature.typeParameters) {
if (typeParameter.name.equals(this.name)) {
typeParameterCached = typeParameter;
return typeParameter;
}
}
}
}
throw new IllegalArgumentException(
"Could not resolve " + name + " against parameters of the defining method or enclosing class");
// If that failed, then this is a type variable that cannot be resolved.
// Return a new TypeParameter that only has the name set, with no class or interface bounds. (#706)
final TypeParameter typeParameter = new TypeParameter(name, null, Collections.emptyList());
typeParameter.setScanResult(scanResult);
typeParameterCached = typeParameter;
return typeParameter;
}

// -------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -191,7 +206,16 @@ protected String getClassName() {
*/
@Override
protected void findReferencedClassNames(final Set<String> refdClassNames) {
// No class names present in type variables
// Any class names present in resolved type variables have to be present in enclosing method or class,
// so there's no need to look up class references in resolved type variables
}

@Override
void setScanResult(final ScanResult scanResult) {
super.setScanResult(scanResult);
if (typeParameterCached != null) {
typeParameterCached.setScanResult(scanResult);
}
}

// -------------------------------------------------------------------------------------------------------------
Expand Down
31 changes: 31 additions & 0 deletions src/test/java/io/github/classgraph/issues/issue706/Issue706.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.github.classgraph.issues.issue706;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;

import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfo;
import io.github.classgraph.ScanResult;
import io.github.classgraph.TypeArgument;
import io.github.classgraph.TypeVariableSignature;

public class Issue706 {
static public class GenericBase<T> {
}

static public class GenericBypass<T> extends GenericBase<T> {
}

@Test
void genericSuperclass() {
final ScanResult scanResult = new ClassGraph().acceptPackages(Issue706.class.getPackage().getName())
.enableClassInfo().scan();
final ClassInfo bypassCls = scanResult.getClassInfo(GenericBypass.class.getName());
final TypeArgument superclassArg = bypassCls.getTypeSignature().getSuperclassSignature()
.getSuffixTypeArguments().get(0).get(0);
final TypeVariableSignature superclassArgTVar = (TypeVariableSignature) superclassArg.getTypeSignature();
final Object bypassTParamFromSuperclassArg = superclassArgTVar.resolve();
assertThat(bypassTParamFromSuperclassArg.toString()).isEqualTo("T");
}
}

0 comments on commit 395b6cd

Please sign in to comment.