Fix for Bug 430307 - [1.8][model] NPE trying to get children of a
LambdaExpression restored from handleIdentifier

Signed-off-by: Srikanth Sankaran <srikanth_sankaran@in.ibm.com>
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaElement8Tests.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaElement8Tests.java
index 038aa15..bbe8926 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaElement8Tests.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/JavaElement8Tests.java
@@ -520,7 +520,7 @@
 			assertEquals("Incorrect java element", IJavaElement.LOCAL_VARIABLE, elements[0].getElementType());
 			IType lambda = (IType) elements[0].getParent().getParent();
 			String mem = lambda.getHandleIdentifier();
-			String expected = "=\\(\\[Bug430136\\]\\)/src<{X.java[MyFunction~compose~QMyFunction\\<-QV;+QT;>;=)Lambda\\(MyFunction\\)=\"LMyFunction\\<TV;TR;>;!148!174!151";
+			String expected = "=\\(\\[Bug430136\\])/src<{X.java[MyFunction~compose~QMyFunction\\<-QV;+QT;>;=)Lambda\\(MyFunction)=\"LMyFunction\\<TV;TR;>;!148!174!151=&apply!1=\"TV;=\"v=\"TR;=\"LX\\~MyFunction\\<LX\\~MyFunction;:1TV;LX\\~MyFunction;:TR;>;.apply\\(TV;)TR;@v!148!148!148!148!Ljava\\/lang\\/Object;!0!true=)";
 			assertEquals("Incorrect memento", expected, mem);
 			IJavaElement result = JavaCore.create(expected);
 			assertEquals("Incorrect element created", lambda, result);
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
index f7332be..c4f1fbb 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ResolveTests18.java
@@ -21,11 +21,13 @@
 import org.eclipse.jdt.core.ICodeAssist;
 import org.eclipse.jdt.core.ICompilationUnit;
 import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.ILocalVariable;
 import org.eclipse.jdt.core.IMethod;
 import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.core.WorkingCopyOwner;
 import org.eclipse.jdt.internal.core.LambdaExpression;
+import org.eclipse.jdt.internal.core.LambdaMethod;
 
 public class ResolveTests18 extends AbstractJavaModelTests {
 	ICompilationUnit wc = null;
@@ -2424,14 +2426,14 @@
 	IMethod lambda = (IMethod) elements[0].getParent();
 	String memento = lambda.getHandleIdentifier();
 	assertEquals("Incorrect memento string", 
-			"=Resolve/src<{X.java[X~foo~QList\\<QU;>;=)Lambda\\(Getter)=\"LGetter\\<TU;>;!144!161!152=&get!2=\"Ljava.util.List\\<TU;>;=\"x=\"I=\"i=\"TU;=\"LX\\~Getter\\<LX;:TU;>;.get\\(Ljava\\/util\\/List\\<TU;>;I)TU;@x!145!145!145!145!Ljava\\/util\\/List;!0!true@i!148!148!148!148!I!0!true", 
+			"=Resolve/src<{X.java[X~foo~QList\\<QU;>;=)Lambda\\(Getter)=\"LGetter\\<TU;>;!144!161!152=&get!2=\"Ljava.util.List\\<TU;>;=\"x=\"I=\"i=\"TU;=\"LX\\~Getter\\<LX;:TU;>;.get\\(Ljava\\/util\\/List\\<TU;>;I)TU;@x!145!145!145!145!Ljava\\/util\\/List;!0!true@i!148!148!148!148!I!0!true=&", 
 			memento);
 	IJavaElement result = JavaCore.create(memento);
 	assertEquals("Java elements should be equal", lambda, result);
 	LambdaExpression expression = (LambdaExpression) lambda.getParent();
 	memento = expression.getHandleIdentifier();
 	assertEquals("Incorrect memento string", 
-			"=Resolve/src<{X.java[X~foo~QList\\<QU;>;=)Lambda\\(Getter)=\"LGetter\\<TU;>;!144!161!152", 
+			"=Resolve/src<{X.java[X~foo~QList\\<QU;>;=)Lambda\\(Getter)=\"LGetter\\<TU;>;!144!161!152=&get!2=\"Ljava.util.List\\<TU;>;=\"x=\"I=\"i=\"TU;=\"LX\\~Getter\\<LX;:TU;>;.get\\(Ljava\\/util\\/List\\<TU;>;I)TU;@x!145!145!145!145!Ljava\\/util\\/List;!0!true@i!148!148!148!148!I!0!true=)", 
 			memento);
 	result = JavaCore.create(memento);
 	assertEquals("Java elements should be equal", expression, result);
@@ -2441,16 +2443,137 @@
 	lambda = (IMethod) elements[0].getParent();
 	memento = lambda.getHandleIdentifier();
 	assertEquals("Incorrect memento string", 
-			"=Resolve/src<{X.java[X~foo~QList\\<QU;>;=)Lambda\\(Getter)=\"LGetter\\<TU;>;!180!197!188=&get!2=\"Ljava.util.List\\<TU;>;=\"x=\"I=\"i=\"TU;=\"LX\\~Getter\\<LX;:TU;>;.get\\(Ljava\\/util\\/List\\<TU;>;I)TU;@x!181!181!181!181!Ljava\\/util\\/List;!0!true@i!184!184!184!184!I!0!true", 
+			"=Resolve/src<{X.java[X~foo~QList\\<QU;>;=)Lambda\\(Getter)=\"LGetter\\<TU;>;!180!197!188=&get!2=\"Ljava.util.List\\<TU;>;=\"x=\"I=\"i=\"TU;=\"LX\\~Getter\\<LX;:TU;>;.get\\(Ljava\\/util\\/List\\<TU;>;I)TU;@x!181!181!181!181!Ljava\\/util\\/List;!0!true@i!184!184!184!184!I!0!true=&", 
 			memento);
 	result = JavaCore.create(memento);
 	assertEquals("Java elements should be equal", lambda, result);
 	expression = (LambdaExpression) lambda.getParent();
 	memento = expression.getHandleIdentifier();
 	assertEquals("Incorrect memento string", 
-			"=Resolve/src<{X.java[X~foo~QList\\<QU;>;=)Lambda\\(Getter)=\"LGetter\\<TU;>;!180!197!188", 
+			"=Resolve/src<{X.java[X~foo~QList\\<QU;>;=)Lambda\\(Getter)=\"LGetter\\<TU;>;!180!197!188=&get!2=\"Ljava.util.List\\<TU;>;=\"x=\"I=\"i=\"TU;=\"LX\\~Getter\\<LX;:TU;>;.get\\(Ljava\\/util\\/List\\<TU;>;I)TU;@x!181!181!181!181!Ljava\\/util\\/List;!0!true@i!184!184!184!184!I!0!true=)", 
 			memento);
 	result = JavaCore.create(memento);
 	assertEquals("Java elements should be equal", expression, result);
 }
