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

pmd / pmd / 197

19 Oct 2025 09:43PM UTC coverage: 78.676% (+0.03%) from 78.642%
197

push

github

oowekyala
Fix reviow comments on #6116

18231 of 24023 branches covered (75.89%)

Branch coverage included in aggregate %.

2 of 2 new or added lines in 1 file covered. (100.0%)

38 existing lines in 5 files now uncovered.

39748 of 49670 relevant lines covered (80.02%)

0.81 hits per line

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

87.55
/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.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.types;
6

7
import static net.sourceforge.pmd.lang.java.types.Substitution.EMPTY;
8
import static net.sourceforge.pmd.lang.java.types.Substitution.mapping;
9
import static net.sourceforge.pmd.lang.java.types.TypeConversion.capture;
10

11
import java.lang.reflect.Modifier;
12
import java.util.ArrayList;
13
import java.util.Arrays;
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.Map;
20
import java.util.Map.Entry;
21
import java.util.Objects;
22
import java.util.Set;
23
import java.util.function.BiFunction;
24
import java.util.function.Function;
25
import java.util.function.Predicate;
26
import java.util.stream.Collectors;
27

28
import org.checkerframework.checker.nullness.qual.NonNull;
29
import org.checkerframework.checker.nullness.qual.Nullable;
30

31
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
32
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
33
import net.sourceforge.pmd.lang.java.symbols.JExecutableSymbol;
34
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
35
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
36
import net.sourceforge.pmd.lang.java.symbols.table.coreimpl.CoreResolvers;
37
import net.sourceforge.pmd.lang.java.symbols.table.coreimpl.NameResolver;
38
import net.sourceforge.pmd.lang.java.symbols.table.internal.JavaResolvers;
39
import net.sourceforge.pmd.lang.java.types.JVariableSig.FieldSig;
40
import net.sourceforge.pmd.lang.java.types.internal.infer.InferenceVar;
41
import net.sourceforge.pmd.lang.java.types.internal.infer.InferenceVar.BoundKind;
42
import net.sourceforge.pmd.lang.java.types.internal.infer.OverloadSet;
43
import net.sourceforge.pmd.util.CollectionUtil;
44
import net.sourceforge.pmd.util.IteratorUtil;
45

46
/**
47
 * Common operations on types.
48
 */
