Added AnyServicesAstValidationTest.

Change-Id: I32a64692e2b6f9725ca068433e86a780a8b4d914
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/parser/AstValidator.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/parser/AstValidator.java
index 661c8b5..4a00501 100644
--- a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/parser/AstValidator.java
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/parser/AstValidator.java
@@ -374,91 +374,36 @@
 			final StringBuilder messageWhenFalse = new StringBuilder("Always true:");
 
 			for (IType originalType : originalTypes) {
-				if (originalType instanceof NothingType) {
-					inferredTrueTypes.add(originalType);
-					inferredFalseTypes.add(originalType);
-				} else {
-					for (IType argType : argTypes) {
-						inferOclIsKindOfForArgType(varRef, inferredTrueTypes, inferredFalseTypes,
-								messageWhenTrue, messageWhenFalse, originalType, argType);
+				for (IType argType : argTypes) {
+					final IType lowerArgType = services.lower(argType, argType);
+					if (lowerArgType != null && lowerArgType.isAssignableFrom(originalType)) {
+						inferredTrueTypes.add(originalType);
+						messageWhenFalse.append(String.format(
+								"\nNothing inferred when %s (%s) is not kind of %s",
+								varRef.getVariableName(), originalType, argType));
+					} else if (originalType != null && originalType.isAssignableFrom(lowerArgType)) {
+						inferredTrueTypes.add(lowerArgType);
+						inferredFalseTypes.add(originalType);
+					} else {
+						final Set<IType> intersectionTypes = services
+								.intersection(originalType, lowerArgType);
+						if (intersectionTypes.isEmpty()) {
+							messageWhenTrue.append(String.format(
+									"\nNothing inferred when %s (%s) is kind of %s",
+									varRef.getVariableName(), originalType, argType));
+							inferredFalseTypes.add(originalType);
+						} else {
+							inferredTrueTypes.addAll(intersectionTypes);
+							inferredFalseTypes.add(originalType);
+						}
 					}
 				}
 			}
-			if (!inferredTrueTypes.isEmpty()) {
-				Map<String, Set<IType>> inferredTrueTypesMap = new HashMap<String, Set<IType>>();
-				inferredTrueTypesMap.put(varRef.getVariableName(), inferredTrueTypes);
-				validationResult.putInferredVariableTypes(call, Boolean.TRUE, inferredTrueTypesMap);
-			} else {
-				final AstResult astResult = validationResult.getAstResult();
-				final int startPostion = astResult.getStartPosition(call);
-				final int endPosition = astResult.getEndPosition(call);
-				final ValidationMessage message = new ValidationMessage(ValidationMessageLevel.INFO,
-						messageWhenTrue.toString(), startPostion, endPosition);
-				messages.add(message);
-			}
-			if (!inferredFalseTypes.isEmpty()) {
-				Map<String, Set<IType>> inferredFalseTypesMap = new HashMap<String, Set<IType>>();
-				inferredFalseTypesMap.put(varRef.getVariableName(), inferredFalseTypes);
-				validationResult.putInferredVariableTypes(call, Boolean.FALSE, inferredFalseTypesMap);
-			} else {
-				final AstResult astResult = validationResult.getAstResult();
-				final int startPostion = astResult.getStartPosition(call);
-				final int endPosition = astResult.getEndPosition(call);
-				final ValidationMessage message = new ValidationMessage(ValidationMessageLevel.INFO,
-						messageWhenFalse.toString(), startPostion, endPosition);
-				validationResult.getMessages().add(message);
-			}
-		}
-	}
 
