Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

review: fix: add handling for UnresolvedReferenceBinding in ReferenceBuilder #5294

Merged
merged 5 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/main/java/spoon/support/compiler/jdt/ReferenceBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.UnresolvedReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.VariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.VoidTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.WildcardBinding;
Expand Down Expand Up @@ -867,6 +868,8 @@ <T> CtTypeReference<T> getTypeReference(TypeBinding binding, boolean resolveGene
ref = getTypeReferenceFromProblemReferenceBinding((ProblemReferenceBinding) binding);
} else if (binding instanceof IntersectionTypeBinding18) {
ref = getTypeReferenceFromIntersectionTypeBinding((IntersectionTypeBinding18) binding);
} else if (binding instanceof UnresolvedReferenceBinding) {
ref = getTypeReferenceFromUnresolvedReferenceBinding((UnresolvedReferenceBinding) binding);
} else {
throw new RuntimeException("Unknown TypeBinding: " + binding.getClass() + " " + binding);
}
Expand All @@ -875,6 +878,25 @@ <T> CtTypeReference<T> getTypeReference(TypeBinding binding, boolean resolveGene
return (CtTypeReference<T>) ref;
}

/**
* Resolves a {@link UnresolvedReferenceBinding} to their closest match.
* For this we use the {@link UnresolvedReferenceBinding#closestMatch()} method. This is a best effort approach and can fail.
*
* @param binding the binding to resolve to a type reference.
* @return a type reference or null if the binding has no closest match
*/
@SuppressWarnings("ReturnOfNull")
private CtTypeReference<?> getTypeReferenceFromUnresolvedReferenceBinding(UnresolvedReferenceBinding binding) {
TypeBinding closestMatch = binding.closestMatch();
if (closestMatch != null) {
CtTypeReference<?> ref = this.jdtTreeBuilder.getFactory().Core().createTypeReference();
ref.setSimpleName(new String(binding.sourceName()));
ref.setPackage(getPackageReference(binding.getPackage()));
return ref;
}
return null;
}

private static boolean isParameterizedProblemReferenceBinding(TypeBinding binding) {
String sourceName = String.valueOf(binding.sourceName());
return binding instanceof ProblemReferenceBinding && typeRefContainsTypeArgs(sourceName);
Expand Down
21 changes: 19 additions & 2 deletions src/test/java/spoon/reflect/reference/CtTypeReferenceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,20 @@
import org.mockito.stubbing.Answer;
import spoon.Launcher;
import spoon.compiler.Environment;
import spoon.reflect.CtModel;
import spoon.reflect.declaration.CtType;
import spoon.reflect.factory.Factory;
import spoon.reflect.factory.TypeFactory;
import spoon.support.modelobs.FineModelChangeListener;
import spoon.support.reflect.reference.CtTypeReferenceImpl;

import spoon.testing.utils.GitHubIssue;
import java.util.function.Function;
import java.util.function.Supplier;

import static com.google.common.primitives.Primitives.allPrimitiveTypes;
import static com.google.common.primitives.Primitives.wrap;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import static spoon.testing.utils.Check.assertNotNull;

@ExtendWith(MockitoExtension.class)
Expand Down Expand Up @@ -121,4 +123,19 @@ void testGetActualClassForArray(String className, int arrayDepth, String expecte
);
}


@GitHubIssue(fixed = true, issueNumber = 5290)
@Test
void javaLangClassAsInputDoesNotCrashSpoon() {
Launcher launcher = new Launcher();
launcher.getEnvironment().setComplianceLevel(17);
launcher.getEnvironment().setIgnoreSyntaxErrors(true);
launcher.addInputResource("src/test/resources/jdk/Class.java");
CtModel model = launcher.buildModel();
String className = "java.lang.Class";
CtType<?> type = assertDoesNotThrow(() -> model.getAllTypes().stream()
.filter(it -> it.getQualifiedName().equals(className)).findFirst().orElseThrow());
assertEquals("java.lang.Class", type.getQualifiedName(),
"Class name should be java.lang.Class");
}
}