/** Check statement */
 Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
   checkLabel(env, ctx);
   CheckContext newctx = new CheckContext(ctx, this);
   // Vset vsExtra = vset.copy();  // See comment below.
   ConditionVars cvars = cond.checkCondition(env, newctx, reach(env, vset), exp);
   cond = convert(env, newctx, Type.tBoolean, cond);
   // The following code, now deleted, was apparently an erroneous attempt
   // at providing better error diagnostics.  The comment read: 'If either
   // the true clause or the false clause is unreachable, do a reasonable
   // check on the child anyway.'
   //    Vset vsTrue  = cvars.vsTrue.isDeadEnd() ? vsExtra : cvars.vsTrue;
   //    Vset vsFalse = cvars.vsFalse.isDeadEnd() ? vsExtra : cvars.vsFalse;
   // Unfortunately, this violates the rules laid out in the JLS, and leads to
   // blatantly incorrect results.  For example, 'i' will not be recognized
   // as definitely assigned following the statement 'if (true) i = 1;'.
   // It is best to slavishly follow the JLS here.  A cleverer approach could
   // only correctly issue warnings, as JLS 16.2.6 is quite explicit, and it
   // is OK for a dead branch of an if-statement to omit an assignment that
   // would be required in the other branch.  A complication: This code also
   // had the effect of implementing the special-case rules for 'if-then' and
   // 'if-then-else' in JLS 14.19, "Unreachable Statements".  We now use
   // 'Vset.clearDeadEnd' to remove the dead-end status of unreachable branches
   // without affecting the definite-assignment status of the variables, thus
   // maintaining a correct implementation of JLS 16.2.6.  Fixes 4094353.
   // Note that the code below will not consider the branches unreachable if
   // the entire statement is unreachable.  This is consistent with the error
   // recovery policy that reports the only the first unreachable statement
   // along an acyclic execution path.
   Vset vsTrue = cvars.vsTrue.clearDeadEnd();
   Vset vsFalse = cvars.vsFalse.clearDeadEnd();
   vsTrue = ifTrue.check(env, newctx, vsTrue, exp);
   if (ifFalse != null) vsFalse = ifFalse.check(env, newctx, vsFalse, exp);
   vset = vsTrue.join(vsFalse.join(newctx.vsBreak));
   return ctx.removeAdditionalVars(vset);
 }
Пример #2
0
  /** Check statement */
  Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
    checkLabel(env, ctx);
    vset = reach(env, vset);
    if (expr != null) {
      vset = expr.checkValue(env, ctx, vset, exp);
    }

    // Make sure the return isn't inside a static initializer
    if (ctx.field.isInitializer()) {
      env.error(where, "return.inside.static.initializer");
      return DEAD_END;
    }
    // Check return type
    if (ctx.field.getType().getReturnType().isType(TC_VOID)) {
      if (expr != null) {
        if (ctx.field.isConstructor()) {
          env.error(where, "return.with.value.constr", ctx.field);
        } else {
          env.error(where, "return.with.value", ctx.field);
        }
        expr = null;
      }
    } else {
      if (expr == null) {
        env.error(where, "return.without.value", ctx.field);
      } else {
        expr = convert(env, ctx, ctx.field.getType().getReturnType(), expr);
      }
    }
    CheckContext mctx = ctx.getReturnContext();
    if (mctx != null) {
      mctx.vsBreak = mctx.vsBreak.join(vset);
    }
    CheckContext exitctx = ctx.getTryExitContext();
    if (exitctx != null) {
      exitctx.vsTryExit = exitctx.vsTryExit.join(vset);
    }
    if (expr != null) {
      // see if we are returning a value out of a try or synchronized
      // statement.  If so, find the outermost one. . . .
      Node outerFinallyNode = null;
      for (Context c = ctx; c != null; c = c.prev) {
        if (c.node == null) {
          continue;
        }
        if (c.node.op == METHOD) {
          // Don't search outside current method. Fixes 4084230.
          break;
        }
        if (c.node.op == SYNCHRONIZED) {
          outerFinallyNode = c.node;
          break;
        } else if (c.node.op == FINALLY && ((CheckContext) c).vsContinue != null) {
          outerFinallyNode = c.node;
        }
      }
      if (outerFinallyNode != null) {
        if (outerFinallyNode.op == FINALLY) {
          ((FinallyStatement) outerFinallyNode).needReturnSlot = true;
        } else {
          ((SynchronizedStatement) outerFinallyNode).needReturnSlot = true;
        }
      }
    }
    return DEAD_END;
  }