-	/**
-	 * Computes inferred {@link IType} for {@link AstBuilderListener#OCL_IS_KIND_OF_SERVICE_NAME} {@link Call}
-	 * for one argument {@link IType}.
-	 * 
-	 * @param varRef
-	 *            the {@link Call} {@link VarRef}
-	 * @param inferredTrueTypes
-	 *            the {@link Set} of inferred {@link IType} when {@link Boolean#TRUE}
-	 * @param inferredFalseTypes
-	 *            the {@link Set} of inferred {@link IType} when {@link Boolean#FALSE}
-	 * @param messageWhenTrue
-	 *            the message when {@link Boolean#TRUE}
-	 * @param messageWhenFalse
-	 *            the message when {@link Boolean#FALSE}
-	 * @param originalType
-	 *            the original {@link VarRef} {@link IType}
-	 * @param argType
-	 *            the argument {@link IType}
-	 */
-	private void inferOclIsKindOfForArgType(VarRef varRef, final Set<IType> inferredTrueTypes,
-			final Set<IType> inferredFalseTypes, final StringBuilder messageWhenTrue,
-			final StringBuilder messageWhenFalse, IType originalType, IType argType) {
-		final IType lowerType = services.lower(originalType, argType);
-		if (lowerType != null) {
-			inferredTrueTypes.add(lowerType);
-			if (lowerType.isAssignableFrom(argType) && !lowerType.equals(originalType)) {
-				inferredFalseTypes.add(originalType);
-			} else {
-				messageWhenFalse.append(String.format("\nNothing inferred when %s (%s) is not kind of %s",
-						varRef.getVariableName(), originalType, argType));
+			if (!argTypes.isEmpty()) {
+				registerInferredTypes(call, varRef, inferredTrueTypes, inferredFalseTypes, messageWhenTrue,
+						messageWhenFalse);
 			}
-		} else if (originalType.getType() instanceof EClass && argType.getType() instanceof EClass) {
-			Set<IType> intesectionTypes = new LinkedHashSet<IType>();
-			for (EClass eCls : services.getSubTypesTopIntersection((EClass)originalType.getType(),
-					(EClass)argType.getType())) {
-				intesectionTypes.add(new EClassifierType(services.getQueryEnvironment(), eCls));
-			}
-			if (intesectionTypes.isEmpty()) {
-				messageWhenTrue.append(String.format("\nNothing inferred when %s (%s) is kind of %s", varRef
-						.getVariableName(), originalType, argType));
-			} else {
-				inferredTrueTypes.addAll(intesectionTypes);
-			}
-			inferredFalseTypes.add(originalType);
-		} else {
-			messageWhenTrue.append(String.format("\nNothing inferred when %s (%s) is kind of %s", varRef
-					.getVariableName(), originalType, argType));
-			inferredFalseTypes.add(originalType);
 		}
 	}
 
@@ -486,7 +431,7 @@
 				for (IType argType : argTypes) {
 					final IType lowerArgType = services.lower(argType, argType);
 					final IType lowerType = services.lower(originalType, lowerArgType);
-					if (lowerArgType.equals(originalType)) {
+					if (lowerArgType != null && lowerArgType.equals(originalType)) {
 						inferredTrueTypes.add(lowerArgType);
 						final Set<EClass> upperSubEClasses = getUpperSubTypes(originalType);
 						if (upperSubEClasses.isEmpty()) {
@@ -510,30 +455,55 @@
 				}
 			}
 
-			if (!inferredTrueTypes.isEmpty()) {
-				Map<String, Set<IType>> inferredTrueTypesMap = new HashMap<String, Set<IType>>();
-				inferredTrueTypesMap.put(varRef.getVariableName(), inferredTrueTypes);
-				validationResult.putInferredVariableTypes(call, Boolean.TRUE, inferredTrueTypesMap);
-			} else {
-				final AstResult astResult = validationResult.getAstResult();
-				final int startPostion = astResult.getStartPosition(call);
-				final int endPosition = astResult.getEndPosition(call);
-				final ValidationMessage message = new ValidationMessage(ValidationMessageLevel.INFO,
-						messageWhenTrue.toString(), startPostion, endPosition);
-				messages.add(message);
+			if (!argTypes.isEmpty()) {
+				registerInferredTypes(call, varRef, inferredTrueTypes, inferredFalseTypes, messageWhenTrue,
+						messageWhenFalse);
 			}
-			if (!inferredFalseTypes.isEmpty()) {
-				Map<String, Set<IType>> inferredFalseTypesMap = new HashMap<String, Set<IType>>();
-				inferredFalseTypesMap.put(varRef.getVariableName(), inferredFalseTypes);
-				validationResult.putInferredVariableTypes(call, Boolean.FALSE, inferredFalseTypesMap);
-			} else {
-				final AstResult astResult = validationResult.getAstResult();
-				final int startPostion = astResult.getStartPosition(call);
-				final int endPosition = astResult.getEndPosition(call);
-				final ValidationMessage message = new ValidationMessage(ValidationMessageLevel.INFO,
-						messageWhenFalse.toString(), startPostion, endPosition);
-				validationResult.getMessages().add(message);
-			}
+		}
+	}
+
+	/**
+	 * Registers inferred {@link IType} and mesages.
+	 * 
+	 * @param call
+	 *            the {@link Call} that inferred types (oclIsKindOf, oclIsTypeOf, ...)
+	 * @param varRef
+	 *            the {@link VarRef} use in the {@link Call}
+	 * @param inferredTrueTypes
+	 *            inferred {@link IType} when <code>true</code>
+	 * @param inferredFalseTypes
+	 *            inferred {@link IType} when <code>false</code>
+	 * @param messageWhenTrue
+	 *            message when <code>true</code>
+	 * @param messageWhenFalse
+	 *            message when <code>false</code>
+	 */
+	private void registerInferredTypes(Call call, VarRef varRef, final Set<IType> inferredTrueTypes,
+			final Set<IType> inferredFalseTypes, final StringBuilder messageWhenTrue,
+			final StringBuilder messageWhenFalse) {
+		if (!inferredTrueTypes.isEmpty()) {
+			Map<String, Set<IType>> inferredTrueTypesMap = new HashMap<String, Set<IType>>();
+			inferredTrueTypesMap.put(varRef.getVariableName(), inferredTrueTypes);
+			validationResult.putInferredVariableTypes(call, Boolean.TRUE, inferredTrueTypesMap);
+		} else {
+			final AstResult astResult = validationResult.getAstResult();
+			final int startPostion = astResult.getStartPosition(call);
+			final int endPosition = astResult.getEndPosition(call);
+			final ValidationMessage message = new ValidationMessage(ValidationMessageLevel.INFO,
+					messageWhenTrue.toString(), startPostion, endPosition);
+			messages.add(message);
+		}
+		if (!inferredFalseTypes.isEmpty()) {
+			Map<String, Set<IType>> inferredFalseTypesMap = new HashMap<String, Set<IType>>();
+			inferredFalseTypesMap.put(varRef.getVariableName(), inferredFalseTypes);
+			validationResult.putInferredVariableTypes(call, Boolean.FALSE, inferredFalseTypesMap);
+		} else {
+			final AstResult astResult = validationResult.getAstResult();
+			final int startPostion = astResult.getStartPosition(call);
+			final int endPosition = astResult.getEndPosition(call);
+			final ValidationMessage message = new ValidationMessage(ValidationMessageLevel.INFO,
+					messageWhenFalse.toString(), startPostion, endPosition);
+			validationResult.getMessages().add(message);
 		}
 	}
 
diff --git a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/services/AnyServices.java b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/services/AnyServices.java
index 3391079..4bede11 100644
--- a/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/services/AnyServices.java
+++ b/query/plugins/org.eclipse.acceleo.query/src/org/eclipse/acceleo/query/services/AnyServices.java
@@ -433,7 +433,8 @@
 					result.add(services.nothing("%s is not registered within the current environment.",
 							filterType));
 				} else {
-					result.add(services.nothing("%s is not compatible with %s", receiverType, filterType));
+					result.add(services
+							.nothing("%s is not compatible with type %s", receiverType, filterType));
 				}
 			}
 
