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

pmd / pmd / 495

07 May 2026 09:12AM UTC coverage: 79.021% (-0.002%) from 79.023%
495

push

github

adangel
[java] Fix StackOverflowError in TypeOps projection of cyclic captured type vars (#6553)

18738 of 24637 branches covered (76.06%)

Branch coverage included in aggregate %.

29 of 31 new or added lines in 1 file covered. (93.55%)

2 existing lines in 1 file now uncovered.

40841 of 50759 relevant lines covered (80.46%)

0.81 hits per line

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

87.47
/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.AssertionUtil;
44
import net.sourceforge.pmd.util.CollectionUtil;
45
import net.sourceforge.pmd.util.IteratorUtil;
46

47
/**
48
 * Common operations on types.
49
 */
50
@SuppressWarnings("PMD.CompareObjectsWithEquals")
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, true, 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, true, 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 None of this is published API, and compatibility can be broken anytime! Use this only at your own risk.
99
     */
100
    static boolean isSameTypeInInference(JTypeMirror t, JTypeMirror s) {
101
        return isSameType(t, s, false, false);
1✔
102
    }
103

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

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

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

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

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

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

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

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

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

167

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

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

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

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

183
        @Override
184
        public Boolean visit(JTypeMirror t, JTypeMirror s) {
185
            throw AssertionUtil.shouldNotReachHere("other overload should be chosen");
×
186
        }
187

188
        @Override
189
        public Boolean visitSentinel(JTypeMirror t, JTypeMirror s) {
190
            return t == s;
1!
191
        }
192

193
        @Override
194
        public Boolean visitPrimitive(JPrimitiveType t, JTypeMirror s) {
195
            return s.isPrimitive(t.getKind());
1✔
196
        }
197

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

210
        @Override
211
        public Boolean visitTypeVar(JTypeVar t, JTypeMirror s) {
212
            return t.equals(s);
1✔
213
        }
214

215
        @Override
216
        public Boolean visitWildcard(JWildcardType t, JTypeMirror s) {
217
            if (!(s instanceof JWildcardType)) {
1✔
218
                return false;
1✔
219
            }
220
            JWildcardType s2 = (JWildcardType) s;
1✔
221
            return s2.isUpperBound() == t.isUpperBound() && isSameType(t.getBound(), s2.getBound(), pure, considerAnnotations);
1✔
222
        }
223

224
        @Override
225
        public Boolean visitInferenceVar(InferenceVar t, JTypeMirror s) {
226
            if (pure) {
1✔
227
                return t == s || t.getBounds(BoundKind.EQ).contains(s);
1!
228
            }
229

230
            if (s instanceof JPrimitiveType) {
1!
231
                return false;
×
232
            }
233

234
            if (s instanceof JWildcardType) {
1✔
235
                JWildcardType s2 = (JWildcardType) s;
1✔
236
                if (s2.isUpperBound()) {
1✔
237
                    t.addBound(BoundKind.UPPER, s2.asUpperBound());
1✔
238
                } else {
239
                    t.addBound(BoundKind.LOWER, s2.asLowerBound());
1✔
240
                }
241
                return true;
1✔
242
            }
243

244
            // add an equality bound
245
            t.addBound(BoundKind.EQ, s);
1✔
246
            return true;
1✔
247
        }
248

249
        @Override
250
        public Boolean visitIntersection(JIntersectionType t, JTypeMirror s) {
251
            if (!(s instanceof JIntersectionType)) {
1✔
252
                return false;
1✔
253
            }
254

255
            JIntersectionType s2 = (JIntersectionType) s;
1✔
256

257
            // order is irrelevant
258

259
            if (s2.getComponents().size() != t.getComponents().size()) {
1!
260
                return false;
×
261
            }
262

263
            if (!isSameType(t.getPrimaryBound(), s2.getPrimaryBound(), pure, considerAnnotations)) {
1!
264
                return false;
×
265
            }
266

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

284
        @Override
285
        public Boolean visitArray(JArrayType t, JTypeMirror s) {
286
            return s instanceof JArrayType
1✔
287
                && isSameType(t.getComponentType(), ((JArrayType) s).getComponentType(), pure, considerAnnotations);
1✔
288
        }
289
    }
290

291
    // </editor-fold>
292

293
    // <editor-fold  defaultstate="collapsed" desc="Supertype enumeration">
294

295

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

308
    private static final class SuperTypesVisitor implements JTypeVisitor<Void, Set<JTypeMirror>> {
309

310
        static final SuperTypesVisitor INSTANCE = new SuperTypesVisitor();
1✔
311

312
        @Override
313
        public Void visit(JTypeMirror t, Set<JTypeMirror> result) {
314
            throw new IllegalStateException("Should not be called");
×
315
        }
316

317
        @Override
318
        public Void visitTypeVar(JTypeVar t, Set<JTypeMirror> result) {
319
            if (result.add(t)) {
1!
320
                // prevent infinite loop
321
                t.getUpperBound().acceptVisitor(this, result);
1✔
322
            }
323
            return null;
1✔
324
        }
325

326
        @Override
327
        public Void visitNullType(JTypeMirror t, Set<JTypeMirror> result) {
328
            // too many types
329
            throw new UnsupportedOperationException("The null type has all reference types as supertype");
1✔
330
        }
331

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

338
        @Override
339
        public Void visitInferenceVar(InferenceVar t, Set<JTypeMirror> result) {
340
            result.add(t);
×
341
            return null;
×
342
        }
343

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

351
        @Override
352
        public Void visitClass(JClassType t, Set<JTypeMirror> result) {
353
            result.add(t);
1✔
354

355

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

370
        @Override
371
        public Void visitIntersection(JIntersectionType t, Set<JTypeMirror> result) {
372
            for (JTypeMirror it : t.getComponents()) {
1✔
373
                it.acceptVisitor(this, result);
1✔
374
            }
1✔
375
            return null;
1✔
376
        }
377

378
        @Override
379
        public Void visitArray(JArrayType t, Set<JTypeMirror> result) {
380
            result.add(t);
1✔
381

382
            TypeSystem ts = t.getTypeSystem();
1✔
383

384
            for (JTypeMirror componentSuper : t.getComponentType().getSuperTypeSet()) {
1✔
385
                result.add(ts.arrayType(componentSuper));
1✔
386
            }
1✔
387
            result.add(ts.CLONEABLE);
1✔
388
            result.add(ts.SERIALIZABLE);
1✔
389
            result.add(ts.OBJECT);
1✔
390

391
            return null;
1✔
392
        }
393

394
        @Override
395
        public Void visitPrimitive(JPrimitiveType t, Set<JTypeMirror> result) {
396
            result.addAll(t.getSuperTypeSet()); // special implementation in JPrimitiveType
×
397
            return null;
×
398
        }
399
    }
400

401
    // </editor-fold>
402

403
    // <editor-fold  defaultstate="collapsed" desc="Subtyping">
404

405

406
    public static Convertibility isConvertible(@NonNull JTypeMirror t, @NonNull JTypeMirror s) {
407
        return SubtypeVisitor.INFERENCE.isConvertible(t, s, true);
1✔
408
    }
409

410
    /**
411
     * @deprecated Since 7.2.0. Use {@link #isConvertible(JTypeMirror, JTypeMirror)} or {@link #isConvertibleNoCapture(JTypeMirror, JTypeMirror)} instead.
412
     */
413
    @Deprecated // unused
414
    public static Convertibility isConvertible(@NonNull JTypeMirror t, @NonNull JTypeMirror s, boolean capture) {
415
        return SubtypeVisitor.PURE.isConvertible(t, s, capture);
×
416
    }
417

418
    public static Convertibility isConvertibleNoCapture(@NonNull JTypeMirror t, @NonNull JTypeMirror s) {
419
        return SubtypeVisitor.PURE.isConvertible(t, s, false);
1✔
420
    }
421

422
    // does not perform side effects on inference vars
423
    public static Convertibility isConvertiblePure(JTypeMirror t, JTypeMirror s) {
424
        return SubtypeVisitor.PURE.isConvertible(t, s);
1✔
425
    }
426

427
    public static boolean allArgsAreUnboundedWildcards(List<JTypeMirror> sargs) {
428
        for (JTypeMirror sarg : sargs) {
1✔
429
            if (!(sarg instanceof JWildcardType) || !((JWildcardType) sarg).isUnbounded()) {
1✔
430
                return false;
1✔
431
            }
432
        }
1✔
433
        return true;
1✔
434
    }
435

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

474
        /**
475
         * T is not a subtype of S, but every time T is used in a context
476
         * where an S is expected, unchecked conversion converts the T to
477
         * an S with a mandated warning. For example the raw type {@code Class}
478
         * is convertible to {@code Class<String>} with an unchecked warning.
479
         */
480
        UNCHECKED_WARNING,
1✔
481

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

495
        /**
496
         * T is a subtype of S ({@code T <: S}). In particular, any type
497
         * is a subtype of itself ({@code T <: T}).
498
         *
499
         * <p>For example, {@code int} can be widened to {@code long},
500
         * so we consider {@code int <: long}.
501
         */
502
        SUBTYPING;
1✔
503

504
        // public:
505

506
        /** Returns true if this is {@link #NEVER}. */
507
        public boolean never() {
508
            return this == NEVER;
1✔
509
        }
510

511
        /**
512
         * Returns true if this is anything but {@link #NEVER}.
513
         */
514
        public boolean somehow() {
515
            return this != NEVER;
1✔
516
        }
517

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

525
        /**
526
         * True if this is {@link #UNCHECKED_WARNING}.
527
         */
528
        public boolean withUncheckedWarning() {
529
            return this == UNCHECKED_WARNING;
1✔
530
        }
531

532
        /** True if this is {@link #SUBTYPING} or {@link #UNCHECKED_NO_WARNING}. */
533
        public boolean withoutWarnings() {
534
            return this == SUBTYPING || this == UNCHECKED_NO_WARNING;
1✔
535
        }
536

537
        // package:
538

539

540
        /** Preserves an unchecked warning. */
541
        Convertibility and(Convertibility b) {
542
            return min(this, b);
1✔
543
        }
544

545
        static Convertibility min(Convertibility c1, Convertibility c2) {
546
            return c1.ordinal() < c2.ordinal() ? c1 : c2;
1!
547
        }
548

549
        static Convertibility subtypeIf(boolean b) {
550
            return b ? SUBTYPING : NEVER;
1✔
551
        }
552

553
    }
554

555
    private static JTypeMirror wildUpperBound(JTypeMirror type) {
556
        if (type instanceof JWildcardType) {
1✔
557
            JWildcardType wild = (JWildcardType) type;
1✔
558
            if (wild.isUpperBound()) {
1✔
559
                return wildUpperBound(wild.asUpperBound());
1✔
560
            } else if (wild.asLowerBound() instanceof JTypeVar) {
1!
561
                return ((JTypeVar) wild.asLowerBound()).getUpperBound();
×
562
            }
563
        } else if (type instanceof JTypeVar && ((JTypeVar) type).isCaptured()) {
1✔
564
            // note: tvar.getUpperBound() != tvar.getCapturedOrigin().asUpperBound()
565
            return wildUpperBound(((JTypeVar) type).getUpperBound());
1✔
566
        }
567
        return type;
1✔
568
    }
569

570
    private static JTypeMirror wildLowerBound(JTypeMirror type) {
571
        if (type instanceof JWildcardType) {
1✔
572
            return wildLowerBound(((JWildcardType) type).asLowerBound());
1✔
573
        }
574
        return type;
1✔
575
    }
576

577
    private static JTypeMirror lowerBoundRec(JTypeMirror type) {
578
        if (type instanceof JWildcardType) {
1!
579
            return lowerBoundRec(((JWildcardType) type).asLowerBound());
×
580
        } else if (type instanceof JTypeVar && ((JTypeVar) type).isCaptured()) {
1✔
581
            return lowerBoundRec(((JTypeVar) type).getLowerBound());
1✔
582
        }
583
        return type;
1✔
584
    }
585

586
    private static boolean isTypeRange(JTypeMirror s) {
587
        return s instanceof JWildcardType || isCvar(s);
1!
588
    }
589

590
    private static boolean isCvar(JTypeMirror s) {
591
        return s instanceof JTypeVar && ((JTypeVar) s).isCaptured();
1✔
592
    }
593

594

595
    private static final class SubtypeVisitor implements JTypeVisitor<Convertibility, JTypeMirror> {
596

597
        static final SubtypeVisitor INFERENCE = new SubtypeVisitor(false);
1✔
598
        static final SubtypeVisitor PURE = new SubtypeVisitor(true);
1✔
599
        private final boolean pure;
600

601
        private SubtypeVisitor(boolean pure) {
1✔
602
            this.pure = pure;
1✔
603
        }
1✔
604

605

606
        Convertibility isConvertible(@NonNull JTypeMirror t, @NonNull JTypeMirror s) {
607
            return isConvertible(t, s, false);
1✔
608
        }
609

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

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

662
            if (capture) {
1✔
663
                t = capture(t);
1✔
664
            }
665
            return t.acceptVisitor(this, s);
1✔
666
        }
667

668
        Convertibility subtypesAll(JTypeMirror t, Iterable<? extends JTypeMirror> supers) {
669
            Convertibility result = Convertibility.SUBTYPING;
1✔
670
            for (JTypeMirror ui : supers) {
1✔
671
                Convertibility sub = isConvertible(t, ui);
1✔
672
                if (sub == Convertibility.NEVER) {
1✔
673
                    return Convertibility.NEVER;
1✔
674
                }
675
                result = result.and(sub);
1✔
676
            }
1✔
677
            return result;
1✔
678
        }
679

680
        Convertibility anySubTypesAny(Iterable<? extends JTypeMirror> us, Iterable<? extends JTypeMirror> vs) {
681
            for (JTypeMirror ui : us) {
1✔
682
                for (JTypeMirror vi : vs) {
1✔
683
                    Convertibility sub = isConvertible(ui, vi);
1✔
684
                    if (sub != Convertibility.NEVER) {
1✔
685
                        return sub.and(Convertibility.SUBTYPING); // never return identity here
1✔
686
                    }
687
                }
1✔
688
            }
1✔
689
            return Convertibility.NEVER;
1✔
690
        }
691

692
        /**
693
         * Generalises containment to check if for each i, {@code Ti <= Si}.
694
         */
695
        Convertibility typeArgsAreContained(JClassType t, JClassType s) {
696
            List<JTypeMirror> targs = t.getTypeArgs();
1✔
697
            List<JTypeMirror> sargs = s.getTypeArgs();
1✔
698

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

729
            if (targs.size() != sargs.size()) {
1✔
730
                // types are not well-formed
731
                return Convertibility.NEVER;
1✔
732
            }
733

734
            Convertibility result = Convertibility.SUBTYPING;
1✔
735
            for (int i = 0; i < targs.size(); i++) {
1✔
736
                Convertibility sub = typeArgContains(sargs.get(i), targs.get(i));
1✔
737
                if (sub == Convertibility.NEVER) {
1✔
738
                    return Convertibility.NEVER;
1✔
739
                }
740
                result = result.and(sub);
1✔
741
            }
742

743
            return result;
1✔
744
        }
745

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

764
            // ⊥ ---------L(S)---L(T)------U(T)-----U(S)---> Object
765
            // range of S   [-------------------------]
766
            // range of T          [---------]
767

768
            // here S contains T because its range is greater
769

770
            // since a wildcard is either "super" or "extends", in reality
771
            // either L(S) = ⊥, or U(S) = Object.
772

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

775
            //      ⊥ -------U(T)-----U(S)------> Object   (L(T) = L(S) = ⊥)
776
            //      ⊥ -------L(S)-----L(T)------> Object   (U(T) = U(S) = Object)
777

778
            if (isSameType(s, t, pure, false)) {
1✔
779
                // S <= S
780
                return Convertibility.SUBTYPING;
1✔
781
            }
782

783
            if (s instanceof JWildcardType) {
1✔
784
                JWildcardType sw = (JWildcardType) s;
1✔
785

786
                // capt(? extends T) <= ? extends T
787
                // capt(? super T) <= ? super T
788
                if (t instanceof JTypeVar && ((JTypeVar) t).isCaptureOf(sw)) {
1✔
789
                    return Convertibility.SUBTYPING;
1✔
790
                }
791

792
                if (sw.isUpperBound()) {
1✔
793
                    // Test U(T) <: U(S),  we already know L(S) <: L(T), because L(S) is bottom
794
                    return this.isConvertible(wildUpperBound(t), sw.asUpperBound());
1✔
795
                } else {
796
                    // Test L(S) <: L(T), we already know U(T) <: U(S), because U(S) is top
797
                    return this.isConvertible(sw.asLowerBound(), wildLowerBound(t));
1✔
798
                }
799
            }
800

801
            return Convertibility.NEVER;
1✔
802
        }
