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

pmd / pmd / 315

18 Dec 2025 03:00PM UTC coverage: 78.963% (+0.2%) from 78.784%
315

push

github

adangel
[doc] Explain how to build or pull snapshot dependencies for single module builds (#6287)

18491 of 24300 branches covered (76.09%)

Branch coverage included in aggregate %.

40287 of 50137 relevant lines covered (80.35%)

0.81 hits per line

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

86.59
/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprOps.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.internal.infer;
6

7
import static net.sourceforge.pmd.lang.java.types.TypeConversion.capture;
8
import static net.sourceforge.pmd.lang.java.types.internal.InternalMethodTypeItf.cast;
9
import static net.sourceforge.pmd.util.CollectionUtil.listOf;
10

11
import java.util.Collections;
12
import java.util.List;
13
import java.util.function.Predicate;
14
import java.util.function.Supplier;
15
import java.util.stream.Collectors;
16

17
import org.checkerframework.checker.nullness.qual.NonNull;
18
import org.checkerframework.checker.nullness.qual.Nullable;
19

20
import net.sourceforge.pmd.lang.java.ast.JavaNode;
21
import net.sourceforge.pmd.lang.java.symbols.JClassSymbol;
22
import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol;
23
import net.sourceforge.pmd.lang.java.symbols.JTypeDeclSymbol;
24
import net.sourceforge.pmd.lang.java.types.JClassType;
25
import net.sourceforge.pmd.lang.java.types.JMethodSig;
26
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
27
import net.sourceforge.pmd.lang.java.types.JTypeVar;
28
import net.sourceforge.pmd.lang.java.types.Substitution;
29
import net.sourceforge.pmd.lang.java.types.TypeOps;
30
import net.sourceforge.pmd.lang.java.types.TypeSystem;
31
import net.sourceforge.pmd.lang.java.types.TypingContext;
32
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.BranchingMirror;
33
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.FunctionalExprMirror;
34
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.InvocationMirror;
35
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.InvocationMirror.MethodCtDecl;
36
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.LambdaExprMirror;
37
import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.MethodRefMirror;
38
import net.sourceforge.pmd.util.CollectionUtil;
39

40
public final class ExprOps {
1✔
41

42
    private final Infer infer;
43
    private final TypeSystem ts;
44

45
    ExprOps(Infer infer) {
1✔
46
        this.infer = infer;
1✔
47
        this.ts = infer.getTypeSystem();
1✔
48
        assert ts != null;
1!
49
    }
1✔
50

51
    /**
52
     * Returns true if the argument expression is potentially
53
     * compatible with type t, as specified by JLSยง15.12.2.1:
54
     *
55
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.12.1
56
     *
57
     * @param m Method for which the potential applicability is being tested
58
     * @param e Argument expression
59
     * @param t Formal parameter type
60
     */
61
    boolean isPotentiallyCompatible(JMethodSig m, ExprMirror e, JTypeMirror t) {
62
        if (e instanceof BranchingMirror) {
1✔
63
            // A conditional expression (ยง15.25) is potentially compatible with a type if each
64
            // of its second and third operand expressions are potentially compatible with that type.
65

66
            BranchingMirror cond = (BranchingMirror) e;
1✔
67
            return cond.branchesMatch(branch -> isPotentiallyCompatible(m, branch, t));
1✔
68

69
        }
70

71
        boolean isLambdaOrRef = e instanceof FunctionalExprMirror;
1✔
72

73
        if (isLambdaOrRef) {
1✔
74
            if (t instanceof JTypeVar) {
1✔
75
                //  A lambda expression or a method reference expression is potentially compatible with
76
                //  a type variable if the type variable is a type parameter of the candidate method.
77
                return m.getTypeParameters().contains(t);
1✔
78
            }
79
            if (TypeOps.isUnresolved(t)) {
1✔
80
                // Then we will not find a functional interface method.
81
                // Treat the argument as potentially compatible though.
82
                return true;
1✔
83
            }
84
            JMethodSig fun = TypeOps.findFunctionalInterfaceMethod(t);
1✔
85
            if (fun == null) {
1✔
86
                // t is not a functional interface
87
                return false;
1✔
88
            }
89

90
            if (e instanceof LambdaExprMirror) {
1✔
91
                LambdaExprMirror lambda = (LambdaExprMirror) e;
1✔
92
                if (fun.getArity() != lambda.getParamCount()) {
1✔
93
                    return false;
1✔
94
                }
95

96
                boolean expectsVoid = fun.getReturnType() == ts.NO_TYPE;
1✔
97

98
                return expectsVoid && lambda.isVoidCompatible() || lambda.isValueCompatible();
1!
99

100
            } else {
101
                // is method reference
102
                MethodRefMirror mref = (MethodRefMirror) e;
1✔
103
                if (TypeOps.isUnresolved(mref.getTypeToSearch())) {
1✔
104
                    // don't fail if the LHS is not known or not fully known
105
                    return true;
1✔
106
                }
107
                if (mref.isLhsAType() && !mref.isConstructorRef()) {
1✔
108
                    // The method reference expression has the form
109
                    // ReferenceType :: [TypeArguments] Identifier and
110
                    // at least one potentially applicable method is
111
                    // either (i) static and supports arity n, or
112
                    // (ii) not static and supports arity n-1.
113
                    return hasCandidate(mref, fun, false, true)
1✔
114
                        || hasCandidate(mref, fun, true, false);
1✔
115
                } else {
116
                    // The method reference expression has some other form and at least one potentially applicable method is not static.
117
                    return hasCandidate(mref, fun, false, false);
1✔
118
                }
119
            }
120
        }
121

122
        // A class instance creation expression, a method invocation expression, or an expression of
123
        // a standalone form (ยง15.2) is potentially compatible with any type.
124
        // (ie anything else)
125
        return true;
1✔
126
    }
127

128
    private boolean hasCandidate(MethodRefMirror mref, JMethodSig fun, boolean firstParamIsReceiver, boolean expectStatic) {
129
        InvocationMirror asMethodCall = methodRefAsInvocation(mref, fun, firstParamIsReceiver);
1✔
130
        for (JMethodSig cand : asMethodCall.getAccessibleCandidates()) {
1✔
131
            if (cand.isStatic() == expectStatic
1✔
132
                && infer.isPotentiallyApplicable(cand, asMethodCall)) {
1✔
133
                return true;
1✔
134
            }
135
        }
1✔
136
        return false;
1✔
137
    }
138

139
    /**
140
     * Returns true if the the argument expression is pertinent
141
     * to applicability for the potentially applicable method m,
142
     * called at site 'invoc', as specified by JLSยง15.12.2.2:
143
     *
144
     * https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.12.2.2
145
     *
146
     * @param arg        Argument expression
147
     * @param m          Method type
148
     * @param formalType Type of the formal parameter
149
     * @param invoc      Invocation expression
150
     */
151
    static boolean isPertinentToApplicability(ExprMirror arg, JMethodSig m, JTypeMirror formalType, InvocationMirror invoc) {
152
        // An argument expression is considered pertinent to applicability
153
        // for a potentially applicable method m unless it has one of the following forms:
154

155
        if (arg instanceof LambdaExprMirror) {
1✔
156
            LambdaExprMirror lambda = (LambdaExprMirror) arg;
1✔
157

158
            // An implicitly typed lambda expression(ยง 15.27 .1).
159
            if (!lambda.isExplicitlyTyped()) {
1✔
160
                return false;
1✔
161
            }
162

163
            // An explicitly typed lambda expression where at least
164
            // one result expression is not pertinent to applicability.
165
            for (ExprMirror it : lambda.getResultExpressions()) {
1✔
166
                if (!isPertinentToApplicability(it, m, formalType, invoc)) {
1!
167
                    return false;
×
168
                }
169
            }
1✔
170
        }
171

172
        if (arg instanceof MethodRefMirror) {
1✔
173
            // An inexact method reference expression(ยง 15.13 .1).
174
            if (getExactMethod((MethodRefMirror) arg) == null) {
1✔
175
                return false;
1✔
176
            }
177
        }
178

179
        if (arg instanceof FunctionalExprMirror) {
1✔
180
            //  If m is a generic method and the method invocation does
181
            //  not provide explicit type arguments, an explicitly typed
182
            //  lambda expression or an exact method reference expression
183
            //  for which the corresponding target type (as derived from
184
            //  the signature of m) is a type parameter of m.
185
            if (m.isGeneric() && !invoc.getExplicitTypeArguments().isEmpty()
1✔
186
                && m.getTypeParameters().contains(formalType)) {
1!
187
                return false;
×
188
            }
189
        }
190

191
        if (arg instanceof BranchingMirror) {
1✔
192
            // A conditional expression (ยง15.25) is potentially compatible with a type if each
193
            // of its second and third operand expressions are potentially compatible with that type.
194

195
            BranchingMirror cond = (BranchingMirror) arg;
1✔
196
            return cond.branchesMatch(branch -> isPertinentToApplicability(branch, m, formalType, invoc));
1✔
197
        }
198

199
        return true;
1✔
200
    }
201

202

203
    /**
204
     * Returns null if the method reference is inexact.
205
     */
206
    public static @Nullable JMethodSig getExactMethod(MethodRefMirror mref) {
207
        JMethodSig cached = mref.getCachedExactMethod();
1✔
208

209
        if (cached == null) { // inexact
1✔
210
            return null;
1✔
211
        }
212

213
        if (cached.getTypeSystem().UNRESOLVED_METHOD == cached) {
1✔
214
            cached = computeExactMethod(mref);
1✔
215
            mref.setCachedExactMethod(cached); // set to null if inexact, sentinel is UNRESOLVED_METHOD
1✔
216
        }
217

218
        return cached;
1✔
219
    }
220

221
    private static @Nullable JMethodSig computeExactMethod(MethodRefMirror mref) {
222

223

224
        final @Nullable JTypeMirror lhs = mref.getLhsIfType();
1✔
225

226
        List<JMethodSig> accessible;
227

228
        if (mref.isConstructorRef()) {
1✔
229
            if (lhs == null) {
1!
230
                // ct error, already reported as a missing symbol in our system
231
                return null;
×
232
            } else if (lhs.isArray()) {
1✔
233
                // A method reference expression of the form ArrayType :: new is always exact.
234
                // But:  If a method reference expression has the form ArrayType :: new, then ArrayType
235
                // must denote a type that is reifiable (ยง4.7), or a compile-time error occurs.
236
                if (lhs.isReifiable()) {
1!
237
                    JTypeDeclSymbol symbol = lhs.getSymbol();
1✔
238

239
                    assert symbol instanceof JClassSymbol && ((JClassSymbol) symbol).isArray()
1!
240
                        : "Reifiable array should present a symbol! " + lhs;
241

242
                    return lhs.getConstructors().get(0);
1✔
243
                } else {
244
                    // todo compile time error
245
                    return null;
×
246
                }
247
            } else {
248
                if (lhs.isRaw() || !(lhs instanceof JClassType)) {
1!
249
                    return null;
1✔
250
                }
251

252
                accessible = TypeOps.filterAccessible(lhs.getConstructors(),
1✔
253
                                                      mref.getEnclosingType().getSymbol());
1✔
254
            }
255
        } else {
256
            JClassType enclosing = mref.getEnclosingType();
1✔
257
            accessible = mref.getTypeToSearch()
1✔
258
                             .streamMethods(TypeOps.accessibleMethodFilter(mref.getMethodName(), enclosing.getSymbol()))
1✔
259
                             .collect(OverloadSet.collectMostSpecific(enclosing));
1✔
260
        }
261

262
        if (accessible.size() == 1) {
1✔
263
            JMethodSig candidate = accessible.get(0);
1✔
264
            if (candidate.isVarargs()
1!
265
                || candidate.isGeneric() && mref.getExplicitTypeArguments().isEmpty()) {
1✔
266
                return null;
1✔
267
            }
268

269
            candidate = candidate.subst(Substitution.mapping(candidate.getTypeParameters(), mref.getExplicitTypeArguments()));
1✔
270

271
            if (lhs != null && lhs.isRaw()) {
1✔
272
                // can be raw if the method doesn't mention type vars
273
                // of the original owner, ie the erased method is the
274
                // same as the generic method.
275
                JClassType lhsClass = (JClassType) candidate.getDeclaringType();
1✔
276
                JMethodSig unerased = cast(cast(candidate).withOwner(lhsClass.getGenericTypeDeclaration())).originalMethod();
1✔
277
                if (TypeOps.mentionsAny(unerased, lhsClass.getFormalTypeParams())) {
1✔
278
                    return null;
1✔
279
                }
280
            }
281

282
            // For exact method references, the return type is Class<? extends T> (no erasure).
283
            // So it's mref::getTypeToSearch and not mref.getTypeToSearch()::getErasure
284
            return adaptGetClass(candidate, mref::getTypeToSearch);
1✔
285
        } else {
286
            return null;
1✔
287
        }
288
    }
289

290

291
    // for inexact method refs
292
    @Nullable MethodCtDecl findInexactMethodRefCompileTimeDecl(MethodRefMirror mref, JMethodSig targetType) {
293
        // https://docs.oracle.com/javase/specs/jls/se14/html/jls-15.html#jls-15.13.1
294

295
        JTypeMirror lhsIfType = mref.getLhsIfType();
1✔
296
        boolean acceptLowerArity = lhsIfType != null && lhsIfType.isClassOrInterface() && !mref.isConstructorRef();
1!
297

298
        MethodCallSite site1 = infer.newCallSite(methodRefAsInvocation(mref, targetType, false), null);
1✔
299
        site1.setLogging(!acceptLowerArity);
1✔
300
        MethodCtDecl ctd1 = infer.LOG.inContext("Method ref ctdectl search 1 (static) ", () -> infer.determineInvocationTypeOrFail(site1));
1✔
301
        JMethodSig m1 = ctd1.getMethodType();
1✔
302

303
        if (lhsIfType != null && !mref.isConstructorRef()) {
1✔
304
            // then we need to perform two searches, one with arity n, looking for static methods,
305
            // one with n-1, looking for instance methods
306

307
            MethodCtDecl ctd2 = null;
1✔
308
            JMethodSig m2 = ts.UNRESOLVED_METHOD;
1✔
309
            if (!targetType.getFormalParameters().isEmpty()
1✔
310
                && targetType.getFormalParameters().get(0).isSubtypeOf(lhsIfType)) {
1✔
311
                // todo prevent this to add constraints to variables in the target type?
312
                MethodCallSite site2 = infer.newCallSite(methodRefAsInvocation(mref, targetType, true), null);
1✔
313
                site1.setLogging(false);
1✔
314
                ctd2 = infer.LOG.inContext("Method ref ctdectl search 2 (instance) ", () -> infer.determineInvocationTypeOrFail(site2));
1✔
315
                m2 = ctd2.getMethodType();
1✔
316
            }
317

318
            //  If the first search produces a most specific method that is static,
319
            //  and the set of applicable methods produced by the second search
320
            //  contains no non-static methods, then the compile-time declaration
321
            //  is the most specific method of the first search.
322
            if (m1 != ts.UNRESOLVED_METHOD && m1.isStatic() && (m2 == ts.UNRESOLVED_METHOD || m2.isStatic())) {
1!
323
                return ctd1;
1✔
324
            } else if (m2 != ts.UNRESOLVED_METHOD && !m2.isStatic() && (m1 == ts.UNRESOLVED_METHOD || !m1.isStatic())) {
1!
325
                // Otherwise, if the set of applicable methods produced by the
326
                // first search contains no static methods, and the second search
327
                // produces a most specific method that is non-static, then the
328
                // compile-time declaration is the most specific method of the second search.
329
                return ctd2;
1✔
330
            }
331

332
            //  Otherwise, there is no compile-time declaration.
333
            return null;
1✔
334
        } else if (m1 == ts.UNRESOLVED_METHOD || m1.isStatic()) {
1!
335
            // if the most specific applicable method is static, there is no compile-time declaration.
336
            return null;
×
337
        } else {
338
            // Otherwise, the compile-time declaration is the most specific applicable method.
339
            return ctd1;
1✔
340
        }
341
    }
342

343
    static InvocationMirror methodRefAsInvocation(final MethodRefMirror mref, JMethodSig targetType, boolean asInstanceMethod) {
344
        // the arguments are treated as if they were of the type
345
        // of the formal parameters of the candidate
346
        List<JTypeMirror> formals = targetType.getFormalParameters();
1✔
347
        if (asInstanceMethod && !formals.isEmpty()) {
1!
348
            formals = formals.subList(1, formals.size()); // skip first param (receiver)
1✔
349
        }
350

351
        List<ExprMirror> arguments = CollectionUtil.map(
1✔
352
            formals,
353
            fi -> new ExprMirror() {
1✔
354

355
                @Override
356
                public void setInferredType(JTypeMirror mirror) {
357
                    // do nothing
358
                }
1✔
359

360
                @Override
361
                public @Nullable JTypeMirror getInferredType() {
362
                    throw new UnsupportedOperationException();
×
363
                }
364

365
                @Override
366
                public JavaNode getLocation() {
367
                    return mref.getLocation();
1✔
368
                }
369

370
                @Override
371
                public JTypeMirror getStandaloneType() {
372
                    return fi;
1✔
373
                }
374

375
                @Override
376
                public String toString() {
377
                    return "formal : " + fi;
×
378
                }
379

380
                @Override
381
                public TypingContext getTypingContext() {
382
                    return mref.getTypingContext();
×
383
                }
384

385
                @Override
386
                public boolean isEquivalentToUnderlyingAst() {
387
                    throw new UnsupportedOperationException("Cannot invoque isSemanticallyEquivalent on this mirror, it doesn't have a backing AST node: " + this);
×
388
                }
389
            }
390
        );
391

392

393
        return new InvocationMirror() {
1✔
394

395
            private MethodCtDecl mt;
396

397
            @Override
398
            public JavaNode getLocation() {
399
                return mref.getLocation();
×
400
            }
401

402
            @Override
403
            public CharSequence getLocationText() {
404
                return mref.getLocationText() + " (viewed as method call)";
×
405
            }
406

407
            @Override
408
            public Iterable<JMethodSig> getAccessibleCandidates() {
409
                return ExprOps.getAccessibleCandidates(mref, asInstanceMethod, targetType);
1✔
410
            }
411

412
            @Override
413
            public JTypeMirror getErasedReceiverType() {
414
                return mref.getTypeToSearch().getErasure();
×
415
            }
416

417
            @Override
418
            public @Nullable JTypeMirror getReceiverType() {
419
                return mref.getTypeToSearch();
1✔
420
            }
421

422
            @Override
423
            public List<JTypeMirror> getExplicitTypeArguments() {
424
                return mref.getExplicitTypeArguments();
1✔
425
            }
426

427
            @Override
428
            public JavaNode getExplicitTargLoc(int i) {
429
                throw new IndexOutOfBoundsException();
×
430
            }
431

432
            @Override
433
            public String getName() {
434
                return mref.getMethodName();
×
435
            }
436

437
            @Override
438
            public List<ExprMirror> getArgumentExpressions() {
439
                return arguments;
1✔
440
            }
441

442
            @Override
443
            public int getArgumentCount() {
444
                return arguments.size();
1✔
445
            }
446

447
            @Override
448
            public void setCompileTimeDecl(MethodCtDecl methodType) {
449
                this.mt = methodType;
1✔
450
            }
1✔
451

452
            @Override
453
            public @Nullable MethodCtDecl getCtDecl() {
454
                return mt;
1✔
455
            }
456

457
            JTypeMirror inferred;
458

459
            @Override
460
            public void setInferredType(JTypeMirror mirror) {
461
                // todo is this useful for method refs?
462
                inferred = mirror;
1✔
463
            }
1✔
464

465
            @Override
466
            public JTypeMirror getInferredType() {
467
                return inferred;
×
468
            }
469

470
            @Override
471
            public @NonNull JClassType getEnclosingType() {
472
                return mref.getEnclosingType();
×
473
            }
474

475
            @Override
476
            public String toString() {
477
                return "Method ref adapter (for " + mref + ")";
×
478
            }
479

480
            @Override
481
            public TypingContext getTypingContext() {
482
                return mref.getTypingContext();
×
483
            }
484

485
            @Override
486
            public boolean isEquivalentToUnderlyingAst() {
487
                throw new UnsupportedOperationException("Cannot invoque isSemanticallyEquivalent on this mirror, it doesn't have a backing AST node: " + this);
×
488
            }
489
        };
490
    }
491

492
    private static Iterable<JMethodSig> getAccessibleCandidates(MethodRefMirror mref, boolean asInstanceMethod, JMethodSig targetType) {
493
        JMethodSig exactMethod = getExactMethod(mref);
1✔
494
        if (exactMethod != null) {
1✔
495
            return Collections.singletonList(exactMethod);
1✔
496
        } else {
497
            final JTypeMirror actualTypeToSearch;
498
            {
499
                JTypeMirror typeToSearch = mref.getTypeToSearch();
1✔
500
                if (typeToSearch.isArray() && mref.isConstructorRef()) {
1!
501
                    // ArrayType :: new
502
                    return typeToSearch.getConstructors();
×
503
                } else if (typeToSearch instanceof JClassType && mref.isConstructorRef()) {
1!
504
                    // ClassType :: [TypeArguments] new
505
                    // TODO treatment of raw constructors is whacky
506
                    return TypeOps.lazyFilterAccessible(typeToSearch.getConstructors(), mref.getEnclosingType().getSymbol());
1✔
507
                }
508

509
                if (asInstanceMethod && typeToSearch.isRaw() && typeToSearch instanceof JClassType
1!
510
                    && targetType.getArity() > 0) {
1!
511
                    //  In the second search, if P1, ..., Pn is not empty
512
                    //  and P1 is a subtype of ReferenceType, then the
513
                    //  method reference expression is treated as if it were
514
                    //  a method invocation expression with argument expressions
515
                    //  of types P2, ..., Pn. If ReferenceType is a raw type,
516
                    //  and there exists a parameterization of this type, G<...>,
517
                    //  that is a supertype of P1, the type to search is the result
518
                    //  of capture conversion (ยง5.1.10) applied to G<...>; otherwise,
519
                    //  the type to search is the same as the type of the first search.
520

521
                    JClassType type = (JClassType) typeToSearch;
1✔
522
                    JTypeMirror p1 = targetType.getFormalParameters().get(0);
1✔
523
                    JTypeMirror asSuper = p1.getAsSuper(type.getSymbol());
1✔
524
                    if (asSuper != null && asSuper.isParameterizedType()) {
1!
525
                        typeToSearch = capture(asSuper);
1✔
526
                    }
527
                }
528
                actualTypeToSearch = typeToSearch;
1✔
529
            }
530

531
            // Primary :: [TypeArguments] Identifier
532
            // ExpressionName :: [TypeArguments] Identifier
533
            // super :: [TypeArguments] Identifier
534
            // TypeName.super :: [TypeArguments] Identifier
535
            // ReferenceType :: [TypeArguments] Identifier
536

537
            Predicate<JMethodSymbol> prefilter = TypeOps.accessibleMethodFilter(mref.getMethodName(), mref.getEnclosingType().getSymbol());
1✔
538
            return actualTypeToSearch.streamMethods(prefilter).collect(Collectors.toList());
1✔
539
        }
540
    }
541

542

543

544
    /**
545
     * Calls to {@link Object#getClass()} on a type {@code T} have type
546
     * {@code Class<? extends |T|>}. If the selected method is that method, then
547
     * we need to replace its return type (the symbol has return type {@link Object}).
548
     *
549
     * <p>For exact method reference expressions, the type is {@code <? extends T>} (no erasure).
550
     *
551
     * @param sig                   Selected signature
552
     * @param replacementReturnType Lazily created, because in many cases it's not necessary
553
     *
554
     * @return Signature, adapted if it is {@link Object#getClass()}
555
     */
556
    static JMethodSig adaptGetClass(JMethodSig sig, Supplier<JTypeMirror> replacementReturnType) {
557
        TypeSystem ts = sig.getTypeSystem();
1✔
558
        if ("getClass".equals(sig.getName()) && sig.getDeclaringType().equals(ts.OBJECT)) {
1!
559
            return cast(cast(sig).withReturnType(getClassReturn(replacementReturnType.get(), ts))).markAsAdapted();
1✔
560
        }
561
        return sig;
1✔
562
    }
563

564
    private static JTypeMirror getClassReturn(JTypeMirror erasedReceiverType, TypeSystem ts) {
565
        return ts.parameterise(ts.getClassSymbol(Class.class), listOf(ts.wildcard(true, erasedReceiverType)));
1✔
566
    }
567

568
    static boolean isContextDependent(JMethodSig m) {
569
        m = cast(m).adaptedMethod();
1✔
570
        return m.isGeneric() && TypeOps.mentionsAny(m.getReturnType(), m.getTypeParameters());
1✔
571
    }
572
}
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