[491264] Cache Functions in CG
diff --git a/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/analyzer/QVTiAS2CGVisitor.java b/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/analyzer/QVTiAS2CGVisitor.java
index c920b63..288e676 100644
--- a/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/analyzer/QVTiAS2CGVisitor.java
+++ b/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/analyzer/QVTiAS2CGVisitor.java
@@ -634,6 +634,9 @@
 			analyzer.setNames(cgFunctionParameter, asFunctionParameter);
 			setAst(cgFunctionParameter, asFunctionParameter);
 			cgFunctionParameter.setTypeId(analyzer.getTypeId(asFunctionParameter.getTypeId()));
+			if (asFunctionParameter.isIsRequired()) {
+				cgFunctionParameter.setNonNull();
+			}
 			addParameter(asFunctionParameter, cgFunctionParameter);
 		}
 		return cgFunctionParameter;
diff --git a/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/java/QVTiCG2JavaVisitor.java b/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/java/QVTiCG2JavaVisitor.java
index e9fd7ad..7f880dd 100644
--- a/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/java/QVTiCG2JavaVisitor.java
+++ b/plugins/org.eclipse.qvtd.codegen/src/org/eclipse/qvtd/codegen/qvti/java/QVTiCG2JavaVisitor.java
@@ -28,6 +28,7 @@
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.ocl.examples.codegen.analyzer.NameManager;
 import org.eclipse.ocl.examples.codegen.cgmodel.CGAccumulator;
+import org.eclipse.ocl.examples.codegen.cgmodel.CGClass;
 import org.eclipse.ocl.examples.codegen.cgmodel.CGCollectionExp;
 import org.eclipse.ocl.examples.codegen.cgmodel.CGEcorePropertyCallExp;
 import org.eclipse.ocl.examples.codegen.cgmodel.CGExecutorProperty;
@@ -47,6 +48,7 @@
 import org.eclipse.ocl.examples.codegen.java.JavaLocalContext;
 import org.eclipse.ocl.examples.codegen.java.JavaStream;
 import org.eclipse.ocl.examples.codegen.java.types.BoxedDescriptor;
+import org.eclipse.ocl.examples.codegen.utilities.CGUtil;
 import org.eclipse.ocl.pivot.Element;
 import org.eclipse.ocl.pivot.NavigationCallExp;
 import org.eclipse.ocl.pivot.Operation;
@@ -524,6 +526,51 @@
 		return true;
 	}
 
+	protected boolean doFunctionBody(@NonNull CGFunction cgFunction, @NonNull String instanceName) {
+		CGValuedElement body = getExpression(cgFunction.getBody());
+		ElementId elementId = cgFunction.getTypeId().getElementId();
+		// FIXME merge locals into AST as LetExps.
+		if (cgFunction.getBody() != null) {
+			if (!js.appendLocalStatements(body)) {
+				return false;
+			}
+			js.append("this." + instanceName + " = ");
+			js.appendValueName(body);
+			js.append(";\n");
+		}
+		else {
+			TypeId asTypeId = cgFunction.getASTypeId();
+			if (asTypeId == TypeId.STRING) {			// FIXME Fudge for body-less functions
+				js.append("this." + instanceName + " = \"\";\n");
+			}
+			else if (asTypeId == TypeId.REAL) {			// FIXME Fudge for body-less functions
+				js.append("this." + instanceName + " = 0;\n");
+			}
+			else if (asTypeId == TypeId.INTEGER) {			// FIXME Fudge for body-less functions
+				js.append("this." + instanceName + " = 0;\n");
+			}
+			else if (asTypeId instanceof CollectionTypeId) {			// FIXME Fudge for body-less functions
+				if (js.isUseNullAnnotations()) {
+					js.append("@SuppressWarnings(\"null\")");
+					js.appendIsRequired(true);
+					js.append(" ");
+				}
+				if (elementId != null) {
+					TypeDescriptor javaTypeDescriptor = context.getUnboxedDescriptor(elementId);
+					js.appendClassReference(javaTypeDescriptor);
+				}
+				js.append(" emptyList = ");
+				js.appendClassReference(Collections.class);
+				js.append(".emptyList();\n");
+				js.append("this." + instanceName + " = emptyList;\n");
+			}
+			else {			// FIXME Fudge for body-less functions
+				js.append("this." + instanceName + " = \"\";\n");
+			}
+		}
+		return true;
+	}
+
 	protected boolean doFunctionBody2(@NonNull CGFunction cgFunction, @NonNull CGShadowExp cgShadowExp, @NonNull String instanceName) {
 		js.append(" {\n");
 		js.pushIndentation(null);
@@ -572,6 +619,40 @@
 		return true;
 	}
 