diff --git a/query/tests/org.eclipse.acceleo.query.tests/resources/uml/uml.qmodel b/query/tests/org.eclipse.acceleo.query.tests/resources/uml/uml.qmodel
index 9fe4619..5c7c708 100644
--- a/query/tests/org.eclipse.acceleo.query.tests/resources/uml/uml.qmodel
+++ b/query/tests/org.eclipse.acceleo.query.tests/resources/uml/uml.qmodel
@@ -1583,7 +1583,7 @@
     </expectations>
     <expectations xsi:type="qmodel:QueryValidationResultExpectation">
       <expectedResult interpreter="manual">
-         <validationMessages severity="ERROR" message="Nothing will be left after calling oclAsType:&#xA;EClassifier=Package is not compatible with EClassifierLiteral=Component" startPosition="4" endPosition="30"/>
+         <validationMessages severity="ERROR" message="Nothing will be left after calling oclAsType:&#xA;EClassifier=Package is not compatible with type EClassifierLiteral=Component" startPosition="4" endPosition="30"/>
       </expectedResult>
     </expectations>
   </queries>
@@ -1710,7 +1710,7 @@
     <expectations xsi:type="qmodel:QueryValidationResultExpectation">
       <expectedResult interpreter="manual">
         <validationMessages message="Always false:&#xA;Nothing inferred when self (EClassifier=Model) is type of EClassifierLiteral=Property" endPosition="31"/>
-        <validationMessages severity="ERROR" message="Nothing will be left after calling oclAsType:&#xA;EClassifier=Model is not compatible with EClassifierLiteral=Property" startPosition="40" endPosition="65"/>
+        <validationMessages severity="ERROR" message="Nothing will be left after calling oclAsType:&#xA;EClassifier=Model is not compatible with type EClassifierLiteral=Property" startPosition="40" endPosition="65"/>
       </expectedResult>
     </expectations>
   </queries>
@@ -1721,7 +1721,7 @@
     <expectations xsi:type="qmodel:QueryValidationResultExpectation">
       <expectedResult interpreter="manual">
         <validationMessages message="Always false:&#xA;Nothing inferred when self (EClassifier=Model) is type of EClassifierLiteral=Property" endPosition="31"/>
-        <validationMessages severity="ERROR" message="Nothing will be left after calling oclAsType:&#xA;EClassifier=Model is not compatible with EClassifierLiteral=Property" startPosition="40" endPosition="65"/>
+        <validationMessages severity="ERROR" message="Nothing will be left after calling oclAsType:&#xA;EClassifier=Model is not compatible with type EClassifierLiteral=Property" startPosition="40" endPosition="65"/>
       </expectedResult>
     </expectations>
   </queries>
@@ -1892,7 +1892,7 @@
     </expectations>
     <expectations xsi:type="qmodel:QueryValidationResultExpectation">
       <expectedResult interpreter="manual">
-        <validationMessages severity="ERROR" message="Nothing will be left after calling oclAsType:&#xA;EClassifier=Behavior is not compatible with EClassifierLiteral=UseCase" startPosition="14" endPosition="38"/>
+        <validationMessages severity="ERROR" message="Nothing will be left after calling oclAsType:&#xA;EClassifier=Behavior is not compatible with type EClassifierLiteral=UseCase" startPosition="14" endPosition="38"/>
       </expectedResult>
     </expectations>
   </queries>
