• 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

90.28
/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/table/internal/SymTableFactory.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.table.internal;
6

7

8
import static net.sourceforge.pmd.lang.java.symbols.table.ScopeInfo.FORMAL_PARAM;
9
import static net.sourceforge.pmd.lang.java.symbols.table.ScopeInfo.SAME_FILE;
10
import static net.sourceforge.pmd.util.AssertionUtil.isValidJavaPackageName;
11

12
import java.lang.reflect.Modifier;
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.HashSet;
17
import java.util.LinkedHashSet;
18
import java.util.List;
19
import java.util.Optional;
20
import java.util.Set;
21
import java.util.function.BinaryOperator;
22

23
import org.apache.commons.lang3.tuple.Pair;
24
import org.checkerframework.checker.nullness.qual.NonNull;
25
import org.checkerframework.checker.nullness.qual.Nullable;
26

27
import net.sourceforge.pmd.lang.ast.NodeStream;
28
import net.sourceforge.pmd.lang.ast.SemanticErrorReporter;
29
import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
30
import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
31
import net.sourceforge.pmd.lang.java.ast.ASTList;
32
import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration;
33
import net.sourceforge.pmd.lang.java.ast.ASTTypeParameter;
34
import net.sourceforge.pmd.lang.java.ast.ASTTypeParameters;
35
import net.sourceforge.pmd.lang.java.ast.ASTVariableId;
36
import net.sourceforge.pmd.lang.java.ast.InternalApiBridge;
37
import net.sourceforge.pmd.lang.java.ast.JavaNode;
38
import net.sourceforge.pmd.lang.java.internal.JavaAstProcessor;
39
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
40
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
41
import net.sourceforge.pmd.lang.java.symbols.JFormalParamSymbol;
42
import net.sourceforge.pmd.lang.java.symbols.JLocalVariableSymbol;
43
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
44
import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol;
45
import net.sourceforge.pmd.lang.java.symbols.SymbolResolver;
46
import net.sourceforge.pmd.lang.java.symbols.table.JSymbolTable;
47
import net.sourceforge.pmd.lang.java.symbols.table.ScopeInfo;
48
import net.sourceforge.pmd.lang.java.symbols.table.coreimpl.NameResolver;
49
import net.sourceforge.pmd.lang.java.symbols.table.coreimpl.ShadowChainBuilder;
50
import net.sourceforge.pmd.lang.java.symbols.table.coreimpl.ShadowChainNode;
51
import net.sourceforge.pmd.lang.java.types.JClassType;
52
import net.sourceforge.pmd.lang.java.types.JMethodSig;
53
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
54
import net.sourceforge.pmd.lang.java.types.JTypeVar;
55
import net.sourceforge.pmd.lang.java.types.JVariableSig;
56
import net.sourceforge.pmd.util.CollectionUtil;
57

