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

pmd / pmd / #3722

pending completion
#3722

push

github actions

adangel
Suppress MissingOverride for Chars::isEmpty (#4291)

67270 of 127658 relevant lines covered (52.7%)

0.53 hits per line

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

97.64
/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/ast/AstClassSym.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.ast;
6

7
import java.util.ArrayList;
8
import java.util.Collections;
9
import java.util.List;
10
import java.util.Objects;
11

12
import org.checkerframework.checker.nullness.qual.NonNull;
13
import org.checkerframework.checker.nullness.qual.Nullable;
14
import org.pcollections.HashTreePSet;
15
import org.pcollections.PSet;
16

17
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
18
import net.sourceforge.pmd.lang.java.ast.ASTBodyDeclaration;
19
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
20
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
21
import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall;
22
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
23
import net.sourceforge.pmd.lang.java.ast.ASTEnumConstant;
24
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
25
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
26
import net.sourceforge.pmd.lang.java.ast.ASTRecordComponent;
27
import net.sourceforge.pmd.lang.java.ast.ASTRecordComponentList;
28
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
29
import net.sourceforge.pmd.lang.java.ast.InternalApiBridge;
30
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
31
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
32
import net.sourceforge.pmd.lang.java.symbols.JElementSymbol;
33
import net.sourceforge.pmd.lang.java.symbols.JExecutableSymbol;
34
import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
35
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
36
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
37
import net.sourceforge.pmd.lang.java.symbols.JTypeParameterOwnerSymbol;
38
import net.sourceforge.pmd.lang.java.symbols.internal.ImplicitMemberSymbols;
39
import net.sourceforge.pmd.lang.java.types.JClassType;
40
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
41
import net.sourceforge.pmd.lang.java.types.Substitution;
42
import net.sourceforge.pmd.lang.java.types.TypeOps;
43
import net.sourceforge.pmd.lang.java.types.TypeSystem;
44
import net.sourceforge.pmd.util.CollectionUtil;
45

46

47
final class AstClassSym
1✔
48
    extends AbstractAstTParamOwner<ASTAnyTypeDeclaration>
49
    implements JClassSymbol {
50

51
    private final @Nullable JTypeParameterOwnerSymbol enclosing;
52
    private final List<JClassSymbol> declaredClasses;
53
    private final List<JMethodSymbol> declaredMethods;
54
    private final List<JConstructorSymbol> declaredCtors;
55
    private final List<JFieldSymbol> declaredFields;
56
    private final List<JFieldSymbol> enumConstants; // subset of declaredFields
57
    private final PSet<String> annotAttributes;
58

59
    AstClassSym(ASTAnyTypeDeclaration node,
60
                AstSymFactory factory,
61
                @Nullable JTypeParameterOwnerSymbol enclosing) {
62
        super(node, factory);
1✔
63
        this.enclosing = enclosing;
1✔
64

65
        // evaluate everything strictly
66
        // this populates symbols on the relevant AST nodes
67

68
        final List<JClassSymbol> myClasses = new ArrayList<>();
1✔
69
        final List<JMethodSymbol> myMethods = new ArrayList<>();
1✔
70
        final List<JConstructorSymbol> myCtors = new ArrayList<>();
1✔
71
        final List<JFieldSymbol> myFields = new ArrayList<>();
1✔
72
        final List<JFieldSymbol> enumConstants;
73
        final List<JFieldSymbol> recordComponents;
74

75
        if (isRecord()) {
1✔
76
            ASTRecordComponentList components = Objects.requireNonNull(node.getRecordComponents(),
1✔
77
                                                                       "Null component list for " + node);
78
            recordComponents = mapComponentsToMutableList(factory, components);
1✔
79
            myFields.addAll(recordComponents);
1✔
80

81
            JConstructorSymbol canonicalRecordCtor = ImplicitMemberSymbols.recordConstructor(this, recordComponents, components.isVarargs());
1✔
82
            myCtors.add(canonicalRecordCtor);
1✔
83
            InternalApiBridge.setSymbol(components, canonicalRecordCtor);
1✔
84

85
        } else {
1✔
86
            recordComponents = Collections.emptyList();
1✔
87
        }
88

89
        if (isEnum()) {
1✔
90
            enumConstants = new ArrayList<>();
1✔
91
            node.getEnumConstants()
1✔
92
                .forEach(constant -> {
1✔
93
                    AstFieldSym fieldSym = new AstFieldSym(constant.getVarId(), factory, this);
1✔
94
                    enumConstants.add(fieldSym);
1✔
95
                    myFields.add(fieldSym);
1✔
96
                });
1✔
97
        } else {
98
            enumConstants = null;
1✔
99
        }
100

101

102
        for (ASTBodyDeclaration dnode : node.getDeclarations()) {
1✔
103

104
            if (dnode instanceof ASTAnyTypeDeclaration) {
1✔
105
                myClasses.add(new AstClassSym((ASTAnyTypeDeclaration) dnode, factory, this));
1✔
106
            } else if (dnode instanceof ASTMethodDeclaration) {
1✔
107
                if (!recordComponents.isEmpty() && ((ASTMethodDeclaration) dnode).getArity() == 0) {
1✔
108
                    // filter out record component, so that the accessor is not generated
109
                    recordComponents.removeIf(f -> f.nameEquals(((ASTMethodDeclaration) dnode).getName()));
1✔
110
                }
111
                myMethods.add(new AstMethodSym((ASTMethodDeclaration) dnode, factory, this));
1✔
112
            } else if (dnode instanceof ASTConstructorDeclaration) {
1✔
113
                myCtors.add(new AstCtorSym((ASTConstructorDeclaration) dnode, factory, this));
1✔
114
            } else if (dnode instanceof ASTFieldDeclaration) {
1✔
115
                for (ASTVariableDeclaratorId varId : ((ASTFieldDeclaration) dnode).getVarIds()) {
1✔
116
                    myFields.add(new AstFieldSym(varId, factory, this));
1✔
117
                }
1✔
118
            }
119
        }
1✔
120
        
121

122
        if (!recordComponents.isEmpty()) {
1✔
123
            // then the recordsComponents contains all record components
124
            // for which we must synthesize an accessor (explicitly declared
125
            // accessors have been filtered out)
126
            for (JFieldSymbol component : recordComponents) {
1✔
127
                myMethods.add(ImplicitMemberSymbols.recordAccessor(this, component));
1✔
128
            }
1✔
129
        }
130

131
        if (myCtors.isEmpty() && isClass() && !isAnonymousClass()) {
1✔
132
            myCtors.add(ImplicitMemberSymbols.defaultCtor(this));
1✔
133
        }
134

135
        if (this.isEnum()) {
1✔
136
            myMethods.add(ImplicitMemberSymbols.enumValues(this));
1✔
137
            myMethods.add(ImplicitMemberSymbols.enumValueOf(this));
1✔
138
        }
139

140
        this.declaredClasses = Collections.unmodifiableList(myClasses);
1✔
141
        this.declaredMethods = Collections.unmodifiableList(myMethods);
1✔
142
        this.declaredCtors = Collections.unmodifiableList(myCtors);
1✔
143
        this.declaredFields = Collections.unmodifiableList(myFields);
1✔
144
        this.enumConstants = CollectionUtil.makeUnmodifiableAndNonNull(enumConstants);
1✔
145
        this.annotAttributes = isAnnotation()
1✔
146
                               ? getDeclaredMethods().stream().filter(JMethodSymbol::isAnnotationAttribute).map(JElementSymbol::getSimpleName).collect(CollectionUtil.toPersistentSet())
1✔
147
                               : HashTreePSet.empty();
1✔
148
    }
1✔
149

150
    private List<JFieldSymbol> mapComponentsToMutableList(AstSymFactory factory, ASTRecordComponentList components) {
151
        List<JFieldSymbol> list = new ArrayList<>();
1✔
152
        for (ASTRecordComponent comp : components) {
1✔
153
            list.add(new AstFieldSym(comp.getVarId(), factory, this));
1✔
154
        }
1✔
155
        return list;
1✔
156
    }
157

158
    @Override
159
    public @NonNull String getSimpleName() {
160
        return node.getSimpleName();
1✔
161
    }
162

163

164
    @Override
165
    public @NonNull String getBinaryName() {
166
        return node.getBinaryName();
1✔
167
    }
168

169
    @Override
170
    public @Nullable String getCanonicalName() {
171
        return node.getCanonicalName();
1✔
172
    }
173

174
    @Override
175
    public boolean isUnresolved() {
176
        return false;
1✔
177
    }
178

179
    @Override
180
    public @Nullable JClassSymbol getEnclosingClass() {
181
        if (enclosing instanceof JClassSymbol) {
1✔
182
            return (JClassSymbol) enclosing;
1✔
183
        } else if (enclosing instanceof JExecutableSymbol) {
1✔
184
            return enclosing.getEnclosingClass();
1✔
185
        }
186
        assert enclosing == null;
1✔
187
        return null;
1✔
188
    }
189

190
    @Override
191
    public @Nullable JExecutableSymbol getEnclosingMethod() {
192
        return enclosing instanceof JExecutableSymbol ? (JExecutableSymbol) enclosing : null;
1✔
193
    }
194

195
    @Override
196
    public List<JClassSymbol> getDeclaredClasses() {
197
        return declaredClasses;
1✔
198
    }
199

200
    @Override
201
    public List<JMethodSymbol> getDeclaredMethods() {
202
        return declaredMethods;
1✔
203
    }
204

205
    @Override
206
    public List<JConstructorSymbol> getConstructors() {
207
        return declaredCtors;
1✔
208
    }
209

210
    @Override
211
    public List<JFieldSymbol> getDeclaredFields() {
212
        return declaredFields;
1✔
213
    }
214

215
    @Override
216
    public @NonNull List<JFieldSymbol> getEnumConstants() {
217
        return enumConstants;
1✔
218
    }
219
    
220
    @Override
221
    public @Nullable JClassType getSuperclassType(Substitution substitution) {
222
        TypeSystem ts = getTypeSystem();
1✔
223

224
        if (node.isEnum()) {
1✔
225

226
            return factory.enumSuperclass(this);
1✔
227

228
        } else if (node instanceof ASTClassOrInterfaceDeclaration) {
1✔
229

230
            ASTClassOrInterfaceType superClass = ((ASTClassOrInterfaceDeclaration) node).getSuperClassTypeNode();
1✔
231
            return superClass == null
1✔
232
                   ? ts.OBJECT
1✔
233
                   // this cast relies on the fact that the superclass is not a type variable
234
                   : (JClassType) TypeOps.subst(superClass.getTypeMirror(), substitution);
1✔
235

236
        } else if (isAnonymousClass()) {
1✔
237

238
            if (node.getParent() instanceof ASTEnumConstant) {
1✔
239

240
                return node.getEnclosingType().getTypeMirror().subst(substitution);
1✔
241

242
            } else if (node.getParent() instanceof ASTConstructorCall) {
1✔
243

244
                @NonNull JTypeMirror sym = ((ASTConstructorCall) node.getParent()).getTypeMirror();
1✔
245

246
                return sym instanceof JClassType && !sym.isInterface()
1✔
247
                       ? (JClassType) sym
1✔
248
                       : factory.types().OBJECT;
1✔
249
            }
250

251
        } else if (isRecord()) {
1✔
252

253
            return factory.recordSuperclass();
1✔
254

255
        } else if (isAnnotation()) {
1✔
256

257
            return ts.OBJECT;
1✔
258

259
        }
260

261
        return null;
×
262
    }
263

264
    @Override
265
    public @Nullable JClassSymbol getSuperclass() {
266
        // notice this relies on the fact that the extends clause
267
        // (or the type node of the constructor call, for an anonymous class),
268
        // was disambiguated early
269

270
        // We special case anonymous classes so as not to trigger overload resolution
271
        if (isAnonymousClass() && node.getParent() instanceof ASTConstructorCall) {
1✔
272

273
            @NonNull JTypeMirror sym = ((ASTConstructorCall) node.getParent()).getTypeNode().getTypeMirror();
1✔
274

275
            return sym instanceof JClassType && !sym.isInterface()
1✔
276
                   ? ((JClassType) sym).getSymbol()
1✔
277
                   : factory.types().OBJECT.getSymbol();
1✔
278

279
        }
280

281
        JClassType sup = getSuperclassType(Substitution.EMPTY);
1✔
282
        return sup == null ? null : sup.getSymbol();
1✔
283
    }
284

285
    @Override
286
    public List<JClassSymbol> getSuperInterfaces() {
287
        List<JClassSymbol> itfs = CollectionUtil.mapNotNull(
1✔
288
            node.getSuperInterfaceTypeNodes(),
1✔
289
            n -> {
290
                // we play safe here, but the symbol is either a JClassSymbol
291
                // or a JTypeParameterSymbol, with the latter case being a
292
                // compile-time error
293
                JTypeDeclSymbol sym = n.getTypeMirror().getSymbol();
1✔
294
                return sym instanceof JClassSymbol ? (JClassSymbol) sym : null;
1✔
295
            }
296
        );
297
        if (isAnnotation()) {
1✔
298
            itfs = CollectionUtil.concatView(Collections.singletonList(factory.annotationSym()), itfs);
1✔
299
        }
300
        return itfs;
1✔
301
    }
302

303
    @Override
304
    public List<JClassType> getSuperInterfaceTypes(Substitution subst) {
305
        List<JClassType> itfs = CollectionUtil.map(node.getSuperInterfaceTypeNodes(), n -> (JClassType) TypeOps.subst(n.getTypeMirror(), subst));
1✔
306
        if (isAnnotation()) {
1✔
307
            itfs = CollectionUtil.concatView(Collections.singletonList(factory.annotationType()), itfs);
1✔
308
        }
309
        return itfs;
1✔
310
    }
311

312
    @Override
313
    public @Nullable JTypeDeclSymbol getArrayComponent() {
314
        return null;
×
315
    }
316

317
    @Override
318
    public boolean isArray() {
319
        return false;
1✔
320
    }
321

322
    @Override
323
    public boolean isPrimitive() {
324
        return false;
1✔
325
    }
326

327
    @Override
328
    public boolean isInterface() {
329
        return node.isInterface();
1✔
330
    }
331

332
    @Override
333
    public boolean isEnum() {
334
        return node.isEnum();
1✔
335
    }
336

337
    @Override
338
    public boolean isRecord() {
339
        return node.isRecord();
1✔
340
    }
341

342
    @Override
343
    public boolean isAnnotation() {
344
        return node.isAnnotation();
1✔
345
    }
346

347
    @Override
348
    public boolean isLocalClass() {
349
        return node.isLocal();
1✔
350
    }
351

352
    @Override
353
    public boolean isAnonymousClass() {
354
        return node.isAnonymous();
1✔
355
    }
356

357
    @Override
358
    public PSet<String> getAnnotationAttributeNames() {
359
        return annotAttributes;
×
360
    }
361
}
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