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

pmd / pmd / 4476

27 Feb 2025 08:31AM UTC coverage: 77.717% (+0.02%) from 77.694%
4476

push

github

adangel
[apex] New Rule: Avoid Stateful Database Results (#5425)

Merge pull request #5425 from mitchspano:stateful

17395 of 23322 branches covered (74.59%)

Branch coverage included in aggregate %.

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

99 existing lines in 9 files now uncovered.

38180 of 48187 relevant lines covered (79.23%)

0.8 hits per line

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

86.27
/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ExprMirror.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.internal.infer.ExprMirror.TypeSpecies.UNKNOWN;
8
import static net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.TypeSpecies.getSpecies;
9
import static net.sourceforge.pmd.lang.java.types.internal.infer.MethodResolutionPhase.STRICT;
10

11
import java.util.List;
12
import java.util.function.Predicate;
13

14
import org.checkerframework.checker.nullness.qual.NonNull;
15
import org.checkerframework.checker.nullness.qual.Nullable;
16

17
import net.sourceforge.pmd.lang.java.ast.JavaNode;
18
import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol;
19
import net.sourceforge.pmd.lang.java.types.JClassType;
20
import net.sourceforge.pmd.lang.java.types.JMethodSig;
21
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
22
import net.sourceforge.pmd.lang.java.types.JTypeVar;
23
import net.sourceforge.pmd.lang.java.types.OverloadSelectionResult;
24
import net.sourceforge.pmd.lang.java.types.TypeOps;
25
import net.sourceforge.pmd.lang.java.types.TypeSystem;
26
import net.sourceforge.pmd.lang.java.types.TypingContext;
27

28
/**
29
 * Adapter class to manipulate expressions. The framework
30
 * ideally keeps focus on types and doesn't have a dependency
31
 * on the AST. Only the impl package can have such dependencies.
32
 */
33
public interface ExprMirror {
34

35
    /**
36
     * Returns a node which is used as a location to report messages.
37
     * Do not use this any other way.
38
     */
39
    JavaNode getLocation();
40

41

42
    /**
43
     * If this expression is of a standalone form, returns the type of
44
     * the expression. Otherwise returns null.
45
     *
46
     * <p>Note that standalone types can directly be set on the type
47
     * node.
48
     *
49
     * @return The type of the expression if it is standalone
50
     */
51
    @Nullable JTypeMirror getStandaloneType();
52

53
    /**
54
     * For a standalone expr, finish type inference by computing properties
55
     * that are guarded by the type res lock. For instance for a standalone
56
     * ctor call, the standalone type is trivially known (it's the type node).
57
     * But we still need to do overload resolution.
58
     */
59
    default void finishStandaloneInference(@NonNull JTypeMirror standaloneType) {
60
        // do nothing
61
    }
1✔
62

63

64
    /**
65
     * Set the type of the underlying ast node. Used when we need
66
     * to find out the type of a poly to infer the type of another,
67
     * that way, we don't repeat computation.
68
     */
69
    void setInferredType(JTypeMirror mirror);
70

71
    /** Return the value set in the last call to {@link #setInferredType(JTypeMirror)}. */
72
    @Nullable JTypeMirror getInferredType();
73

74
    /**
75
     * Returns typing information for the lambdas parameters in scope
76
     * in this expression and its subexpressions. When overload resolution
77
     * involves lambdas, we might have to try several target types for each
78
     * lambda. Each of those may give a different type to the lambda parameters,
79
     * and hence, to every expression in the lambda body. These "tentative"
80
     * typing are kept in the {@link TypingContext} object and only
81
     * committed to the AST for the overload that is selected in the end.
82
     */
83
    TypingContext getTypingContext();
84

85
    /**
86
     * Returns the species that this expression produces. The species
87
     * may be known even if the expr is not standalone. For example a
88
     * diamond constructor call is not standalone, but its species is
89
     * obviously REFERENCE.
90
     *
91
     * <p>This is used for specificity tests for lambdas. They use species
92
     * because invocation needs to be done exactly once, and the actual
93
     * type of the expression may differ depending on the selected overload.
94
     * Eg given the signatures {@code <T>foo(Supplier<T>)} and {@code foo(Runnable)},
95
     * the expression {@code foo(() -> new List<>())} must select the supplier
96
     * overload, even before the invocation type of {@code List<>} is known.
97
     * The overload selection compares the expected species of both function
98
     * types (REFERENCE for Supplier, VOID for Runnable), and determines that
99
     * the supplier is more appropriate.
100
     */
101
    default @NonNull TypeSpecies getStandaloneSpecies() {
102
        JTypeMirror std = getStandaloneType();
1✔
103
        return std == null ? UNKNOWN : getSpecies(std);
1!
104
    }
105

106

107
    /**
108
     * Returns true if this mirror and its subexpressions are equivalent
109
     * to the underlying AST node. This is only relevant when making mirrors
110
     * that are not exactly equal to the AST node (eg, omitting explicit type arguments),
111
     * in order to check if the transformation does not change the meaning of the program.
112
     * It verifies that method and constructor calls are overload-selected
113
     * to the same compile-time declaration, and that nested lambdas
114
     * have the same type as in the AST.
115
     *
116
     * <p>This mirror's state, as filled-in during type resolution by
117
     * {@link Infer} using the various setters of {@link ExprMirror}
118
     * interfaces, is compared to the AST's corresponding state. Consequently,
119
     * if this state is missing (meaning, that no overload resolution
120
     * has been run using this mirror), the analysis cannot be performed
121
     * and an exception is thrown.
122
     *
123
     * @throws IllegalStateException If this mirror has not been used for overload resolution
124
     */
125
    boolean isEquivalentToUnderlyingAst();
126

127
    /** A general category of types. */
128
    enum TypeSpecies {
1✔
129
        PRIMITIVE,
1✔
130
        REFERENCE,
1✔
131
        VOID,
1✔
132
        UNKNOWN;
1✔
133

134

135
        public static TypeSpecies getSpecies(JTypeMirror t) {
136
            if (t.isPrimitive()) {
1✔
137
                return PRIMITIVE;
1✔
138
            } else if (t.isVoid()) {
1✔
139
                return VOID;
1✔
140
            } else if (TypeOps.isSpecialUnresolved(t)) {
1!
141
                return UNKNOWN;
×
142
            }
143
            return REFERENCE;
1✔
144
        }
145
    }
146

147

148
    interface PolyExprMirror extends ExprMirror {
149

150

151
        /**
152
         * Returns the class declaration wherein this invocation occurs.
153
         * Returns null if it's unresolved.
154
         */
155
        @NonNull JClassType getEnclosingType();
156

157

158
        @Override
159
        default @Nullable JTypeMirror getStandaloneType() {
160
            return null;
1✔
161
        }
162

163

164
        /**
165
         * If inference failed to determine the type of this node, returns
166
         * a fallback for it. This should not query the context of the expression,
167
         * or nodes whose type is unstable because it may be being inferred.
168
         *
169
         * <p>If no fallback should be used, returns null.
170
         */
171
        default @Nullable JTypeMirror unresolvedType() {
172
            return null;
1✔
173
        }
174
    }
175

176

177
    /** Mirrors a conditional or switch expression. */
178
    interface BranchingMirror extends PolyExprMirror {
179

180
        /**
181
         * Returns true if every result expression matches the given
182
         * predicate.
183
         */
184
        boolean branchesMatch(Predicate<? super ExprMirror> condition);
185

186
        /**
187
         * Record on the AST node that is is a standalone expression.
188
         * This accounts for special cases in the spec which are made
189
         * for numeric and boolean conditional expressions. For those
190
         * types of standalone exprs, the branches may have an additional
191
         * implicit unboxing/widening conversion, that does not depend
192
         * on the usual target type (the context of the ternary itself),
193
         * but just on the other branch.
194
         */
195
        default void setStandalone() {
196
            // do nothing by default
197
        }
1✔
198

199

200
        @Override
201
        default boolean isEquivalentToUnderlyingAst() {
202
            return branchesMatch(ExprMirror::isEquivalentToUnderlyingAst);
×
203
        }
204
    }
205

206
    /**
207
     * Mirror of some expression that targets a functional interface type:
208
     * lambda or method reference.
209
     */
210
    interface FunctionalExprMirror extends PolyExprMirror {
211

212
        /**
213
         * For a method ref or lambda, this is the type of the functional interface.
214
         * E.g. in {@code stringStream.map(String::isEmpty)}, this is
215
         * {@code java.util.function.Function<java.lang.String, java.lang.Boolean>}
216
         *
217
         * <p>May be null if we're resetting some partial data.
218
         */
219
        @Override
220
        void setInferredType(@Nullable JTypeMirror mirror);
221

222

223
        /**
224
         * This is the method that is overridden in getInferredType.
225
         * E.g. in {@code stringStream.map(String::isEmpty)}, this is
226
         * {@code java.util.function.Function<java.lang.String, java.lang.Boolean>.apply(java.lang.String) ->
227
         * java.lang.Boolean}
228
         *
229
         * <p>May be null if we're resetting some partial data.
230
         */
231
        void setFunctionalMethod(@Nullable JMethodSig methodType);
232

233
        /**
234
         * If the matching between this expr and its target type failed,
235
         * finish the inference by setting the data to UNKNOWN, or likely
236
         * values. This is used as a fallback.
237
         *
238
         * @param targetType Target type for the expression, null if there is none
239
         */
240
        void finishFailedInference(@Nullable JTypeMirror targetType);
241
    }
242

243
    /**
244
     * Mirror of a method reference expression.
245
     */
246
    interface MethodRefMirror extends FunctionalExprMirror {
247

248
        /** True if this references a ctor. */
249
        boolean isConstructorRef();
250

251

252
        /**
253
         * Returns the type to search as defined by the first section of
254
         * <a href="https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.13.1">JLS§15.13.1</a>
255
         * , except it may also return an array type (the jls makes an exception for it,
256
         * while we don't).
257
         */
258
        JTypeMirror getTypeToSearch();
259

260

261
        /**
262
         * Returns the type of the left hand-side, if it is not an expression.
263
         * Note that the following qualifier super forms are considered "expressions",
264
         * that have a context-dependent type (depends on the type of the {@code this} expr):
265
         * <pre>
266
         * super :: [TypeArguments] Identifier
267
         * TypeName.super :: [TypeArguments] Identifier
268
         * </pre>
269
         */
270
        @Nullable
271
        JTypeMirror getLhsIfType();
272

273

274
        /**
275
         * Returns the name of the invoked method, or {@link JConstructorSymbol#CTOR_NAME}
276
         * if this is a constructor reference.
277
         */
278
        String getMethodName();
279

280

281
        /** Returns the explicit type arguments (the ones to the right of the "::"). */
282
        @NonNull List<JTypeMirror> getExplicitTypeArguments();
283

284
        /**
285
         * This is the method that is referenced.
286
         * E.g. in {@code stringStream.map(String::isEmpty)}, this is
287
         * {@code java.lang.String.isEmpty() -> boolean}
288
         */
289
        void setCompileTimeDecl(JMethodSig methodType);
290

291

292
        /**
293
         * UNRESOLVED_METHOD if not yet computed, null if computed but
294
         * inexact, otherwise the real method.
295
         */
296
        @Nullable
297
        JMethodSig getCachedExactMethod();
298

299

300
        void setCachedExactMethod(@Nullable JMethodSig sig);
301

302
    }
303

304
    /** Mirrors a lambda expression. */
305
    interface LambdaExprMirror extends FunctionalExprMirror {
306

307
        /**
308
         * Returns the types of the explicit parameters. If the lambda
309
         * is implicitly typed, then returns null. If some parameters
310
         * have a var type, returns {@link TypeSystem#UNKNOWN} for those.
311
         *
312
         * <p>Note that a degenerate case of explicitly typed lambda
313
         * expression is a lambda with zero formal parameters.
314
         */
315
        @Nullable List<JTypeMirror> getExplicitParameterTypes();
316

317
        /**
318
         * See {@link #getExplicitParameterTypes()}.
319
         */
320
        default boolean isExplicitlyTyped() {
321
            return getExplicitParameterTypes() != null;
1✔
322
        }
323

324
        /**
325
         * Return the number of parameters of the lambda, regardless of
326
         * whether it's explicitly typed or not.
327
         */
328
        int getParamCount();
329

330

331
        /**
332
         * Returns all the expressions that appear in {@code return}
333
         * statements within the lambda. If this is an expression-bodied
334
         * lambda, returns the expression.
335
         */
336
        Iterable<ExprMirror> getResultExpressions();
337

338

339
        /**
340
         * Returns true if the body is value-compatible {@literal (JLS§15.27.2)}.
341
         * <blockquote>
342
         *     A block lambda body is value-compatible if it cannot complete
343
         *     normally (§14.21) and every return statement in the block
344
         *     has the form return Expression;.
345
         * </blockquote>
346
         */
347
        boolean isValueCompatible();
348

349
        /**
350
         * Returns true if the body is void-compatible {@literal (JLS§15.27.2)}.
351
         * <blockquote>
352
         *     A block lambda body is void-compatible if every return
353
         *     statement in the block has the form return;.
354
         * </blockquote>
355
         */
356
        boolean isVoidCompatible();
357

358
        /**
359
         * Set the currently considered type of the parameters.
360
         * This may change depending on which target type we are currently
361
         * considering. The type of parameters (and therefore the typing context)
362
         * may influence the type of the return values of the lambda.
363
         *
364
         * @param formalParameters formal parameter types of the lambda
365
         */
366
        void updateTypingContext(List<? extends JTypeMirror> formalParameters);
367
    }
368

369
    /**
370
     * Adapter over a method or constructor invocation expression.
371
     */
372
    interface InvocationMirror extends PolyExprMirror {
373

374
        /**
375
         * Enumerates *accessible* method (or ctor) signatures with
376
         * *the same name* as this invocation. Name and accessibility
377
         * will not be checked later.
378
         *
379
         * The details on how to determine this are here:
380
         *
381
         * https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.12.1
382
         */
383
        Iterable<JMethodSig> getAccessibleCandidates();
384

385

386
        /**
387
         * Returns the erased receiver type. This is only used to adapt the
388
         * {@code Object::getClass} method, other types of invocations don't
389
         * need to implement this.
390
         */
391
        default @Nullable JTypeMirror getErasedReceiverType() {
392
            return null;
×
393
        }
394

395

396
        /**
397
         * Returns the erased receiver type. This is only used for method
398
         * invocations.
399
         */
400
        @Nullable JTypeMirror getReceiverType();
401

402

403
        /**
404
         * Returns the explicit type arguments, eg in {@code Arrays.<String>asList("q")},
405
         * or {@code new <String> Foo("q")}. If none are mentioned, returns an empty list.
406
         */
407
        List<JTypeMirror> getExplicitTypeArguments();
408

409

410
        /**
411
         * @throws IndexOutOfBoundsException If there's no explicit type argument at the given index
412
         */
413
        JavaNode getExplicitTargLoc(int i);
414

415

416
        /**
417
         * Returns the name of the invoked method. If this is a
418
         * constructor call, returns {@link JConstructorSymbol#CTOR_NAME}.
419
         */
420
        String getName();
421

422

423
        /** Returns the expressions corresponding to the arguments of the call. */
424
        List<ExprMirror> getArgumentExpressions();
425

426

427
        int getArgumentCount();
428

429

430
        void setCtDecl(MethodCtDecl methodType);
431

432

433
        /**
434
         * Returns the method type set with {@link #setCtDecl(MethodCtDecl)}
435
         * or null if that method was never called. This is used to perform
436
         * overload resolution exactly once per call site.
437
         */
438
        @Nullable MethodCtDecl getCtDecl();
439

440

441
        /**
442
         * Information about the overload-resolution for a specific method.
443
         */
444
        class MethodCtDecl implements OverloadSelectionResult {
445
            // note this data is gathered by the MethodCallSite during
446
            // applicability inference, stashed in this object, and
447
            // restored when we do invocation.
448

449
            private final JMethodSig methodType;
450
            private final MethodResolutionPhase resolvePhase;
451
            private final boolean canSkipInvocation;
452
            private final boolean needsUncheckedConversion;
453
            private final boolean failed;
454

455
            MethodCtDecl(JMethodSig methodType,
456
                         MethodResolutionPhase resolvePhase,
457
                         boolean canSkipInvocation,
458
                         boolean needsUncheckedConversion,
459
                         boolean failed) {
1✔
460
                this.methodType = methodType;
1✔
461
                this.resolvePhase = resolvePhase;
1✔
462
                this.canSkipInvocation = canSkipInvocation;
1✔
463
                this.needsUncheckedConversion = needsUncheckedConversion;
1✔
464
                this.failed = failed;
1✔
465
            }
1✔
466

467
            // package-private:
468

469
            MethodCtDecl withMethod(JMethodSig method) {
470
                return withMethod(method, failed);
1✔
471
            }
472

473
            MethodCtDecl withMethod(JMethodSig method, boolean failed) {
474
                return new MethodCtDecl(method, resolvePhase, canSkipInvocation, needsUncheckedConversion, failed);
1✔
475
            }
476

477
            MethodCtDecl asFailed() {
478
                return withMethod(methodType, true);
1✔
479
            }
480

481
            boolean canSkipInvocation() {
482
                return canSkipInvocation;
1✔
483
            }
484

485
            MethodResolutionPhase getResolvePhase() {
486
                return resolvePhase;
1✔
487
            }
488

489
            static MethodCtDecl unresolved(TypeSystem ts) {
490
                return new MethodCtDecl(ts.UNRESOLVED_METHOD, STRICT, true, false, true);
1✔
491
            }
492

493
            // public:
494

495

496
            @Override
497
            public JMethodSig getMethodType() {
498
                return methodType;
1✔
499
            }
500

501
            @Override
502
            public boolean needsUncheckedConversion() {
503
                return needsUncheckedConversion;
1✔
504
            }
505

506
            @Override
507
            public boolean isVarargsCall() {
508
                return resolvePhase.requiresVarargs();
1✔
509
            }
510

511
            @Override
512
            public boolean isFailed() {
513
                return failed;
1✔
514
            }
515

516
            @Override
517
            public String toString() {
UNCOV
518
                return "CtDecl[phase=" + resolvePhase + ", method=" + methodType + ']';
×
519
            }
520

521
        }
522
    }
523

524
    /**
525
     * An invocation mirror reflecting a constructor invocation expression.
526
     */
527
    interface CtorInvocationMirror extends InvocationMirror {
528

529
        /**
530
         * Return the type name being instantiated. If the constructor call
531
         * is a diamond invocation (or no type args), returns the generic type declaration.
532
         * Otherwise returns the parameterised type. If the call declares
533
         * an anonymous class, then this does *not* return the anonymous
534
         * type, but its explicit supertype.
535
         *
536
         * <ul>
537
         *  <li>e.g. for {@code new ArrayList<>()}, returns {@code ArrayList<T>}.
538
         *  <li>e.g. for {@code new ArrayList()}, returns {@code ArrayList}.
539
         *  <li>e.g. for {@code new ArrayList<String>()}, returns {@code ArrayList<String>}.
540
         *  <li>e.g. for {@code new Runnable() {}} (anonymous), returns {@code Runnable}.
541
         * </ul>
542
         *
543
         * <p>Note that this returns a {@link JClassType} in valid code.
544
         * Other return values may be eg {@link TypeSystem#UNKNOWN}, or
545
         * a {@link JTypeVar}, but indicate malformed code.
546
         */
547
        @NonNull JTypeMirror getNewType();
548

549
        /**
550
         * True if this creates an anonymous class. Since java 9 those
551
         * can also be diamond-inferred.
552
         */
553
        boolean isAnonymous();
554

555
        /**
556
         * Return true if this is a diamond constructor call. In that
557
         * case the type parameters of the created instance must be inferred.
558
         * Returns false if the constructor call mentions no type arguments.
559
         * <ul>
560
         *  <li>e.g. for {@code new ArrayList<>()}, returns true.
561
         *  <li>e.g. for {@code new ArrayList()}, returns false.
562
         *  <li>e.g. for {@code new ArrayList<String>()}, returns false.
563
         * </ul>
564
         */
565
        boolean isDiamond();
566

567

568
        /**
569
         * {@inheritDoc}
570
         *
571
         * <p>Returns the constructor of the {@link #getNewType()}. If
572
         * this is an anonymous class declaration implementing an interface,
573
         * then returns the constructors of class {@link Object}.
574
         *
575
         * <p>This default implementation uses {@link #getAccessibleCandidates(JTypeMirror)},
576
         * which should be implemented instead.
577
         */
578
        @Override
579
        default Iterable<JMethodSig> getAccessibleCandidates() {
580
            return getAccessibleCandidates(getNewType());
1✔
581
        }
582

583
        /**
584
         * Returns the accessible candidates for this node, as if {@link #getNewType()}
585
         * returned the type passed as parameter. Since candidates depend on the
586
         * new type, this allows us to write simple "spy" wrappers to redo an invocation
587
         * in different conditions (ie, pretending the newtype is the parameter)
588
         *
589
         * @param newType Assumed value of {@link #getNewType()}
590
         */
591
        Iterable<JMethodSig> getAccessibleCandidates(JTypeMirror newType);
592

593

594
        /** Must return {@link JConstructorSymbol#CTOR_NAME}. */
595
        @Override
596
        default String getName() {
UNCOV
597
            return JConstructorSymbol.CTOR_NAME;
×
598
        }
599

600

601
    }
602
}
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