Skip to content

Commit c224b9a

Browse files
authored
Added Sonar codemod to remove unthrown exceptions (#445)
This change introduces a new codemod for removing unthrown exceptions as reported by Sonar.
1 parent dbd28fa commit c224b9a

File tree

8 files changed

+193
-1
lines changed

8 files changed

+193
-1
lines changed

core-codemods/src/main/java/io/codemodder/codemods/DefaultCodemods.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,16 @@ public static List<Class<? extends CodeChanger>> asList() {
5656
SemgrepOverlyPermissiveFilePermissionsCodemod.class,
5757
SimplifyRestControllerAnnotationsCodemod.class,
5858
SubstituteReplaceAllCodemod.class,
59+
SonarRemoveUnthrowableExceptionCodemod.class,
5960
SonarXXECodemod.class,
6061
SonarSQLInjectionCodemod.class,
62+
SonarUnsafeReflectionRemediationCodemod.class,
6163
SQLParameterizerCodemod.class,
6264
SSRFCodemod.class,
6365
StackTraceExposureCodemod.class,
6466
SwitchLiteralFirstComparisonsCodemod.class,
6567
SwitchToStandardCharsetsCodemod.class,
6668
UnverifiedJwtCodemod.class,
67-
SonarUnsafeReflectionRemediationCodemod.class,
6869
UpgradeSSLContextTLSCodemod.class,
6970
UpgradeSSLEngineTLSCodemod.class,
7071
UpgradeSSLParametersTLSCodemod.class,
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package io.codemodder.codemods;
2+
3+
import com.github.javaparser.ast.CompilationUnit;
4+
import com.github.javaparser.ast.type.ClassOrInterfaceType;
5+
import io.codemodder.*;
6+
import io.codemodder.codetf.DetectorRule;
7+
import io.codemodder.javaparser.ChangesResult;
8+
import io.codemodder.providers.sonar.ProvidedSonarScan;
9+
import io.codemodder.providers.sonar.RuleIssue;
10+
import io.codemodder.providers.sonar.SonarPluginJavaParserChanger;
11+
import io.codemodder.sonar.model.Issue;
12+
import javax.inject.Inject;
13+
14+
/** A codemod for automatically removing unthrowable exceptions. */
15+
@Codemod(
16+
id = "sonar:java/remove-unthrowable-exceptions-s1130",
17+
reviewGuidance = ReviewGuidance.MERGE_AFTER_CURSORY_REVIEW,
18+
importance = Importance.LOW,
19+
executionPriority = CodemodExecutionPriority.HIGH)
20+
public final class SonarRemoveUnthrowableExceptionCodemod
21+
extends SonarPluginJavaParserChanger<ClassOrInterfaceType, Issue> {
22+
23+
@Inject
24+
public SonarRemoveUnthrowableExceptionCodemod(
25+
@ProvidedSonarScan(ruleId = "java:S1130") final RuleIssue issues) {
26+
super(issues, ClassOrInterfaceType.class);
27+
}
28+
29+
@Override
30+
public ChangesResult onFindingFound(
31+
final CodemodInvocationContext context,
32+
final CompilationUnit cu,
33+
final ClassOrInterfaceType type,
34+
final Issue issue) {
35+
type.remove();
36+
return ChangesResult.changesApplied;
37+
}
38+
39+
@Override
40+
public DetectorRule detectorRule() {
41+
return new DetectorRule(
42+
"java:S1130",
43+
"Exceptions in \"throws\" clauses should not be superfluous",
44+
"https://rules.sonarsource.com/java/RSPEC-1130/");
45+
}
46+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
This change removes exceptions that Sonar believes are not possible to be thrown. Cleaning these improves readability and helps callers of the method understand how to effectively use the methods.
2+
3+
Our changes look something like this:
4+
5+
```diff
6+
- void it_throws_stuff() throws URISyntaxException {
7+
+ void it_throws_stuff() {
8+
// not yet implemented
9+
}
10+
```
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"summary" : "Removed unthrowable exception",
3+
"change" : "Removed unthrowable exception",
4+
"reviewGuidanceJustification" : "There should be no functional difference after the change, but the source code will be easier to understand.",
5+
"references" : [
6+
"https://rules.sonarsource.com/java/RSPEC-1130/"
7+
]
8+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.codemodder.codemods;
2+
3+
import io.codemodder.testutils.CodemodTestMixin;
4+
import io.codemodder.testutils.Metadata;
5+
6+
/** Test for {@link SonarRemoveUnthrowableExceptionCodemod}. */
7+
@Metadata(
8+
codemodType = SonarRemoveUnthrowableExceptionCodemod.class,
9+
testResourceDir = "remove-unthrowable-s1130",
10+
renameTestFile = "src/main/ThingTest.java",
11+
expectingFixesAtLines = {24},
12+
doRetransformTest = false,
13+
dependencies = {})
14+
final class SonarRemoveUnthrowableCodemodTest implements CodemodTestMixin {}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.acme;
2+
3+
import com.acme.Foo;
4+
import com.acme.Bar;
5+
import java.io.IOException;
6+
import java.net.URISyntaxException;
7+
import java.net.http.HttpResponse;
8+
import java.util.List;
9+
import org.junit.jupiter.api.Disabled;
10+
import org.junit.jupiter.api.Test;
11+
import org.kohsuke.github.GHIssueState;
12+
import org.kohsuke.github.GHPullRequest;
13+
import org.kohsuke.github.GHRepository;
14+
import org.kohsuke.github.GitHub;
15+
import org.slf4j.Logger;
16+
import org.slf4j.LoggerFactory;
17+
18+
/** This utility is not a real test -- just a way to quickly test these API invocations. */
19+
final class ThingTest {
20+
21+
@Disabled
22+
@Test
23+
void it_does_foo()
24+
throws IOException, InterruptedException {
25+
String a = "a";
26+
String b = "b";
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.acme;
2+
3+
import com.acme.Foo;
4+
import com.acme.Bar;
5+
import java.io.IOException;
6+
import java.net.URISyntaxException;
7+
import java.net.http.HttpResponse;
8+
import java.util.List;
9+
import org.junit.jupiter.api.Disabled;
10+
import org.junit.jupiter.api.Test;
11+
import org.kohsuke.github.GHIssueState;
12+
import org.kohsuke.github.GHPullRequest;
13+
import org.kohsuke.github.GHRepository;
14+
import org.kohsuke.github.GitHub;
15+
import org.slf4j.Logger;
16+
import org.slf4j.LoggerFactory;
17+
18+
/** This utility is not a real test -- just a way to quickly test these API invocations. */
19+
final class ThingTest {
20+
21+
@Disabled
22+
@Test
23+
void it_does_foo()
24+
throws IOException, URISyntaxException, InterruptedException {
25+
String a = "a";
26+
String b = "b";
27+
}
28+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"total": 4,
3+
"p": 1,
4+
"ps": 500,
5+
"paging": {
6+
"pageIndex": 1,
7+
"pageSize": 500,
8+
"total": 4
9+
},
10+
"effortTotal": 20,
11+
"debtTotal": 20,
12+
"issues": [
13+
{
14+
"key": "AY92LqQsXaXxNZYph9K2",
15+
"rule": "java:S1130",
16+
"severity": "MINOR",
17+
"component": "project_foo:src/main/ThingTest.java",
18+
"project": "project_foo",
19+
"hash": "eb19688940073fe18e692e9a5fc935f3",
20+
"textRange": {
21+
"startLine": 24,
22+
"endLine": 24,
23+
"startOffset": 26,
24+
"endOffset": 44
25+
},
26+
"flows": [],
27+
"resolution": "FIXED",
28+
"status": "CLOSED",
29+
"message": "Remove the declaration of thrown exception 'java.net.URISyntaxException', as it cannot be thrown from method's body.",
30+
"effort": "5min",
31+
"debt": "5min",
32+
"assignee": "zxc@github",
33+
"author": "[email protected]",
34+
"tags": [
35+
"clumsy",
36+
"error-handling",
37+
"redundant",
38+
"unused"
39+
],
40+
"creationDate": "2022-07-27T16:44:52+0200",
41+
"updateDate": "2024-08-14T00:29:42+0200",
42+
"closeDate": "2024-08-14T00:29:42+0200",
43+
"type": "CODE_SMELL",
44+
"organization": "pixee",
45+
"cleanCodeAttribute": "CLEAR",
46+
"cleanCodeAttributeCategory": "INTENTIONAL",
47+
"impacts": [
48+
{
49+
"softwareQuality": "MAINTAINABILITY",
50+
"severity": "LOW"
51+
}
52+
],
53+
"issueStatus": "FIXED"
54+
}
55+
]
56+
57+
}

0 commit comments

Comments
 (0)