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

pmd / pmd / #3722

pending completion
#3722

push

github actions

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

67270 of 127658 relevant lines covered (52.7%)

0.53 hits per line

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

85.34
/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.annotation.InternalApi;
32
import net.sourceforge.pmd.internal.util.IteratorUtil;
33
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
34
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
35
import net.sourceforge.pmd.lang.java.symbols.JExecutableSymbol;
36
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
37
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
38
import net.sourceforge.pmd.lang.java.symbols.table.coreimpl.CoreResolvers;
39
import net.sourceforge.pmd.lang.java.symbols.table.coreimpl.NameResolver;
40
import net.sourceforge.pmd.lang.java.symbols.table.internal.JavaResolvers;
41
import net.sourceforge.pmd.lang.java.types.JVariableSig.FieldSig;
42
import net.sourceforge.pmd.lang.java.types.internal.infer.InferenceVar;
43
import net.sourceforge.pmd.lang.java.types.internal.infer.InferenceVar.BoundKind;
44
import net.sourceforge.pmd.lang.java.types.internal.infer.OverloadSet;
45
import net.sourceforge.pmd.util.CollectionUtil;
46

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

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

57

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

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

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

76

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

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

94
    /**
95
     * Return true if t and s are the same type. This may perform side effects
96
     * on inference variables. Annotations are ignored.
97
     */
98
    @InternalApi
99
    public static boolean isSameTypeInInference(JTypeMirror t, JTypeMirror s) {
100
        return isSameType(t, s, true, 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 inInference, 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 (!inInference) {
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, false, false);
×
140
    }
141

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

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

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

154
    private static boolean areSameTypes(List<JTypeMirror> ts, List<JTypeMirror> ss, Substitution subst, boolean inInference, 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), inInference, considerAnnotations)) {
1✔
160
                return false;
1✔
161
            }
162
        }
163
        return true;
1✔
164
    }
165

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

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

173
        private final boolean inInference;
174
        private final boolean considerAnnotations;
175

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

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

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

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

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

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

218
        @Override
219
        public Boolean visitInferenceVar(InferenceVar t, JTypeMirror s) {
220
            if (!inInference) {
1✔
221
                return t == s;
×
222
            }
223

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

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

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

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

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

251
            // order is irrelevant
252

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

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

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

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

285
    // </editor-fold>
286

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

289

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

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

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

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

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

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

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

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

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

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

349

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

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

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

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

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

385
            return null;
1✔
386
        }
387

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

395
    // </editor-fold>
396

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

399

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

404
    public static Convertibility isConvertibleNoCapture(@NonNull JTypeMirror t, @NonNull JTypeMirror s) {
405
        return isConvertible(t, s, false);
×
406
    }
407

408
    /**
409
     * Returns whether if {@code T <: S}, ie T is a subtype of S.
410
     *
411
     * <p>Note that {@link TypeSystem#ERROR} and {@link TypeSystem#UNKNOWN}
412
     * are considered subtypes of anything.
413
     *
414
     * @param t A type T
415
     * @param s A type S
416
     */
417
    public static Convertibility isConvertible(@NonNull JTypeMirror t, @NonNull JTypeMirror s, boolean capture) {
418
        // This is commented out as it makes JTypeMirror#isSubtypeOf partial,
419
        // which is not nice for the API... But this assert caught a bug and
420
        // should probably be enabled.
421
        // assert !(t instanceof JWildcardType || s instanceof JWildcardType) : "Wildcards do not support subtyping";
422

423
        if (t == s) {
1✔
424
            Objects.requireNonNull(t);
1✔
425
            return Convertibility.SUBTYPING;
1✔
426
        } else if (s.isTop()) {
1✔
427
            return Convertibility.subtypeIf(!t.isPrimitive());
1✔
428
        } else if (s.isVoid() || t.isVoid()) { // t != s
1✔
429
            return Convertibility.NEVER;
1✔
430
        } else if (s instanceof InferenceVar) {
1✔
431
            // it's possible to add a bound to UNKNOWN or ERROR
432
            ((InferenceVar) s).addBound(BoundKind.LOWER, t);
1✔
433
            return Convertibility.SUBTYPING;
1✔
434
        } else if (isTypeRange(s)) {
1✔
435
            // If s is a type range L..U,
436
            // then showing t <: s is the same thing as t <: L
437
            JTypeMirror lower = lowerBoundRec(s);
1✔
438
            if (!lower.isBottom()) {
1✔
439
                return isConvertible(t, lower, capture);
1✔
440
            }
441
            // otherwise fallthrough
442
        } else if (isSpecialUnresolved(t)) {
1✔
443
            // error type or unresolved type
444
            return Convertibility.SUBTYPING;
1✔
445
        } else if (hasUnresolvedSymbol(t) && t instanceof JClassType) {
1✔
446
            // This also considers types with an unresolved symbol
447
            // subtypes of (nearly) anything. This allows them to
448
            // pass bound checks on type variables.
449
            if (Objects.equals(t.getSymbol(), s.getSymbol())) {
1✔
450
                return typeArgsAreContained((JClassType) t, (JClassType) s);
1✔
451
            } else {
452
                return Convertibility.subtypeIf(s instanceof JClassType); // excludes array or so
1✔
453
            }
454
        } else if (s instanceof JIntersectionType) { // TODO test intersection with tvars & arrays
1✔
455
            // If S is an intersection, then T must conform to *all* bounds of S
456
            // Symmetrically, if T is an intersection, T <: S requires only that
457
            // at least one bound of T is a subtype of S.
458
            return Convertibility.subtypesAll(t, asList(s));
1✔
459
        }
460

461
        if (capture) {
1✔
462
            t = capture(t);
1✔
463
        }
464
        return t.acceptVisitor(SubtypeVisitor.INSTANCE, s);
1✔
465
    }
466

467
    // does not perform side effects on inference vars
468
    private static Convertibility isSubtypePure(JTypeMirror t, JTypeMirror s) {
469
        if (t instanceof InferenceVar) {
1✔
470
            return Convertibility.subtypeIf(((InferenceVar) t).isSubtypeNoSideEffect(s));
×
471
        } else if (s instanceof InferenceVar) {
1✔
472
            return Convertibility.subtypeIf(((InferenceVar) s).isSupertypeNoSideEffect(t));
×
473
        }
474

475
        return isConvertible(t, s);
1✔
476
    }
477

478
    public static boolean allArgsAreUnboundedWildcards(List<JTypeMirror> sargs) {
479
        for (JTypeMirror sarg : sargs) {
1✔
480
            if (!(sarg instanceof JWildcardType) || !((JWildcardType) sarg).isUnbounded()) {
1✔
481
                return false;
1✔
482
            }
483
        }
1✔
484
        return true;
1✔
485
    }
486

487
    /**
488
     * A result for a convertibility check. This is a tiny generalization of
489
     * a subtyping check.
490
     *
491
     * <p>Primitive types are implicitly convertible to each other by
492
     * widening primitive conversion. For reference types, subtyping
493
     * implies convertibility (the conversion is technically called
494
     * "widening reference conversion"). You can check those cases using:
495
     *
496
     * {@link #bySubtyping() t.isConvertibleTo(s).bySubtyping()}
497
     *
498
     * <p>Unchecked conversion may go backwards from subtyping. For example,
499
     * {@code List<String>} is a subtype of the raw type {@code List}, and
500
     * as such is convertible to it by reference widening. But {@code List}
501
     * may be "coerced" to {@code List<String>} with an unchecked warning:
502
     *
503
     * {@link #withUncheckedWarning() t.isConvertibleTo(s).withUncheckedWarning()}
504
     *
505
     * <p>If the parameterized type only has wildcard type arguments,
506
     * then the conversion produces no warning.
507
     *
508
     * {@link #UNCHECKED_NO_WARNING t.isConvertibleTo(s) == UNCHECKED_NO_WARNING}
509
     *
510
     * <p>Two types may be unconvertible:
511
     *
512
     * {@link #never() t.isConvertibleTo(s).never()}
513
     *
514
     * <p>the negation of which being
515
     *
516
     * {@link #somehow() t.isConvertibleTo(s).somehow()}
517
     *
518
     * <p>Note that this does not check for boxing or unboxing conversions,
519
     * nor for narrowing conversions, which may happen through casts.
520
     */