803

804
        @Override
805
        public Convertibility visit(JTypeMirror t, JTypeMirror s) {
806
            throw new IllegalStateException("Should not be called");
×
807
        }
808

809
        @Override
810
        public Convertibility visitTypeVar(JTypeVar t, JTypeMirror s) {
811
            if (s instanceof JTypeVar && t.getSymbol() != null && Objects.equals(t.getSymbol(), s.getSymbol())) {
1✔
812
                return Convertibility.SUBTYPING;
1✔
813
            } else if (s instanceof SentinelType) {
1!
814
                return Convertibility.SUBTYPING;
×
815
            }
816

817
            if (isTypeRange(s)) {
1✔
818
                return isConvertible(t, lowerBoundRec(s));
1✔
819
            }
820
            return isConvertible(t.getUpperBound(), s);
1✔
821
        }
822

823
        @Override
824
        public Convertibility visitNullType(JTypeMirror t, JTypeMirror s) {
825
            return Convertibility.subtypeIf(!s.isPrimitive());
1✔
826
        }
827

828
        @Override
829
        public Convertibility visitSentinel(JTypeMirror t, JTypeMirror s) {
830
            // t may be (*unknown*), (*error*) or void
831
            // we know t != s
832
            if (t.isVoid()) {
1!
833
                return Convertibility.NEVER;
×
834
            }
835
            // unknown and error are subtypes of everything.
836
            // however we want them to add constrains on unknown
837
            if (!pure && !(s instanceof SentinelType)) {
1!
838
                s.acceptVisitor(this, t);
1✔
839
            }
840
            return Convertibility.SUBTYPING;
1✔
841
        }
842

843
        @Override
844
        public Convertibility visitInferenceVar(InferenceVar t, JTypeMirror s) {
845
            if (s == t.getTypeSystem().NULL_TYPE || s instanceof JPrimitiveType) {
1!
846
                return Convertibility.NEVER;
×
847
            }
848
            if (!pure) {
1!
849
                // here we add a constraint on the variable
850
                t.addBound(BoundKind.UPPER, s);
1✔
851
            }
852
            return Convertibility.SUBTYPING;
1✔
853
        }
854

855
        @Override
856
        public Convertibility visitWildcard(JWildcardType t, JTypeMirror s) {
857
            // wildcards should be captured and so we should not end up here
858
            return Convertibility.NEVER;
1✔
859
        }
860

861
        @Override
862
        public Convertibility visitClass(JClassType t, JTypeMirror s) {
863
            if (isSpecialUnresolved(s)) {
1✔
864
                if (!pure) {
1!
865
                    for (JTypeMirror arg : t.getTypeArgs()) {
1✔
866
                        typeArgContains(arg, s);
1✔
867
                    }
1✔
868
                }
869
                return Convertibility.SUBTYPING;
1✔
870
            }
871
            if (!(s instanceof JClassType)) {
1✔
872
                // note, that this ignores wildcard types,
873
                // because they're only compared through
874
                // type argument containment.
875
                return Convertibility.NEVER;
1✔
876
            }
877

878
            JClassType cs = (JClassType) s;
1✔
879

880
            JClassType superDecl = t.getAsSuper(cs.getSymbol());
1✔
881

882
            if (superDecl == null) {
1✔
883
                return Convertibility.NEVER;
1✔
884
            } else if (cs.isRaw()) {
1✔
885
                // a raw type C is a supertype for all the family of parameterized type generated by C<F1, .., Fn>
886
                return Convertibility.SUBTYPING;
1✔
887
            } else {
888
                return typeArgsAreContained(superDecl, cs);
1✔
889
            }
890
        }
891

892
        @Override
893
        public Convertibility visitIntersection(JIntersectionType t, JTypeMirror s) {
894
            // A & B <: A
895
            // A & B <: B
896

897
            // But for a class C, `C <: A & B` if `C <: A` and `C <: B`
898

899
            // So we can't just say, "any component of t must subtype s",
900
            // because if s is itself an intersection we have a problem:
901
            // Eg let T = S = A & B
902
            // T <: S -> A & B <: S
903
            //        -> A <: S OR B <: S
904
            //        -> A <: A & B OR B <: A & B
905
            //        -> A <: A AND A <: B OR B <: A AND B <: B
906
            //        -> true   AND false  OR false  AND true
907
            //        -> false
908

909
            // what we mean is, if S is an intersection, then
910
            // "any component of T subtypes any component of S"
911

912
            return anySubTypesAny(t.getComponents(), asList(s));
1✔
913
        }
914

915
        @Override
916
        public Convertibility visitArray(JArrayType t, JTypeMirror s) {
917
            TypeSystem ts = t.getTypeSystem();
1✔
918
            if (s == ts.OBJECT || s.equals(ts.CLONEABLE) || s.equals(ts.SERIALIZABLE)) {
1!
919
                return Convertibility.SUBTYPING;
1✔
920
            }
921
            if (isSpecialUnresolved(s)) {
1✔
922
                if (!pure) {
1!
923
                    t.getElementType().acceptVisitor(this, s);
1✔
924
                }
925
                return Convertibility.SUBTYPING;
1✔
926
            }
927

928
            if (!(s instanceof JArrayType)) {
1✔
929
                // not comparable to any other type
930
                return Convertibility.NEVER;
1✔
931
            }
932

933
            JArrayType cs = (JArrayType) s;
1✔
934

935
            if (t.getComponentType().isPrimitive() || cs.getComponentType().isPrimitive()) {
1✔
936
                // arrays of primitive types have no sub-/ supertype
937
                return Convertibility.subtypeIf(cs.getComponentType() == t.getComponentType());
1✔
938
            } else {
939
                return isConvertible(t.getComponentType(), cs.getComponentType());
1✔
940
            }
941
        }
942

943
        @Override
944
        public Convertibility visitPrimitive(JPrimitiveType t, JTypeMirror s) {
945
            if (s instanceof JPrimitiveType) {
1✔
946
                return t.superTypes.contains(s) ? Convertibility.SUBTYPING
1✔
947
                                                : Convertibility.NEVER;
1✔
948
            }
949
            return Convertibility.NEVER;
1✔
950
        }
951
    }
952

953
    public static boolean isStrictSubtype(@NonNull JTypeMirror t, @NonNull JTypeMirror s) {
954
        return !t.equals(s) && t.isSubtypeOf(s);
1!
955
    }
956

957
    // </editor-fold>
958

959
    // <editor-fold  defaultstate="collapsed" desc="Substitution">
960

961
    /**
962
     * Replace the type variables occurring in the given type to their
963
     * image by the given function. Substitutions are not applied
964
     * recursively.
965
     *
966
     * @param type  Type to substitute
967
     * @param subst Substitution function, eg a {@link Substitution}
968
     */
969
    public static JTypeMirror subst(@Nullable JTypeMirror type, Function<? super SubstVar, ? extends @NonNull JTypeMirror> subst) {
970
        if (type == null || Substitution.isEmptySubst(subst)) {
1!
971
            return type;
1✔
972
        }
973
        return type.subst(subst);
1✔
974
    }
975

976

977
    /** Substitute on a list of types. */
978
    public static List<JTypeMirror> subst(List<? extends JTypeMirror> ts, Function<? super SubstVar, ? extends @NonNull JTypeMirror> subst) {
979
        if (Substitution.isEmptySubst(subst)) {
1✔
980
            return CollectionUtil.makeUnmodifiableAndNonNull(ts);
1✔
981
        }
982
        return mapPreservingSelf(ts, t -> t.subst(subst));
1✔
983
    }
984

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

992
    public static List<JTypeVar> substInBoundsOnly(List<JTypeVar> ts, Function<? super SubstVar, ? extends @NonNull JTypeMirror> subst) {
993
        if (Substitution.isEmptySubst(subst)) {
1✔
994
            return ts;
1✔
995
        }
996
        return mapPreservingSelf(ts, t -> t.substInBounds(subst));
1✔
997
    }
998

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

1018
        // subst relies on the fact that the original list is returned
1019
        // to avoid new type creation. Thus one cannot use
1020
        // Collections::unmodifiableList here
1021
        return list != null ? list : (List<T>) ts;
1✔
1022
    }
1023

1024
    // </editor-fold>
1025

1026
    // <editor-fold  defaultstate="collapsed" desc="Projection">
1027

1028

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

1041
    private static final JTypeMirror NO_DOWN_PROJECTION = null;
1✔
1042
    private static final ProjectionVisitor UPWARDS_PROJECTOR = new ProjectionVisitor(true) {
1✔
1043

1044
        @Override
1045
        public JTypeMirror visitTypeVar(JTypeVar t, RecursionStop recursionStop) {
1046
            if (t.isCaptured()) {
1✔
1047
                if (recursionStop.contains(t)) {
1✔
1048
                    // Called via recurseIfNotDone body (direct type-arg path).
1049
                    // Guard separately against re-entry through wildcards within this traversal.
1050
                    if (recursionStop.enterContainsVar(t)) {
1✔
1051
                        try {
1052
                            return t.getUpperBound().acceptVisitor(UPWARDS_PROJECTOR, recursionStop);
1✔
1053
                        } finally {
1054
                            recursionStop.leaveContainsVar(t);
1✔
1055
                        }
1056
                    }
1057
                    // Cycle: t's bound is already being projected via the contains path.
1058
                    return t;
1✔
1059
                } else if (recursionStop.enterFreshVar(t)) {
1✔
1060
                    // Fresh call or via wildcard bound. Guard against re-entry through wildcards.
1061
                    try {
1062
                        return t.getUpperBound().acceptVisitor(UPWARDS_PROJECTOR, recursionStop);
1✔
1063
                    } finally {
1064
                        recursionStop.leaveFreshVar(t);
1✔
1065
                    }
1066
                } else {
1067
                    // Cycle via wildcard path: this captured var's bound is already being visited.
1068
                    return t;
1✔
1069
                }
1070
            }
1071
            return t;
1✔
1072
        }
1073

1074

1075
        @Override
1076
        public JTypeMirror visitWildcard(JWildcardType t, RecursionStop recursionStop) {
1077
            JTypeMirror u = t.getBound().acceptVisitor(UPWARDS_PROJECTOR, recursionStop);
1✔
1078
            TypeSystem ts = t.getTypeSystem();
1✔
1079
            if (u == t.getBound()) {
1✔
1080
                return t;
1✔
1081
            }
1082

1083
            if (t.isUpperBound()) {
1!
1084
                return ts.wildcard(true, u);
×
1085
            } else {
1086
                JTypeMirror down = t.getBound().acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
1✔
1087
                return down == NO_DOWN_PROJECTION ? ts.UNBOUNDED_WILD : ts.wildcard(false, down);
1!
1088
            }
1089
        }
1090

1091

1092
        @Override
1093
        public JTypeMirror visitNullType(JTypeMirror t, RecursionStop recursionStop) {
1094
            return t;
×
1095
        }
1096

1097
    };
1098

1099

1100
    private static final ProjectionVisitor DOWNWARDS_PROJECTOR = new ProjectionVisitor(false) {
1✔
1101

1102
        @Override
1103
        public JTypeMirror visitWildcard(JWildcardType t, RecursionStop recursionStop) {
1104
            JTypeMirror u = t.getBound().acceptVisitor(UPWARDS_PROJECTOR, recursionStop);
×
1105
            if (u == t.getBound()) {
×
1106
                return t;
×
1107
            }
1108
            TypeSystem ts = t.getTypeSystem();
×
1109

1110
            if (t.isUpperBound()) {
×
1111
                JTypeMirror down = t.getBound().acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
×
1112
                return down == NO_DOWN_PROJECTION ? NO_DOWN_PROJECTION
×
1113
                                                  : ts.wildcard(true, down);
×
1114
            } else {
1115
                return ts.wildcard(false, u);
×
1116
            }
1117
        }
1118

1119

1120
        @Override
1121
        public JTypeMirror visitTypeVar(JTypeVar t, RecursionStop recursionStop) {
1122
            if (t.isCaptured()) {
1!
1123
                if (recursionStop.contains(t)) {
1✔
1124
                    if (recursionStop.enterContainsVar(t)) {
1!
1125
                        try {
1126
                            return t.getLowerBound().acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
1✔
1127
                        } finally {
1128
                            recursionStop.leaveContainsVar(t);
1✔
1129
                        }
1130
                    }
NEW
1131
                    return NO_DOWN_PROJECTION;
×
1132
                } else if (recursionStop.enterFreshVar(t)) {
1!
1133
                    try {
1134
                        return t.getLowerBound().acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
1✔
1135
                    } finally {
1136
                        recursionStop.leaveFreshVar(t);
1✔
1137
                    }
1138
                } else {
NEW
1139
                    return NO_DOWN_PROJECTION;
×
1140
                }
1141
            }
1142
            return t;
×
1143
        }
1144

1145
        @Override
1146
        public JTypeMirror visitNullType(JTypeMirror t, RecursionStop recursionStop) {
1147
            return NO_DOWN_PROJECTION;
1✔
1148
        }
1149
    };
1150