@@ -1902,7 +1902,7 @@
     </expectations>
     <expectations xsi:type="qmodel:QueryValidationResultExpectation">
       <expectedResult interpreter="manual">
-        <validationMessages severity="ERROR" message="Nothing will be left after calling oclAsType:&#xA;EClassifier=Behavior is not compatible with EClassifierLiteral=UseCase" startPosition="14" endPosition="38"/>
+        <validationMessages severity="ERROR" message="Nothing will be left after calling oclAsType:&#xA;EClassifier=Behavior is not compatible with type EClassifierLiteral=UseCase" startPosition="14" endPosition="38"/>
       </expectedResult>
     </expectations>
   </queries>
diff --git a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/parser/tests/ValidationInferrenceTest.java b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/parser/tests/ValidationInferrenceTest.java
index 35d6cc4..9d393af 100644
--- a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/parser/tests/ValidationInferrenceTest.java
+++ b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/parser/tests/ValidationInferrenceTest.java
@@ -183,13 +183,25 @@
 				varName);
 		final Set<IType> inferredWhenFalse = validationResult.getInferredVariableTypes(ast, Boolean.FALSE)
 				.get(varName);
-		assertNotNull(inferredWhenTrue);
-		assertNotNull(inferredWhenFalse);
-		assertEquals(inferredWhenTrue, inferredWhenFalse);
 
-		assertEquals(1, validationResult.getMessages().size());
+		assertNull(inferredWhenTrue);
+
+		assertNotNull(inferredWhenFalse);
+		assertEquals(1, inferredWhenFalse.size());
+		Iterator<IType> it = inferredWhenFalse.iterator();
+		IType type = it.next();
+		assertTrue(type instanceof NothingType);
+		assertEquals("Nothing", ((NothingType)type).getMessage());
+
+		assertEquals(2, validationResult.getMessages().size());
 		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
 				ValidationMessageLevel.ERROR, "Nothing", 0, 10);
+		ValidationTest
+				.assertValidationMessage(
+						validationResult.getMessages().get(1),
+						ValidationMessageLevel.INFO,
+						"Always false:\nNothing inferred when varNothing (Nothing(Nothing)) is kind of EClassifierLiteral=B",
+						0, 31);
 	}
 
 	@Test
@@ -563,13 +575,25 @@
 				varName);
 		final Set<IType> inferredWhenFalse = validationResult.getInferredVariableTypes(ast, Boolean.FALSE)
 				.get(varName);
-		assertNotNull(inferredWhenTrue);
-		assertNotNull(inferredWhenFalse);
-		assertEquals(inferredWhenTrue, inferredWhenFalse);
 
-		assertEquals(1, validationResult.getMessages().size());
+		assertNotNull(inferredWhenTrue);
+		assertEquals(1, inferredWhenTrue.size());
+		Iterator<IType> it = inferredWhenTrue.iterator();
+		IType type = it.next();
+		assertTrue(type instanceof NothingType);
+		assertEquals("Nothing", ((NothingType)type).getMessage());
+
+		assertNull(inferredWhenFalse);
+
+		assertEquals(2, validationResult.getMessages().size());
 		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
 				ValidationMessageLevel.ERROR, "Nothing", 4, 14);
+		ValidationTest
+				.assertValidationMessage(
+						validationResult.getMessages().get(1),
+						ValidationMessageLevel.INFO,
+						"Always false:\nNothing inferred when varNothing (Nothing(Nothing)) is kind of EClassifierLiteral=B",
+						4, 35);
 	}
 
 	@Test
diff --git a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/parser/tests/ValidationTest.java b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/parser/tests/ValidationTest.java
index 99e6d2f..1a77218 100644
--- a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/parser/tests/ValidationTest.java
+++ b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/parser/tests/ValidationTest.java
@@ -1115,14 +1115,14 @@
 		assertEquals(1, possibleTypes.size());
 		assertTrue(possibleType instanceof NothingType);
 		assertEquals(
-				"Nothing will be left after calling oclAsType:\nEClassifier=EPackage is not compatible with EClassifierLiteral=EInt\nEClassifier=EAnnotation is not compatible with EClassifierLiteral=EInt",
+				"Nothing will be left after calling oclAsType:\nEClassifier=EPackage is not compatible with type EClassifierLiteral=EInt\nEClassifier=EAnnotation is not compatible with type EClassifierLiteral=EInt",
 				((NothingType)possibleType).getMessage());
 
 		assertEquals(1, validationResult.getMessages().size());
 		assertValidationMessage(
 				validationResult.getMessages().get(0),
 				ValidationMessageLevel.ERROR,
-				"Nothing will be left after calling oclAsType:\nEClassifier=EPackage is not compatible with EClassifierLiteral=EInt\nEClassifier=EAnnotation is not compatible with EClassifierLiteral=EInt",
+				"Nothing will be left after calling oclAsType:\nEClassifier=EPackage is not compatible with type EClassifierLiteral=EInt\nEClassifier=EAnnotation is not compatible with type EClassifierLiteral=EInt",
 				17, 40);
 	}
 