521
    public enum Convertibility {
1✔
522
        /** T is never implicitly convertible to S. */
523
        NEVER,
1✔
524

525
        /**
526
         * T is not a subtype of S, but every time T is used in a context
527
         * where an S is expected, unchecked conversion converts the T to
528
         * an S with a mandated warning. For example the raw type {@code Class}
529
         * is convertible to {@code Class<String>} with an unchecked warning.
530
         */
531
        UNCHECKED_WARNING,
1✔
532

533
        /**
534
         * {@code T <: |S|} and {@code T </: S}, but S is
535
         * parameterized with only unbounded wildcards. This is a special
536
         * case of unchecked conversion that produces no warning. We keep
537
         * it distinct from subtyping to help some algorithms that require
538
         * subtyping to be a partial order.
539
         *
540
         * <p>For example, {@code List<String>} is a subtype of the raw
541
         * {@code Collection}, not a subtype of {@code Collection<?>},
542
         * but it is still convertible without warning.
543
         */
544
        UNCHECKED_NO_WARNING,
1✔
545

546
        /**
547
         * T is a subtype of S ({@code T <: S}). In particular, any type
548
         * is a subtype of itself ({@code T <: T}).
549
         *
550
         * <p>For example, {@code int} can be widened to {@code long},
551
         * so we consider {@code int <: long}.
552
         */
553
        SUBTYPING;
1✔
554

555
        // public:
556

557
        /** Returns true if this is {@link #NEVER}. */
558
        public boolean never() {
559
            return this == NEVER;
1✔
560
        }
561

562
        /**
563
         * Returns true if this is anything but {@link #NEVER}.
564
         */
565
        public boolean somehow() {
566
            return this != NEVER;
1✔
567
        }
568

569
        /**
570
         * True if this is {@link #SUBTYPING}.
571
         */
572
        public boolean bySubtyping() {
573
            return this == SUBTYPING;
1✔
574
        }
575

576
        /**
577
         * True if this is {@link #UNCHECKED_WARNING}.
578
         */
579
        public boolean withUncheckedWarning() {
580
            return this == UNCHECKED_WARNING;
1✔
581
        }
582

583
        // package:
584

585

586
        /** Preserves an unchecked warning. */
587
        Convertibility and(Convertibility b) {
588
            return min(this, b);
1✔
589
        }
590

591
        static Convertibility min(Convertibility c1, Convertibility c2) {
592
            return c1.ordinal() < c2.ordinal() ? c1 : c2;
1✔
593
        }
594

595
        static Convertibility subtypeIf(boolean b) {
596
            return b ? SUBTYPING : NEVER;
1✔
597
        }
598

599
        static Convertibility subtypesAll(JTypeMirror t, Iterable<? extends JTypeMirror> supers) {
600
            Convertibility result = SUBTYPING;
1✔
601
            for (JTypeMirror ui : supers) {
1✔
602
                Convertibility sub = isConvertible(t, ui);
1✔
603
                if (sub == NEVER) {
1✔
604
                    return NEVER;
1✔
605
                }
606
                result = result.and(sub);
1✔
607
            }
1✔
608
            return result;
1✔
609
        }
610

611
        static Convertibility anySubTypesAny(Iterable<? extends JTypeMirror> us, Iterable<? extends JTypeMirror> vs) {
612
            for (JTypeMirror ui : us) {
1✔
613
                for (JTypeMirror vi : vs) {
1✔
614
                    Convertibility sub = isConvertible(ui, vi);
1✔
615
                    if (sub != NEVER) {
1✔
616
                        return sub.and(SUBTYPING); // never return identity here
1✔
617
                    }
618
                }
1✔
619
            }
1✔
620
            return NEVER;
1✔
621
        }
622
    }
623

624
    private static JTypeMirror wildUpperBound(JTypeMirror type) {
625
        if (type instanceof JWildcardType) {
1✔
626
            JWildcardType wild = (JWildcardType) type;
1✔
627
            if (wild.isUpperBound()) {
1✔
628
                return wildUpperBound(wild.asUpperBound());
1✔
629
            } else if (wild.asLowerBound() instanceof JTypeVar) {
×
630
                return ((JTypeVar) wild.asLowerBound()).getUpperBound();
×
631
            }
632
        } else if (type instanceof JTypeVar && ((JTypeVar) type).isCaptured()) {
1✔
633
            // note: tvar.getUpperBound() != tvar.getCapturedOrigin().asUpperBound()
634
            return wildUpperBound(((JTypeVar) type).getUpperBound());
1✔
635
        }
636
        return type;
1✔
637
    }
638

639
    private static JTypeMirror wildLowerBound(JTypeMirror type) {
640
        if (type instanceof JWildcardType) {
1✔
641
            return wildLowerBound(((JWildcardType) type).asLowerBound());
×
642
        }
643
        return type;
1✔
644
    }
645

646
    private static JTypeMirror lowerBoundRec(JTypeMirror type) {
647
        if (type instanceof JWildcardType) {
1✔
648
            return lowerBoundRec(((JWildcardType) type).asLowerBound());
×
649
        } else if (type instanceof JTypeVar && ((JTypeVar) type).isCaptured()) {
1✔
650
            return lowerBoundRec(((JTypeVar) type).getLowerBound());
1✔
651
        }
652
        return type;
1✔
653
    }
654

655
    private static boolean isTypeRange(JTypeMirror s) {
656
        return s instanceof JWildcardType || isCvar(s);
1✔
657
    }
658

659
    private static boolean isCvar(JTypeMirror s) {
660
        return s instanceof JTypeVar && ((JTypeVar) s).isCaptured();
1✔
661
    }
662

663

664
    /**
665
     * Returns true if {@code T <= S}, ie "S contains T".
666
     *
667
     * <p>S contains T if:
668
     *
669
     * <p>{@code L(S) <: L(T) && U(T) <: U(S)}
670
     *
671
     * <p>This only makes sense for type arguments, it's a component of
672
     * subtype checks for parameterized types:
673
     *
674
     * <p>{@code C<S> <: C<T> if S <= T}
675
     *
676
     * <p>Defined in JLS§4.5.1 (Type Arguments of Parameterized Types)
677
     */
678
    static Convertibility typeArgContains(JTypeMirror s, JTypeMirror t) {
679
        // the contains relation can be understood intuitively if we
680
        // represent types as ranges on a line:
681

682
        // ⊥ ---------L(S)---L(T)------U(T)-----U(S)---> Object
683
        // range of S   [-------------------------]
684
        // range of T          [---------]
685

686
        // here S contains T because its range is greater
687

688
        // since a wildcard is either "super" or "extends", in reality
689
        // either L(S) = ⊥, or U(S) = Object.
690

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

693
        //      ⊥ -------U(T)-----U(S)------> Object   (L(T) = L(S) = ⊥)
694
        //      ⊥ -------L(S)-----L(T)------> Object   (U(T) = U(S) = Object)
695

696
        if (isSameTypeInInference(s, t)) {
1✔
697
            // S <= S
698
            return Convertibility.SUBTYPING;
1✔
699
        }
700

701
        if (s instanceof JWildcardType) {
1✔
702
            JWildcardType sw = (JWildcardType) s;
1✔
703

704
            // capt(? extends T) <= ? extends T
705
            // capt(? super T) <= ? super T
706
            if (t instanceof JTypeVar && ((JTypeVar) t).isCaptureOf(sw)) {
1✔
707
                return Convertibility.SUBTYPING;
1✔
708
            }
709

710
            if (sw.isUpperBound()) {
1✔
711
                // Test U(T) <: U(S),  we already know L(S) <: L(T), because L(S) is bottom
712
                return isConvertible(wildUpperBound(t), sw.asUpperBound());
1✔
713
            } else {
714
                // Test L(S) <: L(T), we already know U(T) <: U(S), because U(S) is top
715
                return isConvertible(sw.asLowerBound(), wildLowerBound(t));
1✔
716
            }
717
        }
718

719
        return Convertibility.NEVER;
1✔
720
    }
721

722

723
    /**
724
     * Generalises containment to check if for each i, {@code Ti <= Si}.
725
     */
726
    static Convertibility typeArgsAreContained(JClassType t, JClassType s) {
727
        List<JTypeMirror> targs = t.getTypeArgs();
1✔
728
        List<JTypeMirror> sargs = s.getTypeArgs();
1✔
729

730
        if (targs.isEmpty()) {
1✔
731
            if (sargs.isEmpty()) {
1✔
732
                // Some "erased" non-generic types may appear as the supertypes
733
                // of raw types, and they're different from the regular flavor
734
                // as their own supertypes are erased, yet they're not considered
735
                // raw. To fix the subtyping relation, we say that `C <: (erased) C`
736
                // but `(erased) C` converts to `C` by unchecked conversion, without
737
                // warning.
738
                boolean tRaw = t.hasErasedSuperTypes();
1✔
739
                boolean sRaw = s.hasErasedSuperTypes();
1✔
740
                if (tRaw && !sRaw) {
1✔
741
                    return Convertibility.UNCHECKED_NO_WARNING;
1✔
742
                } else {
743
                    return Convertibility.SUBTYPING;
1✔
744
                }
745
            }
746
            // for some C, S = C<...> and T = C, ie T is raw
747
            // T is convertible to S, by unchecked conversion.
748
            // If S = D<?, .., ?>, then the conversion produces
749
            // no unchecked warning.
750
            return allArgsAreUnboundedWildcards(sargs) ? Convertibility.UNCHECKED_NO_WARNING
1✔
751
                                                       : Convertibility.UNCHECKED_WARNING;
1✔
752
        }
753

754
        if (targs.size() != sargs.size()) {
1✔
755
            // types are not well-formed
756
            return Convertibility.NEVER;
1✔
757
        }
758

759
        Convertibility result = Convertibility.SUBTYPING;
1✔
760
        for (int i = 0; i < targs.size(); i++) {
1✔
761
            Convertibility sub = typeArgContains(sargs.get(i), targs.get(i));
1✔
762
            if (sub == Convertibility.NEVER) {
1✔
763
                return Convertibility.NEVER;
1✔
764
            }
765
            result = result.and(sub);
1✔
766
        }
767

768
        return result;
1✔
769
    }
770

