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

Preserve MustImplementMethodsVisitor method type ancestors #329

Merged
merged 18 commits into from
Jul 25, 2024

Conversation

theron-wang
Copy link
Collaborator

This PR addresses an issue I found in NullAway issue #103, where compile-time errors were caused by missing methods and types. The missing methods were caused by the following:

1) Methods not preserved

Foo extends (abstract) Bar extends [Some JDK interface]

If Bar contains an abstract method also present in the JDK interface, those implementations in Foo were removed while the abstract definition was maintained in Bar, causing compile-time errors. A check was added to ensure that all super abstract methods did not contain anything that needed to be preserved (i.e. when in Foo, instead of just checking Bar, we check Bar and the JDK interface).

2. Classes not preserved

If a non-target class needs its method implementations to be preserved, and some of its return/parameter types are solvable but were untracked so far by usedTypeElements, their ancestors were not preserved. For example, if a method visited by MustImplementMethodsVisitor is of type PeekingIterator<E> which extends Iterator<E>, the extends Iterator<E> portion is kept in the original definition but its import statement was removed, leading to compile-time errors. The new approach to this is, if a type element was not previously in usedTypeElements, all of its ancestors (interfaces and super classes) would also be marked for preservation.

A test case can be found in Issue103Test.

Thanks!

@kelloggm kelloggm self-requested a review July 24, 2024 14:00
Copy link
Collaborator

@kelloggm kelloggm left a comment

Choose a reason for hiding this comment

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

There are two failing integration tests:

  • CF-6060 appears to be failing because exception types thrown by preserved interface methods aren't themselves preserved. I think this is an easy fix (see comment).
  • CF-6030 is failing because a meta-annotation on a preserved annotation isn't being preserved. I'm not sure what that has to do with this PR, so you'll have to investigate @theron-wang

|| (overridden == null && overridesAnInterfaceMethod(method))) {
ResolvedMethodDeclaration resolvedMethod = method.resolve();
Set<String> returnAndParamTypes = new HashSet<>();
Map<String, ResolvedType> returnAndParamTypes = new HashMap<>();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the values in this map also need to include thrown exceptional types. The new code exposes a problem caused by not doing that in CF-6060, which it looks like is why that integration test fails.

@theron-wang
Copy link
Collaborator Author

CF-6030 is failing because a meta-annotation on a preserved annotation isn't being preserved. I'm not sure what that has to do with this PR, so you'll have to investigate

Yep, I believe this was a side-effect of the approach I took with this PR; basically, a previously-unincluded method which had a parent abstract method which had another parent interface method in the JDK (it's strange, sorry) was now marked to be preserved, along with its annotation. The annotation definition referenced an inner annotation which was not included due to an issue with #302 which I fixed in this PR.

@theron-wang theron-wang requested a review from kelloggm July 25, 2024 16:54
Copy link
Collaborator

@kelloggm kelloggm left a comment

Choose a reason for hiding this comment

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

LGTM other than one minor request. I don't need to review again before merging.

@@ -184,6 +265,7 @@ private boolean overridesAnInterfaceMethodImpl(
for (String name : typeParametersMap.getNames()) {
String interfaceViewpointName = name.substring(name.lastIndexOf('.') + 1);
String localViewpointName = typeParametersMap.getValueBySignature(name).get().describe();
localViewpointName = Pattern.quote(localViewpointName);
Copy link
Collaborator

Choose a reason for hiding this comment

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

A comment justifying why quoting this is necessary will be helpful later, so that we don't accidentally delete it.

@kelloggm kelloggm merged commit 8710e4a into njit-jerse:main Jul 25, 2024
2 checks passed
@theron-wang theron-wang deleted the abstract-method-types branch July 25, 2024 19:03
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