58
final class SymTableFactory {
59

60

61
    private final String thisPackage;
62
    private final JavaAstProcessor processor;
63

64
    static final ShadowChainBuilder<JTypeMirror, ScopeInfo> TYPES = new ShadowChainBuilder<JTypeMirror, ScopeInfo>() {
1✔
65

66
        @Override
67
        public String getSimpleName(JTypeMirror type) {
68
            if (type instanceof JClassType) {
1✔
69
                return ((JClassType) type).getSymbol().getSimpleName();
1✔
70
            } else if (type instanceof JTypeVar) {
1!
71
                JTypeDeclSymbol sym = type.getSymbol();
1✔
72
                assert sym != null : "Must contain named symbols";
1!
73
                return sym.getSimpleName();
1✔
74
            }
75
            throw new AssertionError("Cannot contain type " + type);
×
76
        }
77
    };
78

79
    static final ShadowChainBuilder<JVariableSig, ScopeInfo> VARS = new ShadowChainBuilder<JVariableSig, ScopeInfo>() {
1✔
80
        @Override
81
        public String getSimpleName(JVariableSig sym) {
82
            return sym.getSymbol().getSimpleName();
1✔
83
        }
84
    };
85

86
    static final ShadowChainBuilder<JMethodSig, ScopeInfo> METHODS = new ShadowChainBuilder<JMethodSig, ScopeInfo>() {
1✔
87
        @Override
88
        public String getSimpleName(JMethodSig sym) {
89
            return sym.getName();
×
90
        }
91
    };
92

93

94
    SymTableFactory(String thisPackage, JavaAstProcessor processor) {
1✔
95
        this.thisPackage = thisPackage;
1✔
96
        this.processor = processor;
1✔
97
    }
1✔
98

99
    // <editor-fold defaultstate="collapsed" desc="Utilities for classloading">
100

101

102
    public void disambig(NodeStream<? extends JavaNode> nodes, ReferenceCtx context) {
103
        InternalApiBridge.disambigWithCtx(nodes, context);
1✔
104
    }
1✔
105

106
    SemanticErrorReporter getLogger() {
107
        return processor.getLogger();
1✔
108
    }
109

110
    JClassSymbol loadClassReportFailure(JavaNode location, String fqcn) {
111
        JClassSymbol loaded = loadClassOrFail(fqcn);
1✔
112
        if (loaded == null) {
1✔
113
            getLogger().warning(location, JavaSemanticErrors.CANNOT_RESOLVE_SYMBOL, fqcn);
1✔
114
        }
115

116
        return loaded;
1✔
117
    }
118

119
    /** @see SymbolResolver#resolveClassFromCanonicalName(String) */
120
    @Nullable
121
    JClassSymbol loadClassOrFail(String fqcn) {
122
        return processor.getSymResolver().resolveClassFromCanonicalName(fqcn);
1✔
123
    }
124

125
    // </editor-fold>
126

127
    private @NonNull JSymbolTable buildTable(JSymbolTable parent,
128
                                             ShadowChainNode<JVariableSig, ScopeInfo> vars,
129
                                             ShadowChainNode<JMethodSig, ScopeInfo> methods,
130
                                             ShadowChainNode<JTypeMirror, ScopeInfo> types) {
131
        if (vars == parent.variables() && methods == parent.methods() && types == parent.types()) { // NOPMD CompareObjectsWithEquals
1✔
132
            return parent;
1✔
133
        } else {
134
            return new SymbolTableImpl(vars, types, methods);
1✔
135
        }
136
    }
137

138
    private ShadowChainNode<JTypeMirror, ScopeInfo> typeNode(JSymbolTable parent) {
139
        return parent.types().asNode();
1✔
140
    }
141

142
    private ShadowChainNode<JVariableSig, ScopeInfo> varNode(JSymbolTable parent) {
143
        return parent.variables().asNode();
1✔
144
    }
145

146
    private ShadowChainNode<JMethodSig, ScopeInfo> methodNode(JSymbolTable parent) {
147
        return parent.methods().asNode();
1✔
148
    }
149

150
    JSymbolTable importsOnDemand(JSymbolTable parent, Collection<ASTImportDeclaration> importsOnDemand) {
151
        if (importsOnDemand.isEmpty()) {
1✔
152
            return parent;
1✔
153
        }
154

155
        ShadowChainBuilder<JTypeMirror, ScopeInfo>.ResolverBuilder importedTypes = TYPES.new ResolverBuilder();
1✔
156
        ShadowChainBuilder<JVariableSig, ScopeInfo>.ResolverBuilder importedFields = VARS.new ResolverBuilder();
1✔
157
        List<JClassType> importedMethodContainers = new ArrayList<>();
1✔
158

159
        Set<String> lazyImportedPackagesAndTypes = new LinkedHashSet<>();
1✔
160

161
        fillImportOnDemands(importsOnDemand, importedTypes, importedFields, importedMethodContainers, lazyImportedPackagesAndTypes);
1✔
162

163
        NameResolver<JMethodSig> methodResolver =
1✔
164
            NameResolver.composite(CollectionUtil.map(importedMethodContainers, c -> JavaResolvers.staticImportOnDemandMethodResolver(c, thisPackage)));
1✔
165

166
        ShadowChainNode<JVariableSig, ScopeInfo> vars = VARS.shadow(varNode(parent), ScopeInfo.IMPORT_ON_DEMAND, importedFields);
1✔
167
        ShadowChainNode<JMethodSig, ScopeInfo> methods = METHODS.shadow(methodNode(parent), ScopeInfo.IMPORT_ON_DEMAND, methodResolver);
1✔
168
        ShadowChainNode<JTypeMirror, ScopeInfo> types;
169
        if (lazyImportedPackagesAndTypes.isEmpty()) {
1✔
170
            // then we don't need to use the lazy impl
171
            types = TYPES.shadow(typeNode(parent), ScopeInfo.IMPORT_ON_DEMAND, importedTypes);
1✔
172
        } else {
173
            types = TYPES.shadowWithCache(
1✔
174
                typeNode(parent),
1✔
175
                ScopeInfo.IMPORT_ON_DEMAND,
176
                importedTypes.getMutableMap(),
1✔
177
                JavaResolvers.importedOnDemand(lazyImportedPackagesAndTypes, processor.getSymResolver(), thisPackage)
1✔
178
            );
179
        }
180

181
        return buildTable(parent, vars, methods, types);
1✔
182
    }
183

184
    private void fillImportOnDemands(Iterable<ASTImportDeclaration> importsOnDemand,
185
                                     ShadowChainBuilder<JTypeMirror, ?>.ResolverBuilder importedTypes,
186
                                     ShadowChainBuilder<JVariableSig, ?>.ResolverBuilder importedFields,
187
                                     List<JClassType> importedMethodContainers,
188
                                     Set<String> importedPackagesAndTypes) {
189

190
        for (ASTImportDeclaration anImport : importsOnDemand) {
1✔
191
            assert anImport.isImportOnDemand() : "Expected import on demand: " + anImport;
1!
192

193
            if (anImport.isStatic()) {
1✔
194
                fillStaticImportOnDemand(Optional.of(anImport), anImport.getImportedName(),
1✔
195
                        importedTypes, importedFields, importedMethodContainers);
196
            } else {
197
                // Type-Import-on-Demand Declaration
198
                // This is of the kind <packageName>.*;
199
                importedPackagesAndTypes.add(anImport.getPackageName());
1✔
200
            }
201
        }
1✔
202
    }
1✔
203

204
    private void fillStaticImportOnDemand(Optional<JavaNode> reportLocation, String importedName,
205
                                          ShadowChainBuilder<JTypeMirror, ?>.ResolverBuilder importedTypes,
206
                                          ShadowChainBuilder<JVariableSig, ?>.ResolverBuilder importedFields,
207
                                          List<JClassType> importedMethodContainers) {
208
        // Static-Import-on-Demand Declaration
209
        // A static-import-on-demand declaration allows all accessible static members of a named type to be imported as needed.
210
        // includes types members, methods & fields
211

212
        @Nullable JClassSymbol containerClass;
213
        if (reportLocation.isPresent()) {
1!
214
            containerClass = loadClassReportFailure(reportLocation.get(), importedName);
1✔
215
        } else {
216
            containerClass = loadClassOrFail(importedName);
×
217
        }
218
        if (containerClass != null) {
1✔
219
            // populate the inherited state
220

221
            JClassType containerType = (JClassType) containerClass.getTypeSystem().typeOf(containerClass, false);
1✔
222

223
            Pair<ShadowChainBuilder<JTypeMirror, ?>.ResolverBuilder, ShadowChainBuilder<JVariableSig, ?>.ResolverBuilder> pair =
1✔
224
                    JavaResolvers.importOnDemandMembersResolvers(containerType, thisPackage);
1✔
225

226
            importedTypes.absorb(pair.getLeft());
1✔
227
            importedFields.absorb(pair.getRight());
1✔
228

229
            importedMethodContainers.add(containerType);
1✔
230
        }
231

232
        // can't be resolved sorry
233
    }
1✔
234

235
    JSymbolTable moduleImports(JSymbolTable parent, Collection<ASTImportDeclaration> moduleImports) {
236
        if (moduleImports.isEmpty()) {
1✔
237
            return parent;
1✔
238
        }
239

240
        Set<String> lazyImportedModules = new HashSet<>();
1✔
241
        for (ASTImportDeclaration anImport : moduleImports) {
1✔
242
            assert anImport.isModuleImport() : "Expected module import: " + anImport;
1!
243
            lazyImportedModules.add(anImport.getImportedName());
1✔
244
        }
1✔
245

246
        ShadowChainBuilder<JTypeMirror, ScopeInfo>.ResolverBuilder importedTypes = TYPES.new ResolverBuilder();
1✔
247

248
        ShadowChainNode<JTypeMirror, ScopeInfo> types = TYPES.shadowWithCache(
1✔
249
                typeNode(parent),
1✔
250
                ScopeInfo.MODULE_IMPORT,
251
                importedTypes.getMutableMap(),
1✔
252
                JavaResolvers.moduleImport(lazyImportedModules, processor.getSymResolver(), thisPackage)
1✔
253
        );
254

255
        return SymbolTableImpl.withTypes(parent, types);
1✔
256
    }
257

258

259
    JSymbolTable singleImportsSymbolTable(JSymbolTable parent, Collection<ASTImportDeclaration> singleImports) {
260
        if (singleImports.isEmpty()) {
1✔
261
            return parent;
1✔
262
        }
263

264
        ShadowChainBuilder<JTypeMirror, ScopeInfo>.ResolverBuilder importedTypes = TYPES.new ResolverBuilder();
1✔
265

266
        List<NameResolver<? extends JTypeMirror>> importedStaticTypes = new ArrayList<>();
1✔
267
        List<NameResolver<? extends JVariableSig>> importedStaticFields = new ArrayList<>();
1✔
268
        List<NameResolver<? extends JMethodSig>> importedStaticMethods = new ArrayList<>();
1✔
269

270
        fillSingleImports(singleImports, importedTypes);
1✔
271
        fillSingleStaticImports(singleImports, importedStaticTypes, importedStaticFields, importedStaticMethods);
1✔
272

273
        return buildTable(
1✔
274
            parent,
275
            VARS.shadow(varNode(parent), ScopeInfo.SINGLE_IMPORT, NameResolver.composite(importedStaticFields)),
1✔
276
            METHODS.shadow(methodNode(parent), ScopeInfo.SINGLE_IMPORT, NameResolver.composite(importedStaticMethods)),
1✔
277
            TYPES.augment(
1✔
278
                TYPES.shadow(typeNode(parent), ScopeInfo.SINGLE_IMPORT, importedTypes.build()),
1✔
279
                false,
280
                ScopeInfo.SINGLE_IMPORT,
281
                NameResolver.composite(importedStaticTypes)
1✔
282
            )
283
        );
284

285
    }
286

287

288
    private void fillSingleImports(Iterable<ASTImportDeclaration> singleImports,
289
                                   ShadowChainBuilder<JTypeMirror, ?>.ResolverBuilder importedTypes) {
290

291
        for (ASTImportDeclaration anImport : singleImports) {
1✔
292
            if (anImport.isImportOnDemand()) {
1!
293
                throw new IllegalArgumentException(anImport.toString());
×
294
            }
295

296
            if (!anImport.isStatic()) {
1✔
297
                // Single-Type-Import Declaration
298
                JClassSymbol type = processor.findSymbolCannotFail(anImport, anImport.getImportedName());
1✔
299
                importedTypes.append(type.getTypeSystem().typeOf(type, false));
1✔
300
            }
301
        }
1✔
302
    }
1✔
303

304
    private void fillSingleStaticImports(Iterable<ASTImportDeclaration> singleImports,
305
                                         List<NameResolver<? extends JTypeMirror>> importedTypes,
306
                                         List<NameResolver<? extends JVariableSig>> importedFields,
307
                                         List<NameResolver<? extends JMethodSig>> importedStaticMethods) {
308
        for (ASTImportDeclaration anImport : singleImports) {
1✔
309
            if (anImport.isImportOnDemand()) {
1!
310
                throw new IllegalArgumentException(anImport.toString());
×
311
            }
312

313
            String simpleName = anImport.getImportedSimpleName();
1✔
314
            String name = anImport.getImportedName();
1✔
315

316
            if (anImport.isStatic()) {
1✔
317
                // Single-Static-Import Declaration
318
                // types, fields or methods having the same name
319

320
                int idx = name.lastIndexOf('.');
1✔
321
                if (idx < 0) {
1✔
322
                    continue; // invalid syntax
1✔
323
                }
324
                String className = name.substring(0, idx);
1✔
325

326
                JClassSymbol containerClass = loadClassReportFailure(anImport, className);
1✔
327

328
                if (containerClass == null) {
1✔
329
                    // the auxclasspath is wrong
330
                    // bc static imports can't import toplevel types
331
                    // already reported
332
                    continue;
1✔
333
                }
334

335
                JClassType containerType = (JClassType) containerClass.getTypeSystem().declaration(containerClass);
1✔
336

337
                importedStaticMethods.add(JavaResolvers.staticImportMethodResolver(containerType, thisPackage, simpleName));
1✔
338
                importedFields.add(JavaResolvers.staticImportFieldResolver(containerType, thisPackage, simpleName));
1✔
339
                importedTypes.add(JavaResolvers.staticImportClassResolver(containerType, thisPackage, simpleName));
1✔
340
            }
341
        }
1✔
342
    }
1✔
343

344
    JSymbolTable javaLangSymTable(JSymbolTable parent) {
345
        return typesInPackage(parent, "java.lang", ScopeInfo.JAVA_LANG);
1✔
346
    }
347

348
    JSymbolTable moduleImportJavaBase(JSymbolTable parent) {
349
        ShadowChainBuilder<JTypeMirror, ScopeInfo>.ResolverBuilder importedTypes = TYPES.new ResolverBuilder();
1✔
350

351
        ShadowChainNode<JTypeMirror, ScopeInfo> types = TYPES.shadowWithCache(
1✔
352
                typeNode(parent),
1✔
353
                ScopeInfo.SIMPLE_COMPILATION_UNIT,
354
                importedTypes.getMutableMap(),
1✔
355
                JavaResolvers.moduleImport(Collections.singleton("java.base"), processor.getSymResolver(), thisPackage)
1✔
356
        );
357

358
        return SymbolTableImpl.withTypes(parent, types);
1✔
359
    }
360

361
    JSymbolTable importsOnDemandJavaIo(JSymbolTable parent) {
362
        ShadowChainBuilder<JTypeMirror, ScopeInfo>.ResolverBuilder importedTypes = TYPES.new ResolverBuilder();
×
363
        ShadowChainBuilder<JVariableSig, ScopeInfo>.ResolverBuilder importedFields = VARS.new ResolverBuilder();
×
364
        List<JClassType> importedMethodContainers = new ArrayList<>();
×
365

366
        fillStaticImportOnDemand(Optional.empty(), "java.io.IO", importedTypes, importedFields, importedMethodContainers);
×
367

368
        NameResolver<JMethodSig> methodResolver =
×
369
                NameResolver.composite(CollectionUtil.map(importedMethodContainers, c -> JavaResolvers.staticImportOnDemandMethodResolver(c, thisPackage)));
×
370

371
        ShadowChainNode<JVariableSig, ScopeInfo> vars = VARS.shadow(varNode(parent), ScopeInfo.SIMPLE_COMPILATION_UNIT, importedFields);
×
372
        ShadowChainNode<JMethodSig, ScopeInfo> methods = METHODS.shadow(methodNode(parent), ScopeInfo.SIMPLE_COMPILATION_UNIT, methodResolver);
×
373
        // then we don't need to use the lazy impl
374
        ShadowChainNode<JTypeMirror, ScopeInfo> types = TYPES.shadow(typeNode(parent), ScopeInfo.SIMPLE_COMPILATION_UNIT, importedTypes);
×
375

376
        return buildTable(parent, vars, methods, types);
×
377
    }
378

379
    JSymbolTable samePackageSymTable(JSymbolTable parent) {
380
        return typesInPackage(parent, thisPackage, ScopeInfo.SAME_PACKAGE);
1✔
381
    }
382

383
    @NonNull
384
    private JSymbolTable typesInPackage(JSymbolTable parent, String packageName, ScopeInfo scopeTag) {
385
        assert isValidJavaPackageName(packageName) : "Not a package name: " + packageName;
1!
386

387
        return SymbolTableImpl.withTypes(
1✔
388
            parent,
389
            TYPES.augmentWithCache(typeNode(parent), true, scopeTag, JavaResolvers.packageResolver(processor.getSymResolver(), packageName))
1✔
390
        );
391
    }
392

393
    JSymbolTable typeBody(JSymbolTable parent, @NonNull JClassType t) {
394

395
        Pair<NameResolver<JTypeMirror>, NameResolver<JVariableSig>> inherited = JavaResolvers.inheritedMembersResolvers(t);
1✔
396

397
        JClassSymbol sym = t.getSymbol();
1✔
398

399
        ShadowChainNode<JTypeMirror, ScopeInfo> types = typeNode(parent);
1✔
400
        if (!sym.isAnonymousClass()) {
1✔
401
            types = TYPES.shadow(types, ScopeInfo.ENCLOSING_TYPE, t);                                                        // self name
1✔
402
        }
403
        types = TYPES.shadow(types, ScopeInfo.INHERITED, inherited.getLeft());                                           // inherited classes (note they shadow the enclosing type)
1✔
404
        types = TYPES.shadow(types, ScopeInfo.ENCLOSING_TYPE_MEMBER, TYPES.groupByName(t.getDeclaredClasses()));       // inner classes declared here
1✔
405
        types = TYPES.shadow(types, ScopeInfo.TYPE_PARAM, TYPES.groupByName(sym.getTypeParameters()));                   // type parameters
1✔
406

407
        ShadowChainNode<JVariableSig, ScopeInfo> fields = varNode(parent);
1✔
408
        fields = VARS.shadow(fields, ScopeInfo.INHERITED, inherited.getRight());
1✔
409
        fields = VARS.shadow(fields, ScopeInfo.ENCLOSING_TYPE_MEMBER, VARS.groupByName(t.getDeclaredFields()));
1✔
410

411
        ShadowChainNode<JMethodSig, ScopeInfo> methods = methodNode(parent);
1✔
412
        BinaryOperator<List<JMethodSig>> merger = JavaResolvers.methodMerger(Modifier.isStatic(t.getSymbol().getModifiers()));
1✔
413
        methods = METHODS.augmentWithCache(methods, false, ScopeInfo.METHOD_MEMBER, JavaResolvers.subtypeMethodResolver(t), merger);
1✔
414

415
        return buildTable(parent, fields, methods, types);
1✔
416
    }
417

418
    JSymbolTable typesInFile(JSymbolTable parent, NodeStream<ASTTypeDeclaration> decls) {
419
        return SymbolTableImpl.withTypes(parent, TYPES.shadow(typeNode(parent), SAME_FILE, TYPES.groupByName(decls, ASTTypeDeclaration::getTypeMirror)));
1✔
420
    }
421

422
    JSymbolTable selfType(JSymbolTable parent, JClassType sym) {
423
        return SymbolTableImpl.withTypes(parent, TYPES.shadow(typeNode(parent), ScopeInfo.ENCLOSING_TYPE_MEMBER, TYPES.groupByName(sym)));
1✔
424
    }
425

426
    JSymbolTable typeHeader(JSymbolTable parent, JClassSymbol sym) {
427
        return SymbolTableImpl.withTypes(parent, TYPES.shadow(typeNode(parent), ScopeInfo.TYPE_PARAM, TYPES.groupByName(sym.getTypeParameters())));
1✔
428
    }
429

430
    /**
431
     * Symbol table for a body declaration. This places a shadowing
432
     * group for variables, ie, nested variable shadowing groups will
433
     * be merged into it but not into the parent. This implements shadowing
434
     * of fields by local variables and formals.
435
     */
436
    JSymbolTable bodyDeclaration(JSymbolTable parent, JClassType enclosing, @Nullable ASTFormalParameters formals, @Nullable ASTTypeParameters tparams) {
437
        return new SymbolTableImpl(
1✔
438
            VARS.shadow(varNode(parent), ScopeInfo.FORMAL_PARAM, VARS.groupByName(ASTList.orEmptyStream(formals), fp -> {
1✔
439
                ASTVariableId varId = fp.getVarId();
1✔
440
                if (varId.isUnnamed()) {
1✔
441
                    return null;
1✔
442
                }
443
                JVariableSymbol sym = varId.getSymbol();
1✔
444
                return sym.getTypeSystem().sigOf(enclosing, (JFormalParamSymbol) sym);
1✔
445
            })),
446
            TYPES.shadow(typeNode(parent), ScopeInfo.TYPE_PARAM, TYPES.groupByName(ASTList.orEmptyStream(tparams), ASTTypeParameter::getTypeMirror)),
1✔
447
            methodNode(parent)
1✔
448
        );
449
    }
450

451
    JSymbolTable recordCtor(JSymbolTable parent, JClassType recordType, JConstructorSymbol symbol) {
452
        return SymbolTableImpl.withVars(parent, VARS.shadow(varNode(parent), FORMAL_PARAM, VARS.groupByName(symbol.getFormalParameters(), s -> s.getTypeSystem().sigOf(recordType, s))));
1✔
453
    }
454

455
    /**
456
     * Local vars are merged into the parent shadowing group. They don't
457
     * shadow other local vars, they conflict with them.
458
     */
459
    JSymbolTable localVarSymTable(JSymbolTable parent, JClassType enclosing, Iterable<ASTVariableId> ids) {
460
        List<JVariableSig> sigs = new ArrayList<>();
1✔
461
        for (ASTVariableId id : ids) {
1✔
462
            if (id.isUnnamed()) {
1✔
463
                continue;
1✔
464
            }
465
            sigs.add(id.getTypeSystem().sigOf(enclosing, (JLocalVariableSymbol) id.getSymbol()));
1✔
466
        }
1✔
467
        return SymbolTableImpl.withVars(parent, VARS.augment(varNode(parent), false, ScopeInfo.LOCAL, VARS.groupByName(sigs)));
1✔
468
    }
469

470
    JSymbolTable localVarSymTable(JSymbolTable parent, JClassType enclosing, ASTVariableId id) {
471
        assert !id.isField();
1!
472
        if (id.isUnnamed()) { // checks language version already
1✔
473
            return parent;
1✔
474
        }
475
        return SymbolTableImpl.withVars(parent, VARS.augment(varNode(parent), false, ScopeInfo.LOCAL, id.getTypeSystem().sigOf(enclosing, (JLocalVariableSymbol) id.getSymbol())));
1✔
476
    }
477

478
    JSymbolTable localTypeSymTable(JSymbolTable parent, JClassType sym) {
479
        // TODO is this really not a shadow barrier?
480
        return SymbolTableImpl.withTypes(parent, TYPES.augment(typeNode(parent), false, ScopeInfo.LOCAL, sym));
1✔
481
    }
482

483
}
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