771
    private static final class SubtypeVisitor implements JTypeVisitor<Convertibility, JTypeMirror> {
772

773
        static final SubtypeVisitor INSTANCE = new SubtypeVisitor();
1✔
774

775
        @Override
776
        public Convertibility visit(JTypeMirror t, JTypeMirror s) {
777
            throw new IllegalStateException("Should not be called");
×
778
        }
779

780
        @Override
781
        public Convertibility visitTypeVar(JTypeVar t, JTypeMirror s) {
782
            if (s instanceof JTypeVar && t.getSymbol() != null && Objects.equals(t.getSymbol(), s.getSymbol())) {
1✔
783
                return Convertibility.SUBTYPING;
1✔
784
            }
785
            if (isTypeRange(s)) {
1✔
786
                return isConvertible(t, lowerBoundRec(s));
1✔
787
            }
788
            return isConvertible(t.getUpperBound(), s);
1✔
789
        }
790

791
        @Override
792
        public Convertibility visitNullType(JTypeMirror t, JTypeMirror s) {
793
            return Convertibility.subtypeIf(!s.isPrimitive());
1✔
794
        }
795

796
        @Override
797
        public Convertibility visitSentinel(JTypeMirror t, JTypeMirror s) {
798
            // we know t != s
799
            return t.isVoid() ? Convertibility.NEVER
×
800
                              : Convertibility.SUBTYPING;
×
801
        }
802

803
        @Override
804
        public Convertibility visitInferenceVar(InferenceVar t, JTypeMirror s) {
805
            if (s == t.getTypeSystem().NULL_TYPE || s instanceof JPrimitiveType) {
1✔
806
                return Convertibility.NEVER;
×
807
            }
808
            // here we add a constraint on the variable
809
            t.addBound(BoundKind.UPPER, s);
1✔
810
            return Convertibility.SUBTYPING;
1✔
811
        }
812

813
        @Override
814
        public Convertibility visitWildcard(JWildcardType t, JTypeMirror s) {
815
            // wildcards should be captured and so we should not end up here
816
            return Convertibility.NEVER;
×
817
        }
818

819
        @Override
820
        public Convertibility visitClass(JClassType t, JTypeMirror s) {
821
            if (!(s instanceof JClassType)) {
1✔
822
                // note, that this ignores wildcard types,
823
                // because they're only compared through
824
                // type argument containment.
825
                return Convertibility.NEVER;
1✔
826
            }
827

828
            JClassType cs = (JClassType) s;
1✔
829

830
            JClassType superDecl = t.getAsSuper(cs.getSymbol());
1✔
831

832
            if (superDecl == null) {
1✔
833
                return Convertibility.NEVER;
1✔
834
            } else if (cs.isRaw()) {
1✔
835
                // a raw type C is a supertype for all the family of parameterized type generated by C<F1, .., Fn>
836
                return Convertibility.SUBTYPING;
1✔
837
            } else {
838
                return typeArgsAreContained(superDecl, cs);
1✔
839
            }
840
        }
841

842
        @Override
843
        public Convertibility visitIntersection(JIntersectionType t, JTypeMirror s) {
844
            // A & B <: A
845
            // A & B <: B
846

847
            // But for a class C, `C <: A & B` if `C <: A` and `C <: B`
848

849
            // So we can't just say, "any component of t must subtype s",
850
            // because if s is itself an intersection we have a problem:
851
            // Eg let T = S = A & B
852
            // T <: S -> A & B <: S
853
            //        -> A <: S OR B <: S
854
            //        -> A <: A & B OR B <: A & B
855
            //        -> A <: A AND A <: B OR B <: A AND B <: B
856
            //        -> true   AND false  OR false  AND true
857
            //        -> false
858

859
            // what we mean is, if S is an intersection, then
860
            // "any component of T subtypes any component of S"
861

862
            return Convertibility.anySubTypesAny(t.getComponents(), asList(s));
1✔
863
        }
864

865
        @Override
866
        public Convertibility visitArray(JArrayType t, JTypeMirror s) {
867
            TypeSystem ts = t.getTypeSystem();
1✔
868
            if (s == ts.OBJECT || s.equals(ts.CLONEABLE) || s.equals(ts.SERIALIZABLE)) {
1✔
869
                return Convertibility.SUBTYPING;
1✔
870
            }
871

872
            if (!(s instanceof JArrayType)) {
1✔
873
                // not comparable to any other type
874
                return Convertibility.NEVER;
1✔
875
            }
876

877
            JArrayType cs = (JArrayType) s;
1✔
878

879
            if (t.getComponentType().isPrimitive() || cs.getComponentType().isPrimitive()) {
1✔
880
                // arrays of primitive types have no sub-/ supertype
881
                return Convertibility.subtypeIf(cs.getComponentType() == t.getComponentType());
1✔
882
            } else {
883
                return isConvertible(t.getComponentType(), cs.getComponentType());
1✔
884
            }
885
        }
886

887
        @Override
888
        public Convertibility visitPrimitive(JPrimitiveType t, JTypeMirror s) {
889
            if (s instanceof JPrimitiveType) {
1✔
890
                return t.superTypes.contains(s) ? Convertibility.SUBTYPING
1✔
891
                                                : Convertibility.NEVER;
1✔
892
            }
893
            return Convertibility.NEVER;
1✔
894
        }
895
    }
896

897
    public static boolean isStrictSubtype(@NonNull JTypeMirror t, @NonNull JTypeMirror s) {
898
        return !t.equals(s) && t.isSubtypeOf(s);
1✔
899
    }
900

901
    // </editor-fold>
902

903
    // <editor-fold  defaultstate="collapsed" desc="Substitution">
904

905
    /**
906
     * Replace the type variables occurring in the given type to their
907
     * image by the given function. Substitutions are not applied
908
     * recursively.
909
     *
910
     * @param type  Type to substitute
911
     * @param subst Substitution function, eg a {@link Substitution}
912
     */
913
    public static JTypeMirror subst(@Nullable JTypeMirror type, Function<? super SubstVar, ? extends @NonNull JTypeMirror> subst) {
914
        if (type == null || Substitution.isEmptySubst(subst)) {
1✔
915
            return type;
1✔
916
        }
917
        return type.subst(subst);
1✔
918
    }
919

920

921
    /** Substitute on a list of types. */
922
    public static List<JTypeMirror> subst(List<? extends JTypeMirror> ts, Function<? super SubstVar, ? extends @NonNull JTypeMirror> subst) {
923
        if (Substitution.isEmptySubst(subst)) {
1✔
924
            return CollectionUtil.makeUnmodifiableAndNonNull(ts);
1✔
925
        }
926
        return mapPreservingSelf(ts, t -> t.subst(subst));
1✔
927
    }
928

929
    public static List<JClassType> substClasses(List<JClassType> ts, Function<? super SubstVar, ? extends @NonNull JTypeMirror> subst) {
930
        if (Substitution.isEmptySubst(subst)) {
1✔
931
            return ts;
1✔
932
        }
933
        return mapPreservingSelf(ts, t -> t.subst(subst));
1✔
934
    }
935

936
    public static List<JTypeVar> substInBoundsOnly(List<JTypeVar> ts, Function<? super SubstVar, ? extends @NonNull JTypeMirror> subst) {
937
        if (Substitution.isEmptySubst(subst)) {
1✔
938
            return ts;
1✔
939
        }
940
        return mapPreservingSelf(ts, t -> t.substInBounds(subst));
1✔
941
    }
942

943
    // relies on the fact the original list is unmodifiable or won't be
944
    // modified
945
    @SuppressWarnings("unchecked")
946
    private static @NonNull <T> List<T> mapPreservingSelf(List<? extends T> ts, Function<? super T, ? extends @NonNull T> subst) {
947
        // Profiling shows, only 10% of calls to this method need to
948
        // create a new list. Substitution in general is a hot spot
949
        // of the framework, so optimizing this out is nice
950
        List<T> list = null;
1✔
951
        for (int i = 0, size = ts.size(); i < size; i++) {
1✔
952
            T it = ts.get(i);
1✔
953
            T substed = subst.apply(it);
1✔
954
            if (substed != it) {
1✔
955
                if (list == null) {
1✔
956
                    list = Arrays.asList((T[]) ts.toArray()); // NOPMD ClassCastExceptionWithToArray
1✔
957
                }
958
                list.set(i, substed);
1✔
959
            }
960
        }
961

962
        // subst relies on the fact that the original list is returned
963
        // to avoid new type creation. Thus one cannot use
964
        // Collections::unmodifiableList here
965
        return list != null ? list : (List<T>) ts;
1✔
966
    }
967

968
    // </editor-fold>
969

970
    // <editor-fold  defaultstate="collapsed" desc="Projection">
971

972

973
    /**
974
     * Returns the upwards projection of the given type, with respect
975
     * to the set of capture variables that are found in it. This is
976
     * some supertype of T which does not mention those capture variables.
977
     * This is used for local variable type inference.
978
     *
979
     * https://docs.oracle.com/javase/specs/jls/se11/html/jls-4.html#jls-4.10.5
980
     */
981
    public static JTypeMirror projectUpwards(JTypeMirror t) {
982
        return t.acceptVisitor(UPWARDS_PROJECTOR, new RecursionStop());
1✔
983
    }
984

985
    private static final JTypeMirror NO_DOWN_PROJECTION = null;