1151
    static final class RecursionStop {
1✔
1152

1153
        private Set<JTypeVar> set;
1154
        /**
1155
         * Tracks captured vars currently being projected via a fresh call or wildcard-bound
1156
         * path (i.e., NOT via a {@link #recurseIfNotDone} body). Used to detect cycles where
1157
         * a wildcard's bound leads back to the same captured var.
1158
         */
1159
        private Set<JTypeVar> freshCallStack;
1160
        /**
1161
         * Tracks captured vars currently being projected via a {@link #recurseIfNotDone} body
1162
         * call (i.e., {@link #contains} returned true). Used to detect cycles where the var's
1163
         * bound, followed from inside a recurseIfNotDone body, leads back to the same var via
1164
         * a wildcard rather than as a direct type argument.
1165
         */
1166
        private Set<JTypeVar> containsCallStack;
1167

1168
        boolean isAbsent(JTypeVar tvar) {
1169
            if (set == null) {
1✔
1170
                set = new LinkedHashSet<>(1);
1✔
1171
            }
1172
            return set.add(tvar);
1✔
1173
        }
1174

1175
        /** Returns true if {@code tvar} is already in the set managed by {@link #recurseIfNotDone}. */
1176
        boolean contains(JTypeVar tvar) {
1177
            return set != null && set.contains(tvar);
1!
1178
        }
1179

1180
        /**
1181
         * Enters a captured var projection via a fresh or wildcard-bound path.
1182
         * Returns true if the var was not already being projected this way (no cycle),
1183
         * false if a cycle is detected.
1184
         */
1185
        boolean enterFreshVar(JTypeVar tvar) {
1186
            if (freshCallStack == null) {
1✔
1187
                freshCallStack = new HashSet<>(2);
1✔
1188
            }
1189
            return freshCallStack.add(tvar);
1✔
1190
        }
1191

1192
        void leaveFreshVar(JTypeVar tvar) {
1193
            if (freshCallStack != null) {
1!
1194
                freshCallStack.remove(tvar);
1✔
1195
            }
1196
        }
1✔
1197

1198
        /**
1199
         * Enters a captured var projection via a {@link #recurseIfNotDone} body.
1200
         * Returns true if the var was not already being projected this way (no cycle),
1201
         * false if a cycle is detected.
1202
         */
1203
        boolean enterContainsVar(JTypeVar tvar) {
1204
            if (containsCallStack == null) {
1✔
1205
                containsCallStack = new HashSet<>(2);
1✔
1206
            }
1207
            return containsCallStack.add(tvar);
1✔
1208
        }
1209

1210
        void leaveContainsVar(JTypeVar tvar) {
1211
            if (containsCallStack != null) {
1!
1212
                containsCallStack.remove(tvar);
1✔
1213
            }
1214
        }
1✔
1215

1216
        <T extends JTypeMirror> JTypeMirror recurseIfNotDone(T t, BiFunction<T, RecursionStop, JTypeMirror> body) {
1217
            if (t instanceof JTypeVar) {
1✔
1218
                JTypeVar var = (JTypeVar) t;
1✔
1219
                if (isAbsent(var)) {
1✔
1220
                    return body.apply(t, this);
1✔
1221
                } else {
1222
                    return t;
1✔
1223
                }
1224
            } else {
1225
                return body.apply(t, this);
1✔
1226
            }
1227
        }
1228
    }
1229

1230
    /**
1231
     * Restricted type variables are:
1232
     * - Inference vars
1233
     * - Capture vars
1234
     *
1235
     * See
1236
     *
1237
     * https://docs.oracle.com/javase/specs/jls/se11/html/jls-4.html#jls-4.10.5
1238
     *
1239
     *
1240
     * <p>Here we use {@link #NO_DOWN_PROJECTION} as a sentinel
1241
     * (downwards projection is a partial function). If a type does not mention
1242
     * restricted type variables, then the visitor should return the original
1243
     * type (same reference). This allows testing predicates like
1244
     * <blockquote>
1245
     * "If Ai does not mention any restricted type variable, then Ai' = Ai."
1246
     * </blockquote>
1247
     */
1248
    private abstract static class ProjectionVisitor implements JTypeVisitor<JTypeMirror, RecursionStop> {
1249

1250
        private final boolean upwards;
1251

1252
        private ProjectionVisitor(boolean upwards) {
1✔
1253
            this.upwards = upwards;
1✔
1254
        }
1✔
1255

1256

1257
        @Override
1258
        public abstract JTypeMirror visitNullType(JTypeMirror t, RecursionStop recursionStop);
1259

1260

1261
        @Override
1262
        public abstract JTypeMirror visitWildcard(JWildcardType t, RecursionStop recursionStop);
1263

1264

1265
        @Override
1266
        public abstract JTypeMirror visitTypeVar(JTypeVar t, RecursionStop recursionStop);
1267

1268

1269
        @Override
1270
        public JTypeMirror visit(JTypeMirror t, RecursionStop recursionStop) {
1271
            return t;
1✔
1272
        }
1273

1274
        @Override
1275
        public JTypeMirror visitClass(JClassType t, RecursionStop recursionStop) {
1276
            if (t.isParameterizedType()) {
1✔
1277
                TypeSystem ts = t.getTypeSystem();
1✔
1278

1279
                List<JTypeMirror> targs = t.getTypeArgs();
1✔
1280
                List<JTypeMirror> newTargs = new ArrayList<>(targs.size());
1✔
1281
                List<JTypeVar> formals = t.getFormalTypeParams();
1✔
1282
                boolean change = false;
1✔
1283

1284
                for (int i = 0; i < targs.size(); i++) {
1✔
1285
                    JTypeMirror ai = targs.get(i);
1✔
1286
                    JTypeMirror u = recursionStop.recurseIfNotDone(ai, (s, stop) -> s.acceptVisitor(this, stop));
1✔
1287
                    if (u == ai) {
1✔
1288
                        if (isCvar(ai)) { // cvar hit recursion stop
1✔
1289
                            u = ts.UNBOUNDED_WILD;
1✔
1290
                            change = true;
1✔
1291
                        }
1292
                        // no change, or handled by the visitWildcard
1293
                        newTargs.add(u);
1✔
1294
                        continue;
1✔
1295
                    } else if (!upwards) {
1!
1296
                        // If Ai is a type that mentions a restricted type variable, then Ai' is undefined.
1297
                        return NO_DOWN_PROJECTION;
×
1298
                    } else if (u instanceof JWildcardType) {
1✔
1299
                        // The rest of this function, below, treats u as the bound of a wildcard,
1300
                        // but if u is already a wildcard (and therefore ai was a wildcard), we
1301
                        // are already done.
1302
                        newTargs.add(u);
1✔
1303
                        change = true;
1✔
1304
                        continue;
1✔
1305
                    }
1306

1307
                    change = true;
1✔
1308

1309
                    /*
1310
                        If Ai is a type that mentions a restricted type variable...
1311
                     */
1312
                    JTypeMirror bi = formals.get(i).getUpperBound();
1✔
1313

1314
                    if (u != ts.OBJECT && (mentionsAny(bi, formals) || !bi.isSubtypeOf(u))) {
1!
1315
                        newTargs.add(ts.wildcard(true, u));
1✔
1316
                    } else {
1317
                        JTypeMirror down = ai.acceptVisitor(DOWNWARDS_PROJECTOR, recursionStop);
1✔
1318
                        if (down == NO_DOWN_PROJECTION) {
1!
1319
                            newTargs.add(ts.UNBOUNDED_WILD);
1✔
1320
                        } else {
1321
                            newTargs.add(ts.wildcard(false, down));
×
1322
                        }
1323
                    }
1324
                }
1325

1326
                return change ? t.withTypeArguments(newTargs) : t;
1✔
1327
            } else {
1328
                return t;
1✔
1329
            }
1330
        }
1331

1332
        @Override
1333
        public JTypeMirror visitIntersection(JIntersectionType t, RecursionStop recursionStop) {
1334
            List<JTypeMirror> comps = new ArrayList<>(t.getComponents());
1✔
1335
            boolean change = false;
1✔
1336
            for (int i = 0; i < comps.size(); i++) {
1✔
1337
                JTypeMirror ci = comps.get(i);
1✔
1338
                JTypeMirror proj = ci.acceptVisitor(this, recursionStop);
1✔
1339
                if (proj == NO_DOWN_PROJECTION) {
1!
1340
                    return NO_DOWN_PROJECTION;
×
1341
                } else {
1342
                    comps.set(i, proj);
1✔
1343
                    if (ci != proj) {
1!
1344
                        change = true;
×
1345
                    }
1346
                }
1347
            }
1348
            return change ? t.getTypeSystem().glb(comps) : t;
1!
1349
        }
1350

1351
        @Override
1352
        public JTypeMirror visitArray(JArrayType t, RecursionStop recursionStop) {
1353
            JTypeMirror comp2 = t.getComponentType().acceptVisitor(this, recursionStop);
1✔
1354
            return comp2 == NO_DOWN_PROJECTION
1!
1355
                   ? NO_DOWN_PROJECTION
×
1356
                   : comp2 == t.getComponentType()
1!
1357
                     ? t : t.getTypeSystem().arrayType(comp2);
1✔
1358
        }
1359

1360
        @Override
1361
        public JTypeMirror visitSentinel(JTypeMirror t, RecursionStop recursionStop) {
1362
            return t;
1✔
1363
        }
1364
    }
1365

1366
    // </editor-fold>
1367

1368
    // <editor-fold  defaultstate="collapsed" desc="Overriding">
1369

1370
    /**
1371
     * Returns true if m1 is return-type substitutable with m2. The notion of return-type-substitutability
1372
     * supports covariant returns, that is, the specialization of the return type to a subtype.
1373
     *
1374
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.5
1375
     */
1376
    public static boolean isReturnTypeSubstitutable(JMethodSig m1, JMethodSig m2) {
1377

1378
        JTypeMirror r1 = m1.getReturnType();
1✔
1379
        JTypeMirror r2 = m2.getReturnType();
1✔
1380

1381
        if (r1 == r1.getTypeSystem().NO_TYPE) {
1✔
1382
            return r1 == r2;
1!
1383
        }
1384

1385
        if (r1.isPrimitive()) {
1✔
1386
            return r1 == r2;
1!
1387
        }
1388

1389
        JMethodSig m1Prime = adaptForTypeParameters(m1, m2);
1✔
1390
        return m1Prime != null && isConvertible(m1Prime.getReturnType(), r2) != Convertibility.NEVER
1!
1391
                || !haveSameSignature(m1, m2) && isSameType(r1, r2.getErasure());
1!
1392
    }
1393

1394
    /**
1395
     * Adapt m1 to the type parameters of m2. Returns null if that's not possible.
1396
     *
1397
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.4
1398
     *
1399
     * <p>Note that the type parameters of m1 are not replaced, only
1400
     * their occurrences in the rest of the signature.
1401
     */
1402
    static @Nullable JMethodSig adaptForTypeParameters(JMethodSig m1, JMethodSig m2) {
1403
        if (haveSameTypeParams(m1, m2)) {
1!
1404
            return m1.subst(mapping(m1.getTypeParameters(), m2.getTypeParameters()));
1✔
1405
        }
1406

1407
        return null;
×
1408
    }
1409

