• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmd / pmd / 95

22 Jul 2025 05:33PM UTC coverage: 78.418% (-0.02%) from 78.436%
95

push

github

web-flow
chore: [scala] Fix javadoc config (#5920)

17758 of 23477 branches covered (75.64%)

Branch coverage included in aggregate %.

38997 of 48898 relevant lines covered (79.75%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.86
/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/SymbolEquality.java
1
/*
2
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3
 */
4

5
package net.sourceforge.pmd.lang.java.symbols.internal;
6

7
import java.util.Objects;
8

9
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
10
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
11
import net.sourceforge.pmd.lang.java.symbols.JElementSymbol;
12
import net.sourceforge.pmd.lang.java.symbols.JExecutableSymbol;
13
import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
14
import net.sourceforge.pmd.lang.java.symbols.JFormalParamSymbol;
15
import net.sourceforge.pmd.lang.java.symbols.JLocalVariableSymbol;
16
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
17
import net.sourceforge.pmd.lang.java.symbols.JRecordComponentSymbol;
18
import net.sourceforge.pmd.lang.java.symbols.JTypeParameterSymbol;
19
import net.sourceforge.pmd.lang.java.symbols.SymbolVisitor;
20
import net.sourceforge.pmd.lang.java.symbols.SymbolicValue.SymAnnot;
21
import net.sourceforge.pmd.lang.java.types.Substitution;
22

23
/**
24
 * Routines to share logic for equality, respecting the contract of
25
 * {@link JElementSymbol#equals(Object)}.
26
 *
27
 * <p>Despite this two equal symbols may not hold the same amount of
28
 * information... Reflection symbols are nice, but they also add some
29
 * synthetic stuff (eg implicit formal parameters, bridge methods),
30
 * which we must either filter-out or replicate in AST symbols. This is TODO
31
 */
32
public final class SymbolEquality {
33

34
    private SymbolEquality() {
35
        // util class
36
    }
37

38
    public static final EqAndHash<JTypeParameterSymbol> TYPE_PARAM = new EqAndHash<JTypeParameterSymbol>() {
1✔
39
        @Override
40
        public int hash(JTypeParameterSymbol t1) {
41
            return 31 * t1.getDeclaringSymbol().hashCode() + t1.getSimpleName().hashCode();
1✔
42
        }
43

44
        @Override
45
        public boolean equals(JTypeParameterSymbol m1, Object o) {
46
            if (m1 == o) {
1✔
47
                return true;
1✔
48
            }
49
            if (!(o instanceof JTypeParameterSymbol)) {
1!
50
                return false;
×
51
            }
52
            JTypeParameterSymbol m2 = (JTypeParameterSymbol) o;
1✔
53

54
            return Objects.equals(m1.getSimpleName(), m2.getSimpleName())
1✔
55
                && m1.getDeclaringSymbol().equals(m2.getDeclaringSymbol());
1✔
56
        }
57
    };
58

59
    public static final EqAndHash<JMethodSymbol> METHOD = new EqAndHash<JMethodSymbol>() {
1✔
60
        @Override
61
        public int hash(JMethodSymbol t1) {
62
            return t1.getArity() * t1.getModifiers() + 31 * t1.getSimpleName().hashCode();
1✔
63
        }
64

65
        @Override
66
        public boolean equals(JMethodSymbol m1, Object o) {
67
            if (m1 == o) {
1✔
68
                return true;
1✔
69
            }
70
            if (!(o instanceof JMethodSymbol)) {
1!
71
                return false;
×
72
            }
73
            JMethodSymbol m2 = (JMethodSymbol) o;
1✔
74

75
            return executableSymsAreEqual(m1, m2);
1✔
76
        }
77
    };
78

79
    private static boolean executableSymsAreEqual(JExecutableSymbol m1, JExecutableSymbol m2) {
80
        return m1.getModifiers() == m2.getModifiers()
1✔
81
            && m1.getArity() == m2.getArity()
1✔
82
            && Objects.equals(m1.getSimpleName(), m2.getSimpleName())
1!
83
            && m1.getEnclosingClass().equals(m2.getEnclosingClass())
1✔
84
            && m1.getFormalParameterTypes(Substitution.erasing(m1.getTypeParameters()))
1✔
85
                 .equals(m2.getFormalParameterTypes(Substitution.erasing(m2.getTypeParameters())));
1✔
86
    }
87

88
    public static final EqAndHash<JConstructorSymbol> CONSTRUCTOR = new EqAndHash<JConstructorSymbol>() {
1✔
89
        @Override
90
        public int hash(JConstructorSymbol t1) {
91
            return t1.getArity() * t1.getModifiers() + 31 * t1.getSimpleName().hashCode();
1✔
92
        }
93

94
        @Override
95
        public boolean equals(JConstructorSymbol m1, Object o) {
96
            if (m1 == o) {
1✔
97
                return true;
1✔
98
            }
99
            if (!(o instanceof JConstructorSymbol)) {
1!
100
                return false;
×
101
            }
102
            JConstructorSymbol m2 = (JConstructorSymbol) o;
1✔
103

104
            return executableSymsAreEqual(m1, m2);
1✔
105
        }
106
    };
107

108

109
    public static final EqAndHash<JClassSymbol> CLASS = new EqAndHash<JClassSymbol>() {
1✔
110
        @Override
111
        public int hash(JClassSymbol t1) {
112
            return t1.getBinaryName().hashCode();
1✔
113
        }
114

115
        @Override
116
        public boolean equals(JClassSymbol m1, Object o) {
117
            if (m1 == o) {
1✔
118
                return true;
1✔
119
            }
120
            if (!(o instanceof JClassSymbol)) {
1✔
121
                return false;
1✔
122
            }
123
            JClassSymbol m2 = (JClassSymbol) o;
1✔
124

125
            return m1.getBinaryName().equals(m2.getBinaryName());
1✔
126
        }
127
    };
128

129
    public static final EqAndHash<JFieldSymbol> FIELD = new EqAndHash<JFieldSymbol>() {
1✔
130
        @Override
131
        public int hash(JFieldSymbol t1) {
132
            return 31 * t1.getEnclosingClass().hashCode() + t1.getSimpleName().hashCode();
1✔
133
        }
134

135
        @Override
136
        public boolean equals(JFieldSymbol f1, Object o) {
137
            if (!(o instanceof JFieldSymbol)) {
1✔
138
                return false;
1✔
139
            }
140
            JFieldSymbol f2 = (JFieldSymbol) o;
1✔
141
            return Objects.equals(f1.getSimpleName(), f2.getSimpleName())
1✔
142
                && f1.getEnclosingClass().equals(f2.getEnclosingClass());
1✔
143

144
        }
145
    };
146

147
    public static final EqAndHash<SymAnnot> ANNOTATION = new EqAndHash<SymAnnot>() {
1✔
148
        @Override
149
        public int hash(SymAnnot t1) {
150
            return t1.getBinaryName().hashCode();
1✔
151
        }
152

153
        @Override
154
        public boolean equals(SymAnnot f1, Object o) {
155
            if (!(o instanceof SymAnnot)) {
1!
156
                return false;
×
157
            }
158
            SymAnnot f2 = (SymAnnot) o;
1✔
159
            return f1.getBinaryName().equals(f2.getBinaryName());
1✔
160

161
        }
162
    };
163

164
    public static final EqAndHash<JFormalParamSymbol> FORMAL_PARAM = new EqAndHash<JFormalParamSymbol>() {
1✔
165
        @Override
166
        public int hash(JFormalParamSymbol t1) {
167
            return 31 * t1.getDeclaringSymbol().hashCode() + t1.getSimpleName().hashCode();
1✔
168
        }
169

170
        @Override
171
        public boolean equals(JFormalParamSymbol f1, Object o) {
172
            if (!(o instanceof JFormalParamSymbol)) {
1✔
173
                return false;
1✔
174
            }
175
            JFormalParamSymbol f2 = (JFormalParamSymbol) o;
1✔
176
            return Objects.equals(f1.getSimpleName(), f2.getSimpleName())
1✔
177
                && f1.getDeclaringSymbol().equals(f2.getDeclaringSymbol());
1!
178

179
        }
180
    };
181

182

183
    public static final EqAndHash<JRecordComponentSymbol> RECORD_COMPONENT = new EqAndHash<JRecordComponentSymbol>() {
1✔
184
        @Override
185
        public int hash(JRecordComponentSymbol t1) {
186
            return 31 * t1.getEnclosingClass().hashCode() + t1.getSimpleName().hashCode();
×
187
        }
188

189
        @Override
190
        public boolean equals(JRecordComponentSymbol f1, Object o) {
191
            if (!(o instanceof JRecordComponentSymbol)) {
×
192
                return false;
×
193
            }
194
            JRecordComponentSymbol f2 = (JRecordComponentSymbol) o;
×
195
            return Objects.equals(f1.getSimpleName(), f2.getSimpleName())
×
196
                && f1.getEnclosingClass().equals(f2.getEnclosingClass());
×
197

198
        }
199
    };
200

201
    private static final EqAndHash<Object> IDENTITY = new EqAndHash<Object>() {
1✔
202
        @Override
203
        public int hash(Object t1) {
204
            return System.identityHashCode(t1);
×
205
        }
206

207
        @Override
208
        public boolean equals(Object t1, Object t2) {
209
            return t1 == t2;
×
210
        }
211
    };
212

213
    /**
214
     * Strategy to perform equals/hashcode for a type T. There are libraries
215
     * for that, whatever.
216
     */
217
    public abstract static class EqAndHash<T> {
1✔
218

219
        public abstract int hash(T t1);
220

221

222
        public abstract boolean equals(T t1, Object t2);
223

224
    }
225

226
    public static <T extends JElementSymbol> boolean equals(T e1, Object e2) {
227
        if (e1 == e2) {
1✔
228
            return true;
1✔
229
        } else if (e2 == null) {
1✔
230
            return false;
1✔
231
        }
232
        @SuppressWarnings("unchecked")
233
        EqAndHash<T> eqAndHash = (EqAndHash<T>) e1.acceptVisitor(EqAndHashVisitor.INSTANCE, null);
1✔
234
        return eqAndHash.equals(e1, e2);
1✔
235
    }
236

237
    public static <T extends JElementSymbol> int hash(T e1) {
238
        @SuppressWarnings("unchecked")
239
        EqAndHash<T> eqAndHash = (EqAndHash<T>) e1.acceptVisitor(EqAndHashVisitor.INSTANCE, null);
1✔
240
        return eqAndHash.hash(e1);
1✔
241
    }
242

243

244
    private static final class EqAndHashVisitor implements SymbolVisitor<EqAndHash<?>, Void> {
245

246
        static final EqAndHashVisitor INSTANCE = new EqAndHashVisitor();
1✔
247

248
        @Override
249
        public EqAndHash<?> visitSymbol(JElementSymbol sym, Void aVoid) {
250
            throw new IllegalStateException("Unknown symbol " + sym.getClass());
×
251
        }
252

253
        @Override
254
        public EqAndHash<?> visitClass(JClassSymbol sym, Void param) {
255
            return CLASS;
1✔
256
        }
257

258
        @Override
259
        public EqAndHash<?> visitTypeParam(JTypeParameterSymbol sym, Void param) {
260
            return TYPE_PARAM;
1✔
261
        }
262

263
        @Override
264
        public EqAndHash<?> visitCtor(JConstructorSymbol sym, Void param) {
265
            return CONSTRUCTOR;
1✔
266
        }
267

268
        @Override
269
        public EqAndHash<?> visitMethod(JMethodSymbol sym, Void param) {
270
            return METHOD;
1✔
271
        }
272

273
        @Override
274
        public EqAndHash<?> visitField(JFieldSymbol sym, Void param) {
275
            return FIELD;
1✔
276
        }
277

278
        @Override
279
        public EqAndHash<?> visitLocal(JLocalVariableSymbol sym, Void param) {
280
            return IDENTITY;
×
281
        }
282

283
        @Override
284
        public EqAndHash<?> visitFormal(JFormalParamSymbol sym, Void param) {
285
            return FORMAL_PARAM;
1✔
286
        }
287

288

289
        @Override
290
        public EqAndHash<?> visitRecordComponent(JRecordComponentSymbol sym, Void param) {
291
            return RECORD_COMPONENT;
×
292
        }
293
    }
294

295

296
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc