diff --git a/its/autoscan/src/test/resources/autoscan/diffs/diff_S1481.json b/its/autoscan/src/test/resources/autoscan/diffs/diff_S1481.json index 9bd4666fbb..0a9e1c62b2 100644 --- a/its/autoscan/src/test/resources/autoscan/diffs/diff_S1481.json +++ b/its/autoscan/src/test/resources/autoscan/diffs/diff_S1481.json @@ -1,6 +1,6 @@ { "ruleKey": "S1481", "hasTruePositives": true, - "falseNegatives": 10, + "falseNegatives": 8, "falsePositives": 0 } diff --git a/java-checks-test-sources/default/src/main/files/non-compiling/checks/UnusedVariablesFPCheck.java b/java-checks-test-sources/default/src/main/files/non-compiling/checks/UnusedVariablesFPCheck.java new file mode 100644 index 0000000000..006e39ff22 --- /dev/null +++ b/java-checks-test-sources/default/src/main/files/non-compiling/checks/UnusedVariablesFPCheck.java @@ -0,0 +1,105 @@ +package checks; + + +public class UnusedVariablesFPCheck { + public class DeobfuscatedUpdateManager { + // @formatter:off +// uncommenting the following code makes the issue disappear, as the semantic is fully resolved +// private interface DataContainer { +// Iterable getItems(); +// } +// +// private interface ModelObject { +// void performAction(); +// } +// +// private interface ItemElement { +// ModelObject getDataModel(); +// } +// +// private static class SystemConfig { +// static ConfigMode getMode() { +// return ConfigMode.ENABLED; +// } +// } +// +// private enum ConfigMode { +// ENABLED, +// DISABLED +// } +// +// static class A { +// interface GenericCallback { } +// } + // @formatter:on + + void processUpdates( + DataContainer container + // REMARK : the issue arises from the A.GenericCallback callback that is not even used (indirect type resolution problem) + , A.GenericCallback callback + ) { + for (ItemElement element : container.getItems()) { + if (SystemConfig.getMode() == ConfigMode.ENABLED) { + ModelObject dataModel = element.getDataModel(); // Compliant - false positive was raised here, dataModel is used in the next line + dataModel.performAction(); + } + } + } + + } + + static class StringConcatenation { + // @formatter:off +// uncommenting the following code makes the issue disappear, as the semantic is fully resolved +// private class AClass { +// private class BClass { +// public T b; +// } +// } + // @formatter:on + + public String doSomething(AClass.BClass instance) { + String c = "Hi"; // Compliant - false positive was raised here, c is used in the next line + return instance.b + c; + } + } + +/* + A user reported a FP on enhanced switch statements like the one below. + However I was not able to reproduce it in a minimal example. + https://community.sonarsource.com/t/false-positive-for-s1854-unused-assignments-should-be-removed/114110/12 + + static class EnhancedSwitch { +// private enum DocumentStatus { +// DOC01, +// DOC02 +// } +// +// private interface Document { +// void setStatus(DocumentStatus status); +// } +// +// private interface Event { +// } +// +// private class SimpleStatusChangedEvent implements Event { +// } +// +// private class NeedClientRecheckEvent implements Event { +// } +// private interface DocumentRepository { +// void save(Document document); +// } + + void ko(Event event, Document document, DocumentRepository documentRepository) { + final DocumentStatus status = switch (event) { + case SimpleStatusChangedEvent ignored -> DocumentStatus.DOC01; + case NeedClientRecheckEvent ignored -> DocumentStatus.DOC02; + }; + document.setStatus(status); + // ... + documentRepository.save(document); + } + + }*/ +} diff --git a/java-checks/src/test/java/org/sonar/java/checks/DeadStoreCheckTest.java b/java-checks/src/test/java/org/sonar/java/checks/DeadStoreCheckTest.java index 395d5e9635..3255bb089c 100644 --- a/java-checks/src/test/java/org/sonar/java/checks/DeadStoreCheckTest.java +++ b/java-checks/src/test/java/org/sonar/java/checks/DeadStoreCheckTest.java @@ -51,6 +51,15 @@ void test_non_compiling() { .verifyIssues(); } + @Test + void test_incomplete_semantic() { + CheckVerifier.newVerifier() + .onFile(TestUtils.nonCompilingTestSourcesPath("checks/UnusedVariablesFPCheck.java")) + .withJavaVersion(14) + .withCheck(new DeadStoreCheck()) + .verifyNoIssues(); + } + private static class EraseSymbols extends BaseTreeVisitor { @Override diff --git a/java-frontend/src/main/java/org/sonar/java/model/Symbols.java b/java-frontend/src/main/java/org/sonar/java/model/Symbols.java index 901db702be..19b5ef3d6b 100644 --- a/java-frontend/src/main/java/org/sonar/java/model/Symbols.java +++ b/java-frontend/src/main/java/org/sonar/java/model/Symbols.java @@ -99,7 +99,7 @@ public final boolean isTypeSymbol() { } @Override - public final boolean isMethodSymbol() { + public boolean isMethodSymbol() { return false; } @@ -340,6 +340,11 @@ public boolean isVarArgsMethod() { public boolean isNativeMethod() { return false; } + + @Override + public boolean isMethodSymbol() { + return true; + } } public static final class UnknownType implements Type { diff --git a/java-frontend/src/test/java/org/sonar/java/model/JParserSemanticTest.java b/java-frontend/src/test/java/org/sonar/java/model/JParserSemanticTest.java index bd7b0a1766..6dd0136518 100644 --- a/java-frontend/src/test/java/org/sonar/java/model/JParserSemanticTest.java +++ b/java-frontend/src/test/java/org/sonar/java/model/JParserSemanticTest.java @@ -1285,7 +1285,7 @@ private java.util.Collection> samples() { assertThat(recovered.isTypeSymbol()).isFalse(); assertThat(recovered.isVariableSymbol()).isFalse(); - assertThat(recovered.isMethodSymbol()).isFalse(); + assertThat(recovered.isMethodSymbol()).isTrue(); assertThat(recovered.isPackageSymbol()).isFalse(); assertThat(recovered.isAbstract()).isFalse(); diff --git a/java-frontend/src/test/java/org/sonar/java/model/SymbolsTest.java b/java-frontend/src/test/java/org/sonar/java/model/SymbolsTest.java index 1cb3732ed2..bccfc56a32 100644 --- a/java-frontend/src/test/java/org/sonar/java/model/SymbolsTest.java +++ b/java-frontend/src/test/java/org/sonar/java/model/SymbolsTest.java @@ -171,7 +171,6 @@ private static void assertCommonProperties(Symbol unknownSymbol) { assertThat(unknownSymbol.isPackageSymbol()).isFalse(); assertThat(unknownSymbol.isTypeSymbol()).isFalse(); assertThat(unknownSymbol.isVariableSymbol()).isFalse(); - assertThat(unknownSymbol.isMethodSymbol()).isFalse(); assertThat(unknownSymbol.isStatic()).isFalse(); assertThat(unknownSymbol.isFinal()).isFalse();