1410
    public static boolean haveSameTypeParams(JMethodSig m1, JMethodSig m2) {
1411
        List<JTypeVar> tp1 = m1.getTypeParameters();
1✔
1412
        List<JTypeVar> tp2 = m2.getTypeParameters();
1✔
1413
        if (tp1.size() != tp2.size()) {
1✔
1414
            return false;
1✔
1415
        }
1416

1417
        if (tp1.isEmpty()) {
1✔
1418
            return true;
1✔
1419
        }
1420

1421
        Substitution mapping = mapping(tp2, tp1);
1✔
1422
        for (int i = 0; i < tp1.size(); i++) {
1✔
1423
            JTypeVar p1 = tp1.get(i);
1✔
1424
            JTypeVar p2 = tp2.get(i);
1✔
1425

1426
            if (!isSameType(p1.getUpperBound(), subst(p2.getUpperBound(), mapping))) {
1✔
1427
                return false;
1✔
1428
            }
1429
        }
1430

1431
        return true;
1✔
1432
    }
1433

1434
    /**
1435
     * Two method signatures m1 and m2 are override-equivalent iff either
1436
     * m1 is a subsignature of m2 or m2 is a subsignature of m1. This does
1437
     * not look at the origin of the methods (their declaring class).
1438
     *
1439
     * <p>This is a prerequisite for one method to override the other,
1440
     * but not the only condition. See {@link #overrides(JMethodSig, JMethodSig, JTypeMirror)}.
1441
     *
1442
     * See <a href="https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.2">JLS§8</a>
1443
     */
1444
    public static boolean areOverrideEquivalent(JMethodSig m1, JMethodSig m2) {
1445
        // This method is a very hot spot as it is used to prune shadowed/overridden/hidden
1446
        // methods from overload candidates before overload resolution.
1447
        // Any optimization makes a big impact.
1448
        if (m1.getArity() != m2.getArity()) {
1✔
1449
            return false; // easy case
1✔
1450
        } else if (m1 == m2) {
1!
1451
            return true;
×
1452
        } else if (!m1.getName().equals(m2.getName())) {
1!
1453
            // note: most call sites statically know this is true
1454
            // profile to figure out whether this matters
1455
            return false;
×
1456
        }
1457

1458
        List<JTypeMirror> formals1 = m1.getFormalParameters();
1✔
1459
        List<JTypeMirror> formals2 = m2.getFormalParameters();
1✔
1460
        for (int i = 0; i < formals1.size(); i++) {
1✔
1461
            JTypeMirror fi1 = formals1.get(i);
1✔
1462
            JTypeMirror fi2 = formals2.get(i);
1✔
1463

1464
            if (!isSameType(fi1.getErasure(), fi2.getErasure())) {
1✔
1465
                return false;
1✔
1466
            }
1467
        }
1468

1469
        // a non-generic method may override a generic one
1470
        return !m1.isGeneric() || !m2.isGeneric()
1!
1471
            // if both are generic, they must have the same type params
1472
            || haveSameTypeParams(m1, m2);
1✔
1473
    }
1474

1475
    /**
1476
     * The signature of a method m1 is a subsignature of the signature of a method m2 if either:
1477
     * - m2 has the same signature as m1, or
1478
     * - the signature of m1 is the same as the erasure (§4.6) of the signature of m2.
1479
     */
1480
    public static boolean isSubSignature(JMethodSig m1, JMethodSig m2) {
1481
        // prune easy cases
1482
        if (m1.getArity() != m2.getArity() || !m1.getName().equals(m2.getName())) {
1✔
1483
            return false;
1✔
1484
        }
1485
        boolean m1Gen = m1.isGeneric();
1✔
1486
        boolean m2Gen = m2.isGeneric();
1✔
1487
        if (m1Gen ^ m2Gen) {
1✔
1488
            if (m1Gen) {
1!
1489
                return false; // this test is asymmetric
×
1490
            } else {
1491
                m2 = m2.getErasure();
1✔
1492
            }
1493
        }
1494
        return haveSameSignature(m1, m2);
1✔
1495
    }
1496

1497
    /**
1498
     * Two methods or constructors, M and N, have the same signature if
1499
     * they have the same name, the same type parameters (if any) (§8.4.4),
1500
     * and, after adapting the formal parameter types of N to the the type
1501
     * parameters of M, the same formal parameter types.
1502
     *
1503
     * Thrown exceptions are not part of the signature of a method.
1504
     */
1505
    private static boolean haveSameSignature(JMethodSig m1, JMethodSig m2) {
1506
        return m1.getName().equals(m2.getName())
1✔
1507
                && m1.getArity() == m2.getArity()
1✔
1508
                && haveSameTypeParams(m1, m2)
1✔
1509
                && areSameTypes(m1.getFormalParameters(),
1✔
1510
                            m2.getFormalParameters(),
1✔
1511
                            Substitution.mapping(m2.getTypeParameters(), m1.getTypeParameters()));
1✔
1512
    }
1513

1514
    /**
1515
     * Returns true if m1 overrides m2, when both are view as members of
1516
     * class origin. m1 and m2 may be declared in supertypes of origin,
1517
     * possibly unrelated (default methods), which is why we need that
1518
     * third parameter. By convention a method overrides itself.
1519
     *
1520
     * <p>This method ignores the static modifier. If both methods are
1521
     * static, then this method tests for <i>hiding</i>. Otherwise, this
1522
     * method properly tests for overriding. Note that it is an error for
1523
     * a static method to override an instance method, or the reverse.
1524
     */
1525
    public static boolean overrides(JMethodSig m1, JMethodSig m2, JTypeMirror origin) {
1526

1527
        if (m1.isConstructor() || m2.isConstructor()) {
1!
1528
            return m1.equals(m2); // "by convention a method overrides itself"
1✔
1529
        }
1530

1531
        JTypeMirror m1Owner = m1.getDeclaringType();
1✔
1532
        JClassType m2Owner = (JClassType) m2.getDeclaringType();
1✔
1533

1534
        if (isOverridableIn(m2, m1Owner.getSymbol())) {
1✔
1535
            JClassType m2AsM1Supertype = (JClassType) m1Owner.getAsSuper(m2Owner.getSymbol());
1✔
1536
            if (m2AsM1Supertype != null) {
1✔
1537
                JMethodSig m2Prime = m2AsM1Supertype.getDeclaredMethod(m2.getSymbol());
1✔
1538
                assert m2Prime != null;
1!
1539
                if (isSubSignature(m1, m2Prime)) {
1✔
1540
                    return true;
1✔
1541
                }
1542
            }
1543
        }
1544

1545
        // todo that is very weird
1546
        if (m1.isAbstract()
1✔
1547
            || !m2.isAbstract() && !m2.getSymbol().isDefaultMethod()
1!
1548
            || !isOverridableIn(m2, origin.getSymbol())
1!
1549
            || !(m1Owner instanceof JClassType)) {
1550
            return false;
1✔
1551
        }
1552

1553
        JTypeMirror m1AsSuper = origin.getAsSuper(((JClassType) m1Owner).getSymbol());
1✔
1554
        JTypeMirror m2AsSuper = origin.getAsSuper(m2Owner.getSymbol());
1✔
1555
        if (m1AsSuper instanceof JClassType && m2AsSuper instanceof JClassType) {
1!
1556
            m1 = ((JClassType) m1AsSuper).getDeclaredMethod(m1.getSymbol());
1✔
1557
            m2 = ((JClassType) m2AsSuper).getDeclaredMethod(m2.getSymbol());
1✔
1558
            assert m1 != null && m2 != null;
1!
1559
            return isSubSignature(m1, m2);
1✔
1560
        }
1561
        return false;
1✔
1562
    }
1563

1564
    /**
1565
     * Returns true if both methods override the same method of a common supertype.
1566
     */
1567
    public static boolean overrideSameMethod(JMethodSig m1, JMethodSig m2) {
1568
        if (Objects.equals(m1.getSymbol(), m2.getSymbol())) {
1✔
1569
            return true;
1✔
1570
        }
1571
        if (!haveSameSignature(m1, m2)) {
1✔
1572
            return false;
1✔
1573
        }
1574
        JTypeMirror declaringType1 = m1.getDeclaringType();
1✔
1575
        JTypeMirror declaringType2 = m2.getDeclaringType();
1✔
1576
        return declaringType2.getSuperTypeSet().stream().anyMatch(st ->
1✔
1577
            TypeTestUtil.isA(st, declaringType1) && st.streamDeclaredMethods(
1✔
1578
                method -> method.nameEquals(m1.getName())
1✔
1579
                    && method.getFormalParameters().equals(m1.getSymbol().getFormalParameters())
1✔
1580
            ).findAny().isPresent()
1✔
1581
        );
1582
    }
1583

1584
    private static boolean isOverridableIn(JMethodSig m, JTypeDeclSymbol origin) {
1585
        return isOverridableIn(m.getSymbol(), origin);
1✔
1586
    }
1587

1588
    /**
1589
     * Returns true if the given method can be overridden in the origin
1590
     * class. This only checks access modifiers and not eg whether the
1591
     * method is final or static. Regardless of whether the method is
1592
     * final it is overridden - whether this is a compile error or not
1593
     * is another matter.
1594
     *
1595
     * <p>Like {@link #overrides(JMethodSig, JMethodSig, JTypeMirror)},
1596
     * this does not check the static modifier, and tests for hiding
1597
     * if the method is static.
1598
     *
1599
     * @param m      Method to test
1600
     * @param origin Site of the potential override
1601
     */
1602
    public static boolean isOverridableIn(JExecutableSymbol m, JTypeDeclSymbol origin) {
1603
        if (m instanceof JConstructorSymbol) {
1!
1604
            return false;
×
1605
        }
1606

1607
        final int accessFlags = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
1✔
1608

1609
        // JLS 8.4.6.1
1610
        switch (m.getModifiers() & accessFlags) {
1✔
1611
        case Modifier.PUBLIC:
1612
            return true;
1✔
1613
        case Modifier.PROTECTED:
1614
            return !origin.isInterface();
1✔
1615
        case 0:
1616
            // package private
1617
            return
1✔
1618
                m.getPackageName().equals(origin.getPackageName())
1✔
1619
                    && !origin.isInterface();
1!
1620
        default:
1621
            // private
1622
            return false;
1✔
1623
        }
1624
    }
1625

1626
    // </editor-fold>
1627

1628
    // <editor-fold  defaultstate="collapsed" desc="SAM types">
1629

1630
    /*
1631
     * Function types of SAM (single-abstract-method) types.
1632
     *
1633
     * See https://docs.oracle.com/javase/specs/jls/se11/html/jls-9.html#jls-9.9
1634
     */
1635

1636

1637
    /**
1638
     * Returns the non-wildcard parameterization of the given functional
1639
     * interface type. Returns null if such a parameterization does not
1640
     * exist.
1641
     *
1642
     * <p>This is used to remove wildcards from the type of a functional
1643
     * interface.
1644
     *
1645
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-9.html#jls-9.9
1646
     *
1647
     * @param type A parameterized functional interface type
1648
     */
1649
    public static @Nullable JClassType nonWildcardParameterization(@NonNull JClassType type) {
1650
        TypeSystem ts = type.getTypeSystem();
1✔
1651

1652
        List<JTypeMirror> targs = type.getTypeArgs();
1✔
1653
        if (targs.stream().noneMatch(it -> it instanceof JWildcardType)) {
1✔
1654
            return type;
1✔
1655
        }
1656

1657
        List<JTypeVar> tparams = type.getFormalTypeParams();
1✔
1658
        List<JTypeMirror> newArgs = new ArrayList<>();
1✔
1659

1660
        for (int i = 0; i < tparams.size(); i++) {
1✔
1661
            JTypeMirror ai = targs.get(i);
1✔
1662
            if (ai instanceof JWildcardType) {
1✔
1663
                JTypeVar pi = tparams.get(i);
1✔
1664
                JTypeMirror bi = pi.getUpperBound();
1✔
1665
                if (mentionsAny(bi, new HashSet<>(tparams))) {
1!
1666
                    return null;
×
1667
                }
1668

1669
                JWildcardType ai2 = (JWildcardType) ai;
1✔
1670

1671
                if (ai2.isUnbounded()) {
1✔
1672
                    newArgs.add(bi);
1✔
1673
                } else if (ai2.isUpperBound()) {
1✔
1674
                    newArgs.add(ts.glb(Arrays.asList(ai2.asUpperBound(), bi)));
1✔
1675
                } else { // lower bound
1676
                    newArgs.add(ai2.asLowerBound());
1✔
1677
                }
1678

1679
            } else {
1✔
1680
                newArgs.add(ai);
1✔
1681
            }
1682

1683
        }
1684

1685
        return type.withTypeArguments(newArgs);
1✔
1686
    }
1687

1688
    /**
1689
     * Finds the method of the given type that can be overridden as a lambda
1690
     * expression. That is more complicated than "the unique abstract method",
1691
     * it's actually a function type which can override all abstract methods
1692
     * of the SAM at once.
1693
     *
1694
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-9.html#jls-9.9
1695
     *
1696
     * <p>If the parameter is not mappable to a class type with {@link #asClassType(JTypeMirror)},
1697
     * or if the functional method does not exist, returns null.
1698
     */
1699
    public static @Nullable JMethodSig findFunctionalInterfaceMethod(@Nullable JTypeMirror type) {
1700
        JClassType candidateSam = asClassType(type);
1✔
1701
        if (candidateSam == null) {
1✔
1702
            return null;
1✔
1703
        }
1704

1705
        if (candidateSam.isParameterizedType()) {
1✔
1706
            return findFunctionTypeImpl(nonWildcardParameterization(candidateSam));
1✔
1707
        } else if (candidateSam.isRaw()) {
1✔
1708
            //  The function type of the raw type of a generic functional
1709
            //  interface I<...> is the erasure of the function type of the generic functional interface I<...>.
1710
            JMethodSig fun = findFunctionTypeImpl(candidateSam.getGenericTypeDeclaration());
1✔
1711
            return fun == null ? null : fun.getErasure();
1!
1712
        } else {
1713
            return findFunctionTypeImpl(candidateSam);
1✔
1714
        }
1715
    }
1716

1717
    /**
1718
     * Returns t if it is a class or interface type. If it is an intersection type,
1719
     * returns the induced class or interface type. Returns null otherwise, including
1720
     * if the parameter is null.
1721
     */
1722
    public static @Nullable JClassType asClassType(@Nullable JTypeMirror t) {
1723
        if (t instanceof JClassType) {
1✔
1724
            return (JClassType) t;
1✔
1725
        } else if (t instanceof JIntersectionType) {
1✔
1726
            return ((JIntersectionType) t).getInducedClassType();
1✔
1727
        }
1728
        return null;
1✔
1729
    }
1730

1731
    private static @Nullable JMethodSig findFunctionTypeImpl(@Nullable JClassType candidateSam) {
1732

1733
        if (candidateSam == null || !candidateSam.isInterface() || candidateSam.getSymbol().isAnnotation()) {
1!
1734
            return null;
1✔
1735
        }
1736

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

1741

1742
        List<JMethodSig> candidates = new ArrayList<>();
1✔
1743
        for (Entry<String, List<JMethodSig>> entry : relevantMethods.entrySet()) {
1✔
1744
            for (JMethodSig sig : entry.getValue()) {
1✔
1745
                if (sig.isAbstract()) {
1✔
1746
                    candidates.add(sig);
1✔
1747
                }
1748
            }
1✔
1749
        }
1✔
1750

1751
        if (candidates.isEmpty()) {
1✔
1752
            return null;
1✔
1753
        } else if (candidates.size() == 1) {
1✔
1754
            return candidates.get(0);
1✔
1755
        }
1756

1757
        JMethodSig currentBest = null;
1✔
1758

1759
        nextCandidate:
1760
        for (int i = 0; i < candidates.size(); i++) {
1✔
1761
            JMethodSig cand = candidates.get(i);
1✔
1762

1763
            for (JMethodSig other : candidates) {
1!
1764
                if (!isSubSignature(cand, other)
1✔
1765
                    || !isReturnTypeSubstitutable(cand, other)) {
1!
1766
                    continue nextCandidate;
×
1767
                }
1768
            }
1✔
1769

1770
            if (currentBest == null) {
×
1771
                currentBest = cand;
×
1772
            } else if (cand.getReturnType().isSubtypeOf(currentBest.getReturnType())) {
×
1773
                // select the most specific return type
1774
                currentBest = cand;
×
1775
            }
1776
        }
1777

1778
        return currentBest;
1✔
1779
    }
1780

1781
    private static boolean isNotDeclaredInClassObject(JMethodSig it) {
1782
        TypeSystem ts = it.getDeclaringType().getTypeSystem();
1✔
1783
        return ts.OBJECT.streamDeclaredMethods(om -> Modifier.isPublic(om.getModifiers())
1✔
1784
            && om.nameEquals(it.getName()))
1✔
1785
                        .noneMatch(om -> haveSameSignature(it, om));
1✔
1786
    }
1787

1788
    // </editor-fold>
1789

1790
    // <editor-fold  defaultstate="collapsed" desc="As super">
1791

1792
    /**
1793
     * @see JTypeMirror#getAsSuper(JClassSymbol)
1794
     */
1795
    public static @Nullable JTypeMirror asSuper(@NonNull JTypeMirror t, @NonNull JClassSymbol s) {
1796

1797
        if (!t.isPrimitive() && s.equals(t.getTypeSystem().OBJECT.getSymbol())) {
1!
1798
            // interface types need to have OBJECT somewhere up their hierarchy
1799
            return t.getTypeSystem().OBJECT;
1✔
1800
        }
1801

1802
        return t.acceptVisitor(AsSuperVisitor.INSTANCE, s);
1✔
1803
    }
1804

1805
    /**
1806
     * Return the base type of t or any of its outer types that starts
1807
     * with the given type.  If none exists, return null.
1808
     */
1809
    public static @Nullable JClassType asOuterSuper(JTypeMirror t, JClassSymbol sym) {
1810
        if (t instanceof JClassType) {
×
1811
            JClassType ct = (JClassType) t;
×
1812
            do {
1813
                JClassType sup = ct.getAsSuper(sym);
×
1814
                if (sup != null) {
×
1815
                    return sup;
×
1816
                }
1817
                ct = ct.getEnclosingType();
×
1818
            } while (ct != null);
×
1819
        } else if (t instanceof JTypeVar || t instanceof JArrayType) {
×
1820
            return (JClassType) t.getAsSuper(sym);
×
1821
        }
1822
        return null;
×
1823
    }
1824

1825
    /**
1826
     * Return the first enclosing type of the container type
1827
     * that has the given symbol in its supertypes. Return null
1828
     * if this is not found.
1829
     */
1830
    public static @Nullable JClassType getReceiverType(@NonNull JClassType containerType, JClassSymbol sym) {
1831
        JClassType ct = containerType;
1✔
1832
        do {
1833
            JClassType sup = ct.getAsSuper(sym);
1✔
1834
            if (sup != null) {
1✔
1835
                return ct;
1✔
1836
            }
1837
            ct = ct.getEnclosingType();
1✔
1838
        } while (ct != null);
1!
1839
        return null;
×
1840
    }
1841

1842
    private static final class AsSuperVisitor implements JTypeVisitor<@Nullable JTypeMirror, JClassSymbol> {
1843

1844
        static final AsSuperVisitor INSTANCE = new AsSuperVisitor();
1✔
1845

1846
        /** Parameter is the erasure of the target. */
1847

1848
        @Override
1849
        public JTypeMirror visit(JTypeMirror t, JClassSymbol target) {
1850
            return null;
1✔
1851
        }
1852

1853
        @Override
1854
        public JTypeMirror visitClass(JClassType t, JClassSymbol target) {
1855
            if (target.equals(t.getSymbol())) {
1✔
1856
                return t;
1✔
1857
            }
1858

1859
            // prefer digging up the superclass first
1860
            JClassType sup = t.getSuperClass();
1✔
1861
            JClassType res = sup == null ? null : (JClassType) sup.acceptVisitor(this, target);
1✔
1862
            if (res != null) {
1✔
1863
                return res;
1✔
1864
            } else {
1865
                // then look in interfaces if possible
1866
                if (target.isInterface() || target.isUnresolved()) {
1✔
1867
                    return firstResult(target, t.getSuperInterfaces());
1✔
1868
                }
1869
            }
1870

1871
            return null;
1✔
1872
        }
1873

1874
        @Override
1875
        public JTypeMirror visitIntersection(JIntersectionType t, JClassSymbol target) {
1876
            return firstResult(target, t.getComponents());
×
1877
        }
1878

1879
        public @Nullable JTypeMirror firstResult(JClassSymbol target, Iterable<? extends JTypeMirror> components) {
1880
            for (JTypeMirror ci : components) {
1✔
1881
                @Nullable JTypeMirror sup = ci.acceptVisitor(this, target);
1✔
1882
                if (sup != null) {
1✔
1883
                    return sup;
1✔
1884
                }
1885
            }
1✔
1886
            return null;
1✔
1887
        }
1888

1889
        @Override
1890
        public JTypeMirror visitTypeVar(JTypeVar t, JClassSymbol target) {
1891
            // caution, infinite recursion
1892
            return t.getUpperBound().acceptVisitor(this, target);
1✔
1893
        }
1894

1895
        @Override
1896
        public JTypeMirror visitArray(JArrayType t, JClassSymbol target) {
1897
            // Cloneable, Serializable, Object
1898
            JTypeMirror decl = t.getTypeSystem().declaration(target);
×
1899
            return t.isSubtypeOf(decl) ? decl : null;
×
1900
        }
1901
    }