diff --git a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/AbstractServicesValidationTest.java b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/AbstractServicesValidationTest.java
index 2fd16ec..50e1d64 100644
--- a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/AbstractServicesValidationTest.java
+++ b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/AbstractServicesValidationTest.java
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.acceleo.query.services.tests;
 
+import com.google.common.collect.ImmutableSet;
+
 import java.util.Arrays;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
@@ -45,6 +47,23 @@
  */
 public abstract class AbstractServicesValidationTest extends AbstractServicesTest {
 
+	protected static class VariableBuilder {
+		private Map<String, Set<IType>> variables;
+
+		public VariableBuilder() {
+			variables = new LinkedHashMap<String, Set<IType>>();
+		}
+
+		public VariableBuilder addVar(String name, IType... types) {
+			variables.put(name, ImmutableSet.copyOf(types));
+			return this;
+		}
+
+		public Map<String, Set<IType>> build() {
+			return variables;
+		}
+	}
+
 	protected void assertNoService(String serviceName, IType parameterTypes[]) {
 		final IService service = serviceLookUp(serviceName, parameterTypes);
 
diff --git a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/AnyServicesAstValidationTest.java b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/AnyServicesAstValidationTest.java
new file mode 100644
index 0000000..1706352
--- /dev/null
+++ b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/AnyServicesAstValidationTest.java
@@ -0,0 +1,743 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Obeo.
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     Obeo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.acceleo.query.services.tests;
+
+import com.google.common.collect.ImmutableSet;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.acceleo.query.parser.tests.ValidationTest;
+import org.eclipse.acceleo.query.runtime.IQueryBuilderEngine.AstResult;
+import org.eclipse.acceleo.query.runtime.IValidationResult;
+import org.eclipse.acceleo.query.runtime.ValidationMessageLevel;
+import org.eclipse.acceleo.query.validation.type.IType;
+import org.eclipse.acceleo.query.validation.type.NothingType;
+import org.eclipse.emf.ecore.EcorePackage;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class AnyServicesAstValidationTest extends AbstractServicesValidationTest {
+
+	@Test
+	public void testAddNullString() {
+		final IValidationResult validationResult = validate("null + 'string'");
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(String.class)), types);
+	}
+
+	@Test
+	public void testAddStringNull() {
+		final IValidationResult validationResult = validate("'string' + null");
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(String.class)), types);
+	}
+
+	@Test
+	public void testAddNothingString() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("nothing + 'string'", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 0, 7);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testAddStringNothing() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("'string' + nothing", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 11, 18);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testAddObjectString() {
+		final VariableBuilder variables = new VariableBuilder().addVar("object", classType(Object.class));
+		final IValidationResult validationResult = validate("object + 'string'", variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(String.class)), types);
+	}
+
+	@Test
+	public void testAddStringObject() {
+		final VariableBuilder variables = new VariableBuilder().addVar("object", classType(Object.class));
+		final IValidationResult validationResult = validate("'string' + object", variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(String.class)), types);
+	}
+
+	@Test
+	public void testDiffersNullNull() {
+		final IValidationResult validationResult = validate("null <> null");
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(Boolean.class)), types);
+	}
+
+	@Test
+	public void testDiffersNullNothing() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("null <> nothing", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 8, 15);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testDiffersNothingNull() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("nothing <> null", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 0, 7);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testDiffersNullObject() {
+		final VariableBuilder variables = new VariableBuilder().addVar("object", classType(Object.class));
+		final IValidationResult validationResult = validate("null <> object", variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(Boolean.class)), types);
+	}
+
+	@Test
+	public void testDiffersObjectNull() {
+		final VariableBuilder variables = new VariableBuilder().addVar("object", classType(Object.class));
+		final IValidationResult validationResult = validate("object <> null", variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(Boolean.class)), types);
+	}
+
+	@Test
+	public void testDiffersObjectObject() {
+		final VariableBuilder variables = new VariableBuilder().addVar("object", classType(Object.class));
+		final IValidationResult validationResult = validate("object <> object", variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(Boolean.class)), types);
+	}
+
+	@Test
+	public void testEqualsNullNull() {
+		final IValidationResult validationResult = validate("null = null");
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(Boolean.class)), types);
+	}
+
+	@Test
+	public void testEqualsNullNothing() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("null = nothing", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 7, 14);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testEqualsNothingNull() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("nothing = null", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 0, 7);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testEqualsNullObject() {
+		final VariableBuilder variables = new VariableBuilder().addVar("object", classType(Object.class));
+		final IValidationResult validationResult = validate("null = object", variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(Boolean.class)), types);
+	}
+
+	@Test
+	public void testEqualsObjectNull() {
+		final VariableBuilder variables = new VariableBuilder().addVar("object", classType(Object.class));
+		final IValidationResult validationResult = validate("object = null", variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(Boolean.class)), types);
+	}
+
+	@Test
+	public void testEqualsObjectObject() {
+		final VariableBuilder variables = new VariableBuilder().addVar("object", classType(Object.class));
+		final IValidationResult validationResult = validate("object = object", variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(Boolean.class)), types);
+	}
+
+	@Test
+	public void testOclAsTypeNullNull() {
+		final IValidationResult validationResult = validate("null.oclAsType(null)");
+
+		final String expectedMessage = "Nothing will be left after calling oclAsType:\n"
+				+ "null is not compatible with type null";
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, expectedMessage, 4, 20);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(1, types.size());
+		final Iterator<IType> it = types.iterator();
+		final IType type = it.next();
+		assertTrue(type instanceof NothingType);
+		assertEquals(expectedMessage, ((NothingType)type).getMessage());
+	}
+
+	@Test
+	public void testOclAsTypeNothingNull() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("nothing.oclAsType(null)", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 0, 7);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testOclAsTypeNullNothing() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("null.oclAsType(nothing)", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 15, 22);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testOclAsTypeNothingNothing() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("nothing.oclAsType(nothing)", variables.build());
+
+		assertEquals(2, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 0, 7);
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(1),
+				ValidationMessageLevel.ERROR, "Nothing", 18, 25);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testOclAsTypeSameType() {
+		getQueryEnvironment().registerEPackage(EcorePackage.eINSTANCE);
+		final VariableBuilder variables = new VariableBuilder().addVar("eCls",
+				eClassifierType(EcorePackage.eINSTANCE.getEClass()));
+		final IValidationResult validationResult = validate("eCls.oclAsType(ecore::EClass)", variables
+				.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(eClassifierType(EcorePackage.eINSTANCE.getEClass())), types);
+	}
+
+	@Test
+	public void testOclAsTypeNotCompatibleType() {
+		getQueryEnvironment().registerEPackage(EcorePackage.eINSTANCE);
+		final VariableBuilder variables = new VariableBuilder().addVar("eCls",
+				eClassifierType(EcorePackage.eINSTANCE.getEClass()));
+		final IValidationResult validationResult = validate("eCls.oclAsType(ecore::EPackage)", variables
+				.build());
+
+		final String expectedMessage = "Nothing will be left after calling oclAsType:\n"
+				+ "EClassifier=EClass is not compatible with type EClassifierLiteral=EPackage";
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, expectedMessage, 4, 31);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(1, types.size());
+		final Iterator<IType> it = types.iterator();
+		final IType type = it.next();
+		assertTrue(type instanceof NothingType);
+		assertEquals(expectedMessage, ((NothingType)type).getMessage());
+	}
+
+	@Test
+	public void testOclAsTypeMayBeCompatibleType() {
+		getQueryEnvironment().registerEPackage(EcorePackage.eINSTANCE);
+		final VariableBuilder variables = new VariableBuilder().addVar("eClasssifier",
+				eClassifierType(EcorePackage.eINSTANCE.getEClassifier()));
+		final IValidationResult validationResult = validate("eClasssifier.oclAsType(ecore::EClass)",
+				variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(eClassifierType(EcorePackage.eINSTANCE.getEClass())), types);
+	}
+
+	@Test
+	public void testOclIsKindOfNullNull() {
+		final IValidationResult validationResult = validate("null.oclIsKindOf(null)");
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// ClassType(Boolean) because ecore is not registered
+		assertEquals(ImmutableSet.of(classType(Boolean.class)), types);
+	}
+
+	@Test
+	public void testOclIsKindOfNothingNull() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("nothing.oclIsKindOf(null)", variables.build());
+
+		assertEquals(2, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 0, 7);
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(1),
+				ValidationMessageLevel.INFO, "Always false:\n"
+						+ "Nothing inferred when nothing (Nothing(Nothing)) is kind of null", 0, 25);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testOclIsKindOfNullNothing() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("null.oclIsKindOf(nothing)", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 17, 24);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testOclIsKindOfNothingNothing() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("nothing.oclIsKindOf(nothing)", variables.build());
+
+		assertEquals(2, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 0, 7);
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(1),
+				ValidationMessageLevel.ERROR, "Nothing", 20, 27);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testOclIsKindOfSameType() {
+		getQueryEnvironment().registerEPackage(EcorePackage.eINSTANCE);
+		final VariableBuilder variables = new VariableBuilder().addVar("eCls",
+				eClassifierType(EcorePackage.eINSTANCE.getEClass()));
+		final IValidationResult validationResult = validate("eCls.oclIsKindOf(ecore::EClass)", variables
+				.build());
+
+		final String expectedMessage = "Always true:\n"
+				+ "Nothing inferred when eCls (EClassifier=EClass) is not kind of EClassifierLiteral=EClass";
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.INFO, expectedMessage, 0, 31);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(eClassifierType(EcorePackage.eINSTANCE.getEBooleanObject())), types);
+	}
+
+	@Test
+	public void testOclIsKindOfNotCompatibleType() {
+		getQueryEnvironment().registerEPackage(EcorePackage.eINSTANCE);
+		final VariableBuilder variables = new VariableBuilder().addVar("eCls",
+				eClassifierType(EcorePackage.eINSTANCE.getEClass()));
+		final IValidationResult validationResult = validate("eCls.oclIsKindOf(ecore::EPackage)", variables
+				.build());
+
+		final String expectedMessage = "Always false:\n"
+				+ "Nothing inferred when eCls (EClassifier=EClass) is kind of EClassifierLiteral=EPackage";
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.INFO, expectedMessage, 0, 33);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(eClassifierType(EcorePackage.eINSTANCE.getEBooleanObject())), types);
+	}
+
+	@Test
+	public void testOclIsKindOfMayBeCompatibleType() {
+		getQueryEnvironment().registerEPackage(EcorePackage.eINSTANCE);
+		final VariableBuilder variables = new VariableBuilder().addVar("eClasssifier",
+				eClassifierType(EcorePackage.eINSTANCE.getEClassifier()));
+		final IValidationResult validationResult = validate("eClasssifier.oclIsKindOf(ecore::EClass)",
+				variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(eClassifierType(EcorePackage.eINSTANCE.getEBooleanObject())), types);
+	}
+
+	@Test
+	public void testOclIsTypeOfNullNull() {
+		final IValidationResult validationResult = validate("null.oclIsTypeOf(null)");
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// ClassType(Boolean) because ecore is not registered
+		assertEquals(ImmutableSet.of(classType(Boolean.class)), types);
+	}
+
+	@Test
+	public void testOclIsTypeOfNothingNull() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("nothing.oclIsTypeOf(null)", variables.build());
+
+		assertEquals(2, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 0, 7);
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(1),
+				ValidationMessageLevel.INFO, "Always false:\n"
+						+ "Nothing inferred when nothing (Nothing(Nothing)) is type of null", 0, 25);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testOclIsTypeOfNullNothing() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("null.oclIsTypeOf(nothing)", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 17, 24);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testOclIsTypeOfNothingNothing() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("nothing.oclIsTypeOf(nothing)", variables.build());
+
+		assertEquals(2, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 0, 7);
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(1),
+				ValidationMessageLevel.ERROR, "Nothing", 20, 27);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		// the NothingType is removed from possible types then no lookup is done because of empty combination
+		// set
+		assertTrue(types.isEmpty());
+	}
+
+	@Test
+	public void testOclIsTypeOfSameType() {
+		getQueryEnvironment().registerEPackage(EcorePackage.eINSTANCE);
+		final VariableBuilder variables = new VariableBuilder().addVar("eCls",
+				eClassifierType(EcorePackage.eINSTANCE.getEClass()));
+		final IValidationResult validationResult = validate("eCls.oclIsTypeOf(ecore::EClass)", variables
+				.build());
+
+		final String expectedMessage = "Always true:\n"
+				+ "Nothing inferred when eCls (EClassifier=EClass) is not type of EClassifierLiteral=EClass";
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.INFO, expectedMessage, 0, 31);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(eClassifierType(EcorePackage.eINSTANCE.getEBooleanObject())), types);
+	}
+
+	@Test
+	public void testOclIsTypeOfNotCompatibleType() {
+		getQueryEnvironment().registerEPackage(EcorePackage.eINSTANCE);
+		final VariableBuilder variables = new VariableBuilder().addVar("eCls",
+				eClassifierType(EcorePackage.eINSTANCE.getEClass()));
+		final IValidationResult validationResult = validate("eCls.oclIsTypeOf(ecore::EPackage)", variables
+				.build());
+
+		final String expectedMessage = "Always false:\n"
+				+ "Nothing inferred when eCls (EClassifier=EClass) is type of EClassifierLiteral=EPackage";
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.INFO, expectedMessage, 0, 33);
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(eClassifierType(EcorePackage.eINSTANCE.getEBooleanObject())), types);
+	}
+
+	@Test
+	public void testOclIsTypeOfMayBeCompatibleType() {
+		getQueryEnvironment().registerEPackage(EcorePackage.eINSTANCE);
+		final VariableBuilder variables = new VariableBuilder().addVar("eClasssifier",
+				eClassifierType(EcorePackage.eINSTANCE.getEClassifier()));
+		final IValidationResult validationResult = validate("eClasssifier.oclIsTypeOf(ecore::EClass)",
+				variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(eClassifierType(EcorePackage.eINSTANCE.getEBooleanObject())), types);
+	}
+
+	@Test
+	public void testToStringNull() {
+		final IValidationResult validationResult = validate("null.toString()");
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(String.class)), types);
+	}
+
+	@Test
+	public void testToStringNothing() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("nothing.toString()", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 0, 7);
+
+	}
+
+	@Test
+	public void testToStringObject() {
+		final VariableBuilder variables = new VariableBuilder().addVar("object", classType(Object.class));
+		final IValidationResult validationResult = validate("object.trace()", variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(String.class)), types);
+	}
+
+	@Test
+	public void testTraceNull() {
+		final IValidationResult validationResult = validate("null.trace()");
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(String.class)), types);
+	}
+
+	@Test
+	public void testTraceNothing() {
+		final VariableBuilder variables = new VariableBuilder().addVar("nothing", nothingType("Nothing"));
+		final IValidationResult validationResult = validate("nothing.trace()", variables.build());
+
+		assertEquals(1, validationResult.getMessages().size());
+		ValidationTest.assertValidationMessage(validationResult.getMessages().get(0),
+				ValidationMessageLevel.ERROR, "Nothing", 0, 7);
+
+	}
+
+	@Test
+	public void testTraceObject() {
+		final VariableBuilder variables = new VariableBuilder().addVar("object", classType(Object.class));
+		final IValidationResult validationResult = validate("object.trace()", variables.build());
+
+		assertTrue(validationResult.getMessages().isEmpty());
+
+		final AstResult ast = validationResult.getAstResult();
+		final Set<IType> types = validationResult.getPossibleTypes(ast.getAst());
+
+		assertEquals(ImmutableSet.of(classType(String.class)), types);
+	}
+
+}
diff --git a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/AnyServicesValidationTest.java b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/AnyServicesValidationTest.java
index e1a94aa..b75914d 100644
--- a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/AnyServicesValidationTest.java
+++ b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/services/tests/AnyServicesValidationTest.java
@@ -380,7 +380,7 @@
 		IType next = it.next();
 		assertTrue(next instanceof NothingType);
 		String message = ((NothingType)next).getMessage();
