[541380] Ensure OCLstdlib metaclass is resolved and diagnosed
diff --git a/plugins/org.eclipse.ocl.xtext.base/src/org/eclipse/ocl/xtext/base/cs2as/CS2ASConversion.java b/plugins/org.eclipse.ocl.xtext.base/src/org/eclipse/ocl/xtext/base/cs2as/CS2ASConversion.java
index 597f51d..afef7b6 100644
--- a/plugins/org.eclipse.ocl.xtext.base/src/org/eclipse/ocl/xtext/base/cs2as/CS2ASConversion.java
+++ b/plugins/org.eclipse.ocl.xtext.base/src/org/eclipse/ocl/xtext/base/cs2as/CS2ASConversion.java
@@ -197,8 +197,12 @@
 	}
 
 	public void addError(@NonNull ElementCS csElement, /*@NonNull*/ String message, Object... bindings) {
-		String boundMessage = NLS.bind(message, bindings);
 		INode node = NodeModelUtils.getNode(csElement);
+		addError(csElement, node, message, bindings);
+	}
+
+	public void addError(@NonNull ElementCS csElement, /*@NonNull*/ INode node, /*@NonNull*/ String message, Object... bindings) {
+		String boundMessage = NLS.bind(message, bindings);
 		Resource.Diagnostic resourceDiagnostic = new ValidationDiagnostic(node, boundMessage);
 		csElement.eResource().getErrors().add(resourceDiagnostic);
 	}
@@ -207,8 +211,12 @@
 	 * @see org.eclipse.ocl.xtext.base.cs2as.DiagnosticHandler#addWarning(org.eclipse.ocl.xtext.basecs.ModelElementCS, java.lang.String, java.lang.Object)
 	 */
 	public void addWarning(@NonNull ModelElementCS csElement, /*@NonNull*/ String message, Object... bindings) {
-		String boundMessage = NLS.bind(message, bindings);
 		INode node = NodeModelUtils.getNode(csElement);
+		addWarning(csElement, node, message, bindings);
+	}
+
+	public void addWarning(@NonNull ModelElementCS csElement, /*@NonNull*/ INode node, /*@NonNull*/ String message, Object... bindings) {
+		String boundMessage = NLS.bind(message, bindings);
 		Resource.Diagnostic resourceDiagnostic = new ValidationDiagnostic(node, boundMessage);
 		csElement.eResource().getWarnings().add(resourceDiagnostic);
 	}
diff --git a/plugins/org.eclipse.ocl.xtext.oclstdlib/src/org/eclipse/ocl/xtext/oclstdlib/cs2as/OCLstdlibCS2AS.java b/plugins/org.eclipse.ocl.xtext.oclstdlib/src/org/eclipse/ocl/xtext/oclstdlib/cs2as/OCLstdlibCS2AS.java
index d0f03ce..0e3c17c 100644
--- a/plugins/org.eclipse.ocl.xtext.oclstdlib/src/org/eclipse/ocl/xtext/oclstdlib/cs2as/OCLstdlibCS2AS.java
+++ b/plugins/org.eclipse.ocl.xtext.oclstdlib/src/org/eclipse/ocl/xtext/oclstdlib/cs2as/OCLstdlibCS2AS.java
@@ -53,32 +53,38 @@
 		}
 	}
 
