Skip to content

Commit 34bfb95

Browse files
SONARJAVA-6179 Fix FP on S6810 when semantic information is missing (#5501)
1 parent cbc2064 commit 34bfb95

3 files changed

Lines changed: 51 additions & 3 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package checks.spring;
2+
3+
import java.util.concurrent.CompletableFuture;
4+
import java.util.concurrent.Future;
5+
import org.springframework.scheduling.annotation.Async;
6+
7+
public class AsyncMethodsReturnTypeCheckSample {
8+
9+
@Async
10+
public CompletableFuture<Data> unknownTypeArg() { // Compliant
11+
return CompletableFuture.completedFuture(new Data());
12+
}
13+
14+
@Async
15+
public void voidType() { // Compliant
16+
return;
17+
}
18+
19+
@Async
20+
public CompletableFuture<Integer> futureSubtype() { // Compliant
21+
return CompletableFuture.completedFuture(42);
22+
}
23+
24+
@Async
25+
public Data unknownType() { // Compliant, no issue is raised when the return type is unknown (it might be a subtype of Future)
26+
return new Data();
27+
}
28+
29+
@Async
30+
public Integer builtinType() { // Noncompliant {{Async methods should return 'void' or a 'Future' type.}}
31+
// ^^^^^^^
32+
return 42;
33+
}
34+
35+
}

java-checks/src/main/java/org/sonar/java/checks/spring/AsyncMethodsReturnTypeCheck.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
import org.sonar.check.Rule;
2121
import org.sonar.java.checks.helpers.SpringUtils;
2222
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
23+
import org.sonar.plugins.java.api.semantic.Type;
2324
import org.sonar.plugins.java.api.tree.MethodTree;
2425
import org.sonar.plugins.java.api.tree.Tree;
26+
import org.sonar.plugins.java.api.tree.TypeTree;
2527

2628
@Rule(key = "S6810")
2729
public class AsyncMethodsReturnTypeCheck extends IssuableSubscriptionVisitor {
@@ -35,12 +37,14 @@ public List<Tree.Kind> nodesToVisit() {
3537
public void visitNode(Tree tree) {
3638
var mt = (MethodTree) tree;
3739
if (mt.symbol().metadata().isAnnotatedWith(SpringUtils.ASYNC_ANNOTATION)) {
38-
var returnType = mt.returnType();
40+
TypeTree returnType = mt.returnType();
3941
// returnType can only be null if the method is a constructor. Since the @Async annotation is not allowed on constructors, and since
4042
// we hence only visit methods, not constructors, we assume that returnType is not null.
41-
if (!returnType.symbolType().isVoid() && !returnType.symbolType().isSubtypeOf("java.util.concurrent.Future")) {
42-
reportIssue(returnType, "Async methods should return 'void' or a 'Future' type.");
43+
Type symbolType = returnType.symbolType();
44+
if (symbolType.isUnknown() || symbolType.isVoid() || symbolType.isSubtypeOf("java.util.concurrent.Future")) {
45+
return;
4346
}
47+
reportIssue(returnType, "Async methods should return 'void' or a 'Future' type.");
4448
}
4549
}
4650
}

java-checks/src/test/java/org/sonar/java/checks/spring/AsyncMethodsReturnTypeCheckTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.sonar.java.checks.verifier.CheckVerifier;
2121

2222
import static org.sonar.java.checks.verifier.TestUtils.mainCodeSourcesPath;
23+
import static org.sonar.java.checks.verifier.TestUtils.nonCompilingTestSourcesPath;
2324

2425
class AsyncMethodsReturnTypeCheckTest {
2526
@Test
@@ -29,4 +30,12 @@ void test() {
2930
.withCheck(new AsyncMethodsReturnTypeCheck())
3031
.verifyIssues();
3132
}
33+
34+
@Test
35+
void test_non_compiling() {
36+
CheckVerifier.newVerifier()
37+
.onFile(nonCompilingTestSourcesPath("checks/spring/AsyncMethodsReturnTypeCheckSample.java"))
38+
.withCheck(new AsyncMethodsReturnTypeCheck())
39+
.verifyIssues();
40+
}
3241
}

0 commit comments

Comments
 (0)