+// https://bugs.eclipse.org/bugs/show_bug.cgi?id=430307,  [1.8][model] NPE trying to get children of a LambdaExpression restored from handleIdentifier 
+public void test430307() throws CoreException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/Resolve/src/X.java",
+			"import java.util.List;\n" +
+			"interface Getter<E> {\n" +
+			"    E get(List<E> list, int i);\n" +
+			"}\n" +
+			"public class X<U> {\n" +
+			"	public void foo(List<U> l) {\n" +
+			"		Getter<U> g= (x, i) -> x.get(i);\n" +
+			"	} \n" +
+			"}\n"
+			);
+	
+	String str = this.workingCopies[0].getSource();
+	
+	String selection = "x,";
+	int start = str.indexOf(selection);
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, 1);
+	ILocalVariable local = (ILocalVariable) elements[0];
+	String memento = local.getHandleIdentifier();
+	assertEquals("Incorrect memento string", 
+			"=Resolve/src<{X.java[X~foo~QList\\<QU;>;=)Lambda\\(Getter)=\"LGetter\\<TU;>;!144!161!152=&get!2=\"Ljava.util.List\\<TU;>;=\"x=\"I=\"i=\"TU;=\"LX\\~Getter\\<LX;:TU;>;.get\\(Ljava\\/util\\/List\\<TU;>;I)TU;@x!145!145!145!145!Ljava\\/util\\/List;!0!true@i!148!148!148!148!I!0!true=&@x!145!145!145!145!Ljava.util.List\\<LU;>;!0!true", 
+			memento);
+	IJavaElement result = JavaCore.create(memento);
+	assertEquals("Java elements should be equal", local, result);
+
+	IJavaElement parentMethod = result.getParent();
+	IJavaElement parentExpr = parentMethod.getParent();
+	IMethod lambda = (IMethod) elements[0].getParent();
+	memento = lambda.getHandleIdentifier();
+	assertEquals("Incorrect memento string", 
+			"=Resolve/src<{X.java[X~foo~QList\\<QU;>;=)Lambda\\(Getter)=\"LGetter\\<TU;>;!144!161!152=&get!2=\"Ljava.util.List\\<TU;>;=\"x=\"I=\"i=\"TU;=\"LX\\~Getter\\<LX;:TU;>;.get\\(Ljava\\/util\\/List\\<TU;>;I)TU;@x!145!145!145!145!Ljava\\/util\\/List;!0!true@i!148!148!148!148!I!0!true=&", 
+			memento);
+	result = JavaCore.create(memento);
+	assertEquals("Java elements should be equal", lambda, result);
+	assertEquals("Java elements should be equal", result, parentMethod);
+	LambdaExpression expression = (LambdaExpression) lambda.getParent();
+	memento = expression.getHandleIdentifier();
+	assertEquals("Incorrect memento string", 
+			"=Resolve/src<{X.java[X~foo~QList\\<QU;>;=)Lambda\\(Getter)=\"LGetter\\<TU;>;!144!161!152=&get!2=\"Ljava.util.List\\<TU;>;=\"x=\"I=\"i=\"TU;=\"LX\\~Getter\\<LX;:TU;>;.get\\(Ljava\\/util\\/List\\<TU;>;I)TU;@x!145!145!145!145!Ljava\\/util\\/List;!0!true@i!148!148!148!148!I!0!true=)", 
+			memento);
+	LambdaExpression recreatedType = (LambdaExpression) JavaCore.create(memento);
+	assertEquals("Java elements should be equal", expression, recreatedType);
+	assertEquals("Java elements should be equal", recreatedType, parentExpr);
+	LambdaMethod child = (LambdaMethod) recreatedType.getChildren()[0];
+	assertEquals("Java elements should be equal", lambda, child);
+}
+public void test430307a() throws JavaModelException {
+	this.workingCopies = new ICompilationUnit[1];
+	this.workingCopies[0] = getWorkingCopy("/Resolve/src/X.java",
+			"interface I {\n" +
+			"    I doit(I xyz);\n" +
+			"}\n" +
+			"public class X { \n" +
+			"	public static void main(String[] args) {\n" +
+			"		I i = (pqr) -> {\n" +
+			"			return (xyz) -> {\n" +
+			"				return (abc) -> abc; \n" +
+			"			};\n" +
+			"		};\n" +
+			"	}\n" +
+			"}\n");
+	String str = this.workingCopies[0].getSource();
+	
+	String selection = "abc)";
+	int start = str.indexOf(selection);
+	IJavaElement[] elements = this.workingCopies[0].codeSelect(start, 3);
+	ILocalVariable local = (ILocalVariable) elements[0];
+	String memento = local.getHandleIdentifier();
+		assertEquals(
+				"Incorrect memento string",
+				"=Resolve/src<{X.java[X~main~\\[QString;=)Lambda\\(I)=\"LI;!103!169!110=&doit!1=\"LI;=\"pqr=\"LI;=\"LX\\~I;.doit\\(LI;)"
+				+ "LI;@pqr!104!106!104!106!LI;!0!true=&=)Lambda\\(I)=\"LI;!124!164!131=&doit!1=\"LI;=\"xyz=\"LI;=\"LX\\~I;.doit\\(LI;)"
+				+ "LI;@xyz!125!127!125!127!LI;!0!true=&=)Lambda\\(I)=\"LI;!146!157!153=&doit!1=\"LI;=\"abc=\"LI;=\"LX\\~I;.doit\\(LI;)"
+				+ "LI;@abc!147!149!147!149!LI;!0!true=&@abc!147!149!147!149!LI;!0!true",
+				memento);
+	IJavaElement result = JavaCore.create(memento);
+	assertEquals("Java elements should be equal", local, result);
+
+	IJavaElement parentMethod = result.getParent();
+	IJavaElement parentExpr = parentMethod.getParent();
+	assertEquals("Java elements should be equal", parentMethod, local.getParent());
+	assertEquals("Java elements should be equal", parentExpr, local.getParent().getParent());
+	
+	selection = "xyz)";
+	start = str.lastIndexOf(selection);
+	elements = this.workingCopies[0].codeSelect(start, 3);
+	local = (ILocalVariable) elements[0];
+	memento = local.getHandleIdentifier();
+	assertEquals("Incorrect memento string", 
+			"=Resolve/src<{X.java[X~main~\\[QString;=)Lambda\\(I)=\"LI;!103!169!110=&doit!1=\"LI;=\"pqr=\"LI;=\"LX\\~I;.doit\\(LI;)"
+			+ "LI;@pqr!104!106!104!106!LI;!0!true=&=)Lambda\\(I)=\"LI;!124!164!131=&doit!1=\"LI;=\"xyz=\"LI;=\"LX\\~I;.doit\\(LI;)"
+			+ "LI;@xyz!125!127!125!127!LI;!0!true=&@xyz!125!127!125!127!LI;!0!true", 
+			memento);
+	result = JavaCore.create(memento);
+	assertEquals("Java elements should be equal", local, result);
+
+	parentMethod = result.getParent();
+	parentExpr = parentMethod.getParent();
+	assertEquals("Java elements should be equal", parentMethod, local.getParent());
+	assertEquals("Java elements should be equal", parentExpr, local.getParent().getParent());
+	
+	selection = "pqr)";
+	start = str.indexOf(selection);
+	elements = this.workingCopies[0].codeSelect(start, 3);
+	local = (ILocalVariable) elements[0];
+	memento = local.getHandleIdentifier();
+	assertEquals("Incorrect memento string", 
+			"=Resolve/src<{X.java[X~main~\\[QString;=)Lambda\\(I)=\"LI;!103!169!110=&doit!1=\"LI;=\"pqr=\"LI;=\"LX\\~I;.doit\\(LI;)"
+			+ "LI;@pqr!104!106!104!106!LI;!0!true=&@pqr!104!106!104!106!LI;!0!true", 
+			memento);
+	result = JavaCore.create(memento);
+	assertEquals("Java elements should be equal", local, result);
+
+	parentMethod = result.getParent();
+	parentExpr = parentMethod.getParent();
+	assertEquals("Java elements should be equal", parentMethod, local.getParent());
+	assertEquals("Java elements should be equal", parentExpr, local.getParent().getParent());
+}
 }
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java
index b1d0d55..2736fc0 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaExpression.java
@@ -131,11 +131,13 @@
 	 * @see JavaElement#getHandleMemento(StringBuffer)
 	 */
 	protected void getHandleMemento(StringBuffer buff) {
-		getHandleMemento(buff, true);
+		getHandleMemento(buff, true, true);
+		// lambda method and lambda expression cannot share the same memento - add a trailing discriminator.
+		appendEscapedDelimiter(buff, getHandleMementoDelimiter());
 	}
 	
