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

Implement equality checks for UnsolvedMethod based on the JLS rules #97

Merged
merged 5 commits into from
Jan 31, 2024

Conversation

kelloggm
Copy link
Collaborator

This solves one infinite loop that #87 triggers, but not all of them. The new test in this PR causes an infinite loop on main.

@kelloggm
Copy link
Collaborator Author

@LoiNguyenCS please make sure that when you merge this PR, #87 does not get automatically closed by GitHub (that has happened twice already with PRs related to #87, and I have had to go back and correct it).

Copy link
Collaborator

@LoiNguyenCS LoiNguyenCS left a comment

Choose a reason for hiding this comment

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

LGTM

@LoiNguyenCS LoiNguyenCS merged commit 4f1f5b7 into main Jan 31, 2024
1 check passed
@LoiNguyenCS LoiNguyenCS deleted the unsolvedmethod-equals branch January 31, 2024 16:28
kelloggm pushed a commit that referenced this pull request Jul 23, 2024
…rvation (#327)

This PR addresses an issue I discovered while running Specimin on
[NullAway issue #102](uber/NullAway#102),
where methods in an abstract class present in the parent interface of
the implemented interface were not preserved. For example:

Expected:
```java
package com.example;

import java.util.Iterator;

public class Foo<E> {
    public Iterator<E> iterator() {
        return new AbstractLinkedIterator() {
            @OverRide
            E computeNext() {
                throw new Error();
            }
        };
    }

    public abstract class AbstractLinkedIterator implements Iterator1<E> {
        abstract E computeNext();

        @OverRide
        public E next() {
            throw new Error();
        }

        @OverRide
        public boolean hasNext() {
            throw new Error();
        }
    }

    public interface Iterator1<E> extends Iterator<E> {
    }
}
```

Actual:
```java
package com.example;

import java.util.Iterator;

public class Foo<E> {
    public Iterator<E> iterator() {
        return new AbstractLinkedIterator() {
            @OverRide
            E computeNext() {
                throw new Error();
            }
        };
    }

    public abstract class AbstractLinkedIterator implements Iterator1<E> {
        abstract E computeNext();
    }

    public interface Iterator1<E> extends Iterator<E> {
    }
}
```

The current behavior is to only look for method declarations in the
direct parent interface `Iterator1`, but those methods are not present
there. This causes them to be removed and thus compile errors ensue.
However, I modified `MustImplementMethodsVisitor` to explore all
interface ancestors, so the `next()` and `hasNext()` methods are still
preserved. The test case can be found in `InterfaceChainTest`.

I also included a small tweak to annotation preservation in this PR;
previously, we preserved JDK annotations by seeing if it started with
`java.lang`, but I changed it to use `JavaLangUtils.inJdkPackage()`
instead after discovering a conflict when looking at [NullAway issue
#97](uber/NullAway#97).

Thank you!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants