< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java

Print this page
@@ -25,10 +25,11 @@
  
  //todo: one might eliminate uninits.andSets when monotonic
  
  package com.sun.tools.javac.comp;
  
+ import java.util.LinkedHashSet;
  import java.util.Map;
  import java.util.Map.Entry;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Set;

@@ -214,10 +215,11 @@
      private final Resolve rs;
      private final JCDiagnostic.Factory diags;
      private Env<AttrContext> attrEnv;
      private       Lint lint;
      private final Infer infer;
+     private final UnsetFieldsInfo unsetFieldsInfo;
  
      public static Flow instance(Context context) {
          Flow instance = context.get(flowKey);
          if (instance == null)
              instance = new Flow(context);

@@ -339,11 +341,11 @@
          chk = Check.instance(context);
          lint = Lint.instance(context);
          infer = Infer.instance(context);
          rs = Resolve.instance(context);
          diags = JCDiagnostic.Factory.instance(context);
-         Source source = Source.instance(context);
+         unsetFieldsInfo = UnsetFieldsInfo.instance(context);
      }
  
      /**
       * Base visitor class for all visitors implementing dataflow analysis logic.
       * This class define the shared logic for handling jumps (break/continue statements).

@@ -476,12 +478,22 @@
                  brk.target = swtch;
                  scan(brk);
              }
          }
  
-         // Do something with all static or non-static field initializers and initialization blocks.
+         // Do something with static or non-static field initializers and initialization blocks.
          protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
+             forEachInitializer(classDef, isStatic, false, handler);
+         }
+ 
+         /* Do something with static or non-static field initializers and initialization blocks.
+          * the `earlyOnly` argument will determine if we will deal or not with early variable instance
+          * initializers we want to process only those before a super() invocation and ignore them after
+          * it.
+          */
+         protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, boolean earlyOnly,
+                                           Consumer<? super JCTree> handler) {
              if (classDef == initScanClass)          // avoid infinite loops
                  return;
              JCClassDecl initScanClassPrev = initScanClass;
              initScanClass = classDef;
              try {

@@ -495,12 +507,22 @@
                      /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
                       * represented in the symbol but not in the tree modifiers as they were not originally in the source
                       * code
                       */
                      boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
-                     if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic))
-                         handler.accept(def);
+                     if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic)) {
+                         if (def instanceof JCVariableDecl varDecl) {
+                             boolean isEarly = varDecl.init != null &&
+                                     varDecl.sym.isStrict() &&
+                                     !varDecl.sym.isStatic();
+                             if (isEarly == earlyOnly) {
+                                 handler.accept(def);
+                             }
+                         } else if (!earlyOnly) {
+                             handler.accept(def);
+                         }
+                     }
                  }
              } finally {
                  initScanClass = initScanClassPrev;
              }
          }

@@ -2191,16 +2213,17 @@
           */
          protected boolean trackable(VarSymbol sym) {
              return
                  sym.pos >= startPos &&
                  ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
-                 isFinalUninitializedField(sym)));
+                 isFinalOrStrictUninitializedField(sym)));
          }
  