+	protected void doFunctionConstructor(@NonNull CGFunction cgFunction, @NonNull String instanceName) {
+		CGClass cgClass = ClassUtil.nonNullState(CGUtil.getContainingClass(cgFunction));
+		List<@NonNull CGParameter> cgParameters = ClassUtil.nullFree(cgFunction.getParameters());
+		CGValuedElement cgBody = cgFunction.getBody();
+		if (cgBody != null) {
+			js.appendCommentWithOCL(null, cgBody.getAst());
+		}
+		js.append("public ");
+		js.append(getFunctionName(cgFunction));
+		js.append("(");
+		js.appendIsRequired(true);
+		js.append(" Object ");
+		js.appendIsRequired(true);
+		js.append(" [] boundValues) throws ");
+		js.appendClassReference(ReflectiveOperationException.class);
+		js.append(" {\n");
+		js.pushIndentation(null);
+			js.append("this.self = (");
+			js.appendClassReference(cgClass);
+			js.append(")boundValues[0];\n");
+			int i = 1;
+			for (@NonNull CGParameter cgParameter : cgParameters) {
+				String valueName = getValueName(cgParameter);
+				js.append("this.");
+				js.append(valueName);
+				js.append(" = ");
+				js.appendClassCast(cgParameter);
+				js.append("boundValues[" + i++ + "];\n");
+			}
+			doFunctionBody(cgFunction, instanceName);
+		js.popIndentation();
+		js.append("}\n");
+	}
+
 	protected void doFunctionConstructor(@NonNull CGFunction cgFunction, @NonNull CGShadowExp cgShadowExp, @NonNull String instanceName) {
 //		List<@NonNull CGParameter> cgParameters = ClassUtil.nullFree(cgFunction.getParameters());
 		js.append("public ");
@@ -605,7 +686,7 @@
 		for (@NonNull CGOperation cgOperation : cgOperations) {
 			if (cgOperation instanceof CGFunction) {
 				CGFunction cgFunction = (CGFunction)cgOperation;
-				if (useClass(cgFunction) != null) {
+				if ((useClass(cgFunction) != null) || useCache(cgFunction)) {
 					js.append("protected final ");
 					js.appendIsRequired(true);
 					js.append(" ");
@@ -621,7 +702,7 @@
 		for (@NonNull CGOperation cgOperation : ClassUtil.nullFree(cgTransformation.getOperations())) {
 			if (cgOperation instanceof CGFunction) {
 				CGFunction cgFunction = (CGFunction) cgOperation;
-				if (useClass(cgFunction) != null) {
+				if ((useClass(cgFunction) != null) || useCache(cgFunction)) {
 					js.append(getFunctionCtorName(cgFunction) + " = ");
 					js.appendClassReference(ClassUtil.class);
 					js.append(".nonNullState(" + getFunctionName(cgFunction) + ".class.getConstructor(" + className + ".class, " + "Object[].class));\n");
@@ -632,7 +713,8 @@
 
 	protected void doFunctionGetInstance(@NonNull CGFunction cgFunction, @NonNull String instanceName) {
 		js.append("public ");
-		js.appendTypeDeclaration(cgFunction);
+		js.append("Object");
+//		js.appendTypeDeclaration(ClassUtil.nonNullState(cgFunction.getBody()));
 		js.append(" getInstance() {\n");
 		js.pushIndentation(null);
 			js.append("return " + instanceName + ";\n");
@@ -640,6 +722,30 @@
 		js.append("}\n");
 	}
 
+	protected void doFunctionIsEqual(@NonNull CGFunction cgFunction, @NonNull String instanceName) {
+		js.append("public boolean isEqual(");
+		js.appendIsRequired(true);
+		js.append(" ");
+		js.appendClassReference(IdResolver.class);
+		js.append(" idResolver, ");
+		js.appendIsRequired(true);
+		js.append(" Object ");
+		js.appendIsRequired(true);
+		js.append(" [] thoseValues) {\n");
+		js.pushIndentation(null);
+			js.append("return this.self == thoseValues[0]");
+			int index = 1;
+			for (@NonNull CGParameter cgParameter : ClassUtil.nullFree(cgFunction.getParameters())) {
+				js.append("\n    && ");
+				js.append("idResolver.oclEquals(this.");	// FIXME oclEquals / ==
+				js.appendValueName(cgParameter);
+				js.append(", thoseValues[" + index++ + "])");
+			}
+			js.append(";\n");
+		js.popIndentation();
+		js.append("}\n");
+	}
+
 	protected void doFunctionIsEqual(@NonNull CGShadowExp cgShadowExp, @NonNull String instanceName) {
 		js.append("public boolean isEqual(");
 		js.appendIsRequired(true);
@@ -657,7 +763,7 @@
 				if (index > 0) {
 					js.append("\n    && ");
 				}
-				js.append("idResolver.oclEquals(");
+				js.append("idResolver.oclEquals(");	// FIXME oclEquals / ==
 				js.append(instanceName);
 				js.append(".");
 				Property asProperty = ClassUtil.nonNullState(((ShadowPart)cgShadowPart.getAst()).getReferredProperty());
@@ -1022,6 +1128,10 @@
 		}
 	}
 
+	protected boolean useCache(@NonNull CGFunction cgFunction) {
+		return true;
+	}
+
 	protected @Nullable CGShadowExp useClass(@NonNull CGFunction cgFunction) {
 		CGValuedElement cgBody = cgFunction.getBody();
 		while (cgBody instanceof CGLetExp) {
@@ -1262,12 +1372,13 @@
 			localContext = localContext2;
 //			localContext.
 			try {
-				final String instanceName = getSymbolName(null, "instance");
 				List<CGParameter> cgParameters = cgFunction.getParameters();
 				//
 				js.appendCommentWithOCL(null, cgFunction.getAst());
 				CGShadowExp cgShadowExp = useClass(cgFunction);
 				if (cgShadowExp != null) {
+					JavaLocalContext<?> functionContext = ClassUtil.nonNullState(globalContext.getLocalContext(cgFunction));
+					String instanceName = functionContext.getNameManagerContext().getSymbolName(cgFunction.getBody(), "instance");
 //					Type 
 					js.append("protected class ");
 					js.append(getFunctionName(cgFunction));
@@ -1284,14 +1395,47 @@
 						js.append("\n");	
 						doFunctionGetInstance(cgFunction, instanceName);
 						js.append("\n");	
-//						js.append("public boolean execute() throws ");
-//						js.appendClassReference(ReflectiveOperationException.class);
-//						doFunctionBody(cgFunction, true);
-//						js.append("\n");	
 						doFunctionIsEqual(cgShadowExp, instanceName);
 					js.popIndentation();
 					js.append("}\n");
 				}
+				else if (useCache(cgFunction)) {
+					JavaLocalContext<?> functionContext = ClassUtil.nonNullState(globalContext.getLocalContext(cgFunction));
+					String instanceName = functionContext.getNameManagerContext().getSymbolName(cgFunction.getBody(), "instance");
+					CGClass cgClass = ClassUtil.nonNullState(CGUtil.getContainingClass(cgFunction));
+					js.append("protected class ");
+					js.append(getFunctionName(cgFunction));
+					js.append(" extends ");
+					js.appendClassReference(/*isIncremental ? AbstractIdentification.Incremental.class :*/ AbstractIdentification.class);
+					js.append("\n");
+					js.append("{\n");
+					js.pushIndentation(null);
+						js.append("protected final ");
+						js.appendIsRequired(true);
+						js.append(" ");
+						js.appendClassReference(cgClass);
+						js.append(" self;\n");
+						for (@NonNull CGParameter cgParameter : ClassUtil.nullFree(cgFunction.getParameters())) {
+							js.append("protected ");
+							js.appendDeclaration(cgParameter);
+							js.append(";\n");
+						}
+						//		CGValuedElement body = getExpression(cgFunction.getBody());
+						//ElementId elementId = cgFunction.getTypeId().getElementId();
+
+						js.append("protected final ");
+						CGValuedElement cgBody = cgFunction.getBody();
+						js.appendTypeDeclaration(cgBody != null ? cgBody : cgFunction);
+						js.append(" " + instanceName + ";\n");
+						js.append("\n");
+						doFunctionConstructor(cgFunction, instanceName);	
+						js.append("\n");	
+						doFunctionGetInstance(cgFunction, instanceName);
+						js.append("\n");	
+						doFunctionIsEqual(cgFunction, instanceName);
+					js.popIndentation();
+					js.append("}\n");
+				}
 				else {
 					//
 					js.append("protected ");
@@ -1330,7 +1474,9 @@
 	public @NonNull Boolean visitCGFunctionCallExp(@NonNull CGFunctionCallExp cgFunctionCallExp) {
 		Operation pOperation = cgFunctionCallExp.getReferredOperation();
 		CGFunction cgFunction = ClassUtil.nonNullState(cgFunctionCallExp.getFunction());
-		boolean isIdentifiedInstance = useClass(cgFunction) != null;
+		CGShadowExp cgShadowExp = useClass(cgFunction);
+		boolean useCache = useCache(cgFunction);
+		boolean isIdentifiedInstance = (cgShadowExp != null) || useCache;
 		List<CGValuedElement> cgArguments = cgFunctionCallExp.getArguments();
 		List<Parameter> pParameters = pOperation.getOwnedParameters();
 		//
@@ -1343,10 +1489,17 @@
 		//
 		js.appendDeclaration(cgFunctionCallExp);
 		js.append(" = ");
+		boolean needComma =false;
 		if (isIdentifiedInstance) {
 			js.append("getIdentification(");
 			js.append(getFunctionCtorName(cgFunction));
-			js.append(", ");
+			if (useCache && (cgShadowExp == null)) {
+				js.append(", ");
+				CGClass cgClass = ClassUtil.nonNullState(cgFunction.getContainingClass());
+				js.appendClassReference(cgClass);
+				js.append(".this");
+			}
+			needComma = true;
 		}
 		else {
 			js.append(pOperation.getName());
@@ -1354,7 +1507,7 @@
 		}
 		int iMax = Math.min(pParameters.size(), cgArguments.size());
 		for (int i = 0; i < iMax; i++) {
-			if (i > 0) {
+			if (needComma) {
 				js.append(", ");
 			}
 			CGValuedElement cgArgument = cgArguments.get(i);
@@ -1363,10 +1516,15 @@
 //			CGTypeId cgParameterTypeId = analyzer.getTypeId(pParameter.getTypeId());
 			TypeDescriptor parameterTypeDescriptor = context.getUnboxedDescriptor(pParameter.getTypeId());
 			js.appendReferenceTo(parameterTypeDescriptor, argument);
+			needComma = true;
 		}
 		js.append(")");
 		if (isIdentifiedInstance) {
-			js.append(".getInstance()");
+			JavaLocalContext<?> functionContext = ClassUtil.nonNullState(globalContext.getLocalContext(cgFunction));
+			String instanceName = functionContext.getNameManagerContext().getSymbolName(cgFunction.getBody(), "instance");
+//			js.append(".getInstance()");
+			js.append(".");
+			js.append(instanceName);
 		}
 		js.append(";\n");
 		return true;
diff --git a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Identification.java b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Identification.java
index b2124af..0e52c56 100644
--- a/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Identification.java
+++ b/plugins/org.eclipse.qvtd.runtime/src/org/eclipse/qvtd/runtime/evaluation/Identification.java
@@ -10,8 +10,6 @@
  *******************************************************************************/
 package org.eclipse.qvtd.runtime.evaluation;
 
-import org.eclipse.jdt.annotation.NonNull;
-
 /** 
  * An Identification identifies a unique object with its bound values. This is used to support
  * - a function cache which associates a result with its arguments.
@@ -23,7 +21,7 @@
  */
 public interface Identification extends Occurrence
 {
-	@NonNull Object getInstance();
+//	@NonNull Object getInstance();
 	
 	public interface Incremental extends Identification, Occurrence.Incremental
 	{