1✔
986
    private static final ProjectionVisitor UPWARDS_PROJECTOR = new ProjectionVisitor(true) {
1✔
987

988
        @Override
989
        public JTypeMirror visitTypeVar(JTypeVar t, RecursionStop recursionStop) {
990
            if (t.isCaptured()) {
1✔
991
                return t.getUpperBound().acceptVisitor(UPWARDS_PROJECTOR, recursionStop);
1✔
992
            }
993
            return t;
1✔
994
        }
995

996

997
        @Override
998
        public JTypeMirror visitWildcard(JWildcardType t, RecursionStop recursionStop) {
999
            JTypeMirror u = t.getBound().acceptVisitor(UPWARDS_PROJECTOR, recursionStop);
×
1000
            TypeSystem ts = t.getTypeSystem();
×
1001
            if (u == t.getBound()) {
×
1002
                return t;
×
1003
            }
1004

1005
            if (t.isUpperBound()) {
×
1006
                return ts.wildcard(true, u);
×
1007
            } else {
1008
                JTypeMirror down = t.getBound().acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
×
1009
                return down == NO_DOWN_PROJECTION ? ts.UNBOUNDED_WILD : ts.wildcard(false, down);
×
1010
            }
1011
        }
1012

1013

1014
        @Override
1015
        public JTypeMirror visitNullType(JTypeMirror t, RecursionStop recursionStop) {
1016
            return t;
×
1017
        }
1018

1019
    };
1020

1021

1022
    private static final ProjectionVisitor DOWNWARDS_PROJECTOR = new ProjectionVisitor(false) {
1✔
1023

1024
        @Override
1025
        public JTypeMirror visitWildcard(JWildcardType t, RecursionStop recursionStop) {
1026
            JTypeMirror u = t.getBound().acceptVisitor(UPWARDS_PROJECTOR, recursionStop);
×
1027
            if (u == t.getBound()) {
×
1028
                return t;
×
1029
            }
1030
            TypeSystem ts = t.getTypeSystem();
×
1031

1032
            if (t.isUpperBound()) {
×
1033
                JTypeMirror down = t.getBound().acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
×
1034
                return down == NO_DOWN_PROJECTION ? NO_DOWN_PROJECTION
×
1035
                                                  : ts.wildcard(true, down);
×
1036
            } else {
1037
                return ts.wildcard(false, u);
×
1038
            }
1039
        }
1040

1041

1042
        @Override
1043
        public JTypeMirror visitTypeVar(JTypeVar t, RecursionStop recursionStop) {
1044
            if (t.isCaptured()) {
1✔
1045
                return t.getLowerBound().acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
1✔
1046
            }
1047
            return t;
×
1048
        }
1049

1050
        @Override
1051
        public JTypeMirror visitNullType(JTypeMirror t, RecursionStop recursionStop) {
1052
            return NO_DOWN_PROJECTION;
1✔
1053
        }
1054
    };
1055

1056
    static final class RecursionStop {
1✔
1057

1058
        private Set<JTypeVar> set;
1059

1060
        boolean isAbsent(JTypeVar tvar) {
1061
            if (set == null) {
1✔
1062
                set = new LinkedHashSet<>(1);
1✔
1063
            }
1064
            return set.add(tvar);
1✔
1065
        }
1066

1067
        <T extends JTypeMirror> JTypeMirror recurseIfNotDone(T t, BiFunction<T, RecursionStop, JTypeMirror> body) {
1068
            if (t instanceof JTypeVar) {
1✔
1069
                JTypeVar var = (JTypeVar) t;
1✔
1070
                try {
1071
                    if (isAbsent(var)) {
1✔
1072
                        return body.apply(t, this);
1✔
1073
                    } else {
1074
                        return t;
1✔
1075
                    }
1076
                } finally {
1077
                    set.remove(var);
1✔
1078
                }
1079
            } else {
1080
                return body.apply(t, this);
1✔
1081
            }
1082
        }
1083
    }
1084

1085
    /**
1086
     * Restricted type variables are:
1087
     * - Inference vars
1088
     * - Capture vars
1089
     *
1090
     * See
1091
     *
1092
     * https://docs.oracle.com/javase/specs/jls/se11/html/jls-4.html#jls-4.10.5
1093
     *
1094
     *
1095
     * <p>Here we use {@link #NO_DOWN_PROJECTION} as a sentinel
1096
     * (downwards projection is a partial function). If a type does not mention
1097
     * restricted type variables, then the visitor should return the original
1098
     * type (same reference). This allows testing predicates like
1099
     * <blockquote>
1100
     * "If Ai does not mention any restricted type variable, then Ai' = Ai."
1101
     * </blockquote>
1102
     */
1103
    private abstract static class ProjectionVisitor implements JTypeVisitor<JTypeMirror, RecursionStop> {
1104

1105
        private final boolean upwards;
1106

1107
        private ProjectionVisitor(boolean upwards) {
1✔
1108
            this.upwards = upwards;
1✔
1109
        }
1✔
1110

1111

1112
        @Override
1113
        public abstract JTypeMirror visitNullType(JTypeMirror t, RecursionStop recursionStop);
1114

1115

1116
        @Override
1117
        public abstract JTypeMirror visitWildcard(JWildcardType t, RecursionStop recursionStop);
1118

1119

1120
        @Override
1121
        public abstract JTypeMirror visitTypeVar(JTypeVar t, RecursionStop recursionStop);
1122

1123

1124
        @Override
1125
        public JTypeMirror visit(JTypeMirror t, RecursionStop recursionStop) {
1126
            return t;
1✔
1127
        }
1128

1129
        @Override
1130
        public JTypeMirror visitClass(JClassType t, RecursionStop recursionStop) {
1131
            if (t.isParameterizedType()) {
1✔
1132
                TypeSystem ts = t.getTypeSystem();
1✔
1133

1134
                List<JTypeMirror> targs = t.getTypeArgs();
1✔
1135
                List<JTypeMirror> newTargs = new ArrayList<>(targs.size());
1✔
1136
                List<JTypeVar> formals = t.getFormalTypeParams();
1✔
1137
                boolean change = false;
1✔
1138

1139
                for (int i = 0; i < targs.size(); i++) {
1✔
1140
                    JTypeMirror ai = targs.get(i);
1✔
1141
                    JTypeMirror u = recursionStop.recurseIfNotDone(ai, (s, stop) -> s.acceptVisitor(this, stop));
1✔
1142
                    if (u == ai) {
1✔
1143
                        if (isCvar(ai)) { // cvar hit recursion stop
1✔
1144
                            u = ts.UNBOUNDED_WILD;
1✔
1145
                            change = true;
1✔
1146
                        }
1147
                        // no change, or handled by the visitWildcard
1148
                        newTargs.add(u);
1✔
1149
                        continue;
1✔
1150
                    } else if (!upwards) {
1✔
1151
                        // If Ai is a type that mentions a restricted type variable, then Ai' is undefined.
1152
                        return NO_DOWN_PROJECTION;
×
1153
                    }
1154

1155
                    change = true;
1✔
1156

1157
                    /*
1158
                        If Ai is a type that mentions a restricted type variable...
1159
                     */
1160
                    JTypeMirror bi = formals.get(i).getUpperBound();
1✔
1161

1162
                    if (u != ts.OBJECT && (mentionsAny(bi, formals) || !bi.isSubtypeOf(u))) {
1✔
1163
                        newTargs.add(ts.wildcard(true, u));
1✔
1164
                    } else {
1165
                        JTypeMirror down = ai.acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
1✔
1166
                        if (down == NO_DOWN_PROJECTION) {
1✔
1167
                            newTargs.add(ts.UNBOUNDED_WILD);
1✔
1168
                        } else {
1169
                            newTargs.add(ts.wildcard(false, down));
×
1170
                        }
1171
                    }
1172
                }
1173

1174
                return change ? t.withTypeArguments(newTargs) : t;
1✔
1175
            } else {
1176
                return t;
1✔
1177
            }
1178
        }
1179

1180
        @Override
1181
        public JTypeMirror visitIntersection(JIntersectionType t, RecursionStop recursionStop) {
1182
            List<JTypeMirror> comps = new ArrayList<>(t.getComponents());
×
1183
            boolean change = false;
×
1184
            for (int i = 0; i < comps.size(); i++) {
×
1185
                JTypeMirror ci = comps.get(i);
×
1186
                JTypeMirror proj = ci.acceptVisitor(this, recursionStop);
×
1187
                if (proj == NO_DOWN_PROJECTION) {
×
1188
                    return NO_DOWN_PROJECTION;
×
1189
                } else {
1190
                    comps.set(i, proj);
×
1191
                    if (ci != proj) {
×
1192
                        change = true;
×
1193
                    }
1194
                }
1195
            }
1196
            return change ? t.getTypeSystem().glb(comps) : t;
×
1197
        }
1198

1199
        @Override
1200
        public JTypeMirror visitArray(JArrayType t, RecursionStop recursionStop) {
1201
            JTypeMirror comp2 = t.getComponentType().acceptVisitor(this, recursionStop);
1✔
1202
            return comp2 == NO_DOWN_PROJECTION
1✔
1203
                   ? NO_DOWN_PROJECTION
×
1204
                   : comp2 == t.getComponentType()
1✔
1205
                     ? t : t.getTypeSystem().arrayType(comp2);
1✔
1206
        }
1207

1208
        @Override
1209
        public JTypeMirror visitSentinel(JTypeMirror t, RecursionStop recursionStop) {
1210
            return t;
1✔
1211
        }
1212
    }
1213

1214
    // </editor-fold>
1215

