Skip to content

Commit 14f7766

Browse files
authored
Merge pull request #395 from openrewrite/csharp-catch-only-rethrow
Adjust `CatchClauseOnlyRethrows` to work with C#
2 parents 8a0343b + f1a83f4 commit 14f7766

File tree

3 files changed

+132
-23
lines changed

3 files changed

+132
-23
lines changed

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
import org.openrewrite.ExecutionContext;
1919
import org.openrewrite.Recipe;
20+
import org.openrewrite.SourceFile;
2021
import org.openrewrite.TreeVisitor;
22+
import org.openrewrite.csharp.tree.Cs;
2123
import org.openrewrite.internal.ListUtils;
2224
import org.openrewrite.java.JavaIsoVisitor;
2325
import org.openrewrite.java.tree.Expression;
@@ -113,6 +115,13 @@ private boolean onlyRethrows(J.Try.Catch aCatch) {
113115
}
114116

115117
Expression exception = ((J.Throw) aCatch.getBody().getStatements().get(0)).getException();
118+
119+
// In C# an implicit rethrow is possible
120+
if (getCursor().firstEnclosing(SourceFile.class) instanceof Cs &&
121+
exception instanceof J.Empty) {
122+
return true;
123+
}
124+
116125
JavaType catchParameterType = aCatch.getParameter().getType();
117126
if (!(catchParameterType instanceof JavaType.MultiCatch)) {
118127
JavaType.FullyQualified catchType = TypeUtils.asFullyQualified(catchParameterType);

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

Lines changed: 77 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,19 @@
1717

1818
import org.junit.jupiter.api.Test;
1919
import org.openrewrite.DocumentExample;
20+
import org.openrewrite.ExecutionContext;
21+
import org.openrewrite.InMemoryExecutionContext;
22+
import org.openrewrite.Tree;
23+
import org.openrewrite.csharp.tree.Cs;
24+
import org.openrewrite.java.JavaVisitor;
25+
import org.openrewrite.java.tree.J;
26+
import org.openrewrite.java.tree.Space;
27+
import org.openrewrite.marker.Markers;
2028
import org.openrewrite.test.RecipeSpec;
2129
import org.openrewrite.test.RewriteTest;
2230

2331
import static org.openrewrite.java.Assertions.java;
32+
import static org.openrewrite.test.RewriteTest.toRecipe;
2433

2534
@SuppressWarnings("ALL")
2635
class CatchClauseOnlyRethrowsTest implements RewriteTest {
@@ -38,7 +47,7 @@ void rethrownButWithDifferentMessage() {
3847
"""
3948
import java.io.FileReader;
4049
import java.io.IOException;
41-
50+
4251
class A {
4352
void foo() throws IOException {
4453
try {
@@ -63,7 +72,7 @@ void catchShouldBePreservedBecauseLessSpecificCatchFollows() {
6372
"""
6473
import java.io.FileReader;
6574
import java.io.IOException;
66-
75+
6776
class A {
6877
void foo() throws IOException {
6978
try {
@@ -90,7 +99,7 @@ void catchShouldBePreservedBecauseLessSpecificCatchFollowsWithMultiCast() {
9099
"""
91100
import java.io.FileReader;
92101
import java.io.IOException;
93-
102+
94103
class A {
95104
void foo() throws IOException {
96105
try {
@@ -116,7 +125,7 @@ void tryCanBeRemoved() {
116125
"""
117126
import java.io.FileReader;
118127
import java.io.IOException;
119-
128+
120129
class A {
121130
void foo() throws IOException {
122131
try {
@@ -130,7 +139,7 @@ void foo() throws IOException {
130139
"""
131140
import java.io.FileReader;
132141
import java.io.IOException;
133-
142+
134143
class A {
135144
void foo() throws IOException {
136145
new FileReader("").read();
@@ -150,7 +159,7 @@ void tryCanBeRemovedWithMultiCatch() {
150159
import java.io.FileReader;
151160
import java.io.IOException;
152161
import java.io.FileNotFoundException;
153-
162+
154163
class A {
155164
void foo() throws IOException {
156165
try {
@@ -166,16 +175,16 @@ void foo() throws IOException {
166175
}
167176
""",
168177
"""
169-
import java.io.FileReader;
170-
import java.io.IOException;
171-
import java.io.FileNotFoundException;
172-
173-
class A {
174-
void foo() throws IOException {
175-
new FileReader("").read();
176-
}
177-
}
178-
"""
178+
import java.io.FileReader;
179+
import java.io.IOException;
180+
import java.io.FileNotFoundException;
181+
182+
class A {
183+
void foo() throws IOException {
184+
new FileReader("").read();
185+
}
186+
}
187+
"""
179188
)
180189
);
181190
}
@@ -189,7 +198,7 @@ void multiCatchPreservedOnDifferentThrow() {
189198
import java.io.FileReader;
190199
import java.io.IOException;
191200
import java.io.FileNotFoundException;
192-
201+
193202
class A {
194203
void foo() throws IOException {
195204
try {
@@ -214,7 +223,7 @@ void tryShouldBePreservedBecauseFinally() {
214223
"""
215224
import java.io.FileReader;
216225
import java.io.IOException;
217-
226+
218227
class A {
219228
void foo() throws IOException {
220229
try {
@@ -230,7 +239,7 @@ void foo() throws IOException {
230239
"""
231240
import java.io.FileReader;
232241
import java.io.IOException;
233-
242+
234243
class A {
235244
void foo() throws IOException {
236245
try {
@@ -253,7 +262,7 @@ void tryShouldBePreservedBecauseResources() {
253262
"""
254263
import java.io.FileReader;
255264
import java.io.IOException;
256-
265+
257266
class A {
258267
void foo() throws IOException {
259268
try(FileReader fr = new FileReader("")) {
@@ -267,7 +276,7 @@ void foo() throws IOException {
267276
"""
268277
import java.io.FileReader;
269278
import java.io.IOException;
270-
279+
271280
class A {
272281
void foo() throws IOException {
273282
try(FileReader fr = new FileReader("")) {
@@ -288,7 +297,7 @@ void wrappingAndRethrowingIsUnchanged() {
288297
"""
289298
import java.io.FileReader;
290299
import java.io.IOException;
291-
300+
292301
class A {
293302
void foo() {
294303
try {
@@ -311,7 +320,7 @@ void loggingAndRethrowingIsUnchanged() {
311320
"""
312321
import java.io.FileReader;
313322
import java.io.IOException;
314-
323+
315324
class A {
316325
void foo() throws IOException {
317326
try {
@@ -326,4 +335,49 @@ void foo() throws IOException {
326335
)
327336
);
328337
}
338+
339+
@Test
340+
void verifyCsharpImplicitThrow() {
341+
rewriteRun(
342+
spec -> spec.recipe(toRecipe(() -> new JavaVisitor<>() {
343+
@Override
344+
public J visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
345+
// C# can rethrow the caught exception implicitly and so the `e` Identifier is removed by the inline visitor below
346+
Cs.CompilationUnit cscu = JavaToCsharp.compilationUnit(cu);
347+
cscu = (Cs.CompilationUnit) new JavaVisitor<ExecutionContext>() {
348+
@Override
349+
public J visitThrow(J.Throw thrown, ExecutionContext ctx) {
350+
if (thrown.getException() instanceof J.Identifier) {
351+
return thrown.withException(new J.Empty(Tree.randomId(), Space.EMPTY, Markers.EMPTY));
352+
}
353+
return thrown;
354+
}
355+
}.visit(cscu, new InMemoryExecutionContext());
356+
// Exercise the regular recipe with the now modified CSharp compilation unit
357+
return (J) new CatchClauseOnlyRethrows().getVisitor().visit(cscu, ctx);
358+
}
359+
})),
360+
//language=java
361+
java(
362+
"""
363+
class A {
364+
void foo() throws IllegalAccessException {
365+
try {
366+
throw new IllegalAccessException();
367+
} catch (Exception e) {
368+
throw e; // `e` is removed below
369+
}
370+
}
371+
}
372+
""",
373+
"""
374+
class A {
375+
void foo() throws IllegalAccessException {
376+
throw new IllegalAccessException();
377+
}
378+
}
379+
"""
380+
)
381+
);
382+
}
329383
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.staticanalysis;
17+
18+
import org.openrewrite.csharp.tree.Cs;
19+
import org.openrewrite.java.tree.J;
20+
import org.openrewrite.java.tree.JRightPadded;
21+
import org.openrewrite.java.tree.Statement;
22+
23+
import java.util.List;
24+
25+
public class JavaToCsharp {
26+
27+
public static Cs.CompilationUnit compilationUnit(J.CompilationUnit cu) {
28+
return new Cs.CompilationUnit(
29+
cu.getId(),
30+
cu.getPrefix(),
31+
cu.getMarkers(),
32+
cu.getSourcePath(),
33+
cu.getFileAttributes(),
34+
cu.getCharset().name(),
35+
cu.isCharsetBomMarked(),
36+
cu.getChecksum(),
37+
List.of(),
38+
List.of(),
39+
List.of(),
40+
cu.getClasses().stream()
41+
.map(Statement.class::cast)
42+
.map(JRightPadded::build)
43+
.toList(),
44+
cu.getEof());
45+
}
46+
}

0 commit comments

Comments
 (0)