Fixed bug 499809: [null][1.8] VerifyError when Null Analysis is on

Change-Id: I6fee92111d345d6581679479a27a134f875c5852
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java
index e521892..f77f4a5 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/FlowAnalysisTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2012 IBM Corporation and others.
+ * Copyright (c) 2005, 2016 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -2700,6 +2700,50 @@
 		},
 		"test");
 }
+public void testBug499809() {
+	this.runConformTest(
+		new String[] {
+			"Foo.java",
+			"public class Foo {\n" + 
+			"	static void foo( ) {\n" + 
+			"		String _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, a, b,\n" + 
+			"		c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, s0, s1, s2, s3, s4, s5, s6, s7;\n" + 
+			"		Object ob = new Object();\n" + 
+			"		int int1 = 0, int2 = 2, int3, int4;\n" + 
+			"		if (ob != null) {\n" + 
+			"			int4 = 1;\n" + 
+			"		}\n" + 
+			"	}\n" + 
+			"	public static void main(String[] args) {\n" + 
+			"		System.out.println(\"Done\");\n" + 
+			"	}\n" + 
+			"}\n"
+		},
+		"Done");
+}
+public void testBug499809a() {
+	this.runConformTest(
+		new String[] {
+			"Foo.java",
+			"public class Foo {\n" + 
+			"	static void foo( ) {\n" + 
+			"		String _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, a, b,\n" + 
+			"		c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, s0, s1, s2, s3, s4, s5, s6, s7;\n" + 
+			"		Object ob = new Object();\n" + 
+			"		int int1 = 0, int2 = 2, int3, int4;\n" +  
+			"		if (ob == null) {\n" + 
+			"			int1 = 1;\n" + 
+			"		} else {\n" + 
+			"			int4 = 1;\n" +
+			"		}\n" +
+			"	}\n" + 
+			"	public static void main(String[] args) {\n" + 
+			"		System.out.println(\"Done\");\n" + 
+			"	}\n" + 
+			"}\n"
+		},
+		"Done");
+}
 public static Class testClass() {
 	return FlowAnalysisTest.class;
 }
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
index 288fb8f..2d5fd51 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/ConditionalFlowInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -214,7 +214,9 @@
 public UnconditionalFlowInfo mergedWith(UnconditionalFlowInfo otherInits) {
 	return unconditionalInits().mergedWith(otherInits);
 }
-
+public UnconditionalFlowInfo mergeDefiniteInitsWith(UnconditionalFlowInfo otherInits) {
+	return unconditionalInits().mergeDefiniteInitsWith(otherInits);
+}
 public UnconditionalFlowInfo nullInfoLessUnconditionalCopy() {
 	return unconditionalInitsWithoutSideEffect().
 		nullInfoLessUnconditionalCopy();
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
index 838843c..018886f 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/FlowInfo.java
@@ -533,7 +533,8 @@
 			unconditionalInits();
 		// if a variable is only initialized in one branch and not initialized in the other,
 		// then we need to cast a doubt on its initialization in the merged info
-		mergedInfo.definiteInits &= initsWhenFalse.unconditionalCopy().definiteInits;
+		mergedInfo.mergeDefiniteInitsWith(initsWhenFalse.unconditionalCopy());
+		
 		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=415997, classify unreachability precisely, IsElseStatementUnreachable could be due to null analysis
 		if ((mergedInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 && (initsWhenFalse.tagBits & FlowInfo.UNREACHABLE) == FlowInfo.UNREACHABLE_BY_NULLANALYSIS) {
 			mergedInfo.tagBits &= ~UNREACHABLE_OR_DEAD;
@@ -553,7 +554,7 @@
 			unconditionalInits();
 		// if a variable is only initialized in one branch and not initialized in the other,
 		// then we need to cast a doubt on its initialization in the merged info
-		mergedInfo.definiteInits &= initsWhenTrue.unconditionalCopy().definiteInits;
+		mergedInfo.mergeDefiniteInitsWith(initsWhenTrue.unconditionalCopy());
 		// https://bugs.eclipse.org/bugs/show_bug.cgi?id=415997, classify unreachability precisely, IsThenStatementUnreachable could be due to null analysis
 		if ((mergedInfo.tagBits & FlowInfo.UNREACHABLE_OR_DEAD) != 0 && (initsWhenTrue.tagBits & FlowInfo.UNREACHABLE) == FlowInfo.UNREACHABLE_BY_NULLANALYSIS) {
 			mergedInfo.tagBits &= ~UNREACHABLE_OR_DEAD;
@@ -610,6 +611,8 @@
 abstract public UnconditionalFlowInfo mergedWith(
 		UnconditionalFlowInfo otherInits);
 
+abstract public UnconditionalFlowInfo mergeDefiniteInitsWith(UnconditionalFlowInfo otherInits);
+
 /**
  * Return a copy of this unconditional flow info, deprived from its null
  * info. {@link #DEAD_END DEAD_END} is returned unmodified.
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
index 394486e..91ac1c2 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/flow/UnconditionalFlowInfo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2012 IBM Corporation and others.
+ * Copyright (c) 2000, 2016 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -2088,7 +2088,57 @@
 public UnconditionalFlowInfo unconditionalInitsWithoutSideEffect() {
 	return this;
 }
+public UnconditionalFlowInfo mergeDefiniteInitsWith(UnconditionalFlowInfo otherInits) {
+	if ((otherInits.tagBits & UNREACHABLE_OR_DEAD) != 0 && this != DEAD_END) {
+		return this;
+	}
+	if ((this.tagBits & UNREACHABLE_OR_DEAD) != 0) {
+		return (UnconditionalFlowInfo) otherInits.copy(); // make sure otherInits won't be affected
+	}
 
+	// intersection of definitely assigned variables,
+	this.definiteInits &= otherInits.definiteInits;
+	if (this.extra != null) {
+		if (otherInits.extra != null) {
+			// both sides have extra storage
+			int i = 0, length, otherLength;
+			if ((length = this.extra[0].length) < (otherLength = otherInits.extra[0].length)) {
+				// current storage is shorter -> grow current
+				for (int j = 0; j < extraLength; j++) {
+					System.arraycopy(this.extra[j], 0,
+						(this.extra[j] = new long[otherLength]), 0, length);
+				}
+				for (; i < length; i++) {
+					this.extra[0][i] &= otherInits.extra[0][i];
+				}
+				for (; i < otherLength; i++) {
+					this.extra[0][i] = otherInits.extra[0][i];
+				}
+			}
+			else {
+				// current storage is longer
+				for (; i < otherLength; i++) {
+					this.extra[0][i] &= otherInits.extra[0][i];
+				}
+			}
+		} else {
+			for (int i = 0; i < this.extra[0].length; i++) {
+				this.extra[0][i] = 0;
+			}
+		}
+	}
+	else if (otherInits.extra != null) {
+		// no storage here, but other has extra storage.
+		int otherLength = otherInits.extra[0].length;
+		this.extra = new long[extraLength][];
+		for (int j = 0; j < extraLength; j++) {
+			this.extra[j] = new long[otherLength];
+		}
+		System.arraycopy(otherInits.extra[0], 0, this.extra[0], 0,
+				otherLength);
+	}
+	return this;
+}
 public void resetAssignmentInfo(LocalVariableBinding local) {
 	resetAssignmentInfo(local.id + this.maxFieldCount);
 }