1216
    // <editor-fold  defaultstate="collapsed" desc="Overriding">
1217

1218
    /**
1219
     * Returns true if m1 is return-type substitutable with m2. The notion of return-type-substitutability
1220
     * supports covariant returns, that is, the specialization of the return type to a subtype.
1221
     *
1222
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.5
1223
     */
1224
    public static boolean isReturnTypeSubstitutable(JMethodSig m1, JMethodSig m2) {
1225

1226
        JTypeMirror r1 = m1.getReturnType();
1✔
1227
        JTypeMirror r2 = m2.getReturnType();
1✔
1228

1229
        if (r1 == r1.getTypeSystem().NO_TYPE) {
1✔
1230
            return r1 == r2;
1✔
1231
        }
1232

1233
        if (r1.isPrimitive()) {
1✔
1234
            return r1 == r2;
1✔
1235
        }
1236

1237
        JMethodSig m1Prime = adaptForTypeParameters(m1, m2);
1✔
1238
        return m1Prime != null && isConvertible(m1Prime.getReturnType(), r2) != Convertibility.NEVER
1✔
1239
                || !haveSameSignature(m1, m2) && isSameType(r1, r2.getErasure());
1✔
1240
    }
1241

1242
    /**
1243
     * Adapt m1 to the type parameters of m2. Returns null if that's not possible.
1244
     *
1245
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.4
1246
     *
1247
     * <p>Note that the type parameters of m1 are not replaced, only
1248
     * their occurrences in the rest of the signature.
1249
     */
1250
    static @Nullable JMethodSig adaptForTypeParameters(JMethodSig m1, JMethodSig m2) {
1251
        if (haveSameTypeParams(m1, m2)) {
1✔
1252
            return m1.subst(mapping(m1.getTypeParameters(), m2.getTypeParameters()));
1✔
1253
        }
1254

1255
        return null;
×
1256
    }
1257

1258
    public static boolean haveSameTypeParams(JMethodSig m1, JMethodSig m2) {
1259
        List<JTypeVar> tp1 = m1.getTypeParameters();
1✔
1260
        List<JTypeVar> tp2 = m2.getTypeParameters();
1✔
1261
        if (tp1.size() != tp2.size()) {
1✔
1262
            return false;
×
1263
        }
1264

1265
        if (tp1.isEmpty()) {
1✔
1266
            return true;
1✔
1267
        }
1268

1269
        Substitution mapping = mapping(tp2, tp1);
1✔
1270
        for (int i = 0; i < tp1.size(); i++) {
1✔
1271
            JTypeVar p1 = tp1.get(i);
1✔
1272
            JTypeVar p2 = tp2.get(i);
1✔
1273

1274
            if (!isSameType(p1.getUpperBound(), subst(p2.getUpperBound(), mapping))) {
1✔
1275
                return false;
1✔
1276
            }
1277
        }
1278

1279
        return true;
1✔
1280
    }
1281

1282
    /**
1283
     * Two method signatures m1 and m2 are override-equivalent iff either
1284
     * m1 is a subsignature of m2 or m2 is a subsignature of m1. This does
1285
     * not look at the origin of the methods (their declaring class).
1286
     *
1287
     * <p>This is a prerequisite for one method to override the other,
1288
     * but not the only condition. See {@link #overrides(JMethodSig, JMethodSig, JTypeMirror)}.
1289
     *
1290
     * See <a href="https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.2">JLS§8</a>
1291
     */
1292
    public static boolean areOverrideEquivalent(JMethodSig m1, JMethodSig m2) {
1293
        // This method is a very hot spot as it is used to prune shadowed/overridden/hidden
1294
        // methods from overload candidates before overload resolution.
1295
        // Any optimization makes a big impact.
1296
        if (m1.getArity() != m2.getArity()) {
1✔
1297
            return false; // easy case
1✔
1298
        } else if (m1 == m2) {
1✔
1299
            return true;
×
1300
        } else if (!m1.getName().equals(m2.getName())) {
1✔
1301
            // note: most call sites statically know this is true
1302
            // profile to figure out whether this matters
1303
            return false;
×
1304
        }
1305

1306
        List<JTypeMirror> formals1 = m1.getFormalParameters();
1✔
1307
        List<JTypeMirror> formals2 = m2.getFormalParameters();
1✔
1308
        for (int i = 0; i < formals1.size(); i++) {
1✔
1309
            JTypeMirror fi1 = formals1.get(i);
1✔
1310
            JTypeMirror fi2 = formals2.get(i);
1✔
1311

1312
            if (!isSameType(fi1.getErasure(), fi2.getErasure())) {
1✔
1313
                return false;
1✔
1314
            }
1315
        }
1316

1317
        // a non-generic method may override a generic one
1318
        return !m1.isGeneric() || !m2.isGeneric()
1✔
1319
            // if both are generic, they must have the same type params
1320
            || haveSameTypeParams(m1, m2);
1✔
1321
    }
1322

1323
    /**
1324
     * The signature of a method m1 is a subsignature of the signature of a method m2 if either:
1325
     * - m2 has the same signature as m1, or
1326
     * - the signature of m1 is the same as the erasure (§4.6) of the signature of m2.
1327
     */
1328
    public static boolean isSubSignature(JMethodSig m1, JMethodSig m2) {
1329
        // prune easy cases
1330
        if (m1.getArity() != m2.getArity() || !m1.getName().equals(m2.getName())) {
1✔
1331
            return false;
1✔
1332
        }
1333
        boolean m1Gen = m1.isGeneric();
1✔
1334
        boolean m2Gen = m2.isGeneric();
1✔
1335
        if (m1Gen ^ m2Gen) {
1✔
1336
            if (m1Gen) {
×
1337
                return false; // this test is assymetric
×
1338
            } else {
1339
                m2 = m2.getErasure();
×
1340
            }
1341
        }
1342
        return haveSameSignature(m1, m2);
1✔
1343
    }
1344

1345
    /**
1346
     * Two methods or constructors, M and N, have the same signature if
1347
     * they have the same name, the same type parameters (if any) (§8.4.4),
1348
     * and, after adapting the formal parameter types of N to the the type
1349
     * parameters of M, the same formal parameter types.
1350
     *
1351
     * Thrown exceptions are not part of the signature of a method.
1352
     */
1353
    private static boolean haveSameSignature(JMethodSig m1, JMethodSig m2) {
1354
        return m1.getName().equals(m2.getName())
1✔
1355
                && m1.getArity() == m2.getArity()
1✔
1356
                && haveSameTypeParams(m1, m2)
1✔
1357
                && areSameTypes(m1.getFormalParameters(),
1✔
1358
                            m2.getFormalParameters(),
1✔
1359
                            Substitution.mapping(m2.getTypeParameters(), m1.getTypeParameters()));
1✔
1360
    }
1361

1362
    /**
1363
     * Returns true if m1 overrides m2, when both are view as members of
1364
     * class origin. m1 and m2 may be declared in supertypes of origin,
1365
     * possibly unrelated (default methods), which is why we need that
1366
     * third parameter. By convention a method overrides itself.
1367
     *
1368
     * <p>This method ignores the static modifier. If both methods are
1369
     * static, then this method tests for <i>hiding</i>. Otherwise, this
1370
     * method properly tests for overriding. Note that it is an error for
1371
     * a static method to override an instance method, or the reverse.
1372
     */
1373
    public static boolean overrides(JMethodSig m1, JMethodSig m2, JTypeMirror origin) {
1374

1375
        if (m1.isConstructor() || m2.isConstructor()) {
1✔
1376
            return m1.equals(m2); // "by convention a method overrides itself"
×
1377
        }
1378

1379
        JTypeMirror m1Owner = m1.getDeclaringType();
1✔
1380
        JClassType m2Owner = (JClassType) m2.getDeclaringType();
1✔
1381

1382
        if (isOverridableIn(m2, m1Owner.getSymbol())) {
1✔
1383
            JClassType m2AsM1Supertype = (JClassType) m1Owner.getAsSuper(m2Owner.getSymbol());
1✔
1384
            if (m2AsM1Supertype != null) {
1✔
1385
                JMethodSig m2Prime = m2AsM1Supertype.getDeclaredMethod(m2.getSymbol());
1✔
1386
                assert m2Prime != null;
1✔
1387
                if (isSubSignature(m1, m2Prime)) {
1✔
1388
                    return true;
1✔
1389
                }
1390
            }
1391
        }
1392

1393
        // todo that is very weird
1394
        if (m1.isAbstract()
1✔
1395
            || !m2.isAbstract() && !m2.getSymbol().isDefaultMethod()
1✔
1396
            || !isOverridableIn(m2, origin.getSymbol())
1✔
1397
            || !(m1Owner instanceof JClassType)) {
1398
            return false;
1✔
1399
        }
1400

1401
        JTypeMirror m1AsSuper = origin.getAsSuper(((JClassType) m1Owner).getSymbol());
1✔
1402
        JTypeMirror m2AsSuper = origin.getAsSuper(m2Owner.getSymbol());
1✔
1403
        if (m1AsSuper instanceof JClassType && m2AsSuper instanceof JClassType) {
1✔
1404
            m1 = ((JClassType) m1AsSuper).getDeclaredMethod(m1.getSymbol());
1✔
1405
            m2 = ((JClassType) m2AsSuper).getDeclaredMethod(m2.getSymbol());
1✔
1406
            assert m1 != null && m2 != null;
1✔
1407
            return isSubSignature(m1, m2);
1✔
1408
        }
1409
        return false;
1✔
1410
    }