-         boolean isFinalUninitializedField(VarSymbol sym) {
+         boolean isFinalOrStrictUninitializedField(VarSymbol sym) {
              return sym.owner.kind == TYP &&
-                    ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
+                    (((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL ||
+                      (sym.flags() & (STRICT | HASINIT | PARAMETER)) == STRICT) &&
                     classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
          }
  
          /** Initialize new trackable variable by setting its address field
           *  to the next available sequence number and entering it under that

@@ -2268,15 +2291,25 @@
          /** If tree is either a simple name or of the form this.name or
           *  C.this.name, and tree represents a trackable variable,
           *  record an initialization of the variable.
           */
          void letInit(JCTree tree) {
+             letInit(tree, (JCAssign) null);
+         }
+ 
+         void letInit(JCTree tree, JCAssign assign) {
              tree = TreeInfo.skipParens(tree);
              if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
                  Symbol sym = TreeInfo.symbol(tree);
                  if (sym.kind == VAR) {
                      letInit(tree.pos(), (VarSymbol)sym);
+                     if (isConstructor && sym.isStrict()) {
+                         /* we are initializing a strict field inside of a constructor, we now need to find which fields
+                          * haven't been initialized yet
+                          */
+                         unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, assign != null ? assign : tree, findUninitStrictFields());
+                     }
                  }
              }
          }
  
          /** Check that trackable variable is initialized.

@@ -2288,11 +2321,11 @@
          void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
              if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
                  trackable(sym) &&
                  !inits.isMember(sym.adr) &&
                  (sym.flags_field & CLASH) == 0) {
-                     log.error(pos, errkey);
+                 log.error(pos, errkey);
                  inits.incl(sym.adr);
              }
          }
  
          /** Utility method to reset several Bits instances.

@@ -2504,10 +2537,17 @@
                          /*  If we are executing the code from Gen, then there can be
                           *  synthetic or mandated variables, ignore them.
                           */
                          initParam(def);
                      }
+                     if (isConstructor) {
+                         Set<VarSymbol> unsetFields = findUninitStrictFields();
+                         if (unsetFields != null && !unsetFields.isEmpty()) {
+                             unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, tree.body, unsetFields);
+                         }
+                     }
+ 
                      // else we are in an instance initializer block;
                      // leave caught unchanged.
                      scan(tree.body);
  
                      boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||

@@ -2559,10 +2599,21 @@
              } finally {
                  lint = lintPrev;
              }
          }
  
+         Set<VarSymbol> findUninitStrictFields() {
+             Set<VarSymbol> unsetFields = new LinkedHashSet<>();
+             for (int i = uninits.nextBit(0); i >= 0; i = uninits.nextBit(i + 1)) {
+                 JCVariableDecl variableDecl = vardecls[i];
+                 if (variableDecl.sym.isStrict()) {
+                     unsetFields.add(variableDecl.sym);
+                 }
+             }
+             return unsetFields;
+         }
+ 
          private void clearPendingExits(boolean inMethod) {
              List<PendingExit> exits = pendingExits.toList();
              pendingExits = new ListBuffer<>();
              while (exits.nonEmpty()) {
                  PendingExit exit = exits.head;

@@ -3022,18 +3073,26 @@
              scanExpr(tree.expr);
              markDead();
          }
  
          public void visitApply(JCMethodInvocation tree) {
+             Name name = TreeInfo.name(tree.meth);
+             // let's process early initializers
+             if (name == names._super) {
+                 forEachInitializer(classDef, false, true, def -> {
+                     scan(def);
+                     clearPendingExits(false);
+                 });
+             }
              scanExpr(tree.meth);
              scanExprs(tree.args);
  
              // Handle superclass constructor invocations
              if (isConstructor) {
  
                  // If super(): at this point all initialization blocks will execute
-                 Name name = TreeInfo.name(tree.meth);
+ 
                  if (name == names._super) {
                      forEachInitializer(classDef, false, def -> {
                          scan(def);
                          clearPendingExits(false);
                      });

@@ -3041,11 +3100,11 @@
  
                  // If this(): at this point all final uninitialized fields will get initialized
                  else if (name == names._this) {
                      for (int address = firstadr; address < nextadr; address++) {
                          VarSymbol sym = vardecls[address].sym;
-                         if (isFinalUninitializedField(sym) && !sym.isStatic())
+                         if (isFinalOrStrictUninitializedField(sym) && !sym.isStatic())
                              letInit(tree.pos(), sym);
                      }
                  }
              }
          }

@@ -3115,11 +3174,11 @@
  
          public void visitAssign(JCAssign tree) {
              if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
                  scanExpr(tree.lhs);
              scanExpr(tree.rhs);
-             letInit(tree.lhs);
+             letInit(tree.lhs, tree);
          }
  
          // check fields accessed through this.<field> are definitely
          // assigned before reading their value
          public void visitSelect(JCFieldAccess tree) {
< prev index next >