49
@SuppressWarnings("PMD.CompareObjectsWithEquals")
50
public final class TypeOps {
51

52
    private TypeOps() {
53
        // utility class
54
    }
55

56

57
    // <editor-fold  defaultstate="collapsed" desc="Type equality">
58

59
    /**
60
     * Return true if t and s are the same method type. This compares
61
     * their declaring type, and then their signature.
62
     *
63
     * @see #haveSameSignature(JMethodSig, JMethodSig)
64
     */
65
    public static boolean isSameType(JMethodSig t, JMethodSig s) {
66
        return t.getDeclaringType().equals(s.getDeclaringType()) && haveSameSignature(t, s);
1✔
67
    }
68

69
    /*
70
     * Note that type mirror implementations use this method as their
71
     * Object#equals, which means it can't be used here unless it's on
72
     * the smaller parts of a type.
73
     */
74

75

76
    /**
77
     * Return true if t and s are the same type, ignoring any type annotations
78
     * appearing within them. This is the implementation of the equals method
79
     * of {@link JTypeMirror}.
80
     */
81
    public static boolean isSameType(JTypeMirror t, JTypeMirror s) {
82
        return isSameType(t, s, true, false);
1✔
83
    }
84

85
    /**
86
     * Return true if t and s are the same type, considering any type annotations
87
     * appearing within them.
88
     */
89
    public static boolean isSameTypeWithSameAnnotations(JTypeMirror t, JTypeMirror s) {
90
        return isSameType(t, s, true, true);
1✔
91
    }
92

93
    /**
94
     * Return true if t and s are the same type. This may perform side effects
95
     * on inference variables. Annotations are ignored.
96
     *
97
     * @apiNote Internal API
98
     */
99
    static boolean isSameTypeInInference(JTypeMirror t, JTypeMirror s) {
100
        return isSameType(t, s, false, false);
1✔
101
    }
102

103
    /**
104
     * Returns true if t and s are the same type. If 'inInference' is
105
     * true, then encountering inference variables produces side effects
106
     * on them, adding bounds.
107
     */
108
    private static boolean isSameType(JTypeMirror t, JTypeMirror s, boolean pure, boolean considerAnnotations) {
109
        if (t == s) {
1✔
110
            // also returns true if both t and s are null
111
            return true;
1✔
112
        }
113

114
        if (t == null || s == null) {
1!
115
            return false;
×
116
        }
117

118
        if (pure) {
1✔
119
            if (considerAnnotations) {
1✔
120
                if (t instanceof CaptureMatcher || s instanceof CaptureMatcher) {
1!
121
                    return t.equals(s); // skip check for type annotations
1✔
122
                }
123
                return t.getTypeAnnotations().equals(s.getTypeAnnotations())
1!
124
                    && t.acceptVisitor(SameTypeVisitor.PURE_WITH_ANNOTATIONS, s);
1✔
125
            } else {
126
                return t.acceptVisitor(SameTypeVisitor.PURE, s);
1✔
127
            }
128
        }
129

130
        // reorder
131
        if (t instanceof InferenceVar) {
1✔
132
            return t.acceptVisitor(SameTypeVisitor.INFERENCE, s);
1✔
133
        } else {
134
            return s.acceptVisitor(SameTypeVisitor.INFERENCE, t);
1✔
135
        }
136
    }
137

138
    public static boolean areSameTypes(List<JTypeMirror> ts, List<JTypeMirror> ss) {
139
        return areSameTypes(ts, ss, EMPTY, true, false);
×
140
    }
141

142
    public static boolean areSameTypesInInference(List<JTypeMirror> ts, List<JTypeMirror> ss) {
143
        return areSameTypes(ts, ss, EMPTY, false, false);
1✔
144
    }
145

146
    private static boolean areSameTypes(List<JTypeMirror> ts, List<JTypeMirror> ss, boolean pure, boolean considerAnnotations) {
147
        return areSameTypes(ts, ss, EMPTY, pure, considerAnnotations);
1✔
148
    }
149

150
    private static boolean areSameTypes(List<JTypeMirror> ts, List<JTypeMirror> ss, Substitution subst) {
151
        return areSameTypes(ts, ss, subst, true, false);
1✔
152
    }
153

154
    private static boolean areSameTypes(List<JTypeMirror> ts, List<JTypeMirror> ss, Substitution subst, boolean pure, boolean considerAnnotations) {
155
        if (ts.size() != ss.size()) {
1✔
156
            return false;
1✔
157
        }
158
        for (int i = 0; i < ts.size(); i++) {
1✔
159
            if (!isSameType(ts.get(i), ss.get(i).subst(subst), pure, considerAnnotations)) {
1✔
160
                return false;
1✔
161
            }
162
        }
163
        return true;
1✔
164
    }
165

166

167
    // note that this does not take type annotations into account
168
    private static final class SameTypeVisitor implements JTypeVisitor<Boolean, JTypeMirror> {
169

170
        static final SameTypeVisitor INFERENCE = new SameTypeVisitor(false, false);
1✔
171
        static final SameTypeVisitor PURE = new SameTypeVisitor(true, false);
1✔
172
        static final SameTypeVisitor PURE_WITH_ANNOTATIONS = new SameTypeVisitor(true, true);
1✔
173

174
        private final boolean pure;
175
        private final boolean considerAnnotations;
176

177
        private SameTypeVisitor(boolean pure, boolean considerAnnotations) {
1✔
178
            this.pure = pure;
1✔
179
            this.considerAnnotations = considerAnnotations;
1✔
180
        }
1✔
181

182
        @Override
183
        public Boolean visit(JTypeMirror t, JTypeMirror s) {
184
            // for sentinel types
185
            return t == s;
1!
186
        }
187

188
        @Override
189
        public Boolean visitPrimitive(JPrimitiveType t, JTypeMirror s) {
190
            return s.isPrimitive(t.getKind());
1✔
191
        }
192

193
        @Override
194
        public Boolean visitClass(JClassType t, JTypeMirror s) {
195
            if (s instanceof JClassType) {
1✔
196
                JClassType s2 = (JClassType) s;
1✔
197
                return t.getSymbol().equals(s2.getSymbol()) // maybe compare the type system as well.
1✔
198
                    && t.hasErasedSuperTypes() == s2.hasErasedSuperTypes()
1✔
199
                    && isSameType(t.getEnclosingType(), s2.getEnclosingType(), pure, considerAnnotations)
1✔
200
                    && areSameTypes(t.getTypeArgs(), s2.getTypeArgs(), pure, considerAnnotations);
1✔
201
            }
202
            return false;
1✔
203
        }
204

205
        @Override
206
        public Boolean visitTypeVar(JTypeVar t, JTypeMirror s) {
207
            return t.equals(s);
1✔
208
        }
209

210
        @Override
211
        public Boolean visitWildcard(JWildcardType t, JTypeMirror s) {
212
            if (!(s instanceof JWildcardType)) {
1✔
213
                return false;
1✔
214
            }
215
            JWildcardType s2 = (JWildcardType) s;
1✔
216
            return s2.isUpperBound() == t.isUpperBound() && isSameType(t.getBound(), s2.getBound(), pure, considerAnnotations);
1✔
217
        }
218

219
        @Override
220
        public Boolean visitInferenceVar(InferenceVar t, JTypeMirror s) {
221
            if (pure) {
1✔
222
                return t == s || t.getBounds(BoundKind.EQ).contains(s);
1!
223
            }
224

225
            if (s instanceof JPrimitiveType) {
1!
226
                return false;
×
227
            }
228

229
            if (s instanceof JWildcardType) {
1✔
230
                JWildcardType s2 = (JWildcardType) s;
1✔
231
                if (s2.isUpperBound()) {
1✔
232
                    t.addBound(BoundKind.UPPER, s2.asUpperBound());
1✔
233
                } else {
234
                    t.addBound(BoundKind.LOWER, s2.asLowerBound());
1✔
235
                }
236
                return true;
1✔
237
            }
238

239
            // add an equality bound
240
            t.addBound(BoundKind.EQ, s);
1✔
241
            return true;
1✔
242
        }
243

244
        @Override
245
        public Boolean visitIntersection(JIntersectionType t, JTypeMirror s) {
246
            if (!(s instanceof JIntersectionType)) {
1✔
247
                return false;
1✔
248
            }
249

250
            JIntersectionType s2 = (JIntersectionType) s;
1✔
251

252
            // order is irrelevant
253

254
            if (s2.getComponents().size() != t.getComponents().size()) {
1!
255
                return false;
×
256
            }
257

258
            if (!isSameType(t.getPrimaryBound(), s2.getPrimaryBound(), pure, considerAnnotations)) {
1!
259
                return false;
×
260
            }
261

262
            List<JTypeMirror> sComps = ((JIntersectionType) s).getComponents();
1✔
263
            for (JTypeMirror ti : t.getComponents()) {
1✔
264
                boolean found = false;
1✔
265
                for (JTypeMirror si : sComps) {
1!
266
                    // todo won't this behaves weirdly during inference? test it
267
                    if (isSameType(ti, si, pure, considerAnnotations)) {
1✔
268
                        found = true;
1✔
269
                        break;
1✔
270
                    }
271
                }
1✔
272
                if (!found) {
1!
273
                    return false;
×
274
                }
275
            }
1✔
276
            return true;
1✔
277
        }
278

279
        @Override
280
        public Boolean visitArray(JArrayType t, JTypeMirror s) {
281
            return s instanceof JArrayType
1✔
282
                && isSameType(t.getComponentType(), ((JArrayType) s).getComponentType(), pure, considerAnnotations);
1✔
283
        }
284
    }
285

286
    // </editor-fold>
287

288
    // <editor-fold  defaultstate="collapsed" desc="Supertype enumeration">
289

290

291
    /**
292
     * Returns the set of all supertypes of the given type.
293
     *
294
     * @see JTypeMirror#getSuperTypeSet()
295
     */
296
    public static Set<JTypeMirror> getSuperTypeSet(@NonNull JTypeMirror t) {
297
        Set<JTypeMirror> result = new LinkedHashSet<>();
1✔
298
        t.acceptVisitor(SuperTypesVisitor.INSTANCE, result);
1✔
299
        assert !result.isEmpty() : "Empty supertype set for " + t;
1!
300
        return result;
1✔
301
    }
302

303
    private static final class SuperTypesVisitor implements JTypeVisitor<Void, Set<JTypeMirror>> {
304

305
        static final SuperTypesVisitor INSTANCE = new SuperTypesVisitor();
1✔
306

307
        @Override
308
        public Void visit(JTypeMirror t, Set<JTypeMirror> result) {
309
            throw new IllegalStateException("Should not be called");
×
310
        }
311

312
        @Override
313
        public Void visitTypeVar(JTypeVar t, Set<JTypeMirror> result) {
314
            if (result.add(t)) {
1!
315
                // prevent infinite loop
316
                t.getUpperBound().acceptVisitor(this, result);
1✔
317
            }
318
            return null;
1✔
319
        }
320

321
        @Override
322
        public Void visitNullType(JTypeMirror t, Set<JTypeMirror> result) {
323
            // too many types
324
            throw new UnsupportedOperationException("The null type has all reference types as supertype");
1✔
325
        }
326

327
        @Override
328
        public Void visitSentinel(JTypeMirror t, Set<JTypeMirror> result) {
329
            result.add(t);
×
330
            return null;
×
331
        }
332

333
        @Override
334
        public Void visitInferenceVar(InferenceVar t, Set<JTypeMirror> result) {
335
            result.add(t);
×
336
            return null;
×
337
        }
338

339
        @Override
340
        public Void visitWildcard(JWildcardType t, Set<JTypeMirror> result) {
341
            t.asUpperBound().acceptVisitor(this, result);
1✔
342
            // wildcards should be captured and so we should not end up here
343
            return null;
1✔
344
        }
345

346
        @Override
347
        public Void visitClass(JClassType t, Set<JTypeMirror> result) {
348
            result.add(t);
1✔
349

350

351
            // prefer digging up the superclass first
352
            JClassType sup = t.getSuperClass();
1✔
353
            if (sup != null) {
1✔
354
                sup.acceptVisitor(this, result);
1✔
355
            }
356
            for (JClassType i : t.getSuperInterfaces()) {
1✔
357
                visitClass(i, result);
1✔
358
            }
1✔
359
            if (t.isInterface() && t.getSuperInterfaces().isEmpty()) {
1✔
360
                result.add(t.getTypeSystem().OBJECT);
1✔
361
            }
362
            return null;
1✔
363
        }
364

365
        @Override
366
        public Void visitIntersection(JIntersectionType t, Set<JTypeMirror> result) {
367
            for (JTypeMirror it : t.getComponents()) {
1✔
368
                it.acceptVisitor(this, result);
1✔
369
            }
1✔
370
            return null;
1✔
371
        }
372

373
        @Override
374
        public Void visitArray(JArrayType t, Set<JTypeMirror> result) {
375
            result.add(t);
1✔
376

377
            TypeSystem ts = t.getTypeSystem();
1✔
378

379
            for (JTypeMirror componentSuper : t.getComponentType().getSuperTypeSet()) {
1✔
380
                result.add(ts.arrayType(componentSuper));
1✔
381
            }
1✔
382
            result.add(ts.CLONEABLE);
1✔
383
            result.add(ts.SERIALIZABLE);
1✔
384
            result.add(ts.OBJECT);
1✔
385

386
            return null;
1✔
387
        }
388

389
        @Override
390
        public Void visitPrimitive(JPrimitiveType t, Set<JTypeMirror> result) {
391
            result.addAll(t.getSuperTypeSet()); // special implementation in JPrimitiveType
×
392
            return null;
×
393
        }
394
    }
395

396
    // </editor-fold>
397

398
    // <editor-fold  defaultstate="collapsed" desc="Subtyping">
399

400

401
    public static Convertibility isConvertible(@NonNull JTypeMirror t, @NonNull JTypeMirror s) {
402
        return SubtypeVisitor.INFERENCE.isConvertible(t, s, true);
1✔
403
    }
404

405
    @Deprecated // unused
406
    public static Convertibility isConvertible(@NonNull JTypeMirror t, @NonNull JTypeMirror s, boolean capture) {
407
        return SubtypeVisitor.PURE.isConvertible(t, s, capture);
×
408
    }
409

410
    public static Convertibility isConvertibleNoCapture(@NonNull JTypeMirror t, @NonNull JTypeMirror s) {
411
        return SubtypeVisitor.PURE.isConvertible(t, s, false);
1✔
412
    }
413

414
    // does not perform side effects on inference vars
415
    public static Convertibility isConvertiblePure(JTypeMirror t, JTypeMirror s) {
416
        return SubtypeVisitor.PURE.isConvertible(t, s);
1✔
417
    }
418

419
    public static boolean allArgsAreUnboundedWildcards(List<JTypeMirror> sargs) {
420
        for (JTypeMirror sarg : sargs) {
1✔
421
            if (!(sarg instanceof JWildcardType) || !((JWildcardType) sarg).isUnbounded()) {
1✔
422
                return false;
1✔
423
            }
424
        }
1✔
425
        return true;
1✔
426
    }
427

428
    /**
429
     * A result for a convertibility check. This is a tiny generalization of
430
     * a subtyping check.
431
     *
432
     * <p>Primitive types are implicitly convertible to each other by
433
     * widening primitive conversion. For reference types, subtyping
434
     * implies convertibility (the conversion is technically called
435
     * "widening reference conversion"). You can check those cases using:
436
     *
437
     * {@link #bySubtyping() t.isConvertibleTo(s).bySubtyping()}
438
     *
439
     * <p>Unchecked conversion may go backwards from subtyping. For example,
440
     * {@code List<String>} is a subtype of the raw type {@code List}, and
441
     * as such is convertible to it by reference widening. But {@code List}
442
     * may be "coerced" to {@code List<String>} with an unchecked warning:
443
     *
444
     * {@link #withUncheckedWarning() t.isConvertibleTo(s).withUncheckedWarning()}
445
     *
446
     * <p>If the parameterized type only has wildcard type arguments,
447
     * then the conversion produces no warning.
448
     *
449
     * {@link #UNCHECKED_NO_WARNING t.isConvertibleTo(s) == UNCHECKED_NO_WARNING}
450
     *
451
     * <p>Two types may be unconvertible:
452
     *
453
     * {@link #never() t.isConvertibleTo(s).never()}
454
     *
455
     * <p>the negation of which being
456
     *
457
     * {@link #somehow() t.isConvertibleTo(s).somehow()}
458
     *
459
     * <p>Note that this does not check for boxing or unboxing conversions,
460
     * nor for narrowing conversions, which may happen through casts.
461
     */
462
    public enum Convertibility {
1✔
463
        /** T is never implicitly convertible to S. */
464
        NEVER,
1✔
465

466
        /**
467
         * T is not a subtype of S, but every time T is used in a context
468
         * where an S is expected, unchecked conversion converts the T to
469
         * an S with a mandated warning. For example the raw type {@code Class}
470
         * is convertible to {@code Class<String>} with an unchecked warning.
471
         */
472
        UNCHECKED_WARNING,
1✔
473

474
        /**
475
         * {@code T <: |S|} and {@code T </: S}, but S is
476
         * parameterized with only unbounded wildcards. This is a special
477
         * case of unchecked conversion that produces no warning. We keep
478
         * it distinct from subtyping to help some algorithms that require
479
         * subtyping to be a partial order.
480
         *
481
         * <p>For example, {@code List<String>} is a subtype of the raw
482
         * {@code Collection}, not a subtype of {@code Collection<?>},
483
         * but it is still convertible without warning.
484
         */
485
        UNCHECKED_NO_WARNING,
1✔
486

487
        /**
488
         * T is a subtype of S ({@code T <: S}). In particular, any type
489
         * is a subtype of itself ({@code T <: T}).
490
         *
491
         * <p>For example, {@code int} can be widened to {@code long},
492
         * so we consider {@code int <: long}.
493
         */
494
        SUBTYPING;
1✔
495

496
        // public:
497

498
        /** Returns true if this is {@link #NEVER}. */
499
        public boolean never() {
500
            return this == NEVER;
1✔
501
        }
502

503
        /**
504
         * Returns true if this is anything but {@link #NEVER}.
505
         */
506
        public boolean somehow() {
507
            return this != NEVER;
1✔
508
        }
509

510
        /**
511
         * True if this is {@link #SUBTYPING}.
512
         */
513
        public boolean bySubtyping() {
514
            return this == SUBTYPING;
1✔
515
        }
516

517
        /**
518
         * True if this is {@link #UNCHECKED_WARNING}.
519
         */
520
        public boolean withUncheckedWarning() {
521
            return this == UNCHECKED_WARNING;
1✔
522
        }
523

524
        /** True if this is {@link #SUBTYPING} or {@link #UNCHECKED_NO_WARNING}. */
525
        public boolean withoutWarnings() {
526
            return this == SUBTYPING || this == UNCHECKED_NO_WARNING;
1✔
527
        }
528

529
        // package:
530

531

532
        /** Preserves an unchecked warning. */
533
        Convertibility and(Convertibility b) {
534
            return min(this, b);
1✔
535
        }
536

537
        static Convertibility min(Convertibility c1, Convertibility c2) {
538
            return c1.ordinal() < c2.ordinal() ? c1 : c2;
1!
539
        }
540

541
        static Convertibility subtypeIf(boolean b) {
542
            return b ? SUBTYPING : NEVER;
1✔
543
        }
544

545
    }
546

547
    private static JTypeMirror wildUpperBound(JTypeMirror type) {
548
        if (type instanceof JWildcardType) {
1✔
549
            JWildcardType wild = (JWildcardType) type;
1✔
550
            if (wild.isUpperBound()) {
1✔
551
                return wildUpperBound(wild.asUpperBound());
1✔
552
            } else if (wild.asLowerBound() instanceof JTypeVar) {
1!
553
                return ((JTypeVar) wild.asLowerBound()).getUpperBound();
×
554
            }
555
        } else if (type instanceof JTypeVar && ((JTypeVar) type).isCaptured()) {
1✔
556
            // note: tvar.getUpperBound() != tvar.getCapturedOrigin().asUpperBound()
557
            return wildUpperBound(((JTypeVar) type).getUpperBound());
1✔
558
        }
559
        return type;
1✔
560
    }
561

562
    private static JTypeMirror wildLowerBound(JTypeMirror type) {
563
        if (type instanceof JWildcardType) {
1✔
564
            return wildLowerBound(((JWildcardType) type).asLowerBound());
1✔
565
        }
566
        return type;
1✔
567
    }
568

569
    private static JTypeMirror lowerBoundRec(JTypeMirror type) {
570
        if (type instanceof JWildcardType) {
1!
571
            return lowerBoundRec(((JWildcardType) type).asLowerBound());
×
572
        } else if (type instanceof JTypeVar && ((JTypeVar) type).isCaptured()) {
1✔
573
            return lowerBoundRec(((JTypeVar) type).getLowerBound());
1✔
574
        }
575
        return type;
1✔
576
    }
577

578
    private static boolean isTypeRange(JTypeMirror s) {
579
        return s instanceof JWildcardType || isCvar(s);
1!
580
    }
581

582
    private static boolean isCvar(JTypeMirror s) {
583
        return s instanceof JTypeVar && ((JTypeVar) s).isCaptured();
1✔
584
    }
585

586

587
    private static final class SubtypeVisitor implements JTypeVisitor<Convertibility, JTypeMirror> {
588

589
        static final SubtypeVisitor INFERENCE = new SubtypeVisitor(false);
1✔
590
        static final SubtypeVisitor PURE = new SubtypeVisitor(true);
1✔
591
        private final boolean pure;
592

593
        private SubtypeVisitor(boolean pure) {
1✔
594
            this.pure = pure;
1✔
595
        }
1✔
596

597

598
        Convertibility isConvertible(@NonNull JTypeMirror t, @NonNull JTypeMirror s) {
599
            return isConvertible(t, s, false);
1✔
600
        }
601

602
        /**
603
         * Returns whether if {@code T <: S}, ie T is a subtype of S.
604
         *
605
         * <p>Note that {@link TypeSystem#ERROR} and {@link TypeSystem#UNKNOWN}
606
         * are considered subtypes of anything.
607
         *
608
         * @param t A type T
609
         * @param s A type S
610
         */
611
        Convertibility isConvertible(@NonNull JTypeMirror t, @NonNull JTypeMirror s, boolean capture) {
612
            // This is commented out as it makes JTypeMirror#isSubtypeOf partial,
613
            // which is not nice for the API... But this assert caught a bug and
614
            // should probably be enabled.
615
            // assert !(t instanceof JWildcardType || s instanceof JWildcardType) : "Wildcards do not support subtyping";
616

617
            if (t == s) {
1✔
618
                Objects.requireNonNull(t);
1✔
619
                return Convertibility.SUBTYPING;
1✔
620
            } else if (s.isTop()) {
1✔
621
                return Convertibility.subtypeIf(!t.isPrimitive());
1✔
622
            } else if (s.isVoid() || t.isVoid()) { // t != s
1✔
623
                return Convertibility.NEVER;
1✔
624
            } else if (s instanceof InferenceVar) {
1✔
625
                if (!pure) {
1!
626
                    // it's possible to add a bound to UNKNOWN or ERROR
627
                    ((InferenceVar) s).addBound(BoundKind.LOWER, t);
1✔
628
                }
629
                return Convertibility.SUBTYPING;
1✔
630
            } else if (isTypeRange(s)) {
1✔
631
                // If s is a type range L..U,
632
                // then showing t <: s is the same thing as t <: L
633
                JTypeMirror lower = lowerBoundRec(s);
1✔
634
                if (!lower.isBottom()) {
1✔
635
                    return isConvertible(t, lower);
1✔
636
                }
637
                // otherwise fallthrough
638
            } else if (hasUnresolvedSymbol(t)) {
1✔
639
                // This also considers types with an unresolved symbol
640
                // subtypes of (nearly) anything. This allows them to
641
                // pass bound checks on type variables.
642
                if (Objects.equals(t.getSymbol(), s.getSymbol())) {
1✔
643
                    return typeArgsAreContained((JClassType) t, (JClassType) s);
1✔
644
                } else {
645
                    return Convertibility.subtypeIf(s instanceof JClassType); // excludes array or so
1✔
646
                }
647
            } else if (s instanceof JIntersectionType) { // TODO test intersection with tvars & arrays
1✔
648
                // If S is an intersection, then T must conform to *all* bounds of S
649
                // Symmetrically, if T is an intersection, T <: S requires only that
650
                // at least one bound of T is a subtype of S.
651
                return subtypesAll(t, asList(s));
1✔
652
            }
653

654
            if (capture) {
1✔
655
                t = capture(t);
1✔
656
            }
657
            return t.acceptVisitor(this, s);
1✔
658
        }
659

660
        Convertibility subtypesAll(JTypeMirror t, Iterable<? extends JTypeMirror> supers) {
661
            Convertibility result = Convertibility.SUBTYPING;
1✔
662
            for (JTypeMirror ui : supers) {
1✔
663
                Convertibility sub = isConvertible(t, ui);
1✔
664
                if (sub == Convertibility.NEVER) {
1✔
665
                    return Convertibility.NEVER;
1✔
666
                }
667
                result = result.and(sub);
1✔
668
            }
1✔
669
            return result;
1✔
670
        }
671

672
        Convertibility anySubTypesAny(Iterable<? extends JTypeMirror> us, Iterable<? extends JTypeMirror> vs) {
673
            for (JTypeMirror ui : us) {
1✔
674
                for (JTypeMirror vi : vs) {
1✔
675
                    Convertibility sub = isConvertible(ui, vi);
1✔
676
                    if (sub != Convertibility.NEVER) {
1✔
677
                        return sub.and(Convertibility.SUBTYPING); // never return identity here
1✔
678
                    }
679
                }
1✔
680
            }
1✔
681
            return Convertibility.NEVER;
1✔
682
        }
683

684
        /**
685
         * Generalises containment to check if for each i, {@code Ti <= Si}.
686
         */
687
        Convertibility typeArgsAreContained(JClassType t, JClassType s) {
688
            List<JTypeMirror> targs = t.getTypeArgs();
1✔
689
            List<JTypeMirror> sargs = s.getTypeArgs();
1✔
690

691
            if (targs.isEmpty()) {
1✔
692
                if (sargs.isEmpty()) {
1✔
693
                    // Some "erased" non-generic types may appear as the supertypes
694
                    // of raw types, and they're different from the regular flavor
695
                    // as their own supertypes are erased, yet they're not considered
696
                    // raw. To fix the subtyping relation, we say that `C <: (erased) C`
697
                    // but `(erased) C` converts to `C` by unchecked conversion, without
698
                    // warning.
699
                    boolean tRaw = t.hasErasedSuperTypes();
1✔
700
                    boolean sRaw = s.hasErasedSuperTypes();
1✔
701
                    if (tRaw && !sRaw) {
1✔
702
                        return Convertibility.UNCHECKED_NO_WARNING;
1✔
703
                    } else {
704
                        return Convertibility.SUBTYPING;
1✔
705
                    }
706
                }
707
                // for some C, S = C<...> and T = C, ie T is raw
708
                // T is convertible to S, by unchecked conversion.
709
                // If S = D<?, .., ?>, then the conversion produces
710
                // no unchecked warning.
711
                return allArgsAreUnboundedWildcards(sargs) ? Convertibility.UNCHECKED_NO_WARNING
1✔
712
                                                           : Convertibility.UNCHECKED_WARNING;
1✔
713
            } else if (sargs.isEmpty()) {
1✔
714
                // C<T1...TN> <: |C|
715
                // JLS 4.10.2
716
                // unchecked conversion converts a raw type to a generic type
717
                // subtyping converts a generic type to its raw type
718
                return Convertibility.SUBTYPING;
1✔
719
            }
720

721
            if (targs.size() != sargs.size()) {
1✔
722
                // types are not well-formed
723
                return Convertibility.NEVER;
1✔
724
            }
725

726
            Convertibility result = Convertibility.SUBTYPING;
1✔
727
            for (int i = 0; i < targs.size(); i++) {
1✔
728
                Convertibility sub = typeArgContains(sargs.get(i), targs.get(i));
1✔
729
                if (sub == Convertibility.NEVER) {
1✔
730
                    return Convertibility.NEVER;
1✔
731
                }
732
                result = result.and(sub);
1✔
733
            }
734

735
            return result;
1✔
736
        }
737

738
        /**
739
         * Returns true if {@code T <= S}, ie "S contains T".
740
         *
741
         * <p>S contains T if:
742
         *
743
         * <p>{@code L(S) <: L(T) && U(T) <: U(S)}
744
         *
745
         * <p>This only makes sense for type arguments, it's a component of
746
         * subtype checks for parameterized types:
747
         *
748
         * <p>{@code C<S> <: C<T> if S <= T}
749
         *
750
         * <p>Defined in JLS§4.5.1 (Type Arguments of Parameterized Types)
751
         */
752
        Convertibility typeArgContains(JTypeMirror s, JTypeMirror t) {
753
            // the contains relation can be understood intuitively if we
754
            // represent types as ranges on a line:
755

756
            // ⊥ ---------L(S)---L(T)------U(T)-----U(S)---> Object
757
            // range of S   [-------------------------]
758
            // range of T          [---------]
759

760
            // here S contains T because its range is greater
761

762
            // since a wildcard is either "super" or "extends", in reality
763
            // either L(S) = ⊥, or U(S) = Object.
764

765
            // meaning when S != T, we only have two scenarios where T <= S:
766

767
            //      ⊥ -------U(T)-----U(S)------> Object   (L(T) = L(S) = ⊥)
768
            //      ⊥ -------L(S)-----L(T)------> Object   (U(T) = U(S) = Object)
769

770
            if (isSameType(s, t, pure, false)) {
1✔
771
                // S <= S
772
                return Convertibility.SUBTYPING;
1✔
773
            }
774

775
            if (s instanceof JWildcardType) {
1✔
776
                JWildcardType sw = (JWildcardType) s;
1✔
777

778
                // capt(? extends T) <= ? extends T
779
                // capt(? super T) <= ? super T
780
                if (t instanceof JTypeVar && ((JTypeVar) t).isCaptureOf(sw)) {
1✔
781
                    return Convertibility.SUBTYPING;
1✔
782
                }
783

784
                if (sw.isUpperBound()) {
1✔
785
                    // Test U(T) <: U(S),  we already know L(S) <: L(T), because L(S) is bottom
786
                    return this.isConvertible(wildUpperBound(t), sw.asUpperBound());
1✔
787
                } else {
788
                    // Test L(S) <: L(T), we already know U(T) <: U(S), because U(S) is top
789
                    return this.isConvertible(sw.asLowerBound(), wildLowerBound(t));
1✔
790
                }
791
            }
792

793
            return Convertibility.NEVER;
1✔
794
        }
795

796
        @Override
797
        public Convertibility visit(JTypeMirror t, JTypeMirror s) {
798
            throw new IllegalStateException("Should not be called");
×
799
        }
800

801
        @Override
802
        public Convertibility visitTypeVar(JTypeVar t, JTypeMirror s) {
803
            if (s instanceof JTypeVar && t.getSymbol() != null && Objects.equals(t.getSymbol(), s.getSymbol())) {
1✔
804
                return Convertibility.SUBTYPING;
1✔
805
            } else if (s instanceof SentinelType) {
1!
806
                return Convertibility.SUBTYPING;
×
807
            }
808

809
            if (isTypeRange(s)) {
1✔
810
                return isConvertible(t, lowerBoundRec(s));
1✔
811
            }
812
            return isConvertible(t.getUpperBound(), s);
1✔
813
        }
814

815
        @Override
816
        public Convertibility visitNullType(JTypeMirror t, JTypeMirror s) {
817
            return Convertibility.subtypeIf(!s.isPrimitive());
1✔
818
        }
819

820
        @Override
821
        public Convertibility visitSentinel(JTypeMirror t, JTypeMirror s) {
822
            // t may be (*unknown*), (*error*) or void
823
            // we know t != s
824
            if (t.isVoid()) {
1!
825
                return Convertibility.NEVER;
×
826
            }
827
            // unknown and error are subtypes of everything.
828
            // however we want them to add constrains on unknown
829
            if (!pure && !(s instanceof SentinelType)) {
1!
830
                s.acceptVisitor(this, t);
1✔
831
            }
832
            return Convertibility.SUBTYPING;
1✔
833
        }
834

835
        @Override
836
        public Convertibility visitInferenceVar(InferenceVar t, JTypeMirror s) {
837
            if (s == t.getTypeSystem().NULL_TYPE || s instanceof JPrimitiveType) {
1!
838
                return Convertibility.NEVER;
×
839
            }
840
            if (!pure) {
1!
841
                // here we add a constraint on the variable
842
                t.addBound(BoundKind.UPPER, s);
1✔
843
            }
844
            return Convertibility.SUBTYPING;
1✔
845
        }
846

847
        @Override
848
        public Convertibility visitWildcard(JWildcardType t, JTypeMirror s) {
849
            // wildcards should be captured and so we should not end up here
850
            return Convertibility.NEVER;
1✔
851
        }
852

853
        @Override
854
        public Convertibility visitClass(JClassType t, JTypeMirror s) {
855
            if (isSpecialUnresolved(s)) {
1✔
856
                if (!pure) {
1!
857
                    for (JTypeMirror arg : t.getTypeArgs()) {
1✔
858
                        typeArgContains(arg, s);
1✔
859
                    }
1✔
860
                }
861
                return Convertibility.SUBTYPING;
1✔
862
            }
863
            if (!(s instanceof JClassType)) {
1✔
864
                // note, that this ignores wildcard types,
865
                // because they're only compared through
866
                // type argument containment.
867
                return Convertibility.NEVER;
1✔
868
            }
869

870
            JClassType cs = (JClassType) s;
1✔
871

872
            JClassType superDecl = t.getAsSuper(cs.getSymbol());
1✔
873

874
            if (superDecl == null) {
1✔
875
                return Convertibility.NEVER;
1✔
876
            } else if (cs.isRaw()) {
1✔
877
                // a raw type C is a supertype for all the family of parameterized type generated by C<F1, .., Fn>
878
                return Convertibility.SUBTYPING;
1✔
879
            } else {
880
                return typeArgsAreContained(superDecl, cs);
1✔
881
            }
882
        }
883

884
        @Override
885
        public Convertibility visitIntersection(JIntersectionType t, JTypeMirror s) {
886
            // A & B <: A
887
            // A & B <: B
888

889
            // But for a class C, `C <: A & B` if `C <: A` and `C <: B`
890

891
            // So we can't just say, "any component of t must subtype s",
892
            // because if s is itself an intersection we have a problem:
893
            // Eg let T = S = A & B
894
            // T <: S -> A & B <: S
895
            //        -> A <: S OR B <: S
896
            //        -> A <: A & B OR B <: A & B
897
            //        -> A <: A AND A <: B OR B <: A AND B <: B
898
            //        -> true   AND false  OR false  AND true
899
            //        -> false
900

901
            // what we mean is, if S is an intersection, then
902
            // "any component of T subtypes any component of S"
903

904
            return anySubTypesAny(t.getComponents(), asList(s));
1✔
905
        }
906

907
        @Override
908
        public Convertibility visitArray(JArrayType t, JTypeMirror s) {
909
            TypeSystem ts = t.getTypeSystem();
1✔
910
            if (s == ts.OBJECT || s.equals(ts.CLONEABLE) || s.equals(ts.SERIALIZABLE)) {
1!
911
                return Convertibility.SUBTYPING;
1✔
912
            }
913
            if (isSpecialUnresolved(s)) {
1✔
914
                if (!pure) {
1!
915
                    t.getElementType().acceptVisitor(this, s);
1✔
916
                }
917
                return Convertibility.SUBTYPING;
1✔
918
            }
919

920
            if (!(s instanceof JArrayType)) {
1✔
921
                // not comparable to any other type
922
                return Convertibility.NEVER;
1✔
923
            }
924

925
            JArrayType cs = (JArrayType) s;
1✔
926

927
            if (t.getComponentType().isPrimitive() || cs.getComponentType().isPrimitive()) {
1✔
928
                // arrays of primitive types have no sub-/ supertype
929
                return Convertibility.subtypeIf(cs.getComponentType() == t.getComponentType());
1✔
930
            } else {
931
                return isConvertible(t.getComponentType(), cs.getComponentType());
1✔
932
            }
933
        }
934

935
        @Override
936
        public Convertibility visitPrimitive(JPrimitiveType t, JTypeMirror s) {
937
            if (s instanceof JPrimitiveType) {
1✔
938
                return t.superTypes.contains(s) ? Convertibility.SUBTYPING
1✔
939
                                                : Convertibility.NEVER;
1✔
940
            }
941
            return Convertibility.NEVER;
1✔
942
        }
943
    }
944

945
    public static boolean isStrictSubtype(@NonNull JTypeMirror t, @NonNull JTypeMirror s) {
946
        return !t.equals(s) && t.isSubtypeOf(s);
1!
947
    }
948

949
    // </editor-fold>
950

951
    // <editor-fold  defaultstate="collapsed" desc="Substitution">
952

953
    /**
954
     * Replace the type variables occurring in the given type to their
955
     * image by the given function. Substitutions are not applied
956
     * recursively.
957
     *
958
     * @param type  Type to substitute
959
     * @param subst Substitution function, eg a {@link Substitution}
960
     */
961
    public static JTypeMirror subst(@Nullable JTypeMirror type, Function<? super SubstVar, ? extends @NonNull JTypeMirror> subst) {
962
        if (type == null || Substitution.isEmptySubst(subst)) {
1!
963
            return type;
1✔
964
        }
965
        return type.subst(subst);
1✔
966
    }
967

968

969
    /** Substitute on a list of types. */
970
    public static List<JTypeMirror> subst(List<? extends JTypeMirror> ts, Function<? super SubstVar, ? extends @NonNull JTypeMirror> subst) {
971
        if (Substitution.isEmptySubst(subst)) {
1✔
972
            return CollectionUtil.makeUnmodifiableAndNonNull(ts);
1✔
973
        }
974
        return mapPreservingSelf(ts, t -> t.subst(subst));
1✔
975
    }
976

977
    public static List<JClassType> substClasses(List<JClassType> ts, Function<? super SubstVar, ? extends @NonNull JTypeMirror> subst) {
978
        if (Substitution.isEmptySubst(subst)) {
1✔
979
            return ts;
1✔
980
        }
981
        return mapPreservingSelf(ts, t -> t.subst(subst));
1✔
982
    }
983

984
    public static List<JTypeVar> substInBoundsOnly(List<JTypeVar> ts, Function<? super SubstVar, ? extends @NonNull JTypeMirror> subst) {
985
        if (Substitution.isEmptySubst(subst)) {
1✔
986
            return ts;
1✔
987
        }
988
        return mapPreservingSelf(ts, t -> t.substInBounds(subst));
1✔
989
    }
990

991
    // relies on the fact the original list is unmodifiable or won't be
992
    // modified
993
    @SuppressWarnings("unchecked")
994
    private static @NonNull <T> List<T> mapPreservingSelf(List<? extends T> ts, Function<? super T, ? extends @NonNull T> subst) {
995
        // Profiling shows, only 10% of calls to this method need to
996
        // create a new list. Substitution in general is a hot spot
997
        // of the framework, so optimizing this out is nice
998
        List<T> list = null;
1✔
999
        for (int i = 0, size = ts.size(); i < size; i++) {
1✔
1000
            T it = ts.get(i);
1✔
1001
            T substed = subst.apply(it);
1✔
1002
            if (substed != it) {
1✔
1003
                if (list == null) {
1✔
1004
                    list = Arrays.asList((T[]) ts.toArray()); // NOPMD ClassCastExceptionWithToArray
1✔
1005
                }
1006
                list.set(i, substed);
1✔
1007
            }
1008
        }
1009

1010
        // subst relies on the fact that the original list is returned
1011
        // to avoid new type creation. Thus one cannot use
1012
        // Collections::unmodifiableList here
1013
        return list != null ? list : (List<T>) ts;
1✔
1014
    }
1015

1016
    // </editor-fold>
1017

1018
    // <editor-fold  defaultstate="collapsed" desc="Projection">
1019

1020

1021
    /**
1022
     * Returns the upwards projection of the given type, with respect
1023
     * to the set of capture variables that are found in it. This is
1024
     * some supertype of T which does not mention those capture variables.
1025
     * This is used for local variable type inference.
1026
     *
1027
     * https://docs.oracle.com/javase/specs/jls/se11/html/jls-4.html#jls-4.10.5
1028
     */
1029
    public static JTypeMirror projectUpwards(JTypeMirror t) {
1030
        return t.acceptVisitor(UPWARDS_PROJECTOR, new RecursionStop());
1✔
1031
    }
1032

1033
    private static final JTypeMirror NO_DOWN_PROJECTION = null;
1✔
1034
    private static final ProjectionVisitor UPWARDS_PROJECTOR = new ProjectionVisitor(true) {
1✔
1035

1036
        @Override
1037
        public JTypeMirror visitTypeVar(JTypeVar t, RecursionStop recursionStop) {
1038
            if (t.isCaptured()) {
1✔
1039
                return t.getUpperBound().acceptVisitor(UPWARDS_PROJECTOR, recursionStop);
1✔
1040
            }
1041
            return t;
1✔
1042
        }
1043

1044

1045
        @Override
1046
        public JTypeMirror visitWildcard(JWildcardType t, RecursionStop recursionStop) {
1047
            JTypeMirror u = t.getBound().acceptVisitor(UPWARDS_PROJECTOR, recursionStop);
1✔
1048
            TypeSystem ts = t.getTypeSystem();
1✔
1049
            if (u == t.getBound()) {
1✔
1050
                return t;
1✔
1051
            }
1052

1053
            if (t.isUpperBound()) {
1!
1054
                return ts.wildcard(true, u);
×
1055
            } else {
1056
                JTypeMirror down = t.getBound().acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
1✔
1057
                return down == NO_DOWN_PROJECTION ? ts.UNBOUNDED_WILD : ts.wildcard(false, down);
1!
1058
            }
1059
        }
1060

1061

1062
        @Override
1063
        public JTypeMirror visitNullType(JTypeMirror t, RecursionStop recursionStop) {
1064
            return t;
×
1065
        }
1066

1067
    };
1068

1069

1070
    private static final ProjectionVisitor DOWNWARDS_PROJECTOR = new ProjectionVisitor(false) {
1✔
1071

1072
        @Override
1073
        public JTypeMirror visitWildcard(JWildcardType t, RecursionStop recursionStop) {
1074
            JTypeMirror u = t.getBound().acceptVisitor(UPWARDS_PROJECTOR, recursionStop);
×
1075
            if (u == t.getBound()) {
×
1076
                return t;
×
1077
            }
1078
            TypeSystem ts = t.getTypeSystem();
×
1079

1080
            if (t.isUpperBound()) {
×
1081
                JTypeMirror down = t.getBound().acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
×
1082
                return down == NO_DOWN_PROJECTION ? NO_DOWN_PROJECTION
×
1083
                                                  : ts.wildcard(true, down);
×
1084
            } else {
1085
                return ts.wildcard(false, u);
×
1086
            }
1087
        }
1088

1089

1090
        @Override
1091
        public JTypeMirror visitTypeVar(JTypeVar t, RecursionStop recursionStop) {
1092
            if (t.isCaptured()) {
1!
1093
                return t.getLowerBound().acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
1✔
1094
            }
1095
            return t;
×
1096
        }
1097

1098
        @Override
1099
        public JTypeMirror visitNullType(JTypeMirror t, RecursionStop recursionStop) {
1100
            return NO_DOWN_PROJECTION;
1✔
1101
        }
1102
    };
1103

1104
    static final class RecursionStop {
1✔
1105

1106
        private Set<JTypeVar> set;
1107

1108
        boolean isAbsent(JTypeVar tvar) {
1109
            if (set == null) {
1✔
1110
                set = new LinkedHashSet<>(1);
1✔
1111
            }
1112
            return set.add(tvar);
1✔
1113
        }
1114

1115
        <T extends JTypeMirror> JTypeMirror recurseIfNotDone(T t, BiFunction<T, RecursionStop, JTypeMirror> body) {
1116
            if (t instanceof JTypeVar) {
1✔
1117
                JTypeVar var = (JTypeVar) t;
1✔
1118
                if (isAbsent(var)) {
1✔
1119
                    return body.apply(t, this);
1✔
1120
                } else {
1121
                    return t;
1✔
1122
                }
1123
            } else {
1124
                return body.apply(t, this);
1✔
1125
            }
1126
        }
1127
    }
1128

1129
    /**
1130
     * Restricted type variables are:
1131
     * - Inference vars
1132
     * - Capture vars
1133
     *
1134
     * See
1135
     *
1136
     * https://docs.oracle.com/javase/specs/jls/se11/html/jls-4.html#jls-4.10.5
1137
     *
1138
     *
1139
     * <p>Here we use {@link #NO_DOWN_PROJECTION} as a sentinel
1140
     * (downwards projection is a partial function). If a type does not mention
1141
     * restricted type variables, then the visitor should return the original
1142
     * type (same reference). This allows testing predicates like
1143
     * <blockquote>
1144
     * "If Ai does not mention any restricted type variable, then Ai' = Ai."
1145
     * </blockquote>
1146
     */
1147
    private abstract static class ProjectionVisitor implements JTypeVisitor<JTypeMirror, RecursionStop> {
1148

1149
        private final boolean upwards;
1150

1151
        private ProjectionVisitor(boolean upwards) {
1✔
1152
            this.upwards = upwards;
1✔
1153
        }
1✔
1154

1155

1156
        @Override
1157
        public abstract JTypeMirror visitNullType(JTypeMirror t, RecursionStop recursionStop);
1158

1159

1160
        @Override
1161
        public abstract JTypeMirror visitWildcard(JWildcardType t, RecursionStop recursionStop);
1162

1163

1164
        @Override
1165
        public abstract JTypeMirror visitTypeVar(JTypeVar t, RecursionStop recursionStop);
1166

1167

1168
        @Override
1169
        public JTypeMirror visit(JTypeMirror t, RecursionStop recursionStop) {
1170
            return t;
1✔
1171
        }
1172

1173
        @Override
1174
        public JTypeMirror visitClass(JClassType t, RecursionStop recursionStop) {
1175
            if (t.isParameterizedType()) {
1✔
1176
                TypeSystem ts = t.getTypeSystem();
1✔
1177

1178
                List<JTypeMirror> targs = t.getTypeArgs();
1✔
1179
                List<JTypeMirror> newTargs = new ArrayList<>(targs.size());
1✔
1180
                List<JTypeVar> formals = t.getFormalTypeParams();
1✔
1181
                boolean change = false;
1✔
1182

1183
                for (int i = 0; i < targs.size(); i++) {
1✔
1184
                    JTypeMirror ai = targs.get(i);
1✔
1185
                    JTypeMirror u = recursionStop.recurseIfNotDone(ai, (s, stop) -> s.acceptVisitor(this, stop));
1✔
1186
                    if (u == ai) {
1✔
1187
                        if (isCvar(ai)) { // cvar hit recursion stop
1✔
1188
                            u = ts.UNBOUNDED_WILD;
1✔
1189
                            change = true;
1✔
1190
                        }
1191
                        // no change, or handled by the visitWildcard
1192
                        newTargs.add(u);
1✔
1193
                        continue;
1✔
1194
                    } else if (!upwards) {
1!
1195
                        // If Ai is a type that mentions a restricted type variable, then Ai' is undefined.
1196
                        return NO_DOWN_PROJECTION;
×
1197
                    } else if (u instanceof JWildcardType) {
1✔
1198
                        // The rest of this function, below, treats u as the bound of a wildcard,
1199
                        // but if u is already a wildcard (and therefore ai was a wildcard), we
1200
                        // are already done.
1201
                        newTargs.add(u);
1✔
1202
                        change = true;
1✔
1203
                        continue;
1✔
1204
                    }
1205

1206
                    change = true;
1✔
1207

1208
                    /*
1209
                        If Ai is a type that mentions a restricted type variable...
1210
                     */
1211
                    JTypeMirror bi = formals.get(i).getUpperBound();
1✔
1212

1213
                    if (u != ts.OBJECT && (mentionsAny(bi, formals) || !bi.isSubtypeOf(u))) {
1!
1214
                        newTargs.add(ts.wildcard(true, u));
1✔
1215
                    } else {
1216
                        JTypeMirror down = ai.acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
1✔
1217
                        if (down == NO_DOWN_PROJECTION) {
1!
1218
                            newTargs.add(ts.UNBOUNDED_WILD);
1✔
1219
                        } else {
1220
                            newTargs.add(ts.wildcard(false, down));
×
1221
                        }
1222
                    }
1223
                }
1224

1225
                return change ? t.withTypeArguments(newTargs) : t;
1✔
1226
            } else {
1227
                return t;
1✔
1228
            }
1229
        }
1230

1231
        @Override
1232
        public JTypeMirror visitIntersection(JIntersectionType t, RecursionStop recursionStop) {
1233
            List<JTypeMirror> comps = new ArrayList<>(t.getComponents());
1✔
1234
            boolean change = false;
1✔
1235
            for (int i = 0; i < comps.size(); i++) {
1✔
1236
                JTypeMirror ci = comps.get(i);
1✔
1237
                JTypeMirror proj = ci.acceptVisitor(this, recursionStop);
1✔
1238
                if (proj == NO_DOWN_PROJECTION) {
1!
1239
                    return NO_DOWN_PROJECTION;
×
1240
                } else {
1241
                    comps.set(i, proj);
1✔
1242
                    if (ci != proj) {
1!
1243
                        change = true;
×
1244
                    }
1245
                }
1246
            }
1247
            return change ? t.getTypeSystem().glb(comps) : t;
1!
1248
        }
1249

1250
        @Override
1251
        public JTypeMirror visitArray(JArrayType t, RecursionStop recursionStop) {
1252
            JTypeMirror comp2 = t.getComponentType().acceptVisitor(this, recursionStop);
1✔
1253
            return comp2 == NO_DOWN_PROJECTION
1!
1254
                   ? NO_DOWN_PROJECTION
×
1255
                   : comp2 == t.getComponentType()
1!
1256
                     ? t : t.getTypeSystem().arrayType(comp2);
1✔
1257
        }
1258

1259
        @Override
1260
        public JTypeMirror visitSentinel(JTypeMirror t, RecursionStop recursionStop) {
1261
            return t;
1✔
1262
        }
1263
    }
1264

1265
    // </editor-fold>
1266

1267
    // <editor-fold  defaultstate="collapsed" desc="Overriding">
1268

1269
    /**
1270
     * Returns true if m1 is return-type substitutable with m2. The notion of return-type-substitutability
1271
     * supports covariant returns, that is, the specialization of the return type to a subtype.
1272
     *
1273
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.5
1274
     */
1275
    public static boolean isReturnTypeSubstitutable(JMethodSig m1, JMethodSig m2) {
1276

1277
        JTypeMirror r1 = m1.getReturnType();
1✔
1278
        JTypeMirror r2 = m2.getReturnType();
1✔
1279

1280
        if (r1 == r1.getTypeSystem().NO_TYPE) {
1✔
1281
            return r1 == r2;
1!
1282
        }
1283

1284
        if (r1.isPrimitive()) {
1✔
1285
            return r1 == r2;
1!
1286
        }
1287

1288
        JMethodSig m1Prime = adaptForTypeParameters(m1, m2);
1✔
1289
        return m1Prime != null && isConvertible(m1Prime.getReturnType(), r2) != Convertibility.NEVER
1!
1290
                || !haveSameSignature(m1, m2) && isSameType(r1, r2.getErasure());
1!
1291
    }
1292

1293
    /**
1294
     * Adapt m1 to the type parameters of m2. Returns null if that's not possible.
1295
     *
1296
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.4
1297
     *
1298
     * <p>Note that the type parameters of m1 are not replaced, only
1299
     * their occurrences in the rest of the signature.
1300
     */
1301
    static @Nullable JMethodSig adaptForTypeParameters(JMethodSig m1, JMethodSig m2) {
1302
        if (haveSameTypeParams(m1, m2)) {
1!
1303
            return m1.subst(mapping(m1.getTypeParameters(), m2.getTypeParameters()));
1✔
1304
        }
1305

1306
        return null;
×
1307
    }
1308

1309
    public static boolean haveSameTypeParams(JMethodSig m1, JMethodSig m2) {
1310
        List<JTypeVar> tp1 = m1.getTypeParameters();
1✔
1311
        List<JTypeVar> tp2 = m2.getTypeParameters();
1✔
1312
        if (tp1.size() != tp2.size()) {
1✔
1313
            return false;
1✔
1314
        }
1315

1316
        if (tp1.isEmpty()) {
1✔
1317
            return true;
1✔
1318
        }
1319

1320
        Substitution mapping = mapping(tp2, tp1);
1✔
1321
        for (int i = 0; i < tp1.size(); i++) {
1✔
1322
            JTypeVar p1 = tp1.get(i);
1✔
1323
            JTypeVar p2 = tp2.get(i);
1✔
1324

1325
            if (!isSameType(p1.getUpperBound(), subst(p2.getUpperBound(), mapping))) {
1✔
1326
                return false;
1✔
1327
            }
1328
        }
1329

1330
        return true;
1✔
1331
    }
1332

1333
    /**
1334
     * Two method signatures m1 and m2 are override-equivalent iff either
1335
     * m1 is a subsignature of m2 or m2 is a subsignature of m1. This does
1336
     * not look at the origin of the methods (their declaring class).
1337
     *
1338
     * <p>This is a prerequisite for one method to override the other,
1339
     * but not the only condition. See {@link #overrides(JMethodSig, JMethodSig, JTypeMirror)}.
1340
     *
1341
     * See <a href="https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.2">JLS§8</a>
1342
     */
1343
    public static boolean areOverrideEquivalent(JMethodSig m1, JMethodSig m2) {
1344
        // This method is a very hot spot as it is used to prune shadowed/overridden/hidden
1345
        // methods from overload candidates before overload resolution.
1346
        // Any optimization makes a big impact.
1347
        if (m1.getArity() != m2.getArity()) {
1✔
1348
            return false; // easy case
1✔
1349
        } else if (m1 == m2) {
1!
1350
            return true;
×
1351
        } else if (!m1.getName().equals(m2.getName())) {
1!
1352
            // note: most call sites statically know this is true
1353
            // profile to figure out whether this matters
1354
            return false;
×
1355
        }
1356

1357
        List<JTypeMirror> formals1 = m1.getFormalParameters();
1✔
1358
        List<JTypeMirror> formals2 = m2.getFormalParameters();
1✔
1359
        for (int i = 0; i < formals1.size(); i++) {
1✔
1360
            JTypeMirror fi1 = formals1.get(i);
1✔
1361
            JTypeMirror fi2 = formals2.get(i);
1✔
1362

1363
            if (!isSameType(fi1.getErasure(), fi2.getErasure())) {
1✔
1364
                return false;
1✔
1365
            }
1366
        }
1367

1368
        // a non-generic method may override a generic one
1369
        return !m1.isGeneric() || !m2.isGeneric()
1!
1370
            // if both are generic, they must have the same type params
1371
            || haveSameTypeParams(m1, m2);
1✔
1372
    }
1373

1374
    /**
1375
     * The signature of a method m1 is a subsignature of the signature of a method m2 if either:
1376
     * - m2 has the same signature as m1, or
1377
     * - the signature of m1 is the same as the erasure (§4.6) of the signature of m2.
1378
     */
1379
    public static boolean isSubSignature(JMethodSig m1, JMethodSig m2) {
1380
        // prune easy cases
1381
        if (m1.getArity() != m2.getArity() || !m1.getName().equals(m2.getName())) {
1✔
1382
            return false;
1✔
1383
        }
1384
        boolean m1Gen = m1.isGeneric();
1✔
1385
        boolean m2Gen = m2.isGeneric();
1✔
1386
        if (m1Gen ^ m2Gen) {
1✔
1387
            if (m1Gen) {
1!
1388
                return false; // this test is asymmetric
×
1389
            } else {
1390
                m2 = m2.getErasure();
1✔
1391
            }
1392
        }
1393
        return haveSameSignature(m1, m2);
1✔
1394
    }
1395

1396
    /**
1397
     * Two methods or constructors, M and N, have the same signature if
1398
     * they have the same name, the same type parameters (if any) (§8.4.4),
1399
     * and, after adapting the formal parameter types of N to the the type
1400
     * parameters of M, the same formal parameter types.
1401
     *
1402
     * Thrown exceptions are not part of the signature of a method.
1403
     */
1404
    private static boolean haveSameSignature(JMethodSig m1, JMethodSig m2) {
1405
        return m1.getName().equals(m2.getName())
1✔
1406
                && m1.getArity() == m2.getArity()
1✔
1407
                && haveSameTypeParams(m1, m2)
1✔
1408
                && areSameTypes(m1.getFormalParameters(),
1✔
1409
                            m2.getFormalParameters(),
1✔
1410
                            Substitution.mapping(m2.getTypeParameters(), m1.getTypeParameters()));
1✔
1411
    }
1412

1413
    /**
1414
     * Returns true if m1 overrides m2, when both are view as members of
1415
     * class origin. m1 and m2 may be declared in supertypes of origin,
1416
     * possibly unrelated (default methods), which is why we need that
1417
     * third parameter. By convention a method overrides itself.
1418
     *
1419
     * <p>This method ignores the static modifier. If both methods are
1420
     * static, then this method tests for <i>hiding</i>. Otherwise, this
1421
     * method properly tests for overriding. Note that it is an error for
1422
     * a static method to override an instance method, or the reverse.
1423
     */
1424
    public static boolean overrides(JMethodSig m1, JMethodSig m2, JTypeMirror origin) {
1425

1426
        if (m1.isConstructor() || m2.isConstructor()) {
1!
1427
            return m1.equals(m2); // "by convention a method overrides itself"
1✔
1428
        }
1429

1430
        JTypeMirror m1Owner = m1.getDeclaringType();
1✔
1431
        JClassType m2Owner = (JClassType) m2.getDeclaringType();
1✔
1432

1433
        if (isOverridableIn(m2, m1Owner.getSymbol())) {
1✔
1434
            JClassType m2AsM1Supertype = (JClassType) m1Owner.getAsSuper(m2Owner.getSymbol());
1✔
1435
            if (m2AsM1Supertype != null) {
1✔
1436
                JMethodSig m2Prime = m2AsM1Supertype.getDeclaredMethod(m2.getSymbol());
1✔
1437
                assert m2Prime != null;
1!
1438
                if (isSubSignature(m1, m2Prime)) {
1✔
1439
                    return true;
1✔
1440
                }
1441
            }
1442
        }
1443

1444
        // todo that is very weird
1445
        if (m1.isAbstract()
1✔
1446
            || !m2.isAbstract() && !m2.getSymbol().isDefaultMethod()
1!
1447
            || !isOverridableIn(m2, origin.getSymbol())
1!
1448
            || !(m1Owner instanceof JClassType)) {
1449
            return false;
1✔
1450
        }
1451

1452
        JTypeMirror m1AsSuper = origin.getAsSuper(((JClassType) m1Owner).getSymbol());
1✔
1453
        JTypeMirror m2AsSuper = origin.getAsSuper(m2Owner.getSymbol());
1✔
1454
        if (m1AsSuper instanceof JClassType && m2AsSuper instanceof JClassType) {
1!
1455
            m1 = ((JClassType) m1AsSuper).getDeclaredMethod(m1.getSymbol());
1✔
1456
            m2 = ((JClassType) m2AsSuper).getDeclaredMethod(m2.getSymbol());
1✔
1457
            assert m1 != null && m2 != null;
1!
1458
            return isSubSignature(m1, m2);
1✔
1459
        }
1460
        return false;
1✔
1461
    }
1462

1463
    /**
1464
     * Returns true if both methods override the same method of a common supertype.
1465
     */
1466
    public static boolean overrideSameMethod(JMethodSig m1, JMethodSig m2) {
1467
        if (Objects.equals(m1.getSymbol(), m2.getSymbol())) {
1✔
1468
            return true;
1✔
1469
        }
1470
        if (!haveSameSignature(m1, m2)) {
1✔
1471
            return false;
1✔
1472
        }
1473
        JTypeMirror declaringType1 = m1.getDeclaringType();
1✔
1474
        JTypeMirror declaringType2 = m2.getDeclaringType();
1✔
1475
        return declaringType2.getSuperTypeSet().stream().anyMatch(st ->
1✔
1476
            TypeTestUtil.isA(st, declaringType1) && st.streamDeclaredMethods(
1✔
1477
                method -> method.nameEquals(m1.getName())
1✔
1478
                    && method.getFormalParameters().equals(m1.getSymbol().getFormalParameters())
1✔
1479
            ).findAny().isPresent()
1✔
1480
        );
1481
    }
1482

1483
    private static boolean isOverridableIn(JMethodSig m, JTypeDeclSymbol origin) {
1484
        return isOverridableIn(m.getSymbol(), origin);
1✔
1485
    }
1486

1487
    /**
1488
     * Returns true if the given method can be overridden in the origin
1489
     * class. This only checks access modifiers and not eg whether the
1490
     * method is final or static. Regardless of whether the method is
1491
     * final it is overridden - whether this is a compile error or not
1492
     * is another matter.
1493
     *
1494
     * <p>Like {@link #overrides(JMethodSig, JMethodSig, JTypeMirror)},
1495
     * this does not check the static modifier, and tests for hiding
1496
     * if the method is static.
1497
     *
1498
     * @param m      Method to test
1499
     * @param origin Site of the potential override
1500
     */
1501
    public static boolean isOverridableIn(JExecutableSymbol m, JTypeDeclSymbol origin) {
1502
        if (m instanceof JConstructorSymbol) {
1!
UNCOV
1503
            return false;
×
1504
        }
1505

1506
        final int accessFlags = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
1✔
1507

1508
        // JLS 8.4.6.1
1509
        switch (m.getModifiers() & accessFlags) {
1✔
1510
        case Modifier.PUBLIC:
1511
            return true;
1✔
1512
        case Modifier.PROTECTED:
1513
            return !origin.isInterface();
1✔
1514
        case 0:
1515
            // package private
1516
            return
1✔
1517
                m.getPackageName().equals(origin.getPackageName())
1✔
1518
                    && !origin.isInterface();
1!
1519
        default:
1520
            // private
1521
            return false;
1✔
1522
        }
1523
    }
1524

1525
    // </editor-fold>
1526

1527
    // <editor-fold  defaultstate="collapsed" desc="SAM types">
1528

1529
    /*
1530
     * Function types of SAM (single-abstract-method) types.
1531
     *
1532
     * See https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-9.9
1533
     */
1534

1535

1536
    /**
1537
     * Returns the non-wildcard parameterization of the given functional
1538
     * interface type. Returns null if such a parameterization does not
1539
     * exist.
1540
     *
1541
     * <p>This is used to remove wildcards from the type of a functional
1542
     * interface.
1543
     *
1544
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-9.html#jls-9.9
1545
     *
1546
     * @param type A parameterized functional interface type
1547
     */
1548
    public static @Nullable JClassType nonWildcardParameterization(@NonNull JClassType type) {
1549
        TypeSystem ts = type.getTypeSystem();
1✔
1550

1551
        List<JTypeMirror> targs = type.getTypeArgs();
1✔
1552
        if (targs.stream().noneMatch(it -> it instanceof JWildcardType)) {
1✔
1553
            return type;
1✔
1554
        }
1555

1556
        List<JTypeVar> tparams = type.getFormalTypeParams();
1✔
1557
        List<JTypeMirror> newArgs = new ArrayList<>();
1✔
1558

1559
        for (int i = 0; i < tparams.size(); i++) {
1✔
1560
            JTypeMirror ai = targs.get(i);
1✔
1561
            if (ai instanceof JWildcardType) {
1✔
1562
                JTypeVar pi = tparams.get(i);
1✔
1563
                JTypeMirror bi = pi.getUpperBound();
1✔
1564
                if (mentionsAny(bi, new HashSet<>(tparams))) {
1!
UNCOV
1565
                    return null;
×
1566
                }
1567

1568
                JWildcardType ai2 = (JWildcardType) ai;
1✔
1569

1570
                if (ai2.isUnbounded()) {
1✔
1571
                    newArgs.add(bi);
1✔
1572
                } else if (ai2.isUpperBound()) {
1✔
1573
                    newArgs.add(ts.glb(Arrays.asList(ai2.asUpperBound(), bi)));
1✔
1574
                } else { // lower bound
1575
                    newArgs.add(ai2.asLowerBound());
1✔
1576
                }
1577

1578
            } else {
1✔
1579
                newArgs.add(ai);
1✔
1580
            }
1581

1582
        }
1583

1584
        return type.withTypeArguments(newArgs);
1✔
1585
    }
1586

1587
    /**
1588
     * Finds the method of the given type that can be overridden as a lambda
1589
     * expression. That is more complicated than "the unique abstract method",
1590
     * it's actually a function type which can override all abstract methods
1591
     * of the SAM at once.
1592
     *
1593
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-9.html#jls-9.9
1594
     *
1595
     * <p>If the parameter is not mappable to a class type with {@link #asClassType(JTypeMirror)},
1596
     * or if the functional method does not exist, returns null.
1597
     */
1598
    public static @Nullable JMethodSig findFunctionalInterfaceMethod(@Nullable JTypeMirror type) {
1599
        JClassType candidateSam = asClassType(type);
1✔
1600
        if (candidateSam == null) {
1✔
1601
            return null;
1✔
1602
        }
1603

1604
        if (candidateSam.isParameterizedType()) {
1✔
1605
            return findFunctionTypeImpl(nonWildcardParameterization(candidateSam));
1✔
1606
        } else if (candidateSam.isRaw()) {
1✔
1607
            //  The function type of the raw type of a generic functional
1608
            //  interface I<...> is the erasure of the function type of the generic functional interface I<...>.
1609
            JMethodSig fun = findFunctionTypeImpl(candidateSam.getGenericTypeDeclaration());
1✔
1610
            return fun == null ? null : fun.getErasure();
1!
1611
        } else {
1612
            return findFunctionTypeImpl(candidateSam);
1✔
1613
        }
1614
    }
1615

1616
    /**
1617
     * Returns t if it is a class or interface type. If it is an intersection type,
1618
     * returns the induced class or interface type. Returns null otherwise, including
1619
     * if the parameter is null.
1620
     */
1621
    public static @Nullable JClassType asClassType(@Nullable JTypeMirror t) {
1622
        if (t instanceof JClassType) {
1✔
1623
            return (JClassType) t;
1✔
1624
        } else if (t instanceof JIntersectionType) {
1✔
1625
            return ((JIntersectionType) t).getInducedClassType();
1✔
1626
        }
1627
        return null;
1✔
1628
    }
1629

1630
    private static @Nullable JMethodSig findFunctionTypeImpl(@Nullable JClassType candidateSam) {
1631

1632
        if (candidateSam == null || !candidateSam.isInterface() || candidateSam.getSymbol().isAnnotation()) {
1!
1633
            return null;
1✔
1634
        }
1635

1636
        Map<String, List<JMethodSig>> relevantMethods = candidateSam.streamMethods(it -> !Modifier.isStatic(it.getModifiers()))
1✔
1637
                                                                    .filter(TypeOps::isNotDeclaredInClassObject)
1✔
1638
                                                                    .collect(Collectors.groupingBy(JMethodSig::getName, OverloadSet.collectMostSpecific(candidateSam)));
1✔
1639

1640

1641
        List<JMethodSig> candidates = new ArrayList<>();
1✔
1642
        for (Entry<String, List<JMethodSig>> entry : relevantMethods.entrySet()) {
1✔
1643
            for (JMethodSig sig : entry.getValue()) {
1✔
1644
                if (sig.isAbstract()) {
1✔
1645
                    candidates.add(sig);
1✔
1646
                }
1647
            }
1✔
1648
        }
1✔
1649

1650
        if (candidates.isEmpty()) {
1✔
1651
            return null;
1✔
1652
        } else if (candidates.size() == 1) {
1✔
1653
            return candidates.get(0);
1✔
1654
        }
1655

1656
        JMethodSig currentBest = null;
1✔
1657

1658
        nextCandidate:
1659
        for (int i = 0; i < candidates.size(); i++) {
1✔
1660
            JMethodSig cand = candidates.get(i);
1✔
1661

1662
            for (JMethodSig other : candidates) {
1!
1663
                if (!isSubSignature(cand, other)
1✔
1664
                    || !isReturnTypeSubstitutable(cand, other)) {
1!
UNCOV
1665
                    continue nextCandidate;
×
1666
                }
1667
            }
1✔
1668

UNCOV
1669
            if (currentBest == null) {
×
UNCOV
1670
                currentBest = cand;
×
UNCOV
1671
            } else if (cand.getReturnType().isSubtypeOf(currentBest.getReturnType())) {
×
1672
                // select the most specific return type
UNCOV
1673
                currentBest = cand;
×
1674
            }
1675
        }
1676

1677
        return currentBest;
1✔
1678
    }
1679

1680
    private static boolean isNotDeclaredInClassObject(JMethodSig it) {
1681
        TypeSystem ts = it.getDeclaringType().getTypeSystem();
1✔
1682
        return ts.OBJECT.streamDeclaredMethods(om -> Modifier.isPublic(om.getModifiers())
1✔
1683
            && om.nameEquals(it.getName()))
1✔
1684
                        .noneMatch(om -> haveSameSignature(it, om));
1✔
1685
    }
1686

1687
    // </editor-fold>
1688

1689
    // <editor-fold  defaultstate="collapsed" desc="As super">
1690

1691
    /**
1692
     * @see JTypeMirror#getAsSuper(JClassSymbol)
1693
     */
1694
    public static @Nullable JTypeMirror asSuper(@NonNull JTypeMirror t, @NonNull JClassSymbol s) {
1695

1696
        if (!t.isPrimitive() && s.equals(t.getTypeSystem().OBJECT.getSymbol())) {
1!
1697
            // interface types need to have OBJECT somewhere up their hierarchy
1698
            return t.getTypeSystem().OBJECT;
1✔
1699
        }
1700

1701
        return t.acceptVisitor(AsSuperVisitor.INSTANCE, s);
1✔
1702
    }
1703

1704
    /**
1705
     * Return the base type of t or any of its outer types that starts
1706
     * with the given type.  If none exists, return null.
1707
     */
1708
    public static @Nullable JClassType asOuterSuper(JTypeMirror t, JClassSymbol sym) {
UNCOV
1709
        if (t instanceof JClassType) {
×
UNCOV
1710
            JClassType ct = (JClassType) t;
×
1711
            do {
UNCOV
1712
                JClassType sup = ct.getAsSuper(sym);
×
UNCOV
1713
                if (sup != null) {
×
UNCOV
1714
                    return sup;
×
1715
                }
UNCOV
1716
                ct = ct.getEnclosingType();
×
UNCOV
1717
            } while (ct != null);
×
1718
        } else if (t instanceof JTypeVar || t instanceof JArrayType) {
×
UNCOV
1719
            return (JClassType) t.getAsSuper(sym);
×
1720
        }
UNCOV
1721
        return null;
×
1722
    }
1723

1724
    /**
1725
     * Return the first enclosing type of the container type
1726
     * that has the given symbol in its supertypes. Return null
1727
     * if this is not found.
1728
     */
1729
    public static @Nullable JClassType getReceiverType(@NonNull JClassType containerType, JClassSymbol sym) {
1730
        JClassType ct = containerType;
1✔
1731
        do {
1732
            JClassType sup = ct.getAsSuper(sym);
1✔
1733
            if (sup != null) {
1✔
1734
                return ct;
1✔
1735
            }
1736
            ct = ct.getEnclosingType();
1✔
1737
        } while (ct != null);
1!
UNCOV
1738
        return null;
×
1739
    }
1740

1741
    private static final class AsSuperVisitor implements JTypeVisitor<@Nullable JTypeMirror, JClassSymbol> {
1742

1743
        static final AsSuperVisitor INSTANCE = new AsSuperVisitor();
1✔
1744

1745
        /** Parameter is the erasure of the target. */
1746

1747
        @Override
1748
        public JTypeMirror visit(JTypeMirror t, JClassSymbol target) {
1749
            return null;
1✔
1750
        }
1751

1752
        @Override
1753
        public JTypeMirror visitClass(JClassType t, JClassSymbol target) {
1754
            if (target.equals(t.getSymbol())) {
1✔
1755
                return t;
1✔
1756
            }
1757

1758
            // prefer digging up the superclass first
1759
            JClassType sup = t.getSuperClass();
1✔
1760
            JClassType res = sup == null ? null : (JClassType) sup.acceptVisitor(this, target);
1✔
1761
            if (res != null) {
1✔
1762
                return res;
1✔
1763
            } else {
1764
                // then look in interfaces if possible
1765
                if (target.isInterface() || target.isUnresolved()) {
1✔
1766
                    return firstResult(target, t.getSuperInterfaces());
1✔
1767
                }
1768
            }
1769

1770
            return null;
1✔
1771
        }
1772

1773
        @Override
1774
        public JTypeMirror visitIntersection(JIntersectionType t, JClassSymbol target) {
UNCOV
1775
            return firstResult(target, t.getComponents());
×
1776
        }
1777

1778
        public @Nullable JTypeMirror firstResult(JClassSymbol target, Iterable<? extends JTypeMirror> components) {
1779
            for (JTypeMirror ci : components) {
1✔
1780
                @Nullable JTypeMirror sup = ci.acceptVisitor(this, target);
1✔
1781
                if (sup != null) {
1✔
1782
                    return sup;
1✔
1783
                }
1784
            }
1✔
1785
            return null;
1✔
1786
        }
1787

1788
        @Override
1789
        public JTypeMirror visitTypeVar(JTypeVar t, JClassSymbol target) {
1790
            // caution, infinite recursion
1791
            return t.getUpperBound().acceptVisitor(this, target);
1✔
1792
        }
1793

1794
        @Override
1795
        public JTypeMirror visitArray(JArrayType t, JClassSymbol target) {
1796
            // Cloneable, Serializable, Object
UNCOV
1797
            JTypeMirror decl = t.getTypeSystem().declaration(target);
×
UNCOV
1798
            return t.isSubtypeOf(decl) ? decl : null;
×
1799
        }
1800
    }
1801

1802
    // </editor-fold>
1803

1804
    // <editor-fold  defaultstate="collapsed" desc="LUB/GLB">
1805

1806
    /**
1807
     * Returns a subset S of the parameter, whose components have no
1808
     * strict supertype in S.
1809
     *
1810
     * <pre>{@code
1811
     * S = { V | V in set, and for all W ≠ V in set, it is not the case that W <: V }
1812
     * }</pre>
1813
     */
1814
    public static Set<JTypeMirror> mostSpecific(Collection<? extends JTypeMirror> set) {
1815
        Set<JTypeMirror> result = new LinkedHashSet<>(set.size());
1✔
1816

1817
        // Notice that this loop needs a well-behaved subtyping relation,
1818
        // i.e. antisymmetric: A <: B && A != B implies not(B <: A)
1819
        // This is not the case if we include unchecked conversion in there,
1820
        // or special provisions for unresolved types.
1821
        vLoop:
1822
        for (JTypeMirror v : set) {
1✔
1823
            for (JTypeMirror w : set) {
1✔
1824
                if (!w.equals(v) && !hasUnresolvedSymbolOrArray(w)) {
1✔
1825
                    Convertibility isConvertible = isConvertibleNoCapture(w, v);
1✔
1826
                    if (isConvertible.bySubtyping()
1✔
1827
                        // This last case covers unchecked conversion. It is made antisymmetric by the
1828
                        // test for a symbol. eg |G| <~> G<?> so it would fail.
1829
                        // However, |G| ~> S if |G| <: |S|, so we should consider |G| more specific than S.
1830
                        || isConvertible.withoutWarnings() && !Objects.equals(w.getSymbol(), v.getSymbol())) {
1✔
1831
                        continue vLoop;
1✔
1832
                    }
1833
                }
1834
            }
1✔
1835
            result.add(v);
1✔
1836
        }
1✔
1837
        return result;
1✔
1838
    }
1839

1840
    // </editor-fold>
1841

1842
    /**
1843
     * Returns the components of t if it is an intersection type,
1844
     * otherwise returns t.
1845
     */
1846
    public static List<JTypeMirror> asList(JTypeMirror t) {
1847
        if (t instanceof JIntersectionType) {
1✔
1848
            return ((JIntersectionType) t).getComponents();
1✔
1849
        } else {
1850
            return Collections.singletonList(t);
1✔
1851
        }
1852
    }
1853

1854
    /** Returns a list with the erasures of the given types, may be unmodifiable. */
1855
    public static List<JTypeMirror> erase(Collection<? extends JTypeMirror> ts) {
1856
        return CollectionUtil.map(ts, JTypeMirror::getErasure);
1✔
1857
    }
1858

1859
    // <editor-fold  defaultstate="collapsed" desc="Mentions">
1860

1861

1862
    public static boolean mentions(@NonNull JTypeVisitable type, @NonNull InferenceVar parent) {
1863
        return type.acceptVisitor(MentionsVisitor.INSTANCE, Collections.singleton(parent));
1✔
1864
    }
1865

1866
    public static boolean mentionsAny(JTypeVisitable t, Collection<? extends SubstVar> vars) {
1867
        return !vars.isEmpty() && t.acceptVisitor(MentionsVisitor.INSTANCE, vars);
1✔
1868
    }
1869

1870

1871
    private static final class MentionsVisitor implements JTypeVisitor<Boolean, Collection<? extends JTypeMirror>> {
1872

1873
        static final MentionsVisitor INSTANCE = new MentionsVisitor();
1✔
1874

1875
        @Override
1876
        public Boolean visit(JTypeMirror t, Collection<? extends JTypeMirror> targets) {
1877
            return false;
1✔
1878
        }
1879

1880
        @Override
1881
        public Boolean visitTypeVar(JTypeVar t, Collection<? extends JTypeMirror> targets) {
1882
            return targets.contains(t);
1✔
1883
        }
1884

1885
        @Override
1886
        public Boolean visitInferenceVar(InferenceVar t, Collection<? extends JTypeMirror> targets) {
1887
            return targets.contains(t);
1✔
1888
        }
1889

1890
        @Override
1891
        public Boolean visitWildcard(JWildcardType t, Collection<? extends JTypeMirror> targets) {
1892
            return t.getBound().acceptVisitor(this, targets);
1✔
1893
        }
1894

1895
        @Override
1896
        public Boolean visitMethodType(JMethodSig t, Collection<? extends JTypeMirror> targets) {
1897
            if (t.getReturnType().acceptVisitor(this, targets)) {
1✔
1898
                return true;
1✔
1899
            }
1900
            for (JTypeMirror fi : t.getFormalParameters()) {
1✔
1901
                if (fi.acceptVisitor(this, targets)) {
1✔
1902
                    return true;
1✔
1903
                }
1904
            }
1✔
1905
            for (JTypeMirror ti : t.getThrownExceptions()) {
1✔
1906
                if (ti.acceptVisitor(this, targets)) {
1!
UNCOV
1907
                    return true;
×
1908
                }
1909
            }
1✔
1910
            return false;
1✔
1911
        }
1912

1913
        @Override
1914
        public Boolean visitClass(JClassType t, Collection<? extends JTypeMirror> targets) {
1915
            JClassType encl = t.getEnclosingType();
1✔
1916
            if (encl != null && encl.acceptVisitor(this, targets)) {
1✔
1917
                return true;
1✔
1918
            }
1919

1920
            for (JTypeMirror typeArg : t.getTypeArgs()) {
1✔
1921
                if (typeArg.acceptVisitor(this, targets)) {
1✔
1922
                    return true;
1✔
1923
                }
1924
            }
1✔
1925

1926
            return false;
1✔
1927
        }
1928

1929
        @Override
1930
        public Boolean visitIntersection(JIntersectionType t, Collection<? extends JTypeMirror> targets) {
1931
            for (JTypeMirror comp : t.getComponents()) {
1✔
1932
                if (comp.acceptVisitor(this, targets)) {
1!
UNCOV
1933
                    return true;
×
1934
                }
1935
            }
1✔
1936
            return false;
1✔
1937
        }
1938

1939
        @Override
1940
        public Boolean visitArray(JArrayType t, Collection<? extends JTypeMirror> targets) {
1941
            return t.getComponentType().acceptVisitor(this, targets);
1✔
1942
        }
1943
    }
1944

1945
    // </editor-fold>
1946

1947
    // <editor-fold  defaultstate="collapsed" desc="Accessibility utils">
1948

1949

1950
    public static Predicate<JMethodSymbol> accessibleMethodFilter(String name, @NonNull JClassSymbol symbol) {
1951
        return it -> it.nameEquals(name) && isAccessible(it, symbol);
1✔
1952
    }
1953

1954
    public static Iterable<JMethodSig> lazyFilterAccessible(List<JMethodSig> visible, @NonNull JClassSymbol accessSite) {
1955
        return () -> IteratorUtil.filter(visible.iterator(), it -> isAccessible(it.getSymbol(), accessSite));
1✔
1956
    }
1957

1958
    public static List<JMethodSig> filterAccessible(List<JMethodSig> visible, @NonNull JClassSymbol accessSite) {
1959
        return CollectionUtil.mapNotNull(visible, m -> isAccessible(m.getSymbol(), accessSite) ? m : null);
1!
1960
    }
1961

1962
    /**
1963
     * Methods and fields of a type variable come from its upper bound, which must be captured.
1964
     * Capturing a type var does NOT capture its upper bound, so we must treat this
1965
     * case here.
1966
     */
1967
    public static JTypeMirror getMemberSource(JTypeMirror t) {
1968
        if (t instanceof JTypeVar) {
1✔
1969
            JTypeVar tv = (JTypeVar) t;
1✔
1970
            return capture(tv.getUpperBound());
1✔
1971
        }
1972
        return capture(t);
1✔
1973
    }
1974

1975
    public static List<JMethodSig> getMethodsOf(JTypeMirror type, String name, boolean staticOnly, @NonNull JClassSymbol enclosing) {
1976
        if (staticOnly && type.isInterface()) {
1✔
1977
            // static methods, start on interface
1978
            // static interface methods are not inherited
1979
            return type.streamDeclaredMethods(staticMethodFilter(name, true, enclosing)).collect(Collectors.toList());
1✔
1980
        } else if (staticOnly) {
1✔
1981
            // static methods, doesn't start on interface
1982
            // -> ignore non-static, ignore any that are interfaces
1983
            return type.streamMethods(staticMethodFilter(name, false, enclosing)).collect(OverloadSet.collectMostSpecific(type));
1✔
1984
        } else {
1985
            return type.streamMethods(methodFilter(name, enclosing))
1✔
1986
                       .collect(OverloadSet.collectMostSpecific(type));
1✔
1987
        }
1988
    }
1989

1990
    private static @NonNull Predicate<JMethodSymbol> methodFilter(String name, @NonNull JClassSymbol enclosing) {
1991
        return it -> isAccessibleWithName(name, enclosing, it);
1✔
1992
    }
1993

1994
    private static @NonNull Predicate<JMethodSymbol> staticMethodFilter(String name, boolean acceptItfs, @NonNull JClassSymbol enclosing) {
1995
        return it -> Modifier.isStatic(it.getModifiers())
1✔
1996
            && (acceptItfs || !it.getEnclosingClass().isInterface())
1✔
1997
            && isAccessibleWithName(name, enclosing, it);
1✔
1998
    }
1999

2000
    private static boolean isAccessibleWithName(String name, @NonNull JClassSymbol enclosing, JMethodSymbol m) {
2001
        return m.nameEquals(name) && isAccessible(m, enclosing);
1✔
2002
    }
2003

2004

2005
    private static boolean isAccessible(JExecutableSymbol method, JClassSymbol ctx) {
2006
        Objects.requireNonNull(ctx, "Cannot check a null symbol");
1✔
2007

2008
        int mods = method.getModifiers();
1✔
2009
        if (Modifier.isPublic(mods)) {
1✔
2010
            return true;
1✔
2011
        }
2012

2013
        JClassSymbol owner = method.getEnclosingClass();
1✔
2014

2015
        if (Modifier.isPrivate(mods)) {
1✔
2016
            return ctx.getNestRoot().equals(owner.getNestRoot());
1✔
2017
        }
2018

2019
        return ctx.getPackageName().equals(owner.getPackageName())
1✔
2020
            // we can exclude interfaces because their members are all public
2021
            || Modifier.isProtected(mods) && isSubClassOfNoInterface(ctx, owner);
1✔
2022
    }
2023

2024
    private static boolean isSubClassOfNoInterface(JClassSymbol sub, JClassSymbol symbol) {
2025
        if (symbol.equals(sub)) {
1✔
2026
            return true;
1✔
2027
        }
2028

2029
        JClassSymbol superclass = sub.getSuperclass();
1✔
2030
        return superclass != null && isSubClassOfNoInterface(superclass, symbol);
1✔
2031
    }
2032

2033
    public static NameResolver<FieldSig> getMemberFieldResolver(JTypeMirror c, @NonNull String accessPackageName, @Nullable JClassSymbol access, String name) {
2034
        if (c instanceof JClassType) {
1✔
2035
            // fast path
2036
            return JavaResolvers.getMemberFieldResolver((JClassType) c, accessPackageName, access, name);
1✔
2037
        }
2038

2039
        return c.acceptVisitor(GetFieldVisitor.INSTANCE, new FieldSearchParams(accessPackageName, access, name));
1✔
2040
    }
2041

2042
    private static final class FieldSearchParams {
2043

2044
        private final @NonNull String accessPackageName;
2045
        private final @Nullable JClassSymbol access;
2046
        private final String name;
2047

2048
        FieldSearchParams(@NonNull String accessPackageName, @Nullable JClassSymbol access, String name) {
1✔
2049
            this.accessPackageName = accessPackageName;
1✔
2050
            this.access = access;
1✔
2051
            this.name = name;
1✔
2052
        }
1✔
2053
    }
2054

2055
    private static final class GetFieldVisitor implements JTypeVisitor<NameResolver<FieldSig>, FieldSearchParams> {
2056

2057
        static final GetFieldVisitor INSTANCE = new GetFieldVisitor();
1✔
2058

2059
        @Override
2060
        public NameResolver<FieldSig> visit(JTypeMirror t, FieldSearchParams fieldSearchParams) {
2061
            return CoreResolvers.emptyResolver();
1✔
2062
        }
2063

2064
        @Override
2065
        public NameResolver<FieldSig> visitClass(JClassType t, FieldSearchParams fieldSearchParams) {
2066
            return JavaResolvers.getMemberFieldResolver(t, fieldSearchParams.accessPackageName, fieldSearchParams.access, fieldSearchParams.name);
×
2067
        }
2068

2069
        @Override
2070
        public NameResolver<FieldSig> visitTypeVar(JTypeVar t, FieldSearchParams fieldSearchParams) {
UNCOV
2071
            return t.getUpperBound().acceptVisitor(this, fieldSearchParams);
×
2072
        }
2073

2074
        @Override
2075
        public NameResolver<FieldSig> visitIntersection(JIntersectionType t, FieldSearchParams fieldSearchParams) {
UNCOV
2076
            return NameResolver.composite(
×
UNCOV
2077
                CollectionUtil.map(t.getComponents(), c -> c.acceptVisitor(this, fieldSearchParams))
×
2078
            );
2079
        }
2080

2081
        @Override
2082
        public NameResolver<FieldSig> visitArray(JArrayType t, FieldSearchParams fieldSearchParams) {
2083
            if ("length".equals(fieldSearchParams.name)) {
1!
2084
                return CoreResolvers.singleton("length", t.getTypeSystem().sigOf(t, t.getSymbol().getDeclaredField("length")));
1✔
2085
            }
UNCOV
2086
            return CoreResolvers.emptyResolver();
×
2087
        }
2088
    }
2089

2090
    // </editor-fold>
2091

2092
    // <editor-fold  defaultstate="collapsed" desc="Miscellaneous">
2093

2094
    /**
2095
     * Returns true if both types have a common supertype that is not Object.
2096
     * Primitive types are only related to themselves.
2097
     *
2098
     * @param t Non-null type
2099
     * @param s Non-null type
2100
     *
2101
     * @throws NullPointerException if a parameter is null
2102
     */
2103
    public static boolean areRelated(@NonNull JTypeMirror t, JTypeMirror s) {
2104
        if (t.isPrimitive() || s.isPrimitive()) {
1!
UNCOV
2105
            return s.equals(t);
×
2106
        }
2107
        if (t.equals(s)) {
1✔
2108
            return true;
1✔
2109
        }
2110
        // maybe they have a common supertype
2111
        Set<JTypeMirror> tSupertypes = new HashSet<>(t.getSuperTypeSet());
1✔
2112
        tSupertypes.retainAll(s.getSuperTypeSet());
1✔
2113
        return !tSupertypes.equals(Collections.singleton(t.getTypeSystem().OBJECT));
1✔
2114
    }
2115

2116
    /**
2117
     * Returns true if the type is {@link TypeSystem#UNKNOWN},
2118
     * {@link TypeSystem#ERROR}, or a class type with unresolved
2119
     * symbol.
2120
     *
2121
     * @param t Non-null type
2122
     *
2123
     * @throws NullPointerException if the parameter is null
2124
     */
2125
    public static boolean isUnresolved(@NonNull JTypeMirror t) {
2126
        return isSpecialUnresolved(t) || hasUnresolvedSymbol(t);
1✔
2127
    }
2128

2129
    /**
2130
     * Returns true if the type is {@link TypeSystem#UNKNOWN},
2131
     * or {@link TypeSystem#ERROR}, or a class type with unresolved
2132
     * symbol, or an array of such types.
2133
     *
2134
     * @param t Non-null type
2135
     *
2136
     * @throws NullPointerException if the parameter is null
2137
     */
2138
    public static boolean isUnresolvedOrArray(@NonNull JTypeMirror t) {
2139
        return isSpecialUnresolvedOrArray(t) || hasUnresolvedSymbolOrArray(t);
1!
2140
    }
2141

2142
    /**
2143
     * Returns true if the type is {@link TypeSystem#UNKNOWN},
2144
     * or {@link TypeSystem#ERROR}.
2145
     *
2146
     * @param t Non-null type
2147
     *
2148
     * @throws NullPointerException if the parameter is null
2149
     */
2150
    public static boolean isSpecialUnresolved(@NonNull JTypeMirror t) {
2151
        TypeSystem ts = t.getTypeSystem();
1✔
2152
        return t == ts.UNKNOWN || t == ts.ERROR;
1✔
2153
    }
2154

2155
    /**
2156
     * Returns true if the type is {@link TypeSystem#UNKNOWN},
2157
     * or {@link TypeSystem#ERROR}, or an array of such types.
2158
     *
2159
     * @param t Non-null type
2160
     *
2161
     * @throws NullPointerException if the parameter is null
2162
     */
2163
    public static boolean isSpecialUnresolvedOrArray(@Nullable JTypeMirror t) {
2164
        return t == null
1!
2165
            || isSpecialUnresolved(t)
1✔
2166
            || t instanceof JArrayType && isSpecialUnresolved(((JArrayType) t).getElementType());
1✔
2167
    }
2168

2169
    /**
2170
     * Return true if the argument is a {@link JClassType} with
2171
     * {@linkplain JClassSymbol#isUnresolved() an unresolved symbol}.
2172
     */
2173
    public static boolean hasUnresolvedSymbol(@Nullable JTypeMirror t) {
2174
        return t instanceof JClassType && t.getSymbol().isUnresolved();
1✔
2175
    }
2176

2177
    /**
2178
     * Return true if the argument is a {@link JClassType} with
2179
     * {@linkplain JClassSymbol#isUnresolved() an unresolved symbol},
2180
     * or an array whose element type has an unresolved symbol.
2181
     */
2182
    public static boolean hasUnresolvedSymbolOrArray(@Nullable JTypeMirror t) {
2183
        if (!(t instanceof JClassType)) {
1✔
2184
            return t instanceof JArrayType && hasUnresolvedSymbol(((JArrayType) t).getElementType());
1✔
2185
        }
2186
        return hasUnresolvedSymbol(t);
1✔
2187
    }
2188

2189
    public static boolean isUnresolvedOrNull(@Nullable JTypeMirror t) {
2190
        return t == null || isUnresolved(t);
1!
2191
    }
2192

2193
    public static @Nullable JTypeMirror getArrayComponent(@Nullable JTypeMirror t) {
2194
        return t instanceof JArrayType ? ((JArrayType) t).getComponentType() : null;
1!
2195
    }
2196

2197

2198
    /**
2199
     * Return true if the method is context dependent. That
2200
     * means its return type is influenced by the surrounding
2201
     * context during type inference. Generic constructors
2202
     * are always context dependent.
2203
     *
2204
     * @deprecated Since 7.11.0. Use {@link #isContextDependent(JExecutableSymbol)} instead which is more flexible.
2205
     */
2206
    @Deprecated
2207
    public static boolean isContextDependent(JMethodSig sig) {
UNCOV
2208
        return isContextDependent(sig.getSymbol());
×
2209
    }
2210

2211
    /**
2212
     * Return true if the method is context dependent. That
2213
     * means its return type is influenced by the surrounding
2214
     * context during type inference. Generic constructors
2215
     * are always context dependent.
2216
     */
2217
    public static boolean isContextDependent(JExecutableSymbol symbol) {
2218
        if (symbol.isGeneric() || symbol.getEnclosingClass().isGeneric()) {
1!
2219
            if (symbol instanceof JMethodSymbol) {
1!
2220
                JTypeMirror returnType = ((JMethodSymbol) symbol).getReturnType(EMPTY);
1✔
2221
                return mentionsAny(returnType, symbol.getTypeParameters())
1!
2222
                    || mentionsAny(returnType, symbol.getEnclosingClass().getTypeParameters());
1✔
2223
            }
2224
            // generic ctors are context dependent
UNCOV
2225
            return true;
×
2226
        }
2227
        return false;
1✔
2228
    }
2229
    // </editor-fold>
2230
}
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