Skip to content

Commit 49c3ddf

Browse files
protocol7sambsnydknutwannhedentimtebeekgithub-actions[bot]
authored
RemoveRedundantTypeCast should not remove required downcast (#495)
* RemoveRedundantTypeCast should not remove required downcast Adds a failing test case for where RemoveRedundantTypeCast should not remove a downcast that is necessary for chained calls to get matching types. * refactor: Resolve conflict in `RemoveRedundantTypeCastTest` after moved test * Update src/test/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCastTest.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Push potential fix * Apply formatter * Minimize test --------- Co-authored-by: Sam Snyder <sam@moderne.io> Co-authored-by: Knut Wannheden <knut@moderne.io> Co-authored-by: Tim te Beek <tim@moderne.io> Co-authored-by: Tim te Beek <timtebeek@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 12283cf commit 49c3ddf

2 files changed

Lines changed: 43 additions & 0 deletions

File tree

src/main/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCast.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,21 @@ public J visitTypeCast(J.TypeCast typeCast, ExecutionContext ctx) {
112112
return visitedTypeCast;
113113
}
114114

115+
// Special case: if this cast is in a generic method call that's part of a method chain,
116+
// the cast might be necessary to control generic type inference
117+
if (parentValue instanceof J.MethodInvocation &&
118+
TypeUtils.isAssignableTo(castType, expressionType) &&
119+
!castType.equals(expressionType)) {
120+
// Check if the method returns a generic type
121+
JavaType.Method methodType = ((J.MethodInvocation) parentValue).getMethodType();
122+
if (methodType != null && methodType.getReturnType() instanceof JavaType.Parameterized) {
123+
// This cast is widening the type (e.g., BarImpl to Bar) in a generic context
124+
// which might affect how the generic type is inferred in method chains
125+
// Keep the cast to be safe
126+
return visitedTypeCast;
127+
}
128+
}
129+
115130
if (!(targetType instanceof JavaType.Array) && TypeUtils.isOfClassType(targetType, "java.lang.Object") ||
116131
TypeUtils.isOfType(targetType, expressionType) ||
117132
TypeUtils.isAssignableTo(targetType, expressionType)) {

src/test/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCastTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,4 +528,32 @@ void bar(Marshaller marshaller) {
528528
)
529529
);
530530
}
531+
532+
@Test
533+
void dontRemoveNecessaryDowncast() {
534+
rewriteRun(
535+
// language=java
536+
java(
537+
"""
538+
import java.util.Optional;
539+
540+
interface Bar {}
541+
class BarImpl implements Bar {}
542+
class Foo {
543+
private Bar getBar() {
544+
return new BarImpl();
545+
}
546+
547+
private BarImpl getBarImpl() {
548+
return new BarImpl();
549+
}
550+
551+
public Bar baz() {
552+
return Optional.of((Bar) getBarImpl()).orElse(getBar());
553+
}
554+
}
555+
"""
556+
)
557+
);
558+
}
531559
}

0 commit comments

Comments
 (0)