-		assertEquals(argTypes.get(0) + " is not compatible with " + argTypes.get(1), message);
+		assertEquals(argTypes.get(0) + " is not compatible with type " + argTypes.get(1), message);
 
 		final Map<List<IType>, Set<IType>> allTypes = new LinkedHashMap<List<IType>, Set<IType>>();
 		allTypes.put(argTypes, types);
@@ -391,7 +391,7 @@
 		assertTrue(next instanceof NothingType);
 		String allTypesMesg = ((NothingType)next).getMessage();
 		assertTrue(allTypesMesg.startsWith("Nothing will be left after calling oclAsType:"));
-		assertTrue(allTypesMesg.endsWith(argTypes.get(0) + " is not compatible with " + argTypes.get(1)));
+		assertTrue(allTypesMesg.endsWith(argTypes.get(0) + " is not compatible with type " + argTypes.get(1)));
 	}
 
 	@Test
diff --git a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/tests/AllTests.java b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/tests/AllTests.java
index 7da0e3a..0563930 100644
--- a/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/tests/AllTests.java
+++ b/query/tests/org.eclipse.acceleo.query.tests/src/org/eclipse/acceleo/query/tests/AllTests.java
@@ -26,6 +26,7 @@
 import org.eclipse.acceleo.query.runtime.test.EvaluationServicesTest;
 import org.eclipse.acceleo.query.runtime.test.FilterCamelCaseTest;
 import org.eclipse.acceleo.query.runtime.test.ShortcutEvaluationTest;
