42 import com.sun.tools.javac.util.JCDiagnostic.Error;
43 import com.sun.tools.javac.util.JCDiagnostic.Warning;
44
45 import com.sun.tools.javac.code.Symbol.*;
46 import com.sun.tools.javac.tree.JCTree.*;
47
48 import static com.sun.tools.javac.code.Flags.*;
49 import static com.sun.tools.javac.code.Flags.BLOCK;
50 import static com.sun.tools.javac.code.Kinds.Kind.*;
51 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
52 import static com.sun.tools.javac.code.TypeTag.VOID;
53 import com.sun.tools.javac.comp.ExhaustivenessComputer.BindingPattern;
54 import com.sun.tools.javac.comp.ExhaustivenessComputer.EnumConstantPattern;
55 import com.sun.tools.javac.comp.ExhaustivenessComputer.ExhaustivenessResult;
56 import com.sun.tools.javac.comp.ExhaustivenessComputer.PatternDescription;
57 import com.sun.tools.javac.comp.ExhaustivenessComputer.RecordPattern;
58 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
59 import static com.sun.tools.javac.tree.JCTree.Tag.*;
60 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
61 import java.util.Arrays;
62
63 /** This pass implements dataflow analysis for Java programs though
64 * different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
65 * every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
66 * every checked exception that is thrown is declared or caught. Definite assignment analysis
67 * (see AssignAnalyzer) ensures that each variable is assigned when used. Definite
68 * unassignment analysis (see AssignAnalyzer) in ensures that no final variable
69 * is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
70 * determines that local variables accessed within the scope of an inner class/lambda
71 * are either final or effectively-final.
72 *
73 * <p>The JLS has a number of problems in the
74 * specification of these flow analysis problems. This implementation
75 * attempts to address those issues.
76 *
77 * <p>First, there is no accommodation for a finally clause that cannot
78 * complete normally. For liveness analysis, an intervening finally
79 * clause can cause a break, continue, or return not to reach its
80 * target. For exception analysis, an intervening finally clause can
81 * cause any exception to be "caught". For DA/DU analysis, the finally
452 }
453 }
454
455 public void visitPackageDef(JCPackageDecl tree) {
456 // Do nothing for PackageDecl
457 }
458
459 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
460 if (swtch.hasTag(SWITCH_EXPRESSION)) {
461 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
462 .setType(swtch.type));
463 brk.target = swtch;
464 scan(brk);
465 } else {
466 JCBreak brk = make.at(Position.NOPOS).Break(null);
467 brk.target = swtch;
468 scan(brk);
469 }
470 }
471
472 // Do something with all static or non-static field initializers and initialization blocks.
473 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
474 if (classDef == initScanClass) // avoid infinite loops
475 return;
476 JCClassDecl initScanClassPrev = initScanClass;
477 initScanClass = classDef;
478 try {
479 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
480 JCTree def = defs.head;
481
482 // Don't recurse into nested classes
483 if (def.hasTag(CLASSDEF))
484 continue;
485
486 /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
487 * represented in the symbol but not in the tree modifiers as they were not originally in the source
488 * code
489 */
490 boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
491 if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic))
492 handler.accept(def);
493 }
494 } finally {
495 initScanClass = initScanClassPrev;
496 }
497 }
498 }
499
500 /**
501 * This pass implements the first step of the dataflow analysis, namely
502 * the liveness analysis check. This checks that every statement is reachable.
503 * The output of this analysis pass are used by other analyzers. This analyzer
504 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
505 */
506 class AliveAnalyzer extends BaseAnalyzer {
507
508 /** A flag that indicates whether the last statement could
509 * complete normally.
510 */
511 private Liveness alive;
512
548 }
549
550 /* ------------ Visitor methods for various sorts of trees -------------*/
551
552 public void visitClassDef(JCClassDecl tree) {
553 if (tree.sym == null) return;
554 Liveness alivePrev = alive;
555 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
556
557 pendingExits = new ListBuffer<>();
558
559 try {
560 // process all the nested classes
561 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
562 if (l.head.hasTag(CLASSDEF)) {
563 scan(l.head);
564 }
565 }
566
567 // process all the static initializers
568 forEachInitializer(tree, true, def -> {
569 scanDef(def);
570 clearPendingExits(false);
571 });
572
573 // process all the instance initializers
574 forEachInitializer(tree, false, def -> {
575 scanDef(def);
576 clearPendingExits(false);
577 });
578
579 // process all the methods
580 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
581 if (l.head.hasTag(METHODDEF)) {
582 scan(l.head);
583 }
584 }
585 } finally {
586 pendingExits = pendingExitsPrev;
587 alive = alivePrev;
588 }
589 }
590
591 public void visitMethodDef(JCMethodDecl tree) {
592 if (tree.body == null) return;
593
594 Assert.check(pendingExits.isEmpty());
1037 List<Type> thrownPrev = thrown;
1038 List<Type> caughtPrev = caught;
1039 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
1040 boolean anonymousClass = tree.name == names.empty;
1041 pendingExits = new ListBuffer<>();
1042 if (!anonymousClass) {
1043 caught = List.nil();
1044 }
1045 classDef = tree;
1046 thrown = List.nil();
1047
1048 try {
1049 // process all the nested classes
1050 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1051 if (l.head.hasTag(CLASSDEF)) {
1052 scan(l.head);
1053 }
1054 }
1055
1056 // process all the static initializers
1057 forEachInitializer(tree, true, def -> {
1058 scan(def);
1059 errorUncaught();
1060 });
1061
1062 // in an anonymous class, add the set of thrown exceptions to
1063 // the throws clause of the synthetic constructor and propagate
1064 // outwards.
1065 // Changing the throws clause on the fly is okay here because
1066 // the anonymous constructor can't be invoked anywhere else,
1067 // and its type hasn't been cached.
1068 if (anonymousClass) {
1069 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1070 if (TreeInfo.isConstructor(l.head)) {
1071 JCMethodDecl mdef = (JCMethodDecl)l.head;
1072 scan(mdef);
1073 mdef.thrown = make.Types(thrown);
1074 mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
1075 }
1076 }
1077 thrownPrev = chk.union(thrown, thrownPrev);
1381 for (Type t : preciseRethrowTypes.get(sym)) {
1382 markThrown(tree, t);
1383 }
1384 }
1385 else {
1386 markThrown(tree, tree.expr.type);
1387 }
1388 markDead();
1389 }
1390
1391 public void visitApply(JCMethodInvocation tree) {
1392 scan(tree.meth);
1393 scan(tree.args);
1394
1395 // Mark as thrown the exceptions thrown by the method being invoked
1396 for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
1397 markThrown(tree, l.head);
1398
1399 // After super(), scan initializers to uncover any exceptions they throw
1400 if (TreeInfo.name(tree.meth) == names._super) {
1401 forEachInitializer(classDef, false, def -> {
1402 scan(def);
1403 errorUncaught();
1404 });
1405 }
1406 }
1407
1408 public void visitNewClass(JCNewClass tree) {
1409 scan(tree.encl);
1410 scan(tree.args);
1411 // scan(tree.def);
1412 for (List<Type> l = tree.constructorType.getThrownTypes();
1413 l.nonEmpty();
1414 l = l.tail) {
1415 markThrown(tree, l.head);
1416 }
1417 List<Type> caughtPrev = caught;
1418 try {
1419 // If the new class expression defines an anonymous class,
1420 // analysis of the anonymous constructor may encounter thrown
1421 // types which are unsubstituted type variables.
1729 }
1730
1731 @Override
1732 public void resolveJump() {
1733 inits.andSet(exit_inits);
1734 uninits.andSet(exit_uninits);
1735 }
1736 }
1737
1738 public AssignAnalyzer() {
1739 this.inits = new Bits();
1740 uninits = new Bits();
1741 uninitsTry = new Bits();
1742 initsWhenTrue = new Bits(true);
1743 initsWhenFalse = new Bits(true);
1744 uninitsWhenTrue = new Bits(true);
1745 uninitsWhenFalse = new Bits(true);
1746 }
1747
1748 private boolean isConstructor;
1749
1750 @Override
1751 protected void markDead() {
1752 inits.inclRange(returnadr, nextadr);
1753 uninits.inclRange(returnadr, nextadr);
1754 }
1755
1756 /*-------------- Processing variables ----------------------*/
1757
1758 /** Do we need to track init/uninit state of this symbol?
1759 * I.e. is symbol either a local or a blank final variable?
1760 */
1761 protected boolean trackable(VarSymbol sym) {
1762 return
1763 sym.pos >= startPos &&
1764 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
1765 isFinalUninitializedField(sym)));
1766 }
1767
1768 boolean isFinalUninitializedField(VarSymbol sym) {
1769 return sym.owner.kind == TYP &&
1770 ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
1771 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
1772 }
1773
1774 /** Initialize new trackable variable by setting its address field
1775 * to the next available sequence number and entering it under that
1776 * index into the vars array.
1777 */
1778 void newVar(JCVariableDecl varDecl) {
1779 VarSymbol sym = varDecl.sym;
1780 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
1781 if ((sym.flags() & FINAL) == 0) {
1782 sym.flags_field |= EFFECTIVELY_FINAL;
1783 }
1784 sym.adr = nextadr;
1785 vardecls[nextadr] = varDecl;
1786 inits.excl(nextadr);
1787 uninits.incl(nextadr);
1788 nextadr++;
1789 }
1790
1791 /** Record an initialization of a trackable variable.
1822 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
1823 }
1824 }
1825 //where
1826 void uninit(VarSymbol sym) {
1827 if (!inits.isMember(sym.adr)) {
1828 // reachable assignment
1829 uninits.excl(sym.adr);
1830 uninitsTry.excl(sym.adr);
1831 } else {
1832 //log.rawWarning(pos, "unreachable assignment");//DEBUG
1833 uninits.excl(sym.adr);
1834 }
1835 }
1836
1837 /** If tree is either a simple name or of the form this.name or
1838 * C.this.name, and tree represents a trackable variable,
1839 * record an initialization of the variable.
1840 */
1841 void letInit(JCTree tree) {
1842 tree = TreeInfo.skipParens(tree);
1843 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1844 Symbol sym = TreeInfo.symbol(tree);
1845 if (sym.kind == VAR) {
1846 letInit(tree.pos(), (VarSymbol)sym);
1847 }
1848 }
1849 }
1850
1851 /** Check that trackable variable is initialized.
1852 */
1853 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1854 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1855 }
1856
1857 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1858 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1859 trackable(sym) &&
1860 !inits.isMember(sym.adr) &&
1861 (sym.flags_field & CLASH) == 0) {
1862 log.error(pos, errkey);
1863 inits.incl(sym.adr);
1864 }
1865 }
1866
1867 /** Utility method to reset several Bits instances.
1868 */
1869 private void resetBits(Bits... bits) {
1870 for (Bits b : bits) {
1871 b.reset();
1872 }
1873 }
1874
1875 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1876 */
1877 void split(boolean setToNull) {
1878 initsWhenFalse.assign(inits);
1879 uninitsWhenFalse.assign(uninits);
1880 initsWhenTrue.assign(inits);
1881 uninitsWhenTrue.assign(uninits);
1882 if (setToNull) {
1964 pendingExits = new ListBuffer<>();
1965 if (tree.name != names.empty) {
1966 firstadr = nextadr;
1967 }
1968 classDef = tree;
1969 try {
1970 // define all the static fields
1971 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1972 if (l.head.hasTag(VARDEF)) {
1973 JCVariableDecl def = (JCVariableDecl)l.head;
1974 if ((def.mods.flags & STATIC) != 0) {
1975 VarSymbol sym = def.sym;
1976 if (trackable(sym)) {
1977 newVar(def);
1978 }
1979 }
1980 }
1981 }
1982
1983 // process all the static initializers
1984 forEachInitializer(tree, true, def -> {
1985 scan(def);
1986 clearPendingExits(false);
1987 });
1988
1989 // verify all static final fields got initialized
1990 for (int i = firstadr; i < nextadr; i++) {
1991 JCVariableDecl vardecl = vardecls[i];
1992 VarSymbol var = vardecl.sym;
1993 if (var.owner == classDef.sym && var.isStatic()) {
1994 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
1995 }
1996 }
1997
1998 // define all the instance fields
1999 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2000 if (l.head.hasTag(VARDEF)) {
2001 JCVariableDecl def = (JCVariableDecl)l.head;
2002 if ((def.mods.flags & STATIC) == 0) {
2003 VarSymbol sym = def.sym;
2004 if (trackable(sym)) {
2031
2032 public void visitMethodDef(JCMethodDecl tree) {
2033 if (tree.body == null) {
2034 return;
2035 }
2036
2037 /* MemberEnter can generate synthetic methods ignore them
2038 */
2039 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2040 return;
2041 }
2042
2043 final Bits initsPrev = new Bits(inits);
2044 final Bits uninitsPrev = new Bits(uninits);
2045 int nextadrPrev = nextadr;
2046 int firstadrPrev = firstadr;
2047 int returnadrPrev = returnadr;
2048
2049 Assert.check(pendingExits.isEmpty());
2050 boolean isConstructorPrev = isConstructor;
2051 try {
2052 isConstructor = TreeInfo.isConstructor(tree);
2053
2054 // We only track field initialization inside constructors
2055 if (!isConstructor) {
2056 firstadr = nextadr;
2057 }
2058
2059 // Mark all method parameters as DA
2060 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2061 JCVariableDecl def = l.head;
2062 scan(def);
2063 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2064 /* If we are executing the code from Gen, then there can be
2065 * synthetic or mandated variables, ignore them.
2066 */
2067 initParam(def);
2068 }
2069 // else we are in an instance initializer block;
2070 // leave caught unchanged.
2071 scan(tree.body);
2072
2073 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2074 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2075 if (isConstructor) {
2076 boolean isSynthesized = (tree.sym.flags() &
2077 GENERATEDCONSTR) != 0;
2078 for (int i = firstadr; i < nextadr; i++) {
2079 JCVariableDecl vardecl = vardecls[i];
2080 VarSymbol var = vardecl.sym;
2081 if (var.owner == classDef.sym && !var.isStatic()) {
2082 // choose the diagnostic position based on whether
2083 // the ctor is default(synthesized) or not
2084 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2085 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2086 var, Errors.VarNotInitializedInDefaultConstructor(var));
2087 } else if (isCompactOrGeneratedRecordConstructor) {
2088 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2089 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2090 var.owner.kind == TYP;
2091 if (isInstanceRecordField) {
2092 boolean notInitialized = !inits.isMember(var.adr);
2093 if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2094 /* this way we indicate Lower that it should generate an initialization for this field
2098 } else {
2099 checkInit(TreeInfo.diagEndPos(tree.body), var);
2100 }
2101 } else {
2102 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2103 }
2104 } else {
2105 checkInit(TreeInfo.diagEndPos(tree.body), var);
2106 }
2107 }
2108 }
2109 }
2110 clearPendingExits(true);
2111 } finally {
2112 inits.assign(initsPrev);
2113 uninits.assign(uninitsPrev);
2114 nextadr = nextadrPrev;
2115 firstadr = firstadrPrev;
2116 returnadr = returnadrPrev;
2117 isConstructor = isConstructorPrev;
2118 }
2119 }
2120
2121 private void clearPendingExits(boolean inMethod) {
2122 List<PendingExit> exits = pendingExits.toList();
2123 pendingExits = new ListBuffer<>();
2124 while (exits.nonEmpty()) {
2125 PendingExit exit = exits.head;
2126 exits = exits.tail;
2127 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2128 log.hasErrorOn(exit.tree.pos()),
2129 exit.tree);
2130 if (inMethod && isConstructor) {
2131 Assert.check(exit instanceof AssignPendingExit);
2132 inits.assign(((AssignPendingExit) exit).exit_inits);
2133 for (int i = firstadr; i < nextadr; i++) {
2134 checkInit(exit.tree.pos(), vardecls[i].sym);
2135 }
2136 }
2137 }
2566 public void visitReturn(JCReturn tree) {
2567 scanExpr(tree.expr);
2568 recordExit(new AssignPendingExit(tree, inits, uninits));
2569 }
2570
2571 public void visitThrow(JCThrow tree) {
2572 scanExpr(tree.expr);
2573 markDead();
2574 }
2575
2576 public void visitApply(JCMethodInvocation tree) {
2577 scanExpr(tree.meth);
2578 scanExprs(tree.args);
2579
2580 // Handle superclass constructor invocations
2581 if (isConstructor) {
2582
2583 // If super(): at this point all initialization blocks will execute
2584 Name name = TreeInfo.name(tree.meth);
2585 if (name == names._super) {
2586 forEachInitializer(classDef, false, def -> {
2587 scan(def);
2588 clearPendingExits(false);
2589 });
2590 }
2591
2592 // If this(): at this point all final uninitialized fields will get initialized
2593 else if (name == names._this) {
2594 for (int address = firstadr; address < nextadr; address++) {
2595 VarSymbol sym = vardecls[address].sym;
2596 if (isFinalUninitializedField(sym) && !sym.isStatic())
2597 letInit(tree.pos(), sym);
2598 }
2599 }
2600 }
2601 }
2602
2603 public void visitNewClass(JCNewClass tree) {
2604 scanExpr(tree.encl);
2605 scanExprs(tree.args);
2606 scan(tree.def);
2607 }
2608
2609 @Override
2610 public void visitLambda(JCLambda tree) {
2611 final Bits prevUninits = new Bits(uninits);
2612 final Bits prevUninitsTry = new Bits(uninitsTry);
2613 final Bits prevInits = new Bits(inits);
2614 int returnadrPrev = returnadr;
2615 int nextadrPrev = nextadr;
2616 ListBuffer<PendingExit> prevPending = pendingExits;
2617 try {
2618 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
2619 // body. This is by design: a variable that was definitely unassigned before the
2620 // lambda body may end up being assigned to later on, so we cannot conclude that
2621 // the variable will be unassigned when the body is executed.
2622 uninits.excludeFrom(firstadr);
2650 }
2651
2652 public void visitAssert(JCAssert tree) {
2653 final Bits initsExit = new Bits(inits);
2654 final Bits uninitsExit = new Bits(uninits);
2655 scanCond(tree.cond);
2656 uninitsExit.andSet(uninitsWhenTrue);
2657 if (tree.detail != null) {
2658 inits.assign(initsWhenFalse);
2659 uninits.assign(uninitsWhenFalse);
2660 scanExpr(tree.detail);
2661 }
2662 inits.assign(initsExit);
2663 uninits.assign(uninitsExit);
2664 }
2665
2666 public void visitAssign(JCAssign tree) {
2667 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2668 scanExpr(tree.lhs);
2669 scanExpr(tree.rhs);
2670 letInit(tree.lhs);
2671 }
2672
2673 // check fields accessed through this.<field> are definitely
2674 // assigned before reading their value
2675 public void visitSelect(JCFieldAccess tree) {
2676 super.visitSelect(tree);
2677 if (TreeInfo.isThisQualifier(tree.selected) &&
2678 tree.sym.kind == VAR) {
2679 checkInit(tree.pos(), (VarSymbol)tree.sym);
2680 }
2681 }
2682
2683 public void visitAssignop(JCAssignOp tree) {
2684 scanExpr(tree.lhs);
2685 scanExpr(tree.rhs);
2686 letInit(tree.lhs);
2687 }
2688
2689 public void visitUnary(JCUnary tree) {
2690 switch (tree.getTag()) {
|
42 import com.sun.tools.javac.util.JCDiagnostic.Error;
43 import com.sun.tools.javac.util.JCDiagnostic.Warning;
44
45 import com.sun.tools.javac.code.Symbol.*;
46 import com.sun.tools.javac.tree.JCTree.*;
47
48 import static com.sun.tools.javac.code.Flags.*;
49 import static com.sun.tools.javac.code.Flags.BLOCK;
50 import static com.sun.tools.javac.code.Kinds.Kind.*;
51 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
52 import static com.sun.tools.javac.code.TypeTag.VOID;
53 import com.sun.tools.javac.comp.ExhaustivenessComputer.BindingPattern;
54 import com.sun.tools.javac.comp.ExhaustivenessComputer.EnumConstantPattern;
55 import com.sun.tools.javac.comp.ExhaustivenessComputer.ExhaustivenessResult;
56 import com.sun.tools.javac.comp.ExhaustivenessComputer.PatternDescription;
57 import com.sun.tools.javac.comp.ExhaustivenessComputer.RecordPattern;
58 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
59 import static com.sun.tools.javac.tree.JCTree.Tag.*;
60 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
61 import java.util.Arrays;
62 import java.util.function.Predicate;
63
64 /** This pass implements dataflow analysis for Java programs though
65 * different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
66 * every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
67 * every checked exception that is thrown is declared or caught. Definite assignment analysis
68 * (see AssignAnalyzer) ensures that each variable is assigned when used. Definite
69 * unassignment analysis (see AssignAnalyzer) in ensures that no final variable
70 * is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
71 * determines that local variables accessed within the scope of an inner class/lambda
72 * are either final or effectively-final.
73 *
74 * <p>The JLS has a number of problems in the
75 * specification of these flow analysis problems. This implementation
76 * attempts to address those issues.
77 *
78 * <p>First, there is no accommodation for a finally clause that cannot
79 * complete normally. For liveness analysis, an intervening finally
80 * clause can cause a break, continue, or return not to reach its
81 * target. For exception analysis, an intervening finally clause can
82 * cause any exception to be "caught". For DA/DU analysis, the finally
453 }
454 }
455
456 public void visitPackageDef(JCPackageDecl tree) {
457 // Do nothing for PackageDecl
458 }
459
460 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
461 if (swtch.hasTag(SWITCH_EXPRESSION)) {
462 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
463 .setType(swtch.type));
464 brk.target = swtch;
465 scan(brk);
466 } else {
467 JCBreak brk = make.at(Position.NOPOS).Break(null);
468 brk.target = swtch;
469 scan(brk);
470 }
471 }
472
473 /** a predicate that selects all static initializers */
474 static final Predicate<JCTree> STATIC_INITS = tree ->
475 switch (tree) {
476 case JCVariableDecl vdecl -> vdecl.sym.isStatic();
477 case JCBlock b -> b.isStatic();
478 default -> false;
479 };
480
481 /** a predicate that selects early instance initializers */
482 static final Predicate<JCTree> EARLY_INSTANCE_INITS = tree ->
483 tree instanceof JCVariableDecl vdecl && vdecl.sym.isStrictInstance();
484
485 /** a predicate that selects late instance initializers */
486 static final Predicate<JCTree> LATE_INSTANCE_INITS = tree ->
487 switch (tree) {
488 case JCVariableDecl vdecl -> !vdecl.sym.isStatic() && !vdecl.sym.isStrict();
489 case JCBlock b -> !b.isStatic();
490 default -> false;
491 };
492
493 /** a predicate that all instance initializers */
494 static final Predicate<JCTree> INSTANCE_INITS = EARLY_INSTANCE_INITS.or(LATE_INSTANCE_INITS);
495
496 protected void forEachInitializer(JCClassDecl classDef, Predicate<? super JCTree> initFilter,
497 Consumer<? super JCTree> handler) {
498 if (classDef == initScanClass) // avoid infinite loops
499 return;
500 JCClassDecl initScanClassPrev = initScanClass;
501 initScanClass = classDef;
502 try {
503 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
504 JCTree def = defs.head;
505
506 if (!initFilter.test(def)) {
507 continue;
508 }
509
510 handler.accept(def);
511 }
512 } finally {
513 initScanClass = initScanClassPrev;
514 }
515 }
516 }
517
518 /**
519 * This pass implements the first step of the dataflow analysis, namely
520 * the liveness analysis check. This checks that every statement is reachable.
521 * The output of this analysis pass are used by other analyzers. This analyzer
522 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
523 */
524 class AliveAnalyzer extends BaseAnalyzer {
525
526 /** A flag that indicates whether the last statement could
527 * complete normally.
528 */
529 private Liveness alive;
530
566 }
567
568 /* ------------ Visitor methods for various sorts of trees -------------*/
569
570 public void visitClassDef(JCClassDecl tree) {
571 if (tree.sym == null) return;
572 Liveness alivePrev = alive;
573 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
574
575 pendingExits = new ListBuffer<>();
576
577 try {
578 // process all the nested classes
579 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
580 if (l.head.hasTag(CLASSDEF)) {
581 scan(l.head);
582 }
583 }
584
585 // process all the static initializers
586 forEachInitializer(tree, STATIC_INITS, def -> {
587 scanDef(def);
588 clearPendingExits(false);
589 });
590
591 // process all the instance initializers
592 forEachInitializer(tree, INSTANCE_INITS, def -> {
593 scanDef(def);
594 clearPendingExits(false);
595 });
596
597 // process all the methods
598 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
599 if (l.head.hasTag(METHODDEF)) {
600 scan(l.head);
601 }
602 }
603 } finally {
604 pendingExits = pendingExitsPrev;
605 alive = alivePrev;
606 }
607 }
608
609 public void visitMethodDef(JCMethodDecl tree) {
610 if (tree.body == null) return;
611
612 Assert.check(pendingExits.isEmpty());
1055 List<Type> thrownPrev = thrown;
1056 List<Type> caughtPrev = caught;
1057 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
1058 boolean anonymousClass = tree.name == names.empty;
1059 pendingExits = new ListBuffer<>();
1060 if (!anonymousClass) {
1061 caught = List.nil();
1062 }
1063 classDef = tree;
1064 thrown = List.nil();
1065
1066 try {
1067 // process all the nested classes
1068 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1069 if (l.head.hasTag(CLASSDEF)) {
1070 scan(l.head);
1071 }
1072 }
1073
1074 // process all the static initializers
1075 forEachInitializer(tree, STATIC_INITS, def -> {
1076 scan(def);
1077 errorUncaught();
1078 });
1079
1080 // in an anonymous class, add the set of thrown exceptions to
1081 // the throws clause of the synthetic constructor and propagate
1082 // outwards.
1083 // Changing the throws clause on the fly is okay here because
1084 // the anonymous constructor can't be invoked anywhere else,
1085 // and its type hasn't been cached.
1086 if (anonymousClass) {
1087 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1088 if (TreeInfo.isConstructor(l.head)) {
1089 JCMethodDecl mdef = (JCMethodDecl)l.head;
1090 scan(mdef);
1091 mdef.thrown = make.Types(thrown);
1092 mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
1093 }
1094 }
1095 thrownPrev = chk.union(thrown, thrownPrev);
1399 for (Type t : preciseRethrowTypes.get(sym)) {
1400 markThrown(tree, t);
1401 }
1402 }
1403 else {
1404 markThrown(tree, tree.expr.type);
1405 }
1406 markDead();
1407 }
1408
1409 public void visitApply(JCMethodInvocation tree) {
1410 scan(tree.meth);
1411 scan(tree.args);
1412
1413 // Mark as thrown the exceptions thrown by the method being invoked
1414 for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
1415 markThrown(tree, l.head);
1416
1417 // After super(), scan initializers to uncover any exceptions they throw
1418 if (TreeInfo.name(tree.meth) == names._super) {
1419 forEachInitializer(classDef, INSTANCE_INITS, def -> {
1420 scan(def);
1421 errorUncaught();
1422 });
1423 }
1424 }
1425
1426 public void visitNewClass(JCNewClass tree) {
1427 scan(tree.encl);
1428 scan(tree.args);
1429 // scan(tree.def);
1430 for (List<Type> l = tree.constructorType.getThrownTypes();
1431 l.nonEmpty();
1432 l = l.tail) {
1433 markThrown(tree, l.head);
1434 }
1435 List<Type> caughtPrev = caught;
1436 try {
1437 // If the new class expression defines an anonymous class,
1438 // analysis of the anonymous constructor may encounter thrown
1439 // types which are unsubstituted type variables.
1747 }
1748
1749 @Override
1750 public void resolveJump() {
1751 inits.andSet(exit_inits);
1752 uninits.andSet(exit_uninits);
1753 }
1754 }
1755
1756 public AssignAnalyzer() {
1757 this.inits = new Bits();
1758 uninits = new Bits();
1759 uninitsTry = new Bits();
1760 initsWhenTrue = new Bits(true);
1761 initsWhenFalse = new Bits(true);
1762 uninitsWhenTrue = new Bits(true);
1763 uninitsWhenFalse = new Bits(true);
1764 }
1765
1766 private boolean isConstructor;
1767 private boolean isCompactOrGeneratedRecordConstructor;
1768
1769 @Override
1770 protected void markDead() {
1771 inits.inclRange(returnadr, nextadr);
1772 uninits.inclRange(returnadr, nextadr);
1773 }
1774
1775 /*-------------- Processing variables ----------------------*/
1776
1777 /** Do we need to track init/uninit state of this symbol?
1778 * I.e. is symbol either a local or a blank final variable?
1779 */
1780 protected boolean trackable(VarSymbol sym) {
1781 return
1782 sym.pos >= startPos &&
1783 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
1784 isBlankFinalOrStrictField(sym)));
1785 }
1786
1787 boolean isBlankFinalOrStrictField(VarSymbol sym) {
1788 return sym.owner.kind == TYP &&
1789 (sym.flags() & (HASINIT | PARAMETER)) == 0 &&
1790 (sym.isFinal() || sym.isStrict()) &&
1791 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner);
1792 }
1793
1794 /** Initialize new trackable variable by setting its address field
1795 * to the next available sequence number and entering it under that
1796 * index into the vars array.
1797 */
1798 void newVar(JCVariableDecl varDecl) {
1799 VarSymbol sym = varDecl.sym;
1800 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
1801 if ((sym.flags() & FINAL) == 0) {
1802 sym.flags_field |= EFFECTIVELY_FINAL;
1803 }
1804 sym.adr = nextadr;
1805 vardecls[nextadr] = varDecl;
1806 inits.excl(nextadr);
1807 uninits.incl(nextadr);
1808 nextadr++;
1809 }
1810
1811 /** Record an initialization of a trackable variable.
1842 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
1843 }
1844 }
1845 //where
1846 void uninit(VarSymbol sym) {
1847 if (!inits.isMember(sym.adr)) {
1848 // reachable assignment
1849 uninits.excl(sym.adr);
1850 uninitsTry.excl(sym.adr);
1851 } else {
1852 //log.rawWarning(pos, "unreachable assignment");//DEBUG
1853 uninits.excl(sym.adr);
1854 }
1855 }
1856
1857 /** If tree is either a simple name or of the form this.name or
1858 * C.this.name, and tree represents a trackable variable,
1859 * record an initialization of the variable.
1860 */
1861 void letInit(JCTree tree) {
1862 letInit(tree, (JCAssign) null);
1863 }
1864
1865 void letInit(JCTree tree, JCAssign assign) {
1866 tree = TreeInfo.skipParens(tree);
1867 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1868 Symbol sym = TreeInfo.symbol(tree);
1869 if (sym.kind == VAR) {
1870 letInit(tree.pos(), (VarSymbol)sym);
1871 }
1872 }
1873 }
1874
1875 /** Check that trackable variable is initialized.
1876 */
1877 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1878 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1879 }
1880
1881 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1882 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1883 trackable(sym) &&
1884 !inits.isMember(sym.adr) &&
1885 (sym.flags_field & CLASH) == 0) {
1886 log.error(pos, errkey);
1887 inits.incl(sym.adr);
1888 }
1889 }
1890
1891 /** Utility method to reset several Bits instances.
1892 */
1893 private void resetBits(Bits... bits) {
1894 for (Bits b : bits) {
1895 b.reset();
1896 }
1897 }
1898
1899 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1900 */
1901 void split(boolean setToNull) {
1902 initsWhenFalse.assign(inits);
1903 uninitsWhenFalse.assign(uninits);
1904 initsWhenTrue.assign(inits);
1905 uninitsWhenTrue.assign(uninits);
1906 if (setToNull) {
1988 pendingExits = new ListBuffer<>();
1989 if (tree.name != names.empty) {
1990 firstadr = nextadr;
1991 }
1992 classDef = tree;
1993 try {
1994 // define all the static fields
1995 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1996 if (l.head.hasTag(VARDEF)) {
1997 JCVariableDecl def = (JCVariableDecl)l.head;
1998 if ((def.mods.flags & STATIC) != 0) {
1999 VarSymbol sym = def.sym;
2000 if (trackable(sym)) {
2001 newVar(def);
2002 }
2003 }
2004 }
2005 }
2006
2007 // process all the static initializers
2008 forEachInitializer(tree, STATIC_INITS, def -> {
2009 scan(def);
2010 clearPendingExits(false);
2011 });
2012
2013 // verify all static final fields got initialized
2014 for (int i = firstadr; i < nextadr; i++) {
2015 JCVariableDecl vardecl = vardecls[i];
2016 VarSymbol var = vardecl.sym;
2017 if (var.owner == classDef.sym && var.isStatic()) {
2018 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2019 }
2020 }
2021
2022 // define all the instance fields
2023 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2024 if (l.head.hasTag(VARDEF)) {
2025 JCVariableDecl def = (JCVariableDecl)l.head;
2026 if ((def.mods.flags & STATIC) == 0) {
2027 VarSymbol sym = def.sym;
2028 if (trackable(sym)) {
2055
2056 public void visitMethodDef(JCMethodDecl tree) {
2057 if (tree.body == null) {
2058 return;
2059 }
2060
2061 /* MemberEnter can generate synthetic methods ignore them
2062 */
2063 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2064 return;
2065 }
2066
2067 final Bits initsPrev = new Bits(inits);
2068 final Bits uninitsPrev = new Bits(uninits);
2069 int nextadrPrev = nextadr;
2070 int firstadrPrev = firstadr;
2071 int returnadrPrev = returnadr;
2072
2073 Assert.check(pendingExits.isEmpty());
2074 boolean isConstructorPrev = isConstructor;
2075 boolean isCompactOrGeneratedRecordConstructorPrev = isCompactOrGeneratedRecordConstructor;
2076 try {
2077 isConstructor = TreeInfo.isConstructor(tree);
2078 isCompactOrGeneratedRecordConstructor = isConstructor && ((tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2079 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD));
2080
2081 // We only track field initialization inside constructors
2082 if (!isConstructor) {
2083 firstadr = nextadr;
2084 }
2085
2086 // Mark all method parameters as DA
2087 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2088 JCVariableDecl def = l.head;
2089 scan(def);
2090 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2091 /* If we are executing the code from Gen, then there can be
2092 * synthetic or mandated variables, ignore them.
2093 */
2094 initParam(def);
2095 }
2096 if (isConstructor &&
2097 !TreeInfo.hasConstructorCall(tree, names._this)) {
2098 // Strict fields initializers are executed before the first statement
2099 // in the constructor body, unless the constructor is an alternate constructor
2100 forEachInitializer(classDef, EARLY_INSTANCE_INITS, def -> {
2101 scan(def);
2102 clearPendingExits(false);
2103 });
2104 }
2105 // else we are in an instance initializer block;
2106 // leave caught unchanged.
2107 scan(tree.body);
2108
2109 if (isConstructor) {
2110 boolean isSynthesized = (tree.sym.flags() &
2111 GENERATEDCONSTR) != 0;
2112 for (int i = firstadr; i < nextadr; i++) {
2113 JCVariableDecl vardecl = vardecls[i];
2114 VarSymbol var = vardecl.sym;
2115 if (var.owner == classDef.sym && !var.isStatic()) {
2116 // choose the diagnostic position based on whether
2117 // the ctor is default(synthesized) or not
2118 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2119 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2120 var, Errors.VarNotInitializedInDefaultConstructor(var));
2121 } else if (isCompactOrGeneratedRecordConstructor) {
2122 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2123 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2124 var.owner.kind == TYP;
2125 if (isInstanceRecordField) {
2126 boolean notInitialized = !inits.isMember(var.adr);
2127 if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2128 /* this way we indicate Lower that it should generate an initialization for this field
2132 } else {
2133 checkInit(TreeInfo.diagEndPos(tree.body), var);
2134 }
2135 } else {
2136 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2137 }
2138 } else {
2139 checkInit(TreeInfo.diagEndPos(tree.body), var);
2140 }
2141 }
2142 }
2143 }
2144 clearPendingExits(true);
2145 } finally {
2146 inits.assign(initsPrev);
2147 uninits.assign(uninitsPrev);
2148 nextadr = nextadrPrev;
2149 firstadr = firstadrPrev;
2150 returnadr = returnadrPrev;
2151 isConstructor = isConstructorPrev;
2152 isCompactOrGeneratedRecordConstructor = isCompactOrGeneratedRecordConstructorPrev;
2153 }
2154 }
2155
2156 private void clearPendingExits(boolean inMethod) {
2157 List<PendingExit> exits = pendingExits.toList();
2158 pendingExits = new ListBuffer<>();
2159 while (exits.nonEmpty()) {
2160 PendingExit exit = exits.head;
2161 exits = exits.tail;
2162 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2163 log.hasErrorOn(exit.tree.pos()),
2164 exit.tree);
2165 if (inMethod && isConstructor) {
2166 Assert.check(exit instanceof AssignPendingExit);
2167 inits.assign(((AssignPendingExit) exit).exit_inits);
2168 for (int i = firstadr; i < nextadr; i++) {
2169 checkInit(exit.tree.pos(), vardecls[i].sym);
2170 }
2171 }
2172 }
2601 public void visitReturn(JCReturn tree) {
2602 scanExpr(tree.expr);
2603 recordExit(new AssignPendingExit(tree, inits, uninits));
2604 }
2605
2606 public void visitThrow(JCThrow tree) {
2607 scanExpr(tree.expr);
2608 markDead();
2609 }
2610
2611 public void visitApply(JCMethodInvocation tree) {
2612 scanExpr(tree.meth);
2613 scanExprs(tree.args);
2614
2615 // Handle superclass constructor invocations
2616 if (isConstructor) {
2617
2618 // If super(): at this point all initialization blocks will execute
2619 Name name = TreeInfo.name(tree.meth);
2620 if (name == names._super) {
2621 if (!isCompactOrGeneratedRecordConstructor) {
2622 // all strict fields must be initialized at this point
2623 checkStrictFieldsInitializedBeforeSuper(tree);
2624 }
2625 forEachInitializer(classDef, LATE_INSTANCE_INITS,
2626 def -> {
2627 scan(def);
2628 clearPendingExits(false);
2629 });
2630 }
2631
2632 // If this(): at this point all final uninitialized fields will get initialized
2633 else if (name == names._this) {
2634 for (int address = firstadr; address < nextadr; address++) {
2635 VarSymbol sym = vardecls[address].sym;
2636 if (isBlankFinalOrStrictField(sym) && !sym.isStatic())
2637 letInit(tree.pos(), sym);
2638 }
2639 }
2640 }
2641 }
2642
2643 void checkStrictFieldsInitializedBeforeSuper(JCMethodInvocation tree) {
2644 for (int i = firstadr; i < nextadr; i++) {
2645 JCVariableDecl vardecl = vardecls[i];
2646 VarSymbol var = vardecl.sym;
2647 if (var.owner == classDef.sym && var.isStrictInstance()) {
2648 checkInit(TreeInfo.diagEndPos(tree), var, Errors.StrictFieldNotHaveBeenInitializedBeforeSuper(var));
2649 }
2650 }
2651 }
2652
2653 public void visitNewClass(JCNewClass tree) {
2654 scanExpr(tree.encl);
2655 scanExprs(tree.args);
2656 scan(tree.def);
2657 }
2658
2659 @Override
2660 public void visitLambda(JCLambda tree) {
2661 final Bits prevUninits = new Bits(uninits);
2662 final Bits prevUninitsTry = new Bits(uninitsTry);
2663 final Bits prevInits = new Bits(inits);
2664 int returnadrPrev = returnadr;
2665 int nextadrPrev = nextadr;
2666 ListBuffer<PendingExit> prevPending = pendingExits;
2667 try {
2668 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
2669 // body. This is by design: a variable that was definitely unassigned before the
2670 // lambda body may end up being assigned to later on, so we cannot conclude that
2671 // the variable will be unassigned when the body is executed.
2672 uninits.excludeFrom(firstadr);
2700 }
2701
2702 public void visitAssert(JCAssert tree) {
2703 final Bits initsExit = new Bits(inits);
2704 final Bits uninitsExit = new Bits(uninits);
2705 scanCond(tree.cond);
2706 uninitsExit.andSet(uninitsWhenTrue);
2707 if (tree.detail != null) {
2708 inits.assign(initsWhenFalse);
2709 uninits.assign(uninitsWhenFalse);
2710 scanExpr(tree.detail);
2711 }
2712 inits.assign(initsExit);
2713 uninits.assign(uninitsExit);
2714 }
2715
2716 public void visitAssign(JCAssign tree) {
2717 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2718 scanExpr(tree.lhs);
2719 scanExpr(tree.rhs);
2720 letInit(tree.lhs, tree);
2721 }
2722
2723 // check fields accessed through this.<field> are definitely
2724 // assigned before reading their value
2725 public void visitSelect(JCFieldAccess tree) {
2726 super.visitSelect(tree);
2727 if (TreeInfo.isThisQualifier(tree.selected) &&
2728 tree.sym.kind == VAR) {
2729 checkInit(tree.pos(), (VarSymbol)tree.sym);
2730 }
2731 }
2732
2733 public void visitAssignop(JCAssignOp tree) {
2734 scanExpr(tree.lhs);
2735 scanExpr(tree.rhs);
2736 letInit(tree.lhs);
2737 }
2738
2739 public void visitUnary(JCUnary tree) {
2740 switch (tree.getTag()) {
|