1902

1903
    // </editor-fold>
1904

1905
    // <editor-fold  defaultstate="collapsed" desc="LUB/GLB">
1906

1907
    /**
1908
     * Returns a subset S of the parameter, whose components have no
1909
     * strict supertype in S.
1910
     *
1911
     * <pre>{@code
1912
     * S = { V | V in set, and for all W ≠ V in set, it is not the case that W <: V }
1913
     * }</pre>
1914
     */
1915
    public static Set<JTypeMirror> mostSpecific(Collection<? extends JTypeMirror> set) {
1916
        Set<JTypeMirror> result = new LinkedHashSet<>(set.size());
1✔
1917

1918
        // Notice that this loop needs a well-behaved subtyping relation,
1919
        // i.e. antisymmetric: A <: B && A != B implies not(B <: A)
1920
        // This is not the case if we include unchecked conversion in there,
1921
        // or special provisions for unresolved types.
1922
        vLoop:
1923
        for (JTypeMirror v : set) {
1✔
1924
            for (JTypeMirror w : set) {
1✔
1925
                if (!w.equals(v) && !hasUnresolvedSymbolOrArray(w)) {
1✔
1926
                    Convertibility isConvertible = isConvertibleNoCapture(w, v);
1✔
1927
                    if (isConvertible.bySubtyping()
1✔
1928
                        // This last case covers unchecked conversion. It is made antisymmetric by the
1929
                        // test for a symbol. eg |G| <~> G<?> so it would fail.
1930
                        // However, |G| ~> S if |G| <: |S|, so we should consider |G| more specific than S.
1931
                        || isConvertible.withoutWarnings() && !Objects.equals(w.getSymbol(), v.getSymbol())) {
1✔
1932
                        continue vLoop;
1✔
1933
                    }
1934
                }
1935
            }
1✔
1936
            result.add(v);
1✔
1937
        }
1✔
1938
        return result;
1✔
1939
    }
1940

1941
    // </editor-fold>
1942

1943
    /**
1944
     * Returns the components of t if it is an intersection type,
1945
     * otherwise returns t.
1946
     */
1947
    public static List<JTypeMirror> asList(JTypeMirror t) {
1948
        if (t instanceof JIntersectionType) {
1✔
1949
            return ((JIntersectionType) t).getComponents();
1✔
1950
        } else {
1951
            return Collections.singletonList(t);
1✔
1952
        }
1953
    }
1954

1955
    /** Returns a list with the erasures of the given types, may be unmodifiable. */
1956
    public static List<JTypeMirror> erase(Collection<? extends JTypeMirror> ts) {
1957
        return CollectionUtil.map(ts, JTypeMirror::getErasure);
1✔
1958
    }
1959

1960
    // <editor-fold  defaultstate="collapsed" desc="Mentions">
1961

1962

1963
    public static boolean mentions(@NonNull JTypeVisitable type, @NonNull InferenceVar parent) {
1964
        return type.acceptVisitor(MentionsVisitor.INSTANCE, Collections.singleton(parent));
1✔
1965
    }
1966

1967
    public static boolean mentionsAny(JTypeVisitable t, Collection<? extends SubstVar> vars) {
1968
        return !vars.isEmpty() && t.acceptVisitor(MentionsVisitor.INSTANCE, vars);
1✔
1969
    }
1970

1971

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

1974
        static final MentionsVisitor INSTANCE = new MentionsVisitor();
1✔
1975

1976
        @Override
1977
        public Boolean visit(JTypeMirror t, Collection<? extends JTypeMirror> targets) {
1978
            return false;
1✔
1979
        }
1980

1981
        @Override
1982
        public Boolean visitTypeVar(JTypeVar t, Collection<? extends JTypeMirror> targets) {
1983
            return targets.contains(t);
1✔
1984
        }
1985

1986
        @Override
1987
        public Boolean visitInferenceVar(InferenceVar t, Collection<? extends JTypeMirror> targets) {
1988
            return targets.contains(t);
1✔
1989
        }
1990

1991
        @Override
1992
        public Boolean visitWildcard(JWildcardType t, Collection<? extends JTypeMirror> targets) {
1993
            return t.getBound().acceptVisitor(this, targets);
1✔
1994
        }
1995

1996
        @Override
1997
        public Boolean visitMethodType(JMethodSig t, Collection<? extends JTypeMirror> targets) {
1998
            if (t.getReturnType().acceptVisitor(this, targets)) {
1✔
1999
                return true;
1✔
2000
            }
2001
            for (JTypeMirror fi : t.getFormalParameters()) {
1✔
2002
                if (fi.acceptVisitor(this, targets)) {
1✔
2003
                    return true;
1✔
2004
                }
2005
            }
1✔
2006
            for (JTypeMirror ti : t.getThrownExceptions()) {
1✔
2007
                if (ti.acceptVisitor(this, targets)) {
1!
2008
                    return true;
×
2009
                }
2010
            }
1✔
2011
            return false;
1✔
2012
        }
2013

2014
        @Override
2015
        public Boolean visitClass(JClassType t, Collection<? extends JTypeMirror> targets) {
2016
            JClassType encl = t.getEnclosingType();
1✔
2017
            if (encl != null && encl.acceptVisitor(this, targets)) {
1✔
2018
                return true;
1✔
2019
            }
2020

2021
            for (JTypeMirror typeArg : t.getTypeArgs()) {
1✔
2022
                if (typeArg.acceptVisitor(this, targets)) {
1✔
2023
                    return true;
1✔
2024
                }
2025
            }
1✔
2026

2027
            return false;
1✔
2028
        }
2029

2030
        @Override
2031
        public Boolean visitIntersection(JIntersectionType t, Collection<? extends JTypeMirror> targets) {
2032
            for (JTypeMirror comp : t.getComponents()) {
1✔
2033
                if (comp.acceptVisitor(this, targets)) {
1!
2034
                    return true;
×
2035
                }
2036
            }
1✔
2037
            return false;
1✔
2038
        }
2039

2040
        @Override
2041
        public Boolean visitArray(JArrayType t, Collection<? extends JTypeMirror> targets) {
2042
            return t.getComponentType().acceptVisitor(this, targets);
1✔
2043
        }
2044
    }
2045

2046
    // </editor-fold>
2047

2048
    // <editor-fold  defaultstate="collapsed" desc="Accessibility utils">
2049

2050

2051
    public static Predicate<JMethodSymbol> accessibleMethodFilter(String name, @NonNull JClassSymbol symbol) {
2052
        return it -> it.nameEquals(name) && isAccessible(it, symbol);
1✔
2053
    }
2054

2055
    public static Iterable<JMethodSig> lazyFilterAccessible(List<JMethodSig> visible, @NonNull JClassSymbol accessSite) {
2056
        return () -> IteratorUtil.filter(visible.iterator(), it -> isAccessible(it.getSymbol(), accessSite));
1✔
2057
    }
2058

2059
    public static List<JMethodSig> filterAccessible(List<JMethodSig> visible, @NonNull JClassSymbol accessSite) {
2060
        return CollectionUtil.mapNotNull(visible, m -> isAccessible(m.getSymbol(), accessSite) ? m : null);
1!
2061
    }
2062

2063
    /**
2064
     * Methods and fields of a type variable come from its upper bound, which must be captured.
2065
     * Capturing a type var does NOT capture its upper bound, so we must treat this
2066
     * case here.
2067
     */
2068
    public static JTypeMirror getMemberSource(JTypeMirror t) {
2069
        if (t instanceof JTypeVar) {
1✔
2070
            JTypeVar tv = (JTypeVar) t;
1✔
2071
            return capture(tv.getUpperBound());
1✔
2072
        }
2073
        return capture(t);
1✔
2074
    }
2075

2076
    public static List<JMethodSig> getMethodsOf(JTypeMirror type, String name, boolean staticOnly, @NonNull JClassSymbol enclosing) {
2077
        if (staticOnly && type.isInterface()) {
1✔
2078
            // static methods, start on interface
2079
            // static interface methods are not inherited
2080
            return type.streamDeclaredMethods(staticMethodFilter(name, true, enclosing)).collect(Collectors.toList());
1✔
2081
        } else if (staticOnly) {
1✔
2082
            // static methods, doesn't start on interface
2083
            // -> ignore non-static, ignore any that are interfaces
2084
            return type.streamMethods(staticMethodFilter(name, false, enclosing)).collect(OverloadSet.collectMostSpecific(type));
1✔
2085
        } else {
2086
            return type.streamMethods(methodFilter(name, enclosing))
1✔
2087
                       .collect(OverloadSet.collectMostSpecific(type));
1✔
2088
        }
2089
    }
2090

2091
    private static @NonNull Predicate<JMethodSymbol> methodFilter(String name, @NonNull JClassSymbol enclosing) {
2092
        return it -> isAccessibleWithName(name, enclosing, it);
1✔
2093
    }
2094

2095
    private static @NonNull Predicate<JMethodSymbol> staticMethodFilter(String name, boolean acceptItfs, @NonNull JClassSymbol enclosing) {
2096
        return it -> Modifier.isStatic(it.getModifiers())
1✔
2097
            && (acceptItfs || !it.getEnclosingClass().isInterface())
1✔
2098
            && isAccessibleWithName(name, enclosing, it);
1✔
2099
    }
2100

2101
    private static boolean isAccessibleWithName(String name, @NonNull JClassSymbol enclosing, JMethodSymbol m) {
2102
        return m.nameEquals(name) && isAccessible(m, enclosing);
1✔
2103
    }
