public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
   LocalVariableBinding local = this.expression.localVariableBinding();
   if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
     flowInfo =
         this.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
     FlowInfo initsWhenTrue = flowInfo.copy();
     initsWhenTrue.markAsComparedEqualToNonNull(local);
     if ((flowContext.tagBits & FlowContext.HIDE_NULL_COMPARISON_WARNING) != 0) {
       initsWhenTrue.markedAsNullOrNonNullInAssertExpression(local);
     }
     flowContext.recordUsingNullReference(
         currentScope,
         local,
         this.expression,
         FlowContext.CAN_ONLY_NULL | FlowContext.IN_INSTANCEOF,
         flowInfo);
     // no impact upon enclosing try context
     return FlowInfo.conditional(initsWhenTrue, flowInfo.copy());
   }
   return this.expression.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
 }
  public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {

    Constant cst = this.left.optimizedBooleanConstant();
    boolean isLeftOptimizedTrue = cst != Constant.NotAConstant && cst.booleanValue() == true;
    boolean isLeftOptimizedFalse = cst != Constant.NotAConstant && cst.booleanValue() == false;

    if (isLeftOptimizedFalse) {
      // FALSE || anything
      // need to be careful of scenario:
      //		(x || y) || !z, if passing the left info to the right, it would be swapped by the !
      FlowInfo mergedInfo =
          this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
      flowContext.expireNullCheckedFieldInfo();
      mergedInfo = this.right.analyseCode(currentScope, flowContext, mergedInfo);
      flowContext.expireNullCheckedFieldInfo();
      this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
      return mergedInfo;
    }

    FlowInfo leftInfo = this.left.analyseCode(currentScope, flowContext, flowInfo);
    flowContext.expireNullCheckedFieldInfo();

    // need to be careful of scenario:
    //		(x || y) || !z, if passing the left info to the right, it would be swapped by the !
    FlowInfo rightInfo = leftInfo.initsWhenFalse().unconditionalCopy();
    this.rightInitStateIndex = currentScope.methodScope().recordInitializationStates(rightInfo);

    int previousMode = rightInfo.reachMode();
    if (isLeftOptimizedTrue) {
      if ((rightInfo.reachMode() & FlowInfo.UNREACHABLE) == 0) {
        currentScope.problemReporter().fakeReachable(this.right);
        rightInfo.setReachMode(FlowInfo.UNREACHABLE_OR_DEAD);
      }
    }
    rightInfo = this.right.analyseCode(currentScope, flowContext, rightInfo);
    flowContext.expireNullCheckedFieldInfo();
    if ((this.left.implicitConversion & TypeIds.UNBOXING) != 0) {
      this.left.checkNPE(currentScope, flowContext, flowInfo);
    }
    if ((this.right.implicitConversion & TypeIds.UNBOXING) != 0) {
      this.right.checkNPE(currentScope, flowContext, flowInfo);
    }
    // The definitely null variables in right info when true should not be missed out while merging
    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=299900
    FlowInfo leftInfoWhenTrueForMerging =
        leftInfo
            .initsWhenTrue()
            .unconditionalCopy()
            .addPotentialInitializationsFrom(rightInfo.unconditionalInitsWithoutSideEffect());
    FlowInfo mergedInfo =
        FlowInfo.conditional(
            // merging two true initInfos for such a negative case: if ((t && (b = t)) || f) r = b;
            // // b may not have been initialized
            leftInfoWhenTrueForMerging
                .unconditionalInits()
                .mergedWith(
                    rightInfo.safeInitsWhenTrue().setReachMode(previousMode).unconditionalInits()),
            rightInfo.initsWhenFalse());
    this.mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
    return mergedInfo;
  }