Skip to content

Commit c4b475f

Browse files
thakeCopilottimtebeekJenson3210
authored
fix: KotlinVisitor.visitAnnotatedExpression now traverses inner expression (#6870)
* fix: KotlinVisitor.visitAnnotatedExpression now traverses inner expression The visitAnnotatedExpression method visited the annotation list but silently skipped visitAndCast on ae.getExpression(). This caused any visitor override (e.g. visitMethodInvocation) to miss nodes inside an annotated expression like @Suppress try { ... }. Fixes #6868 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: restore accidentally removed annotatedTypeInFunctionTypeParens test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix the AnnotatedExpression inner expression traversal --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Tim te Beek <tim@moderne.io> Co-authored-by: Jente Sondervorst <jentesondervorst@gmail.com>
1 parent fda3bb6 commit c4b475f

4 files changed

Lines changed: 45 additions & 1 deletion

File tree

rewrite-kotlin/src/main/java/org/openrewrite/kotlin/KotlinVisitor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public J visitAnnotatedExpression(K.AnnotatedExpression annotatedExpression, P p
6969
K.AnnotatedExpression ae = annotatedExpression;
7070
ae = ae.withMarkers(visitMarkers(ae.getMarkers(), p));
7171
ae = ae.withAnnotations(ListUtils.map(ae.getAnnotations(), a -> visitAndCast(a, p)));
72+
ae = ae.withExpression(visitAndCast(ae.getExpression(), p));
7273
Expression temp = (Expression) visitExpression(ae, p);
7374
if (!(temp instanceof K.AnnotatedExpression)) {
7475
return temp;

rewrite-kotlin/src/main/java/org/openrewrite/kotlin/format/MergeSpacesVisitor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public J visitAnnotatedExpression(K.AnnotatedExpression annotatedExpression, @Nu
7777
K.AnnotatedExpression ae = annotatedExpression;
7878
ae = ae.withMarkers(visitMarkers(ae.getMarkers(), newAnnotatedExpression.getMarkers()));
7979
ae = ae.withAnnotations(ListUtils.map(ae.getAnnotations(), (index, a) -> visitAndCast(a, newAnnotatedExpression.getAnnotations().get(index))));
80+
ae = ae.withExpression(visitAndCast(ae.getExpression(), newAnnotatedExpression.getExpression()));
8081
Expression temp = (Expression) visitExpression(ae, newAnnotatedExpression);
8182
if (!(temp instanceof K.AnnotatedExpression)) {
8283
return temp;

rewrite-kotlin/src/main/java/org/openrewrite/kotlin/format/TabsAndIndentsVisitor.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,10 @@ public Space visitSpace(Space space, Space.Location loc, P p) {
163163
} else if (parent != null && !getCursor().getParentOrThrow().getPath(J.Annotation.class::isInstance).hasNext()) {
164164
// when annotations are on their own line, other parts of the declaration that follow are aligned left to it
165165
alignToAnnotation = getCursor().pollNearestMessage("afterAnnotation") != null &&
166-
!(getCursor().getParentOrThrow().getValue() instanceof J.Annotation);
166+
!(getCursor().getParentOrThrow().getValue() instanceof J.Annotation) &&
167+
//Unlike Java LST element, where the parent has a list of annotations, AnnotatedExpression has sibling annotation and Expression in this one.
168+
//As the getCursor().pollNearestMessage("afterAnnotation") will not have been null, still the message will be gone if it was an AnnotatedExpression so no further action needed.
169+
!(getCursor().getParentOrThrow().getValue() instanceof K.AnnotatedExpression);
167170

168171
if ((loc == Space.Location.CLASS_KIND ||
169172
loc == Space.Location.METHOD_DECLARATION_PREFIX) &&

rewrite-kotlin/src/test/java/org/openrewrite/kotlin/tree/AnnotationTest.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
import org.junit.jupiter.api.Test;
1919
import org.junit.jupiter.params.ParameterizedTest;
2020
import org.junit.jupiter.params.provider.ValueSource;
21+
import org.openrewrite.ExecutionContext;
2122
import org.openrewrite.Issue;
2223
import org.openrewrite.java.tree.J;
24+
import org.openrewrite.kotlin.KotlinIsoVisitor;
2325
import org.openrewrite.kotlin.KotlinParser;
2426
import org.openrewrite.test.RewriteTest;
2527
import org.openrewrite.test.TypeValidation;
@@ -28,6 +30,7 @@
2830

2931
import static org.assertj.core.api.Assertions.assertThat;
3032
import static org.openrewrite.kotlin.Assertions.kotlin;
33+
import static org.openrewrite.test.RewriteTest.toRecipe;
3134

3235
@SuppressWarnings({"RedundantSuppression", "RedundantNullableReturnType", "RedundantVisibilityModifier", "UnusedReceiverParameter", "SortModifiers", "TrailingComma", "RedundantGetter", "RedundantSetter"})
3336
class AnnotationTest implements RewriteTest {
@@ -782,4 +785,40 @@ fun method ( ) {
782785
)
783786
);
784787
}
788+
789+
@Issue("https://github.com/openrewrite/rewrite/issues/6868")
790+
@Test
791+
void visitAnnotatedExpressionTraversesInnerExpression() {
792+
rewriteRun(
793+
spec -> spec
794+
.recipe(toRecipe(() -> new KotlinIsoVisitor<>() {
795+
@Override
796+
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
797+
if ("foo".equals(method.getSimpleName())) {
798+
return method.withName(method.getName().withSimpleName("bar"));
799+
}
800+
return super.visitMethodInvocation(method, ctx);
801+
}
802+
}))
803+
.typeValidationOptions(TypeValidation.none()),
804+
kotlin(
805+
"""
806+
fun main() {
807+
@Suppress("UNCHECKED_CAST")
808+
try {
809+
foo()
810+
} catch (e: Exception) {}
811+
}
812+
""",
813+
"""
814+
fun main() {
815+
@Suppress("UNCHECKED_CAST")
816+
try {
817+
bar()
818+
} catch (e: Exception) {}
819+
}
820+
"""
821+
)
822+
);
823+
}
785824
}

0 commit comments

Comments
 (0)