diff --git a/its/ruling/src/test/resources/guava/java-S9149.json b/its/ruling/src/test/resources/guava/java-S9149.json index 27b7bf41cdf..668d592520d 100644 --- a/its/ruling/src/test/resources/guava/java-S9149.json +++ b/its/ruling/src/test/resources/guava/java-S9149.json @@ -1,7 +1,4 @@ { -"com.google.guava:guava:src/com/google/common/collect/ContiguousSet.java": [ -193 -], "com.google.guava:guava:src/com/google/common/collect/ImmutableBiMap.java": [ 41, 48, @@ -40,43 +37,15 @@ 180, 218 ], -"com.google.guava:guava:src/com/google/common/collect/ImmutableSortedMapFauxverideShim.java": [ -37, -51, -65, -80, -95, -110 -], "com.google.guava:guava:src/com/google/common/collect/ImmutableSortedMultiset.java": [ 63, 171, 189 ], -"com.google.guava:guava:src/com/google/common/collect/ImmutableSortedMultisetFauxverideShim.java": [ -44, -58, -72, -86, -100, -115, -130, -145 -], "com.google.guava:guava:src/com/google/common/collect/ImmutableSortedSet.java": [ 78, 200, 237, 256 -], -"com.google.guava:guava:src/com/google/common/collect/ImmutableSortedSetFauxverideShim.java": [ -46, -60, -74, -88, -103, -118, -133, -147 ] } diff --git a/java-checks-test-sources/default/src/main/java/checks/StaticMethodHidingCheckSample.java b/java-checks-test-sources/default/src/main/java/checks/StaticMethodHidingCheckSample.java index fab2f12f23b..41dd6b65882 100644 --- a/java-checks-test-sources/default/src/main/java/checks/StaticMethodHidingCheckSample.java +++ b/java-checks-test-sources/default/src/main/java/checks/StaticMethodHidingCheckSample.java @@ -1,5 +1,6 @@ package checks; +import com.google.errorprone.annotations.DoNotCall; import java.util.List; class StaticMethodHidingCheckSample { @@ -223,4 +224,68 @@ static class MultiChild extends MultiParent { static void second() { // Noncompliant {{Rename this method; it hides "second" in "MultiParent".}} } } + + // --- Compliant: intentional hiding with @Deprecated annotation --- + + static class DeprecatingParent { + static void oldMethod() { + } + + static String convert(String input) { + return input; + } + } + + static class DeprecatingChild extends DeprecatingParent { + @Deprecated + static void oldMethod() { // Compliant - intentional hiding with @Deprecated + throw new UnsupportedOperationException(); + } + + @Deprecated + static String convert(String input) { // Compliant - intentional hiding with @Deprecated + throw new UnsupportedOperationException(); + } + } + + // --- Compliant: intentional hiding with @DoNotCall annotation --- + + static class DoNotCallParent { + static void unsafeMethod() { + } + } + + static class DoNotCallChild extends DoNotCallParent { + @DoNotCall("Use alternative method") + static void unsafeMethod() { // Compliant - intentional hiding with @DoNotCall + throw new UnsupportedOperationException(); + } + } + + // --- Compliant: intentional hiding with both @Deprecated and @DoNotCall --- + + static class CombinedParent { + static void legacyApi() { + } + } + + static class CombinedChild extends CombinedParent { + @Deprecated + @DoNotCall("Use newApi instead") + static void legacyApi() { // Compliant - intentional hiding with @Deprecated and @DoNotCall + throw new UnsupportedOperationException(); + } + } + + // --- Noncompliant: hiding without any deprecation annotation --- + + static class PlainParent { + static void compute() { + } + } + + static class PlainChild extends PlainParent { + static void compute() { // Noncompliant {{Rename this method; it hides "compute" in "PlainParent".}} + } + } } diff --git a/java-checks/src/main/java/org/sonar/java/checks/StaticMethodHidingCheck.java b/java-checks/src/main/java/org/sonar/java/checks/StaticMethodHidingCheck.java index 5318c0712f0..bdbbc6675dc 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/StaticMethodHidingCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/StaticMethodHidingCheck.java @@ -41,7 +41,7 @@ public void visitNode(Tree tree) { } MethodTree methodTree = (MethodTree) tree; Symbol.MethodSymbol methodSymbol = methodTree.symbol(); - if (!methodSymbol.isStatic()) { + if (!methodSymbol.isStatic() || isIntentionalHiding(methodSymbol)) { return; } Symbol.TypeSymbol owner = (Symbol.TypeSymbol) methodSymbol.owner(); @@ -79,6 +79,11 @@ private void reportHidingIssue(MethodTree methodTree, Symbol.MethodSymbol method } } + private static boolean isIntentionalHiding(Symbol.MethodSymbol methodSymbol) { + return methodSymbol.metadata().isAnnotatedWith("java.lang.Deprecated") + || methodSymbol.metadata().isAnnotatedWith("com.google.errorprone.annotations.DoNotCall"); + } + private static boolean hasSameParameterTypes(Symbol.MethodSymbol method, Symbol.MethodSymbol candidate) { List methodParams = method.parameterTypes(); List candidateParams = candidate.parameterTypes();