+import org.eclipse.acceleo.query.services.tests.AnyServicesAstValidationTest;
 import org.eclipse.acceleo.query.services.tests.AnyServicesTest;
 import org.eclipse.acceleo.query.services.tests.AnyServicesValidationTest;
 import org.eclipse.acceleo.query.services.tests.BooleanServicesAstValidationTest;
@@ -78,9 +79,9 @@
 		CombineIteratorTest.class, CompletionTest.class, EvaluationTest.class, LexerTest.class,
 		ValidationTest.class, BasicLookupCrossReferencerTest.class, BasicLookupTest.class,
 		EvaluationServiceStatusTests.class, EvaluationServicesTest.class, AnyServicesTest.class,
-		BooleanServicesAstValidationTest.class, AnyServicesValidationTest.class, BooleanServicesTest.class,
-		BooleanServicesValidationTest.class, CollectionServicesTest.class,
-		CollectionServicesValidationTest.class, ComparableServicesTest.class,
+		BooleanServicesAstValidationTest.class, AnyServicesValidationTest.class,
+		AnyServicesAstValidationTest.class, BooleanServicesTest.class, BooleanServicesValidationTest.class,
+		CollectionServicesTest.class, CollectionServicesValidationTest.class, ComparableServicesTest.class,
 		ComparableServicesValidationTest.class, EObjectServicesTest.class, XPathServicesTest.class,
 		EObjectServicesValidationTest.class, XPathServicesValidationTest.class, NumberServicesTest.class,
 		NumberServicesValidationTest.class, StringServicesTest.class, StringServicesValidationTest.class,