+	@Deprecated /* @deprecated - pass String argument */
 	public @Nullable MetaclassNameCS lookUpMetaTypeName(@NonNull EObject csElement, /*@NonNull*/ EStructuralFeature eFeature) {
-		Map<String, MetaclassNameCS> metaTypeNames2 = metaTypeNames;
+		List<INode> featureNodes = NodeModelUtils.findNodesForFeature(csElement, eFeature);
+		if ((featureNodes != null) && (featureNodes.size() > 0)) {
+			String metaclassNameText = NodeModelUtils.getTokenText(featureNodes.get(0));
+			MetaclassNameCS csMetaclassName = metaclassNameText != null ? getMetaclassName(metaclassNameText) : null;
+			csElement.eSet(eFeature, csMetaclassName);
+			return csMetaclassName;
+		}
+		return null;
+	}
+
+	public @Nullable MetaclassNameCS getMetaclassName(@NonNull String metaclassNameText) {
+		Map<@NonNull String, @NonNull MetaclassNameCS> metaTypeNames2 = metaTypeNames;
 		if (metaTypeNames2 == null) {
 			Resource metaTypeResource = new ResourceImpl(URI.createURI("internal_list;;//of_meta-type_names"));
-			List<EObject> metaTypes = metaTypeResource.getContents();
+			List<@NonNull EObject> metaTypes = metaTypeResource.getContents();
 			metaTypeNames2 = metaTypeNames = new HashMap<>();
 			for (EClassifier eClassifier : PivotPackage.eINSTANCE.getEClassifiers()) {
 				if (eClassifier instanceof EClass) {
 					if (PivotPackage.Literals.CLASS.isSuperTypeOf((EClass) eClassifier)) {
-						MetaclassNameCS metaTypeName = OCLstdlibCSFactory.eINSTANCE.createMetaclassNameCS();
+						MetaclassNameCS csMetaclassName = OCLstdlibCSFactory.eINSTANCE.createMetaclassNameCS();
 						String name = eClassifier.getName();
-						metaTypeName.setName(name);
-						metaTypeNames2.put(name, metaTypeName);
-						metaTypes.add(metaTypeName);			// Avoid detection of orphans by EnvironmentView.addElement()
+						assert name != null;
+						csMetaclassName.setName(name);
+						metaTypeNames2.put(name, csMetaclassName);
+						metaTypes.add(csMetaclassName);			// Avoid detection of orphans by EnvironmentView.addElement()
 					}
 				}
 			}
 		}
-		List<INode> featureNodes = NodeModelUtils.findNodesForFeature(csElement, eFeature);
-		if ((featureNodes != null) && (featureNodes.size() > 0)) {
-			String metaTypeNameText = NodeModelUtils.getTokenText(featureNodes.get(0));
-			MetaclassNameCS metaTypeName = metaTypeNames2.get(metaTypeNameText);
-			csElement.eSet(eFeature, metaTypeName);
-			return metaTypeName;
-		}
-		return null;
+		return metaTypeNames2.get(metaclassNameText);
 	}
 
 	public OCLstdlibCS2AS(@NonNull EnvironmentFactoryInternal environmentFactory, @NonNull BaseCSResource csResource, @NonNull ASResource asResource) {
diff --git a/plugins/org.eclipse.ocl.xtext.oclstdlib/src/org/eclipse/ocl/xtext/oclstdlib/cs2as/OCLstdlibCSContainmentVisitor.java b/plugins/org.eclipse.ocl.xtext.oclstdlib/src/org/eclipse/ocl/xtext/oclstdlib/cs2as/OCLstdlibCSContainmentVisitor.java
index 14456d2..d51fb80 100644
--- a/plugins/org.eclipse.ocl.xtext.oclstdlib/src/org/eclipse/ocl/xtext/oclstdlib/cs2as/OCLstdlibCSContainmentVisitor.java
+++ b/plugins/org.eclipse.ocl.xtext.oclstdlib/src/org/eclipse/ocl/xtext/oclstdlib/cs2as/OCLstdlibCSContainmentVisitor.java
@@ -12,7 +12,9 @@
 package org.eclipse.ocl.xtext.oclstdlib.cs2as;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
+import java.util.Map;
 
 import org.eclipse.emf.ecore.EClass;
 import org.eclipse.emf.ecore.resource.Resource;
@@ -52,6 +54,8 @@
 import org.eclipse.ocl.xtext.oclstdlibcs.OCLstdlibCSPackage;
 import org.eclipse.ocl.xtext.oclstdlibcs.PrecedenceCS;
 import org.eclipse.ocl.xtext.oclstdlibcs.util.AbstractOCLstdlibCSContainmentVisitor;
+import org.eclipse.xtext.nodemodel.INode;
+import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
 
 public class OCLstdlibCSContainmentVisitor extends AbstractOCLstdlibCSContainmentVisitor
 {
@@ -74,7 +78,9 @@
 
 	@Override
 	public Continuation<?> visitLibClassCS(@NonNull LibClassCS csClass) {
-		EClass eClass = null;
+		//
+		//	Resolve explicit insstanceClass
+		//
 		String instanceClassName = null;
 		JavaClassCS implementation = csClass.getImplementation();
 		if ((implementation != null) && !implementation.eIsProxy()) {
@@ -88,39 +94,74 @@
 				context.addError(csClass, e.toString(), e);
 			}
 		}
-		if (Boolean.class == instanceClass) {
-			eClass = PivotPackage.Literals.BOOLEAN_TYPE;
+		//
+		//	Resolve explicit metaType name object
+		//
+		MetaclassNameCS csMetaclassName = null;
+		List<INode> featureNodes = NodeModelUtils.findNodesForFeature(csClass, OCLstdlibCSPackage.Literals.LIB_CLASS_CS__METACLASS_NAME);
+		if ((featureNodes != null) && (featureNodes.size() > 0)) {
+			INode metaclassNameNode = featureNodes.get(0);
+			String metaTypeNameText = NodeModelUtils.getTokenText(metaclassNameNode);
+			if (metaTypeNameText != null) {
+				csMetaclassName = ((OCLstdlibCS2AS)context.getConverter()).getMetaclassName(metaTypeNameText);
+			}
+			if (csMetaclassName == null) {
+				context.addError(csClass, metaclassNameNode, "Unresolved metatype for ''{0}''", csClass);
+			}
 		}
-		else if (String.class == instanceClass) {
-			eClass = PivotPackage.Literals.PRIMITIVE_TYPE;
+		csClass.setMetaclassName(csMetaclassName);
+		//
+		//	Resolve metaType EClass and provide a default implicit instanceClass
+		//
+		EClass eClass = null;
+		if ((csMetaclassName != null) && !csMetaclassName.eIsProxy()) {
+			String metaTypeName = csMetaclassName.getName();
+			eClass = (EClass) NameUtil.getENamedElement(PivotPackage.eINSTANCE.getEClassifiers(), metaTypeName);
+			if (eClass != null) {
+				instanceClass = eClass.getInstanceClass();
+			}
 		}
-		else if (instanceClass != null) {
-			if (NumberValue.class.isAssignableFrom(instanceClass)) {
+		//
+		//	Provide a default metaType EClass
+		//
+		if (eClass == null) {
+			if (instanceClass == null) {
+				eClass = PivotPackage.Literals.CLASS;
+			}
+			else if (Boolean.class == instanceClass) {
+				eClass = PivotPackage.Literals.BOOLEAN_TYPE;
+			}
+			else if (String.class == instanceClass) {
+				eClass = PivotPackage.Literals.PRIMITIVE_TYPE;
+			}
+			else if (Collection.class.isAssignableFrom(instanceClass)) {
+				eClass = PivotPackage.Literals.COLLECTION_TYPE;
+			}
+			else if (Map.class.isAssignableFrom(instanceClass)) {
+				eClass = PivotPackage.Literals.MAP_TYPE;
+			}
+			else if (NumberValue.class.isAssignableFrom(instanceClass)) {
 				eClass = PivotPackage.Literals.PRIMITIVE_TYPE;
 			}
 			else if (Number.class.isAssignableFrom(instanceClass)) {
 				eClass = PivotPackage.Literals.PRIMITIVE_TYPE;
 			}
-		}
-		if (eClass == null) {
-			MetaclassNameCS metaType = ((OCLstdlibCS2AS)context.getConverter()).lookUpMetaTypeName(csClass, OCLstdlibCSPackage.Literals.LIB_CLASS_CS__METACLASS_NAME);
-			if ((metaType != null) && !metaType.eIsProxy()) {
-				String metaTypeName = metaType.getName();
-				eClass = (EClass) NameUtil.getENamedElement(PivotPackage.eINSTANCE.getEClassifiers(), metaTypeName);
-				if (eClass != null) {
-					instanceClass = eClass.getInstanceClass();
-				}
-			}
-			if (eClass == null) {
+			else {
 				eClass = PivotPackage.Literals.CLASS;
 			}
 		}
+		//
+		//	Provide a default instanceClass
+		//
 		if (instanceClass == null) {
 			instanceClass = Object.class;
 		}
 		if (instanceClassName == null) {
 			instanceClassName = instanceClass.getName();
 		}
+		//
+		//	Finally refresh the class.
+		//
 		@SuppressWarnings("unchecked")
 		Class<org.eclipse.ocl.pivot.Class> eInstanceClass = (Class<org.eclipse.ocl.pivot.Class>)eClass.getInstanceClass();
 		if (eInstanceClass != null) {
diff --git a/tests/org.eclipse.ocl.examples.xtext.tests/models/oclstdlib/minimal.oclstdlib b/tests/org.eclipse.ocl.examples.xtext.tests/models/oclstdlib/minimal.oclstdlib
index 8aa716a..f24d172 100644
--- a/tests/org.eclipse.ocl.examples.xtext.tests/models/oclstdlib/minimal.oclstdlib
+++ b/tests/org.eclipse.ocl.examples.xtext.tests/models/oclstdlib/minimal.oclstdlib
@@ -6,7 +6,6 @@
 	type Collection(T) : CollectionType conformsTo OclAny {}
 	type Integer : PrimitiveType conformsTo Real {}
 	type Map(K,V) : MapType conformsTo OclAny {}
-	type Metaclass(T) : Metaclass conformsTo OclAny {}
 	type OclAny : AnyType {
 		operation "="(object2 : OclAny) : Boolean;
 	}
diff --git a/tests/org.eclipse.ocl.examples.xtext.tests/src/org/eclipse/ocl/examples/test/xtext/EditTests.java b/tests/org.eclipse.ocl.examples.xtext.tests/src/org/eclipse/ocl/examples/test/xtext/EditTests.java
index 127c75e..e1c2fef 100644
--- a/tests/org.eclipse.ocl.examples.xtext.tests/src/org/eclipse/ocl/examples/test/xtext/EditTests.java
+++ b/tests/org.eclipse.ocl.examples.xtext.tests/src/org/eclipse/ocl/examples/test/xtext/EditTests.java
@@ -28,6 +28,7 @@
 import org.eclipse.emf.ecore.EPackage;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.resource.URIConverter;
+import org.eclipse.emf.ecore.xmi.XMLResource;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.ocl.common.internal.options.CommonOptions;
 import org.eclipse.ocl.examples.xtext.tests.TestCaseAppender;
@@ -276,7 +277,6 @@
 				+ "	type Collection(T) : CollectionType conformsTo OclAny {}\n"
 				+ "	type Integer : PrimitiveType conformsTo Real => 'org.eclipse.ocl.pivot.values.IntegerValue' {}\n"
 				+ "	type Map(K,V) : MapType conformsTo OclAny {}\n"
-				+ "	type Metaclass(T) : Metaclass conformsTo OclAny {}\n"
 				+ "	type OclAny : AnyType {\n"
 	//			+ "		operation \"=\"(object2 : OclAny) : Boolean;\n"
 				+ "	}\n"
@@ -317,6 +317,7 @@
 		//
 		//	Change metatype.
 		//
+		@SuppressWarnings("unused")
 		String newDocument = testDocument.replace("type Boolean : PrimitiveType conformsTo", "type BooleanType conformsTo");
 		{
 			TestCaseAppender.INSTANCE.uninstall();
@@ -771,7 +772,7 @@
 		//	Load and instrument test document
 		//
 		OCLInternal ocl1 = OCLInternal.newInstance(getProjectMap(), null);
-		Resource ecoreResource = ClassUtil.nonNullEMF(ocl1.getResourceSet().getResource(ecoreURI, true));
+		XMLResource ecoreResource = (XMLResource) ClassUtil.nonNullEMF(ocl1.getResourceSet().getResource(ecoreURI, true));
 		assertNoResourceErrors("Ecore load", ecoreResource);
 		assertNoValidationErrors("Ecore load", ecoreResource);
 		ASResource asResource = ocl1.ecore2as(ecoreResource);
@@ -806,7 +807,7 @@
 		//
 		StringWriter writer = new StringWriter();
 		OutputStream outputStream = new URIConverter.WriteableOutputStream(writer, "UTF-8");
-		ecoreResource.save(outputStream, XMIUtil.createSaveOptions());
+		ecoreResource.save(outputStream, XMIUtil.createSaveOptions(ecoreResource));
 		ecoreResource.unload();
 		InputStream inputStream = new URIConverter.ReadableInputStream(writer.toString().replace("tuttut",  "tut"), "UTF-8");
 		ecoreResource.load(inputStream, null);