Skip to content

Commit e0213ae

Browse files
committed
bug fix
1 parent 9c08bc5 commit e0213ae

File tree

2 files changed

+52
-19
lines changed

2 files changed

+52
-19
lines changed

nullaway/src/main/java/com/uber/nullaway/generics/GenericsChecks.java

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1756,28 +1756,35 @@ public Nullness getGenericMethodReturnTypeNullness(
17561756
private @Nullable Type getTypeForSymbol(Symbol symbol, VisitorState state) {
17571757
if (symbol.isAnonymous()) {
17581758
// For anonymous classes, symbol.type does not contain annotations on generic type parameters.
1759-
// So, we get a correct type from the enclosing NewClassTree representing the anonymous class.
1759+
// So, we get a correct type from the NewClassTree representing the anonymous class.
1760+
// The nearest enclosing NewClassTree on the current path may be some other constructor call,
1761+
// such as when `this` from an anonymous class is passed as an argument to a constructor.
17601762
TreePath path = state.getPath();
1761-
path =
1762-
castToNonNull(ASTHelpers.findPathFromEnclosingNodeToTopLevel(path, NewClassTree.class));
1763-
NewClassTree newClassTree = (NewClassTree) path.getLeaf();
1764-
if (newClassTree.getClassBody() == null) {
1765-
throw new RuntimeException(
1766-
"method should be directly inside an anonymous NewClassTree "
1767-
+ state.getSourceForNode(path.getLeaf()));
1768-
}
1769-
Type typeFromTree = getTreeType(newClassTree, state);
1770-
if (typeFromTree != null) {
1771-
verify(
1772-
state.getTypes().isAssignable(symbol.type, typeFromTree),
1773-
"%s is not assignable to %s",
1774-
symbol.type,
1775-
typeFromTree);
1763+
while (path != null) {
1764+
if (path.getLeaf() instanceof NewClassTree newClassTree
1765+
&& newClassTree.getClassBody() != null) {
1766+
Type newClassType = ASTHelpers.getType(newClassTree);
1767+
if (newClassType != null && newClassType.tsym.equals(symbol)) {
1768+
Type typeFromTree = getTreeType(newClassTree, state);
1769+
if (typeFromTree != null) {
1770+
verify(
1771+
state.getTypes().isAssignable(symbol.type, typeFromTree),
1772+
"%s is not assignable to %s",
1773+
symbol.type,
1774+
typeFromTree);
1775+
}
1776+
return typeFromTree;
1777+
}
1778+
}
1779+
path = path.getParentPath();
17761780
}
1777-
return typeFromTree;
1778-
} else {
1779-
return symbol.type;
1781+
throw new RuntimeException(
1782+
"could not find anonymous NewClassTree for symbol "
1783+
+ symbol
1784+
+ " from path "
1785+
+ state.getSourceForNode(state.getPath().getLeaf()));
17801786
}
1787+
return symbol.type;
17811788
}
17821789

17831790
public Nullness getGenericMethodReturnTypeNullness(

nullaway/src/test/java/com/uber/nullaway/jspecify/GenericsTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,6 +1653,32 @@ interface TestInterface<T extends @Nullable Object> {
16531653
.doTest();
16541654
}
16551655

1656+
@Test
1657+
public void constructorCallWithThisFromAnonymousClass() {
1658+
makeHelper()
1659+
.addSourceLines(
1660+
"Test.java",
1661+
"""
1662+
package com.uber;
1663+
import org.jspecify.annotations.NullMarked;
1664+
@NullMarked
1665+
class Test {
1666+
static class TakesRunnable {
1667+
TakesRunnable(Runnable runnable) {}
1668+
}
1669+
void repro() {
1670+
new Runnable() {
1671+
@Override
1672+
public void run() {
1673+
new TakesRunnable(this);
1674+
}
1675+
};
1676+
}
1677+
}
1678+
""")
1679+
.doTest();
1680+
}
1681+
16561682
@Test
16571683
public void explicitlyTypedAnonymousClassAsReceiver() {
16581684
makeHelper()

0 commit comments

Comments
 (0)