Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
f4ad227
upgrade to latest versions
theron-wang Jul 11, 2025
924f0ee
Refactor without unsolved symbol generation
theron-wang Jul 15, 2025
7a4adf5
make SpeciminRunner runnable
theron-wang Jul 15, 2025
637200c
unsolved symbol generation part 1
theron-wang Jul 18, 2025
9d56bff
forgot to include changes to `Slicer`
theron-wang Jul 18, 2025
cd3e6f4
add type parameter support
theron-wang Jul 18, 2025
4d5caf0
add handling for conditionals + operator in type guessing
theron-wang Jul 21, 2025
26f11f7
some fixes + best effort output
theron-wang Jul 24, 2025
224e427
add deleted files
theron-wang Jul 24, 2025
706f4a4
make it build
theron-wang Jul 24, 2025
702e4e3
fix some bugs
theron-wang Jul 25, 2025
e5e905d
more bug fixes + test case updates
theron-wang Jul 28, 2025
c6b6da1
make requested changes + add docs
theron-wang Jul 29, 2025
14e0c4c
handle array types
theron-wang Jul 29, 2025
3518456
some more bug fixes
theron-wang Jul 30, 2025
78523a7
add ambiguity case for unsolved method calls in solvable method/const…
theron-wang Jul 30, 2025
354dd2b
make some changes
theron-wang Jul 31, 2025
d4472fa
make some more changes
theron-wang Jul 31, 2025
8ead882
make comment changes from yesterday's review
theron-wang Jul 31, 2025
ead3cd4
make some fixes
theron-wang Jul 31, 2025
4c837f6
make fixes
theron-wang Jul 31, 2025
81648d5
bug fixes + short review changes
theron-wang Aug 1, 2025
6e928e0
add support for type arguments
theron-wang Aug 4, 2025
c369d72
must implement methods and other fixes
theron-wang Aug 6, 2025
14871d9
pr review changes
theron-wang Aug 6, 2025
f26bd72
fix some bugs
theron-wang Aug 8, 2025
7a6fc1c
fix anonymous classes, override in synthetic types, pr changes, lambd…
theron-wang Aug 8, 2025
02a8153
stop crashing for cases with solvable lambda constraint types
theron-wang Aug 11, 2025
093e895
small fixes and add additional test cases based on #423
theron-wang Aug 13, 2025
e60e057
super type relationships + bug fixes
theron-wang Aug 14, 2025
07bc8ea
allow inheritance for bounded wildcards and other type arguments + ja…
theron-wang Aug 15, 2025
ece78bb
fix a few bugs
theron-wang Aug 15, 2025
ebd54b3
address pr comments and start adding method reference support
theron-wang Aug 19, 2025
379da54
method references
theron-wang Aug 22, 2025
af5fa76
bug fixes + javadoc
theron-wang Aug 22, 2025
7a50937
fix must implement methods
theron-wang Sep 1, 2025
20ee324
must implement methods should generate in unsolved class + private ou…
theron-wang Sep 23, 2025
10a36ee
Merge branch 'main' of https://github.com/njit-jerse/specimin into re…
theron-wang Nov 6, 2025
03ee823
include methods that are implemented but referenced by an abstract su…
theron-wang Nov 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* UnsolvedField} to ensure proper types when alternates are generated.
*/
public abstract class MemberType {
private final List<MemberType> typeArguments;
private List<MemberType> typeArguments;

/**
* Creates a new MemberType with the given type arguments.
Expand All @@ -38,4 +38,13 @@ public MemberType(List<MemberType> typeArguments) {
public List<MemberType> getTypeArguments() {
return typeArguments;
}

/**
* Sets the type arguments for this type.
*
* @param typeArguments The list of member types representing the type arguments of this type
*/
public void setTypeArguments(List<MemberType> typeArguments) {
this.typeArguments = typeArguments;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
Expand Down Expand Up @@ -213,12 +214,17 @@ public void addSuperType(Set<MemberType> superTypes) {
}
}

Set<MemberType> sanitizedSuperTypes = new LinkedHashSet<>();
for (MemberType superType : superTypes) {
sanitizedSuperTypes.add(sanitizeMemberTypeForSuperTyping(superType));
}

if (commonType == UnsolvedClassOrInterfaceType.CLASS) {
superTypeRelationships.put(superTypes, SuperTypeRelationship.EXTENDS);
superTypeRelationships.put(sanitizedSuperTypes, SuperTypeRelationship.EXTENDS);
} else if (commonType == UnsolvedClassOrInterfaceType.INTERFACE) {
superTypeRelationships.put(superTypes, SuperTypeRelationship.IMPLEMENTS);
superTypeRelationships.put(sanitizedSuperTypes, SuperTypeRelationship.IMPLEMENTS);
} else if (superTypeRelationships.get(superTypes) == null) {
superTypeRelationships.put(superTypes, SuperTypeRelationship.UNKNOWN);
superTypeRelationships.put(sanitizedSuperTypes, SuperTypeRelationship.UNKNOWN);
}
}

Expand All @@ -242,7 +248,8 @@ public void forceSuperClass(MemberType superClass) {
setType(UnsolvedClassOrInterfaceType.CLASS);
}

superTypeRelationships.put(Set.of(superClass), SuperTypeRelationship.EXTENDS);
superTypeRelationships.put(
Set.of(sanitizeMemberTypeForSuperTyping(superClass)), SuperTypeRelationship.EXTENDS);
}