1411

1412
    private static boolean isOverridableIn(JMethodSig m, JTypeDeclSymbol origin) {
1413
        return isOverridableIn(m.getSymbol(), origin);
1✔
1414
    }
1415

1416
    /**
1417
     * Returns true if the given method can be overridden in the origin
1418
     * class. This only checks access modifiers and not eg whether the
1419
     * method is final or static. Regardless of whether the method is
1420
     * final it is overridden - whether this is a compile error or not
1421
     * is another matter.
1422
     *
1423
     * <p>Like {@link #overrides(JMethodSig, JMethodSig, JTypeMirror)},
1424
     * this does not check the static modifier, and tests for hiding
1425
     * if the method is static.
1426
     *
1427
     * @param m      Method to test
1428
     * @param origin Site of the potential override
1429
     */
1430
    public static boolean isOverridableIn(JExecutableSymbol m, JTypeDeclSymbol origin) {
1431
        if (m instanceof JConstructorSymbol) {
1✔
1432
            return false;
×
1433
        }
1434

1435
        final int accessFlags = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
1✔
1436

1437
        // JLS 8.4.6.1
1438
        switch (m.getModifiers() & accessFlags) {
1✔
1439
        case Modifier.PUBLIC:
1440
            return true;
1✔
1441
        case Modifier.PROTECTED:
1442
            return !origin.isInterface();
1✔
1443
        case 0:
1444
            // package private
1445
            return
1✔
1446
                m.getPackageName().equals(origin.getPackageName())
1✔
1447
                    && !origin.isInterface();
1✔
1448
        default:
1449
            // private
1450
            return false;
1✔
1451
        }
1452
    }
1453

1454
    // </editor-fold>
1455

1456
    // <editor-fold  defaultstate="collapsed" desc="SAM types">
1457

1458
    /*
1459
     * Function types of SAM (single-abstract-method) types.
1460
     *
1461
     * See https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-9.9
1462
     */
1463

1464

1465
    /**
1466
     * Returns the non-wildcard parameterization of the given functional
1467
     * interface type. Returns null if such a parameterization does not
1468
     * exist.
1469
     *
1470
     * <p>This is used to remove wildcards from the type of a functional
1471
     * interface.
1472
     *
1473
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-9.html#jls-9.9
1474
     *
1475
     * @param type A parameterized functional interface type
1476
     */
1477
    public static @Nullable JClassType nonWildcardParameterization(@NonNull JClassType type) {
1478
        TypeSystem ts = type.getTypeSystem();
1✔
1479

1480
        List<JTypeMirror> targs = type.getTypeArgs();
1✔
1481
        if (targs.stream().noneMatch(it -> it instanceof JWildcardType)) {
1✔
1482
            return type;
1✔
1483
        }
1484

1485
        List<JTypeVar> tparams = type.getFormalTypeParams();
1✔
1486
        List<JTypeMirror> newArgs = new ArrayList<>();
1✔
1487

1488
        for (int i = 0; i < tparams.size(); i++) {
1✔
1489
            JTypeMirror ai = targs.get(i);
1✔
1490
            if (ai instanceof JWildcardType) {
1✔
1491
                JTypeVar pi = tparams.get(i);
1✔
1492
                JTypeMirror bi = pi.getUpperBound();
1✔
1493
                if (mentionsAny(bi, new HashSet<>(tparams))) {
1✔
1494
                    return null;
×
1495
                }
1496

1497
                JWildcardType ai2 = (JWildcardType) ai;
1✔
1498

1499
                if (ai2.isUnbounded()) {
1✔
1500
                    newArgs.add(bi);
1✔
1501
                } else if (ai2.isUpperBound()) {
1✔
1502
                    newArgs.add(ts.glb(Arrays.asList(ai2.asUpperBound(), bi)));
1✔
1503
                } else { // lower bound
1504
                    newArgs.add(ai2.asLowerBound());
1✔
1505
                }
1506

1507
            } else {
1✔
1508
                newArgs.add(ai);
1✔
1509
            }
1510

1511
        }
1512

1513
        return type.withTypeArguments(newArgs);
1✔
1514
    }
1515

1516
    /**
1517
     * Finds the method of the given type that can be overridden as a lambda
1518
     * expression. That is more complicated than "the unique abstract method",
1519
     * it's actually a function type which can override all abstract methods
1520
     * of the SAM at once.
1521
     *
1522
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-9.html#jls-9.9
1523
     *
1524
     * <p>If the parameter is not mappable to a class type with {@link #asClassType(JTypeMirror)},
1525
     * or if the functional method does not exist, returns null.
1526
     */
1527
    public static @Nullable JMethodSig findFunctionalInterfaceMethod(@Nullable JTypeMirror type) {
1528
        JClassType candidateSam = asClassType(type);
1✔
1529
        if (candidateSam == null) {
1✔
1530
            return null;
1✔
1531
        }
1532

1533
        if (candidateSam.isParameterizedType()) {
1✔
1534
            return findFunctionTypeImpl(nonWildcardParameterization(candidateSam));
1✔
1535
        } else if (candidateSam.isRaw()) {
1✔
1536
            //  The function type of the raw type of a generic functional
1537
            //  interface I<...> is the erasure of the function type of the generic functional interface I<...>.
1538
            JMethodSig fun = findFunctionTypeImpl(candidateSam.getGenericTypeDeclaration());
1✔
1539
            return fun == null ? null : fun.getErasure();
1✔
1540
        } else {
1541
            return findFunctionTypeImpl(candidateSam);
1✔
1542
        }
1543
    }
1544

1545
    /**
1546
     * Returns t if it is a class or interface type. If it is an intersection type,
1547
     * returns the induced class or interface type. Returns null otherwise, including
1548
     * if the parameter is null.
1549
     */
1550
    public static @Nullable JClassType asClassType(@Nullable JTypeMirror t) {
1551
        if (t instanceof JClassType) {
1✔
1552
            return (JClassType) t;
1✔
1553
        } else if (t instanceof JIntersectionType) {
1✔
1554
            return ((JIntersectionType) t).getInducedClassType();
1✔
1555
        }
1556
        return null;
1✔
1557
    }
1558

1559
    private static @Nullable JMethodSig findFunctionTypeImpl(@Nullable JClassType candidateSam) {
1560

1561
        if (candidateSam == null || !candidateSam.isInterface() || candidateSam.getSymbol().isAnnotation()) {
1✔
1562
            return null;
1✔
1563
        }
1564

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

1569

1570
        List<JMethodSig> candidates = new ArrayList<>();
1✔
1571
        for (Entry<String, List<JMethodSig>> entry : relevantMethods.entrySet()) {
1✔
1572
            for (JMethodSig sig : entry.getValue()) {
1✔
1573
                if (sig.isAbstract()) {
1✔
1574
                    candidates.add(sig);
1✔
1575
                }
1576
            }
1✔
1577
        }
1✔
1578

1579
        if (candidates.isEmpty()) {
1✔
1580
            return null;
×
1581
        } else if (candidates.size() == 1) {
1✔
1582
            return candidates.get(0);
1✔
1583
        }
1584

1585
        JMethodSig currentBest = null;
1✔
1586

1587
        nextCandidate:
1588
        for (int i = 0; i < candidates.size(); i++) {
1✔
1589
            JMethodSig cand = candidates.get(i);
1✔
1590

1591
            for (JMethodSig other : candidates) {
1✔
1592
                if (!isSubSignature(cand, other)
1✔
1593
                    || !isReturnTypeSubstitutable(cand, other)) {
1✔
1594
                    continue nextCandidate;
×
1595
                }
1596
            }
1✔
1597

1598
            if (currentBest == null) {
×
1599
                currentBest = cand;
×
1600
            } else if (cand.getReturnType().isSubtypeOf(currentBest.getReturnType())) {
×
1601
                // select the most specific return type
1602
                currentBest = cand;
×
1603
            }
1604
        }
1605

1606
        return currentBest;
1✔
1607
    }
1608

1609
    private static boolean isNotDeclaredInClassObject(JMethodSig it) {
1610
        TypeSystem ts = it.getDeclaringType().getTypeSystem();
1✔
1611
        return ts.OBJECT.streamDeclaredMethods(om -> Modifier.isPublic(om.getModifiers())
1✔
1612
            && om.nameEquals(it.getName()))
1✔
1613
                        .noneMatch(om -> haveSameSignature(it, om));
1✔
1614
    }
1615

1616
    // </editor-fold>
1617

1618
    // <editor-fold  defaultstate="collapsed" desc="As super">
1619

1620
    /**
1621
     * @see JTypeMirror#getAsSuper(JClassSymbol)
1622
     */
1623
    public static @Nullable JTypeMirror asSuper(@NonNull JTypeMirror t, @NonNull JClassSymbol s) {
1624

1625
        if (!t.isPrimitive() && s.equals(t.getTypeSystem().OBJECT.getSymbol())) {
1✔
1626
            // interface types need to have OBJECT somewhere up their hierarchy
1627
            return t.getTypeSystem().OBJECT;
1✔
1628
        }
1629

1630
        return t.acceptVisitor(AsSuperVisitor.INSTANCE, s);
1✔
1631
    }
1632