2104

2105

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

2109
        int mods = method.getModifiers();
1✔
2110
        if (Modifier.isPublic(mods)) {
1✔
2111
            return true;
1✔
2112
        }
2113

2114
        JClassSymbol owner = method.getEnclosingClass();
1✔
2115

2116
        if (Modifier.isPrivate(mods)) {
1✔
2117
            return ctx.getNestRoot().equals(owner.getNestRoot());
1✔
2118
        }
2119

2120
        return ctx.getPackageName().equals(owner.getPackageName())
1✔
2121
            // we can exclude interfaces because their members are all public
2122
            || Modifier.isProtected(mods) && isSubClassOfNoInterface(ctx, owner);
1✔
2123
    }
2124

2125
    private static boolean isSubClassOfNoInterface(JClassSymbol sub, JClassSymbol symbol) {
2126
        if (symbol.equals(sub)) {
1✔
2127
            return true;
1✔
2128
        }
2129

2130
        JClassSymbol superclass = sub.getSuperclass();
1✔
2131
        return superclass != null && isSubClassOfNoInterface(superclass, symbol);
1✔
2132
    }
2133

2134
    public static NameResolver<FieldSig> getMemberFieldResolver(JTypeMirror c, @NonNull String accessPackageName, @Nullable JClassSymbol access, String name) {
2135
        if (c instanceof JClassType) {
1✔
2136
            // fast path
2137
            return JavaResolvers.getMemberFieldResolver((JClassType) c, accessPackageName, access, name);
1✔
2138
        }
2139

2140
        return c.acceptVisitor(GetFieldVisitor.INSTANCE, new FieldSearchParams(accessPackageName, access, name));
1✔
2141
    }
2142

2143
    private static final class FieldSearchParams {
2144

2145
        private final @NonNull String accessPackageName;
2146
        private final @Nullable JClassSymbol access;
2147
        private final String name;
2148

2149
        FieldSearchParams(@NonNull String accessPackageName, @Nullable JClassSymbol access, String name) {
1✔
2150
            this.accessPackageName = accessPackageName;
1✔
2151
            this.access = access;
1✔
2152
            this.name = name;
1✔
2153
        }
1✔
2154
    }
2155

2156
    private static final class GetFieldVisitor implements JTypeVisitor<NameResolver<FieldSig>, FieldSearchParams> {
2157

2158
        static final GetFieldVisitor INSTANCE = new GetFieldVisitor();
1✔
2159

2160
        @Override
2161
        public NameResolver<FieldSig> visit(JTypeMirror t, FieldSearchParams fieldSearchParams) {
2162
            return CoreResolvers.emptyResolver();
1✔
2163
        }
2164

2165
        @Override
2166
        public NameResolver<FieldSig> visitClass(JClassType t, FieldSearchParams fieldSearchParams) {
2167
            return JavaResolvers.getMemberFieldResolver(t, fieldSearchParams.accessPackageName, fieldSearchParams.access, fieldSearchParams.name);
×
2168
        }
2169

2170
        @Override
2171
        public NameResolver<FieldSig> visitTypeVar(JTypeVar t, FieldSearchParams fieldSearchParams) {
2172
            return t.getUpperBound().acceptVisitor(this, fieldSearchParams);
×
2173
        }
2174

2175
        @Override
2176
        public NameResolver<FieldSig> visitIntersection(JIntersectionType t, FieldSearchParams fieldSearchParams) {
2177
            return NameResolver.composite(
×
2178
                CollectionUtil.map(t.getComponents(), c -> c.acceptVisitor(this, fieldSearchParams))
×
2179
            );
2180
        }
2181

2182
        @Override
2183
        public NameResolver<FieldSig> visitArray(JArrayType t, FieldSearchParams fieldSearchParams) {
2184
            if ("length".equals(fieldSearchParams.name)) {
1!
2185
                return CoreResolvers.singleton("length", t.getTypeSystem().sigOf(t, t.getSymbol().getDeclaredField("length")));
1✔
2186
            }
2187
            return CoreResolvers.emptyResolver();
×
2188
        }
2189
    }
2190

2191
    // </editor-fold>
2192

2193
    // <editor-fold  defaultstate="collapsed" desc="Miscellaneous">
2194

2195
    /**
2196
     * Returns true if both types have a common supertype that is not Object.
2197
     * Primitive types are only related to themselves.
2198
     *
2199
     * @param t Non-null type
2200
     * @param s Non-null type
2201
     *
2202
     * @throws NullPointerException if a parameter is null
2203
     */
2204
    public static boolean areRelated(@NonNull JTypeMirror t, JTypeMirror s) {
2205
        if (t.isPrimitive() || s.isPrimitive()) {
1!
2206
            return s.equals(t);
×
2207
        }
2208
        if (t.equals(s)) {
1✔
2209
            return true;
1✔
2210
        }
2211
        // maybe they have a common supertype
2212
        Set<JTypeMirror> tSupertypes = new HashSet<>(t.getSuperTypeSet());
1✔
2213
        tSupertypes.retainAll(s.getSuperTypeSet());
1✔
2214
        return !tSupertypes.equals(Collections.singleton(t.getTypeSystem().OBJECT));
1✔
2215
    }
2216

2217
    /**
2218
     * Returns true if the type is {@link TypeSystem#UNKNOWN},
2219
     * {@link TypeSystem#ERROR}, or a class type with unresolved
2220
     * symbol.
2221
     *
2222
     * @param t Non-null type
2223
     *
2224
     * @throws NullPointerException if the parameter is null
2225
     */
2226
    public static boolean isUnresolved(@NonNull JTypeMirror t) {
2227
        return isSpecialUnresolved(t) || hasUnresolvedSymbol(t);
1✔
2228
    }
2229

2230
    /**
2231
     * Returns true if the type is {@link TypeSystem#UNKNOWN},
2232
     * or {@link TypeSystem#ERROR}, or a class type with unresolved
2233
     * symbol, or an array of such types.
2234
     *
2235
     * @param t Non-null type
2236
     *
2237
     * @throws NullPointerException if the parameter is null
2238
     */
2239
    public static boolean isUnresolvedOrArray(@NonNull JTypeMirror t) {
2240
        return isSpecialUnresolvedOrArray(t) || hasUnresolvedSymbolOrArray(t);
1!
2241
    }
2242

2243
    /**
2244
     * Returns true if the type is {@link TypeSystem#UNKNOWN},
2245
     * or {@link TypeSystem#ERROR}.
2246
     *
2247
     * @param t Non-null type
2248
     *
2249
     * @throws NullPointerException if the parameter is null
2250
     */
2251
    public static boolean isSpecialUnresolved(@NonNull JTypeMirror t) {
2252
        TypeSystem ts = t.getTypeSystem();
1✔
2253
        return t == ts.UNKNOWN || t == ts.ERROR;
1✔
2254
    }
2255

2256
    /**
2257
     * Returns true if the type is {@link TypeSystem#UNKNOWN},
2258
     * or {@link TypeSystem#ERROR}, or an array of such types.
2259
     *
2260
     * @param t Non-null type
2261
     *
2262
     * @throws NullPointerException if the parameter is null
2263
     */
2264
    public static boolean isSpecialUnresolvedOrArray(@Nullable JTypeMirror t) {
2265
        return t == null
1!
2266
            || isSpecialUnresolved(t)
1✔
2267
            || t instanceof JArrayType && isSpecialUnresolved(((JArrayType) t).getElementType());
1✔
2268
    }
2269

2270
    /**
2271
     * Return true if the argument is a {@link JClassType} with
2272
     * {@linkplain JClassSymbol#isUnresolved() an unresolved symbol}.
2273
     */
2274
    public static boolean hasUnresolvedSymbol(@Nullable JTypeMirror t) {
2275
        return t instanceof JClassType && t.getSymbol().isUnresolved();
1✔
2276
    }
2277

2278
    /**
2279
     * Return true if the argument is a {@link JClassType} with
2280
     * {@linkplain JClassSymbol#isUnresolved() an unresolved symbol},
2281
     * or an array whose element type has an unresolved symbol.
2282
     */
2283
    public static boolean hasUnresolvedSymbolOrArray(@Nullable JTypeMirror t) {
2284
        if (!(t instanceof JClassType)) {
1✔
2285
            return t instanceof JArrayType && hasUnresolvedSymbol(((JArrayType) t).getElementType());
1✔
2286
        }
2287
        return hasUnresolvedSymbol(t);
1✔
2288
    }
2289

2290
    public static boolean isUnresolvedOrNull(@Nullable JTypeMirror t) {
2291
        return t == null || isUnresolved(t);
1!
2292
    }
2293

2294
    public static @Nullable JTypeMirror getArrayComponent(@Nullable JTypeMirror t) {
2295
        return t instanceof JArrayType ? ((JArrayType) t).getComponentType() : null;
1!
2296
    }
2297

2298

2299
    /**
2300
     * Return true if the method is context dependent. That
2301
     * means its return type is influenced by the surrounding
2302
     * context during type inference. Generic constructors
2303
     * are always context dependent.
2304
     *
2305
     * @deprecated Since 7.11.0. Use {@link #isContextDependent(JExecutableSymbol)} instead which is more flexible.
2306
     */
2307
    @Deprecated
2308
    public static boolean isContextDependent(JMethodSig sig) {
2309
        return isContextDependent(sig.getSymbol());
×
2310
    }
2311

2312
    /**
2313
     * Return true if the method is context dependent. That
2314
     * means its return type is influenced by the surrounding
2315
     * context during type inference. Generic constructors
2316
     * are always context dependent.
2317
     */
2318
    public static boolean isContextDependent(JExecutableSymbol symbol) {
2319
        if (symbol.isGeneric() || symbol.getEnclosingClass().isGeneric()) {
1!
2320
            if (symbol instanceof JMethodSymbol) {
1!
2321
                JTypeMirror returnType = ((JMethodSymbol) symbol).getReturnType(EMPTY);
1✔
2322
                return mentionsAny(returnType, symbol.getTypeParameters())
1!
2323
                    || mentionsAny(returnType, symbol.getEnclosingClass().getTypeParameters());
1✔
2324
            }
2325
            // generic ctors are context dependent
2326
            return true;
×
2327
        }
2328
        return false;
1✔
2329
    }
2330
    // </editor-fold>
2331
}
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