/**
Expand Down Expand Up @@ -273,7 +280,37 @@ public void forceSuperInterface(MemberType superInterface) {
return;
}

superTypeRelationships.put(Set.of(superInterface), SuperTypeRelationship.IMPLEMENTS);
superTypeRelationships.put(
Set.of(sanitizeMemberTypeForSuperTyping(superInterface)), SuperTypeRelationship.IMPLEMENTS);
}

/**
* Sanitizes a member type for supertyping such that it no longer contains any wildcards.
*
* @param memberType The member type to sanitize
* @return The sanitized member type
*/
private MemberType sanitizeMemberTypeForSuperTyping(MemberType memberType) {
if (memberType.getTypeArguments().isEmpty()) {
return memberType;
}

List<MemberType> sanitized = new ArrayList<>();

// I'm pretty sure this is not right, but until we find a better way to do this,
// this is what we'll do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What worries me about this is that the getTypeArgs iterator and the loop aren't moving in concert: getTypeArgs only advances when you find a wildcard. For a member type with a single type variable, this should work, but for something with many type variables (especially if there are two or more wildcards) I think they will get out of sync. For example, consider what would happen for a type like Foo<?, T extends Bar, ? extends Baz, String>.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you're right about this; the approach here is not good at all. I changed it so that it returns all possible types using the current type's defined type parameters. I don't think we'll ever encounter a type like Foo<?, T extends Bar, ? extends Baz, String> (mostly because of the T extends Bar, which isn't a valid type argument, right?), so take Foo<?, Bar, ? extends Baz, String> instead.

Using this example, if the current instance of UnsolvedClassOrInterfaceAlternates represents Bar<T, T1>, then the method should return Foo<T, Bar, T, String>, Foo<T, T extends Bar, T1, String>, Foo<T1, Bar, T1, String>, and so on.

Iterator<String> getTypeArgs = getTypeVariables().iterator();
for (int i = 0; i < memberType.getTypeArguments().size(); i++) {
MemberType typeArg = memberType.getTypeArguments().get(i);
if (typeArg instanceof WildcardMemberType) {
String typeVar = getTypeArgs.next();
typeArg = new SolvedMemberType(typeVar);
}
sanitized.add(sanitizeMemberTypeForSuperTyping(typeArg));
}

memberType.setTypeArguments(sanitized);
return memberType;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,7 @@ private void handleClassOrInterfaceType(
generated.setNumberOfTypeVariables(type.getTypeArguments().get().size());

NodeList<Type> typeArgs = type.getTypeArguments().get();
List<String> typeArgsPreferred =
new ArrayList<>(List.of(generated.getTypeVariablesAsString().split(",\\s*", -1)));
List<String> typeArgsPreferred = new ArrayList<>(generated.getTypeVariables());

boolean changed = false;

Expand Down Expand Up @@ -2473,7 +2472,7 @@ private void handleLHSAndRHSRelationship(
ResolvedType bound = typeParam.asWildcard().getBoundedType();
boolean isUpperBound = typeParam.asWildcard().isUpperBounded();

String erased = JavaParserUtil.erase(bound.describe());
String erased = JavaParserUtil.erase(resolved.describe());

Set<MemberType> rhsTypeParameters = new LinkedHashSet<>();
for (MemberType rhsType : rhsTypes) {
Expand All @@ -2493,7 +2492,7 @@ private void handleLHSAndRHSRelationship(
}
}

if (!typeArg.getFullyQualifiedNames().stream().anyMatch(erased::contains)) {
if (!rhsType.getFullyQualifiedNames().stream().anyMatch(erased::contains)) {
continue;
}

Expand Down Expand Up @@ -2544,7 +2543,7 @@ private void handleLHSAndRHSRelationship(
boolean isUpperBound = wildcard.isUpperBounded();

Set<String> erased =
bound.getFullyQualifiedNames().stream()
lhsType.getFullyQualifiedNames().stream()
.map(JavaParserUtil::erase)
.collect(Collectors.toSet());

Expand All @@ -2566,7 +2565,7 @@ private void handleLHSAndRHSRelationship(
}
}

if (!typeArg.getFullyQualifiedNames().stream().anyMatch(erased::contains)) {
if (!rhsType.getFullyQualifiedNames().stream().anyMatch(erased::contains)) {
continue;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package com.example;
public interface Set<E> extends com.example.Collection<E> {
public interface Set<T> extends com.example.Collection<T> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.example;
public class BadFoo<T> {

public BadFoo() {
throw new java.lang.Error();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.example;
public class Bar3 {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.example;
public class Baz3 extends com.example.Bar3 {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.example;
public class Foo<T> {
public class Foo<T> extends com.example.BadFoo<T> {

public Foo() {
throw new java.lang.Error();
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ public class Simple {

void bar() {
Foo<? extends Bar> foo = new Foo<Baz>();
Foo2<? extends Bar2> foo2 = new Foo2<Baz2>();
Foo<? extends Bar2> foo2 = new Foo<Baz2>();
BadFoo<? extends Bar3> badFoo = new BadFoo<Baz3>();
foo = foo2;
badFoo = foo2;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
public class Simple {
void bar() {
Foo<? extends Bar> foo = new Foo<Baz>();
Foo2<? extends Bar2> foo2 = new Foo2<Baz2>();
Foo<? extends Bar2> foo2 = new Foo<Baz2>();

// Foo2 should extend Foo, and Bar2 should extend Bar
BadFoo<? extends Bar3> badFoo = new BadFoo<Baz3>();

// Bar2 should extend Bar
foo = foo2;
// Foo should extend BadFoo, but Bar3 should have no super/subtypes
badFoo = foo2;
}
}
Loading