Skip to content

Commit e6043db

Browse files
authored
SONARJAVA-4960 False positive for S1854 (#5378)
1 parent 180bd37 commit e6043db

File tree

6 files changed

+124
-4
lines changed

6 files changed

+124
-4
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"ruleKey": "S1481",
33
"hasTruePositives": true,
4-
"falseNegatives": 10,
4+
"falseNegatives": 8,
55
"falsePositives": 0
66
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package checks;
2+
3+
4+
public class UnusedVariablesFPCheck {
5+
public class DeobfuscatedUpdateManager {
6+
// @formatter:off
7+
// uncommenting the following code makes the issue disappear, as the semantic is fully resolved
8+
// private interface DataContainer {
9+
// Iterable<ItemElement> getItems();
10+
// }
11+
//
12+
// private interface ModelObject {
13+
// void performAction();
14+
// }
15+
//
16+
// private interface ItemElement {
17+
// ModelObject getDataModel();
18+
// }
19+
//
20+
// private static class SystemConfig {
21+
// static ConfigMode getMode() {
22+
// return ConfigMode.ENABLED;
23+
// }
24+
// }
25+
//
26+
// private enum ConfigMode {
27+
// ENABLED,
28+
// DISABLED
29+
// }
30+
//
31+
// static class A {
32+
// interface GenericCallback<T> { }
33+
// }
34+
// @formatter:on
35+
36+
void processUpdates(
37+
DataContainer container
38+
// REMARK : the issue arises from the A.GenericCallback<ModelObject> callback that is not even used (indirect type resolution problem)
39+
, A.GenericCallback<X> callback
40+
) {
41+
for (ItemElement element : container.getItems()) {
42+
if (SystemConfig.getMode() == ConfigMode.ENABLED) {
43+
ModelObject dataModel = element.getDataModel(); // Compliant - false positive was raised here, dataModel is used in the next line
44+
dataModel.performAction();
45+
}
46+
}
47+
}
48+
49+
}
50+
51+
static class StringConcatenation {
52+
// @formatter:off
53+
// uncommenting the following code makes the issue disappear, as the semantic is fully resolved
54+
// private class AClass {
55+
// private class BClass<T> {
56+
// public T b;
57+
// }
58+
// }
59+
// @formatter:on
60+
61+
public String doSomething(AClass.BClass<String> instance) {
62+
String c = "Hi"; // Compliant - false positive was raised here, c is used in the next line
63+
return instance.b + c;
64+
}
65+
}
66+
67+
/*
68+
A user reported a FP on enhanced switch statements like the one below.
69+
However I was not able to reproduce it in a minimal example.
70+
https://community.sonarsource.com/t/false-positive-for-s1854-unused-assignments-should-be-removed/114110/12
71+
72+
static class EnhancedSwitch {
73+
// private enum DocumentStatus {
74+
// DOC01,
75+
// DOC02
76+
// }
77+
//
78+
// private interface Document {
79+
// void setStatus(DocumentStatus status);
80+
// }
81+
//
82+
// private interface Event {
83+
// }
84+
//
85+
// private class SimpleStatusChangedEvent implements Event {
86+
// }
87+
//
88+
// private class NeedClientRecheckEvent implements Event {
89+
// }
90+
// private interface DocumentRepository {
91+
// void save(Document document);
92+
// }
93+
94+
void ko(Event event, Document document, DocumentRepository documentRepository) {
95+
final DocumentStatus status = switch (event) {
96+
case SimpleStatusChangedEvent ignored -> DocumentStatus.DOC01;
97+
case NeedClientRecheckEvent ignored -> DocumentStatus.DOC02;
98+
};
99+
document.setStatus(status);
100+
// ...
101+
documentRepository.save(document);
102+
}
103+
104+
}*/
105+
}

java-checks/src/test/java/org/sonar/java/checks/DeadStoreCheckTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ void test_non_compiling() {
5151
.verifyIssues();
5252
}
5353

54+
@Test
55+
void test_incomplete_semantic() {
56+
CheckVerifier.newVerifier()
57+
.onFile(TestUtils.nonCompilingTestSourcesPath("checks/UnusedVariablesFPCheck.java"))
58+
.withCheck(new DeadStoreCheck())
59+
.verifyNoIssues();
60+
}
61+
5462
private static class EraseSymbols extends BaseTreeVisitor {
5563

5664
@Override

java-frontend/src/main/java/org/sonar/java/model/Symbols.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public final boolean isTypeSymbol() {
9999
}
100100

101101
@Override
102-
public final boolean isMethodSymbol() {
102+
public boolean isMethodSymbol() {
103103
return false;
104104
}
105105

@@ -340,6 +340,11 @@ public boolean isVarArgsMethod() {
340340
public boolean isNativeMethod() {
341341
return false;
342342
}
343+
344+
@Override
345+
public boolean isMethodSymbol() {
346+
return true;
347+
}
343348
}
344349

345350
public static final class UnknownType implements Type {

java-frontend/src/test/java/org/sonar/java/model/JParserSemanticTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1287,7 +1287,7 @@ private java.util.Collection<UnknownClass.Entry<E>> samples() {
12871287

12881288
assertThat(recovered.isTypeSymbol()).isFalse();
12891289
assertThat(recovered.isVariableSymbol()).isFalse();
1290-
assertThat(recovered.isMethodSymbol()).isFalse();
1290+
assertThat(recovered.isMethodSymbol()).isTrue();
12911291
assertThat(recovered.isPackageSymbol()).isFalse();
12921292

12931293
assertThat(recovered.isAbstract()).isFalse();

java-frontend/src/test/java/org/sonar/java/model/SymbolsTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ void unknown_symbol() {
125125
Symbol unknownSymbol = Symbol.UNKNOWN_SYMBOL;
126126

127127
assertCommonProperties(unknownSymbol);
128+
assertThat(unknownSymbol.isMethodSymbol()).isFalse();
128129
assertThat(unknownSymbol.name()).isEqualTo("!unknown!");
129130
assertThat(unknownSymbol.owner()).isEqualTo(Symbol.ROOT_PACKAGE);
130131
SymbolMetadata metadata = unknownSymbol.metadata();
@@ -137,6 +138,7 @@ void unknown_type_symbol() {
137138
Symbol.TypeSymbol unknownTypeSymbol = Symbol.TypeSymbol.UNKNOWN_TYPE;
138139

139140
assertCommonProperties(unknownTypeSymbol);
141+
assertThat(unknownTypeSymbol.isMethodSymbol()).isFalse();
140142
assertThat(unknownTypeSymbol.name()).isEqualTo("!unknown!");
141143
assertThat(unknownTypeSymbol.owner()).isEqualTo(Symbol.ROOT_PACKAGE);
142144

@@ -154,6 +156,7 @@ void unknown_method_symbol() {
154156
Symbol.MethodSymbol unknownMethodSymbol = Symbol.MethodSymbol.UNKNOWN_METHOD;
155157

156158
assertCommonProperties(unknownMethodSymbol);
159+
assertThat(unknownMethodSymbol.isMethodSymbol()).isTrue();
157160
assertThat(unknownMethodSymbol.name()).isEqualTo("!unknownMethod!");
158161
assertThat(unknownMethodSymbol.owner()).isEqualTo(Symbol.TypeSymbol.UNKNOWN_TYPE);
159162

@@ -171,7 +174,6 @@ private static void assertCommonProperties(Symbol unknownSymbol) {
171174
assertThat(unknownSymbol.isPackageSymbol()).isFalse();
172175
assertThat(unknownSymbol.isTypeSymbol()).isFalse();
173176
assertThat(unknownSymbol.isVariableSymbol()).isFalse();
174-
assertThat(unknownSymbol.isMethodSymbol()).isFalse();
175177

176178
assertThat(unknownSymbol.isStatic()).isFalse();
177179
assertThat(unknownSymbol.isFinal()).isFalse();

0 commit comments

Comments
 (0)