1633
    /**
1634
     * Return the base type of t or any of its outer types that starts
1635
     * with the given type.  If none exists, return null.
1636
     */
1637
    public static JClassType asOuterSuper(JTypeMirror t, JClassSymbol sym) {
1638
        if (t instanceof JClassType) {
×
1639
            JClassType ct = (JClassType) t;
×
1640
            do {
1641
                JClassType sup = ct.getAsSuper(sym);
×
1642
                if (sup != null) {
×
1643
                    return sup;
×
1644
                }
1645
                ct = ct.getEnclosingType();
×
1646
            } while (ct != null);
×
1647
        } else if (t instanceof JTypeVar || t instanceof JArrayType) {
×
1648
            return (JClassType) t.getAsSuper(sym);
×
1649
        }
1650
        return null;
×
1651
    }
1652

1653
    private static final class AsSuperVisitor implements JTypeVisitor<@Nullable JTypeMirror, JClassSymbol> {
1654

1655
        static final AsSuperVisitor INSTANCE = new AsSuperVisitor();
1✔
1656

1657
        /** Parameter is the erasure of the target. */
1658

1659
        @Override
1660
        public JTypeMirror visit(JTypeMirror t, JClassSymbol target) {
1661
            return null;
×
1662
        }
1663

1664
        @Override
1665
        public JTypeMirror visitClass(JClassType t, JClassSymbol target) {
1666
            if (target.equals(t.getSymbol())) {
1✔
1667
                return t;
1✔
1668
            }
1669

1670
            // prefer digging up the superclass first
1671
            JClassType sup = t.getSuperClass();
1✔
1672
            JClassType res = sup == null ? null : (JClassType) sup.acceptVisitor(this, target);
1✔
1673
            if (res != null) {
1✔
1674
                return res;
1✔
1675
            } else {
1676
                // then look in interfaces if possible
1677
                if (target.isInterface() || target.isUnresolved()) {
1✔
1678
                    return firstResult(target, t.getSuperInterfaces());
1✔
1679
                }
1680
            }
1681

1682
            return null;
1✔
1683
        }
1684

1685
        @Override
1686
        public JTypeMirror visitIntersection(JIntersectionType t, JClassSymbol target) {
1687
            return firstResult(target, t.getComponents());
×
1688
        }
1689

1690
        public @Nullable JTypeMirror firstResult(JClassSymbol target, Iterable<? extends JTypeMirror> components) {
1691
            for (JTypeMirror ci : components) {
1✔
1692
                @Nullable JTypeMirror sup = ci.acceptVisitor(this, target);
1✔
1693
                if (sup != null) {
1✔
1694
                    return sup;
1✔
1695
                }
1696
            }
1✔
1697
            return null;
1✔
1698
        }
1699

1700
        @Override
1701
        public JTypeMirror visitTypeVar(JTypeVar t, JClassSymbol target) {
1702
            // caution, infinite recursion
1703
            return t.getUpperBound().acceptVisitor(this, target);
1✔
1704
        }
1705

1706
        @Override
1707
        public JTypeMirror visitArray(JArrayType t, JClassSymbol target) {
1708
            // Cloneable, Serializable, Object
1709
            JTypeMirror decl = t.getTypeSystem().declaration(target);
×
1710
            return t.isSubtypeOf(decl) ? decl : null;
×
1711
        }
1712
    }
1713

1714
    // </editor-fold>
1715

1716
    // <editor-fold  defaultstate="collapsed" desc="LUB/GLB">
1717

1718
    /**
1719
     * Returns a subset S of the parameter, whose components have no
1720
     * strict supertype in S.
1721
     *
1722
     * <pre>{@code
1723
     * S = { V | V in set, and for all W ≠ V in set, it is not the case that W <: V }
1724
     * }</pre>
1725
     */
1726
    public static Set<JTypeMirror> mostSpecific(Collection<? extends JTypeMirror> set) {
1727
        Set<JTypeMirror> result = new LinkedHashSet<>(set.size());
1✔
1728

1729
        // Notice that this loop needs a well-behaved subtyping relation,
1730
        // i.e. antisymmetric: A <: B && A != B implies not(B <: A)
1731
        // This is not the case if we include unchecked conversion in there,
1732
        // or special provisions for unresolved types.
1733
        vLoop:
1734
        for (JTypeMirror v : set) {
1✔
1735
            for (JTypeMirror w : set) {
1✔
1736
                if (!w.equals(v) && !hasUnresolvedSymbol(w) && isSubtypePure(w, v).bySubtyping()) {
1✔
1737
                    continue vLoop;
1✔
1738
                }
1739
            }
1✔
1740
            result.add(v);
1✔
1741
        }
1✔
1742
        return result;
1✔
1743
    }
1744

1745
    // </editor-fold>
1746

1747
    /**
1748
     * Returns the components of t if it is an intersection type,
1749
     * otherwise returns t.
1750
     */
1751
    public static List<JTypeMirror> asList(JTypeMirror t) {
1752
        if (t instanceof JIntersectionType) {
1✔
1753
            return ((JIntersectionType) t).getComponents();
1✔
1754
        } else {
1755
            return Collections.singletonList(t);
1✔
1756
        }
1757
    }
1758

1759
    /** Returns a list with the erasures of the given types, may be unmodifiable. */
1760
    public static List<JTypeMirror> erase(Collection<? extends JTypeMirror> ts) {
1761
        return CollectionUtil.map(ts, JTypeMirror::getErasure);
1✔
1762
    }
1763

1764
    // <editor-fold  defaultstate="collapsed" desc="Mentions">
1765

1766

1767
    public static boolean mentions(@NonNull JTypeVisitable type, @NonNull InferenceVar parent) {
1768
        return type.acceptVisitor(MentionsVisitor.INSTANCE, Collections.singleton(parent));
1✔
1769
    }
1770

1771
    public static boolean mentionsAny(JTypeVisitable t, Collection<? extends SubstVar> vars) {
1772
        return !vars.isEmpty() && t.acceptVisitor(MentionsVisitor.INSTANCE, vars);
1✔
1773
    }
1774

1775

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

1778
        static final MentionsVisitor INSTANCE = new MentionsVisitor();
1✔
1779

1780
        @Override
1781
        public Boolean visit(JTypeMirror t, Collection<? extends JTypeMirror> targets) {
1782
            return false;
1✔
1783
        }
1784

1785
        @Override
1786
        public Boolean visitTypeVar(JTypeVar t, Collection<? extends JTypeMirror> targets) {
1787
            return targets.contains(t);
1✔
1788
        }
1789

1790
        @Override
1791
        public Boolean visitInferenceVar(InferenceVar t, Collection<? extends JTypeMirror> targets) {
1792
            return targets.contains(t);
1✔
1793
        }
1794

1795
        @Override
1796
        public Boolean visitWildcard(JWildcardType t, Collection<? extends JTypeMirror> targets) {
1797
            return t.getBound().acceptVisitor(this, targets);
1✔
1798
        }
1799

1800
        @Override
1801
        public Boolean visitMethodType(JMethodSig t, Collection<? extends JTypeMirror> targets) {
1802
            if (t.getReturnType().acceptVisitor(this, targets)) {
1✔
1803
                return true;
1✔
1804
            }
1805
            for (JTypeMirror fi : t.getFormalParameters()) {
1✔
1806
                if (fi.acceptVisitor(this, targets)) {
1✔
1807
                    return true;
1✔
1808
                }
1809
            }
1✔
1810
            for (JTypeMirror ti : t.getThrownExceptions()) {
1✔
1811
                if (ti.acceptVisitor(this, targets)) {
1✔
1812
                    return true;
×
1813
                }
1814
            }
1✔
1815
            return false;
1✔
1816
        }
1817

1818
        @Override
1819
        public Boolean visitClass(JClassType t, Collection<? extends JTypeMirror> targets) {
1820
            JClassType encl = t.getEnclosingType();
1✔
1821
            if (encl != null && encl.acceptVisitor(this, targets)) {
1✔
1822
                return true;
1✔
1823
            }
1824

1825
            for (JTypeMirror typeArg : t.getTypeArgs()) {
1✔
1826
                if (typeArg.acceptVisitor(this, targets)) {
1✔
1827
                    return true;
1✔
1828
                }
1829
            }
1✔
1830

1831
            return false;
1✔
1832
        }
1833

1834
        @Override
1835
        public Boolean visitIntersection(JIntersectionType t, Collection<? extends JTypeMirror> targets) {
1836
            for (JTypeMirror comp : t.getComponents()) {
1✔
1837
                if (comp.acceptVisitor(this, targets)) {
1✔
1838
                    return true;
×
1839
                }
1840
            }
1✔
1841
            return false;
1✔
1842
        }
1843

1844
        @Override
1845
        public Boolean visitArray(JArrayType t, Collection<? extends JTypeMirror> targets) {
1846
            return t.getComponentType().acceptVisitor(this, targets);
1✔
1847
        }
1848
    }
1849

1850
    // </editor-fold>
1851

1852
    // <editor-fold  defaultstate="collapsed" desc="Accessibility utils">
1853

1854

1855
    public static Predicate<JMethodSymbol> accessibleMethodFilter(String name, @NonNull JClassSymbol symbol) {
1856
        return it -> it.nameEquals(name) && isAccessible(it, symbol);
1✔
1857
    }
1858