-	protected void getHandleMemento(StringBuffer buff, boolean memoizeParent) {
-		if (memoizeParent) 
+	protected void getHandleMemento(StringBuffer buff, boolean serializeParent, boolean serializeChild) {
+		if (serializeParent) 
 			((JavaElement)getParent()).getHandleMemento(buff);
 		appendEscapedDelimiter(buff, getHandleMementoDelimiter());
 		escapeMementoName(buff, this.name);
@@ -147,6 +149,8 @@
 		buff.append(this.sourceEnd);
 		buff.append(JEM_COUNT);
 		buff.append(this.arrowPosition);
+		if (serializeChild)
+			this.lambdaMethod.getHandleMemento(buff, false);
 	}
 	
 	public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner workingCopyOwner) {
@@ -179,7 +183,17 @@
 		}
 		this.lambdaMethod.elementInfo.arguments  = parameters;
 		this.elementInfo.children = new IJavaElement[] { this.lambdaMethod };
-		return this.lambdaMethod;
+		if (!memento.hasMoreTokens())
+			return this.lambdaMethod;
+		switch (memento.nextToken().charAt(0)) {
+			case JEM_LAMBDA_METHOD:
+				if (!memento.hasMoreTokens())
+					return this.lambdaMethod;
+				return this.lambdaMethod.getHandleFromMemento(memento, workingCopyOwner);
+			case JEM_LAMBDA_EXPRESSION:
+			default:
+				return this;	
+		}
 	}
 
 	public IJavaElement[] getChildren() throws JavaModelException {
@@ -209,8 +223,7 @@
 		if (primaryParent instanceof JavaElement) {
 			JavaElement ancestor = (JavaElement) primaryParent;
 			StringBuffer buffer = new StringBuffer(32);
-			getHandleMemento(buffer, false);
-			this.lambdaMethod.getHandleMemento(buffer, false);
+			getHandleMemento(buffer, false, true);
 			String memento = buffer.toString();
 			return ancestor.getHandleFromMemento(new MementoTokenizer(memento), DefaultWorkingCopyOwner.PRIMARY).getParent();
 		}
@@ -220,4 +233,4 @@
 	public String[] getSuperInterfaceTypeSignatures() throws JavaModelException {
 		return new String[] { this.interphase };
 	}
-}
\ No newline at end of file
+}
diff --git a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaMethod.java b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaMethod.java
index a6912a7..cf3e7c8 100644
--- a/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaMethod.java
+++ b/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/LambdaMethod.java
@@ -134,9 +134,10 @@
 		return this.elementInfo;
 	}
 	
-	public void getHandleMemento(StringBuffer buff, boolean memoizeParent) {
-		if (memoizeParent)
-			((JavaElement) getParent()).getHandleMemento(buff);
+	public void getHandleMemento(StringBuffer buff, boolean serializeParent) {
+		if (serializeParent) {
+			((LambdaExpression) getParent()).getHandleMemento(buff, true, false);
+		}
 		appendEscapedDelimiter(buff, getHandleMementoDelimiter());
 		escapeMementoName(buff, getElementName());
 		buff.append(JEM_COUNT);
@@ -159,6 +160,8 @@
 	}
 	public void getHandleMemento(StringBuffer buff) {
 		getHandleMemento(buff, true);
+		// lambda method and lambda expression cannot share the same memento - add a trailing discriminator.
+		appendEscapedDelimiter(buff, getHandleMementoDelimiter());
 	}
 	
 	protected char getHandleMementoDelimiter() {