Skip to content

Commit 7e473ab

Browse files
author
Vincent Potucek
committed
fix method
1 parent 59318c9 commit 7e473ab

2 files changed

Lines changed: 168 additions & 100 deletions

File tree

pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java

Lines changed: 48 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import static net.sourceforge.pmd.util.CollectionUtil.setOf;
1010

1111
import java.util.Collection;
12-
import java.util.HashMap;
1312
import java.util.Map;
1413
import java.util.Set;
1514
import java.util.stream.Collectors;
@@ -41,15 +40,15 @@
4140
public class UnusedPrivateMethodRule extends AbstractIgnoredAnnotationRule {
4241

4342
private static final Set<String> SERIALIZATION_METHODS =
44-
setOf("readObject", "readObjectNoData", "writeObject", "readResolve", "writeReplace");
43+
setOf("readObject", "readObjectNoData", "writeObject", "readResolve", "writeReplace");
4544

4645
@Override
4746
protected Collection<String> defaultSuppressionAnnotations() {
4847
return listOf(
49-
"java.lang.Deprecated",
50-
"jakarta.annotation.PostConstruct",
51-
"jakarta.annotation.PreDestroy",
52-
"lombok.EqualsAndHashCode.Include"
48+
"java.lang.Deprecated",
49+
"jakarta.annotation.PostConstruct",
50+
"jakarta.annotation.PreDestroy",
51+
"lombok.EqualsAndHashCode.Include"
5352
);
5453
}
5554

@@ -62,73 +61,40 @@ public Object visit(ASTCompilationUnit file, Object param) {
6261
Set<String> methodsUsedByAnnotations = methodsUsedByAnnotations(file);
6362
Map<JExecutableSymbol, ASTMethodDeclaration> candidates = findCandidates(file, methodsUsedByAnnotations);
6463

65-
// First, remove methods that are called from within the same class
66-
removeMethodsCalledFromSameClass(file, candidates);
67-
6864
file.descendants()
69-
.crossFindBoundaries()
70-
.<MethodUsage>map(asInstanceOf(ASTMethodCall.class, ASTMethodReference.class))
71-
.forEach(ref -> {
72-
OverloadSelectionResult selectionInfo = ref.getOverloadSelectionInfo();
73-
JExecutableSymbol calledMethod = selectionInfo.getMethodType().getSymbol();
74-
if (calledMethod.isUnresolved()) {
75-
handleUnresolvedCall(ref, selectionInfo, candidates);
76-
return;
65+
.crossFindBoundaries()
66+
.<MethodUsage>map(asInstanceOf(ASTMethodCall.class, ASTMethodReference.class))
67+
.forEach(ref -> {
68+
OverloadSelectionResult selectionInfo = ref.getOverloadSelectionInfo();
69+
JExecutableSymbol calledMethod = selectionInfo.getMethodType().getSymbol();
70+
if (calledMethod.isUnresolved()) {
71+
handleUnresolvedCall(ref, selectionInfo, candidates);
72+
return;
73+
}
74+
candidates.compute(calledMethod, (sym2, reffed) -> {
75+
if (reffed != null && ref.ancestors(ASTMethodDeclaration.class).first() != reffed) {
76+
// remove mapping, but only if it is called from outside itself
77+
return null;
7778
}
78-
candidates.compute(calledMethod, (sym2, reffed) -> {
79-
if (reffed != null && ref.ancestors(ASTMethodDeclaration.class).first() != reffed) {
80-
// remove mapping, but only if it is called from outside itself
81-
return null;
82-
}
83-
return reffed;
84-
});
79+
return reffed;
8580
});
81+
});
8682

8783
for (ASTMethodDeclaration unusedMethod : candidates.values()) {
8884
asCtx(param).addViolation(unusedMethod, PrettyPrintingUtil.displaySignature(unusedMethod));
8985
}
9086
return null;
9187
}
9288

93-
/**
94-
* Remove methods that are called from within the same class from the candidates map.
95-
* This handles the case where private methods call other private methods in the same class.
96-
*/
97-
private void removeMethodsCalledFromSameClass(ASTCompilationUnit file, Map<JExecutableSymbol, ASTMethodDeclaration> candidates) {
98-
if (candidates.isEmpty()) {
99-
return;
100-
}
101-
102-
// Create a map of method names to their symbols for faster lookup
103-
Map<String, JExecutableSymbol> methodNameToSymbol = new HashMap<>();
104-
for (JExecutableSymbol symbol : candidates.keySet()) {
105-
methodNameToSymbol.put(symbol.getPackageName(), symbol);
106-
}
107-
108-
// Check each candidate method for calls to other private methods in the same class
109-
for (ASTMethodDeclaration method : candidates.values()) {
110-
method.descendants(ASTMethodCall.class)
111-
.crossFindBoundaries()
112-
.forEach(call -> {
113-
String calledMethodName = call.getMethodName();
114-
JExecutableSymbol calledSymbol = methodNameToSymbol.get(calledMethodName);
115-
if (calledSymbol != null && candidates.containsKey(calledSymbol)) {
116-
// This method calls another private method in the same class, so remove the called method
117-
candidates.remove(calledSymbol);
118-
}
119-
});
120-
}
121-
}
122-
12389
private static void handleUnresolvedCall(MethodUsage ref, OverloadSelectionResult selectionInfo, Map<JExecutableSymbol, ASTMethodDeclaration> candidates) {
12490
// If the type is may be an instance of this class, then the method may be
12591
// a call to a private method here. In that case we whitelist all methods
12692
// with that name.
12793
JTypeMirror receive = selectionInfo.getTypeToSearch();
12894
boolean receiverMayBeInstanceOfThisClass =
12995
receive == null
130-
|| TypeOps.isSpecialUnresolved(receive)
131-
|| receive.equals(ref.getEnclosingType().getTypeMirror());
96+
|| TypeOps.isSpecialUnresolved(receive)
97+
|| receive.equals(ref.getEnclosingType().getTypeMirror());
13298

13399
if (receiverMayBeInstanceOfThisClass) {
134100
candidates.values().removeIf(it -> it.getName().equals(ref.getMethodName()));
@@ -143,43 +109,43 @@ private static void handleUnresolvedCall(MethodUsage ref, OverloadSelectionResul
143109
*/
144110
private Map<JExecutableSymbol, ASTMethodDeclaration> findCandidates(ASTCompilationUnit file, Set<String> methodsUsedByAnnotations) {
145111
return file.descendants(ASTMethodDeclaration.class)
146-
.crossFindBoundaries()
147-
.filter(
148-
it -> it.getVisibility() == Visibility.V_PRIVATE
149-
&& !hasIgnoredAnnotation(it)
150-
&& !hasExcludedName(it)
151-
&& !(it.getArity() == 0 && methodsUsedByAnnotations.contains(it.getName())))
152-
.collect(Collectors.toMap(
153-
ASTMethodDeclaration::getSymbol,
154-
m -> m
155-
));
112+
.crossFindBoundaries()
113+
.filter(
114+
it -> it.getVisibility() == Visibility.V_PRIVATE
115+
&& !hasIgnoredAnnotation(it)
116+
&& !hasExcludedName(it)
117+
&& !(it.getArity() == 0 && methodsUsedByAnnotations.contains(it.getName())))
118+
.collect(Collectors.toMap(
119+
ASTMethodDeclaration::getSymbol,
120+
m -> m
121+
));
156122
}
157123

158124
private static Set<String> methodsUsedByAnnotations(ASTCompilationUnit file) {
159125
return file.descendants(ASTAnnotation.class)
160-
.crossFindBoundaries()
161-
.toStream()
162-
.flatMap(UnusedPrivateMethodRule::extractMethodsFromAnnotation)
163-
.collect(Collectors.toSet());
126+
.crossFindBoundaries()
127+
.toStream()
128+
.flatMap(UnusedPrivateMethodRule::extractMethodsFromAnnotation)
129+
.collect(Collectors.toSet());
164130
}
165131

166132
private static Stream<String> extractMethodsFromAnnotation(ASTAnnotation a) {
167133
return Stream.concat(
168-
a.getFlatValues().toStream()
169-
.map(ASTMemberValue::getConstValue)
170-
.map(asInstanceOf(String.class))
171-
.filter(StringUtils::isNotEmpty),
172-
NodeStream.of(a)
173-
.filter(it -> TypeTestUtil.isA("org.junit.jupiter.params.provider.MethodSource", it)
174-
&& it.getFlatValue("value").isEmpty())
175-
.ancestors(ASTMethodDeclaration.class)
176-
.take(1)
177-
.toStream()
178-
.map(ASTMethodDeclaration::getName)
134+
a.getFlatValues().toStream()
135+
.map(ASTMemberValue::getConstValue)
136+
.map(asInstanceOf(String.class))
137+
.filter(StringUtils::isNotEmpty),
138+
NodeStream.of(a)
139+
.filter(it -> TypeTestUtil.isA("org.junit.jupiter.params.provider.MethodSource", it)
140+
&& it.getFlatValue("value").isEmpty())
141+
.ancestors(ASTMethodDeclaration.class)
142+
.take(1)
143+
.toStream()
144+
.map(ASTMethodDeclaration::getName)
179145
);
180146
}
181147

182148
private boolean hasExcludedName(ASTMethodDeclaration node) {
183149
return SERIALIZATION_METHODS.contains(node.getName());
184150
}
185-
}
151+
}

pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml

Lines changed: 120 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2785,22 +2785,6 @@ class Foo {
27852785
<description>addAllImpl</description>
27862786
<expected-problems>0</expected-problems>
27872787
<code><![CDATA[
2788-
/*
2789-
* Copyright (C) 2007 The Guava Authors
2790-
*
2791-
* Licensed under the Apache License, Version 2.0 (the "License");
2792-
* you may not use this file except in compliance with the License.
2793-
* You may obtain a copy of the License at
2794-
*
2795-
* http://www.apache.org/licenses/LICENSE-2.0
2796-
*
2797-
* Unless required by applicable law or agreed to in writing, software
2798-
* distributed under the License is distributed on an "AS IS" BASIS,
2799-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2800-
* See the License for the specific language governing permissions and
2801-
* limitations under the License.
2802-
*/
2803-
28042788
package com.google.common.collect;
28052789
28062790
import static com.google.common.base.Preconditions.checkArgument;
@@ -2840,8 +2824,8 @@ import java.util.stream.Collector;
28402824
import org.jspecify.annotations.Nullable;
28412825
28422826
@GwtCompatible
2843-
public final class Multisets {
2844-
private Multisets() {}
2827+
public final class addAllImpl {
2828+
private addAllImpl() {}
28452829
28462830
/** An implementation of {@link Multiset#addAll}. */
28472831
static <E extends @Nullable Object> boolean addAllImpl(
@@ -2867,6 +2851,124 @@ public final class Multisets {
28672851
}
28682852
]]></code>
28692853
</test-code>
2854+
<test-code>
2855+
<description>addAllImpl2</description>
2856+
<expected-problems>0</expected-problems>
2857+
<code><![CDATA[
2858+
package com.google.common.collect;
2859+
2860+
import static com.google.common.base.Preconditions.checkArgument;
2861+
import static com.google.common.base.Preconditions.checkNotNull;
2862+
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
2863+
import static com.google.common.collect.CollectPreconditions.checkRemove;
2864+
import static java.lang.Math.max;
2865+
import static java.lang.Math.min;
2866+
import static java.util.Arrays.asList;
2867+
import static java.util.Objects.requireNonNull;
2868+
2869+
import com.google.common.annotations.GwtCompatible;
2870+
import com.google.common.annotations.GwtIncompatible;
2871+
import com.google.common.annotations.J2ktIncompatible;
2872+
import com.google.common.base.Predicate;
2873+
import com.google.common.base.Predicates;
2874+
import com.google.common.collect.Multiset.Entry;
2875+
import com.google.common.math.IntMath;
2876+
import com.google.common.primitives.Ints;
2877+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
2878+
import com.google.errorprone.annotations.InlineMe;
2879+
import com.google.errorprone.annotations.concurrent.LazyInit;
2880+
import java.io.Serializable;
2881+
import java.util.Arrays;
2882+
import java.util.Collection;
2883+
import java.util.Collections;
2884+
import java.util.Comparator;
2885+
import java.util.Iterator;
2886+
import java.util.NoSuchElementException;
2887+
import java.util.Objects;
2888+
import java.util.Set;
2889+
import java.util.Spliterator;
2890+
import java.util.function.Function;
2891+
import java.util.function.Supplier;
2892+
import java.util.function.ToIntFunction;
2893+
import java.util.stream.Collector;
2894+
import org.jspecify.annotations.Nullable;
2895+
2896+
@GwtCompatible
2897+
public final class addAllImpl {
2898+
private addAllImpl() {}
2899+
2900+
/** An implementation of {@link Multiset#addAll}. */
2901+
static <E extends @Nullable Object> boolean addAllImpl(
2902+
Multiset<E> self, Collection<? extends E> elements) {
2903+
return addAllImpl(self, (Multiset<? extends E>) elements);
2904+
}
2905+
2906+
/** A specialization of {@code addAllImpl} for when {@code elements} is itself a Multiset. */
2907+
private static <E extends @Nullable Object> boolean addAllImpl(
2908+
Multiset<E> self, Multiset<? extends E> elements) {
2909+
}
2910+
}
2911+
]]></code>
2912+
</test-code>
2913+
<test-code>
2914+
<description>addAllImplFoo</description>
2915+
<expected-problems>0</expected-problems>
2916+
<code><![CDATA[
2917+
package com.google.common.collect;
2918+
2919+
import static com.google.common.base.Preconditions.checkArgument;
2920+
import static com.google.common.base.Preconditions.checkNotNull;
2921+
import static com.google.common.collect.CollectPreconditions.checkNonnegative;
2922+
import static com.google.common.collect.CollectPreconditions.checkRemove;
2923+
import static java.lang.Math.max;
2924+
import static java.lang.Math.min;
2925+
import static java.util.Arrays.asList;
2926+
import static java.util.Objects.requireNonNull;
2927+
2928+
import com.google.common.annotations.GwtCompatible;
2929+
import com.google.common.annotations.GwtIncompatible;
2930+
import com.google.common.annotations.J2ktIncompatible;
2931+
import com.google.common.base.Predicate;
2932+
import com.google.common.base.Predicates;
2933+
import com.google.common.collect.Multiset.Entry;
2934+
import com.google.common.math.IntMath;
2935+
import com.google.common.primitives.Ints;
2936+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
2937+
import com.google.errorprone.annotations.InlineMe;
2938+
import com.google.errorprone.annotations.concurrent.LazyInit;
2939+
import java.io.Serializable;
2940+
import java.util.Arrays;
2941+
import java.util.Collection;
2942+
import java.util.Collections;
2943+
import java.util.Comparator;
2944+
import java.util.Iterator;
2945+
import java.util.NoSuchElementException;
2946+
import java.util.Objects;
2947+
import java.util.Set;
2948+
import java.util.Spliterator;
2949+
import java.util.function.Function;
2950+
import java.util.function.Supplier;
2951+
import java.util.function.ToIntFunction;
2952+
import java.util.stream.Collector;
2953+
import org.jspecify.annotations.Nullable;
2954+
2955+
@GwtCompatible
2956+
public final class addAllImpl {
2957+
private addAllImpl() {}
2958+
2959+
/** An implementation of {@link Multiset#addAll}. */
2960+
static <E extends @Nullable Object> boolean addAllImpl(
2961+
Multiset<E> self, Collection<? extends E> elements) {
2962+
return addAllImplFoo(self, (Multiset<? extends E>) elements);
2963+
}
2964+
2965+
/** A specialization of {@code addAllImpl} for when {@code elements} is itself a Multiset. */
2966+
private static <E extends @Nullable Object> boolean addAllImplFoo(
2967+
Multiset<E> self, Multiset<? extends E> elements) {
2968+
}
2969+
}
2970+
]]></code>
2971+
</test-code>
28702972

28712973

28722974

0 commit comments

Comments
 (0)