1859
    public static Iterable<JMethodSig> lazyFilterAccessible(List<JMethodSig> visible, @NonNull JClassSymbol accessSite) {
1860
        return () -> IteratorUtil.filter(visible.iterator(), it -> isAccessible(it.getSymbol(), accessSite));
1✔
1861
    }
1862

1863
    public static List<JMethodSig> filterAccessible(List<JMethodSig> visible, @NonNull JClassSymbol accessSite) {
1864
        return CollectionUtil.mapNotNull(visible, m -> isAccessible(m.getSymbol(), accessSite) ? m : null);
1✔
1865
    }
1866

1867

1868
    public static List<JMethodSig> getMethodsOf(JTypeMirror type, String name, boolean staticOnly, @NonNull JClassSymbol enclosing) {
1869
        if (staticOnly && type.isInterface()) {
1✔
1870
            // static methods, start on interface
1871
            // static interface methods are not inherited
1872
            return type.streamDeclaredMethods(staticMethodFilter(name, true, enclosing)).collect(Collectors.toList());
1✔
1873
        } else if (staticOnly) {
1✔
1874
            // static methods, doesn't start on interface
1875
            // -> ignore non-static, ignore any that are interfaces
1876
            return type.streamMethods(staticMethodFilter(name, false, enclosing)).collect(OverloadSet.collectMostSpecific(type));
1✔
1877
        } else {
1878
            return type.streamMethods(methodFilter(name, enclosing))
1✔
1879
                       .collect(OverloadSet.collectMostSpecific(type));
1✔
1880
        }
1881
    }
1882

1883
    private static @NonNull Predicate<JMethodSymbol> methodFilter(String name, @NonNull JClassSymbol enclosing) {
1884
        return it -> isAccessibleWithName(name, enclosing, it);
1✔
1885
    }
1886

1887
    private static @NonNull Predicate<JMethodSymbol> staticMethodFilter(String name, boolean acceptItfs, @NonNull JClassSymbol enclosing) {
1888
        return it -> Modifier.isStatic(it.getModifiers())
1✔
1889
            && (acceptItfs || !it.getEnclosingClass().isInterface())
1✔
1890
            && isAccessibleWithName(name, enclosing, it);
1✔
1891
    }
1892

1893
    private static boolean isAccessibleWithName(String name, @NonNull JClassSymbol enclosing, JMethodSymbol m) {
1894
        return m.nameEquals(name) && isAccessible(m, enclosing);
1✔
1895
    }
1896

1897

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

1901
        int mods = method.getModifiers();
1✔
1902
        if (Modifier.isPublic(mods)) {
1✔
1903
            return true;
1✔
1904
        }
1905

1906
        JClassSymbol owner = method.getEnclosingClass();
1✔
1907

1908
        if (Modifier.isPrivate(mods)) {
1✔
1909
            return ctx.getNestRoot().equals(owner.getNestRoot());
1✔
1910
        }
1911

1912
        return ctx.getPackageName().equals(owner.getPackageName())
1✔
1913
            // we can exclude interfaces because their members are all public
1914
            || Modifier.isProtected(mods) && isSubClassOfNoInterface(ctx, owner);
1✔
1915
    }
1916

1917
    private static boolean isSubClassOfNoInterface(JClassSymbol sub, JClassSymbol symbol) {
1918
        if (symbol.equals(sub)) {
1✔
1919
            return true;
1✔
1920
        }
1921

1922
        JClassSymbol superclass = sub.getSuperclass();
1✔
1923
        return superclass != null && isSubClassOfNoInterface(superclass, symbol);
1✔
1924
    }
1925

1926
    public static NameResolver<FieldSig> getMemberFieldResolver(JTypeMirror c, @NonNull String accessPackageName, @Nullable JClassSymbol access, String name) {
1927
        if (c instanceof JClassType) {
1✔
1928
            // fast path
1929
            return JavaResolvers.getMemberFieldResolver((JClassType) c, accessPackageName, access, name);
1✔
1930
        }
1931

1932
        return c.acceptVisitor(GetFieldVisitor.INSTANCE, new FieldSearchParams(accessPackageName, access, name));
1✔
1933
    }
1934

1935
    private static final class FieldSearchParams {
1936

1937
        private final @NonNull String accessPackageName;
1938
        private final @Nullable JClassSymbol access;
1939
        private final String name;
1940

1941
        FieldSearchParams(@NonNull String accessPackageName, @Nullable JClassSymbol access, String name) {
1✔
1942
            this.accessPackageName = accessPackageName;
1✔
1943
            this.access = access;
1✔
1944
            this.name = name;
1✔
1945
        }
1✔
1946
    }
1947

1948
    private static final class GetFieldVisitor implements JTypeVisitor<NameResolver<FieldSig>, FieldSearchParams> {
1949

1950
        static final GetFieldVisitor INSTANCE = new GetFieldVisitor();
1✔
1951

1952
        @Override
1953
        public NameResolver<FieldSig> visit(JTypeMirror t, FieldSearchParams fieldSearchParams) {
1954
            return CoreResolvers.emptyResolver();
1✔
1955
        }
1956

1957
        @Override
1958
        public NameResolver<FieldSig> visitClass(JClassType t, FieldSearchParams fieldSearchParams) {
1959
            return JavaResolvers.getMemberFieldResolver(t, fieldSearchParams.accessPackageName, fieldSearchParams.access, fieldSearchParams.name);
1✔
1960
        }
1961

1962
        @Override
1963
        public NameResolver<FieldSig> visitTypeVar(JTypeVar t, FieldSearchParams fieldSearchParams) {
1964
            return t.getUpperBound().acceptVisitor(this, fieldSearchParams);
1✔
1965
        }
1966

1967
        @Override
1968
        public NameResolver<FieldSig> visitIntersection(JIntersectionType t, FieldSearchParams fieldSearchParams) {
1969
            return NameResolver.composite(
×
1970
                CollectionUtil.map(t.getComponents(), c -> c.acceptVisitor(this, fieldSearchParams))
×
1971
            );
1972
        }
1973

1974
        @Override
1975
        public NameResolver<FieldSig> visitArray(JArrayType t, FieldSearchParams fieldSearchParams) {
1976
            if ("length".equals(fieldSearchParams.name)) {
1✔
1977
                return CoreResolvers.singleton("length", t.getTypeSystem().sigOf(t, t.getSymbol().getDeclaredField("length")));
1✔
1978
            }
1979
            return CoreResolvers.emptyResolver();
×
1980
        }
1981
    }
1982

1983
    // </editor-fold>
1984

1985
    // <editor-fold  defaultstate="collapsed" desc="Miscellaneous">
1986

1987
    /**
1988
     * Returns true if both types have a common supertype that is not Object.
1989
     * Primitive types are only related to themselves.
1990
     *
1991
     * @param t Non-null type
1992
     * @param s Non-null type
1993
     *
1994
     * @throws NullPointerException if a parameter is null
1995
     */
1996
    public static boolean areRelated(@NonNull JTypeMirror t, JTypeMirror s) {
1997
        if (t.isPrimitive() || s.isPrimitive()) {
1✔
1998
            return s.equals(t);
×
1999
        }
2000
        if (t.equals(s)) {
1✔
2001
            return true;
1✔
2002
        }
2003
        // maybe they have a common supertype
2004
        Set<JTypeMirror> tSupertypes = new HashSet<>(t.getSuperTypeSet());
1✔
2005
        tSupertypes.retainAll(s.getSuperTypeSet());
1✔
2006
        return !tSupertypes.equals(Collections.singleton(t.getTypeSystem().OBJECT));
1✔
2007
    }
2008

2009
    /**
2010
     * Returns true if the type is {@link TypeSystem#UNKNOWN},
2011
     * {@link TypeSystem#ERROR}, or its symbol is unresolved.
2012
     *
2013
     * @param t Non-null type
2014
     *
2015
     * @throws NullPointerException if the parameter is null
2016
     */
2017
    public static boolean isUnresolved(@NonNull JTypeMirror t) {
2018
        return isSpecialUnresolved(t) || hasUnresolvedSymbol(t);
1✔
2019
    }
2020

2021
    public static boolean isSpecialUnresolved(@NonNull JTypeMirror t) {
2022
        TypeSystem ts = t.getTypeSystem();
1✔
2023
        return t == ts.UNKNOWN || t == ts.ERROR;
1✔
2024
    }
2025

2026
    /**
2027
     * Return true if the argument is a {@link JClassType} with
2028
     * {@linkplain JClassSymbol#isUnresolved() an unresolved symbol} or
2029
     * a {@link JArrayType} whose element type matches the first criterion.
2030
     */
2031
    public static boolean hasUnresolvedSymbol(@Nullable JTypeMirror t) {
2032
        if (!(t instanceof JClassType)) {
1✔
2033
            return t instanceof JArrayType && hasUnresolvedSymbol(((JArrayType) t).getElementType());
1✔
2034
        }
2035
        return t.getSymbol() != null && t.getSymbol().isUnresolved();
1✔
2036
    }
2037

2038
    public static boolean isUnresolvedOrNull(@Nullable JTypeMirror t) {
2039
        return t == null || isUnresolved(t);
1✔
2040
    }
2041

2042

2043
    public static @Nullable JTypeMirror getArrayComponent(@Nullable JTypeMirror t) {
2044
        return t instanceof JArrayType ? ((JArrayType) t).getComponentType() : null;
1✔
2045
    }
2046

2047
    // </editor-fold>
2048
}
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