/******************************************************************************* * Copyright (c) 2013, 2015 CEA LIST and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * E.D.Willink (CEA LIST) - initial API and implementation *******************************************************************************/ package org.eclipse.ocl.pivot.internal.manager; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.pivot.CollectionType; import org.eclipse.ocl.pivot.CompleteEnvironment; import org.eclipse.ocl.pivot.LambdaType; import org.eclipse.ocl.pivot.Property; import org.eclipse.ocl.pivot.TemplateParameter; import org.eclipse.ocl.pivot.TemplateSignature; import org.eclipse.ocl.pivot.TupleType; import org.eclipse.ocl.pivot.Type; import org.eclipse.ocl.pivot.utilities.ClassUtil; import org.eclipse.ocl.pivot.utilities.NameUtil; /** * A TemplateSpecialisation supports resolution of template parameter within an element referenced from an OCL expression. * For instance a PropertyCallExp.referredProperty references the unspecialised Property and consequently the type and owningType * of the referredProperty may have unresolved template parameters. These may be resolved by exploiting the bindings of * the ProperyCallExp.source. * <p> * Invocation should first invoke needsSpecialisation() to discover whether the cost of constructing a TemplateSpecialisation * can be bypassed. If specialisation is needed a TemplateSpecialisation should be constructed for the prevailing OCL Standard * Library, and known type equivalences installed by invoking installEquivalence() for each. getSpecialisation may then be used * to resolve the type. */ public class TemplateSpecialisation { /** * Return true if a referencedType needs specialisation to resolve a template parameter. */ public static boolean needsSpecialisation(@Nullable Type referencedType) { if (referencedType == null) { return true; } TemplateParameter templateParameter = referencedType.isTemplateParameter(); if (templateParameter != null) { return true; } if (referencedType instanceof CollectionType) { Type elementType = ((CollectionType)referencedType).getElementType(); return needsSpecialisation(elementType); } if (referencedType instanceof TupleType) { TupleType tupleType = (TupleType)referencedType; for (Property tuplePart : tupleType.getOwnedProperties()) { Type tuplePartType = tuplePart.getType(); if (needsSpecialisation(tuplePartType)) { return true; } } return false; } if (referencedType instanceof LambdaType) { LambdaType lambdaType = (LambdaType)referencedType; Type contextType = lambdaType.getContextType(); if (needsSpecialisation(contextType)) { return true; } Type resultType = lambdaType.getResultType(); if (needsSpecialisation(resultType)) { return true; } for (Type parameterType : lambdaType.getParameterTypes()) { if (needsSpecialisation(parameterType)) { return true; } } return false; } if (referencedType instanceof org.eclipse.ocl.pivot.Class) { TemplateSignature templateSignature = ((org.eclipse.ocl.pivot.Class)referencedType).getOwnedSignature(); if (templateSignature != null) { return true; } } return false; } protected final @NonNull CompleteEnvironment environment; // protected final @NonNull DomainStandardLibrary standardLibrary; protected /*@LazyNonNull*/ Map<TemplateParameter, Type> bindings = null; public TemplateSpecialisation(@NonNull CompleteEnvironment environment) { this.environment = environment; // this.standardLibrary = environment.getStandardLibrary(); } /** * Return the specialisation of referencedType if distinct from referencedType. * Returns null if specialisation not available or not distinct from referencedType. */ private @Nullable Type getResolution(@Nullable Type referencedType) { if (referencedType != null) { TemplateParameter templateParameter = referencedType.isTemplateParameter(); if (templateParameter != null) { return bindings != null ? bindings.get(templateParameter) : null; } } if (referencedType instanceof CollectionType) { CollectionType collectionType = (CollectionType)referencedType; Type elementType = getResolution(collectionType.getElementType()); if (elementType == null) { elementType = environment.getOwnedStandardLibrary().getOclAnyType(); } org.eclipse.ocl.pivot.Class containerType = ClassUtil.nonNullState(collectionType.getContainerType()); return environment.getCollectionType(containerType, elementType, false, collectionType.getLowerValue(), collectionType.getUpperValue()); // FIXME isNullFree } if (referencedType instanceof TupleType) { // DomainTupleType tupleType = (DomainTupleType)referencedType; throw new UnsupportedOperationException(); } if (referencedType instanceof LambdaType) { // DomainLambdaType lambdaType = (DomainLambdaType)referencedType; throw new UnsupportedOperationException(); } return null; } public org.eclipse.ocl.pivot.@NonNull Class getSpecialisation(@NonNull Type referredType) { Type specialisation = getResolution(referredType); return (org.eclipse.ocl.pivot.Class) (specialisation != null ? specialisation : referredType); // FIXME cast } public void installEquivalence(@Nullable Type resolvedType, @Nullable Type referencedType) { if (resolvedType == null) { return; } if (referencedType == null) { return; } TemplateParameter templateParameter = referencedType.isTemplateParameter(); if (templateParameter != null) { if (bindings == null) { bindings = new HashMap<TemplateParameter, Type>(); } if (bindings.put(templateParameter, resolvedType) != null) { bindings.put(templateParameter, null); } return; } if (referencedType instanceof CollectionType) { if (resolvedType instanceof CollectionType) { Type resolvedElementType = ((CollectionType)resolvedType).getElementType(); Type referencedElementType = ((CollectionType)referencedType).getElementType(); installEquivalence(resolvedElementType, referencedElementType); } return; } if (referencedType instanceof TupleType) { if (resolvedType instanceof TupleType) { TupleType referencedTupleType = (TupleType)referencedType; TupleType resolvedTupleType = (TupleType)resolvedType; Iterable<? extends Property> referencedTupleParts = referencedTupleType.getOwnedProperties(); for (Property resolvedTuplePart : resolvedTupleType.getOwnedProperties()) { Property referencedTuplePart = NameUtil.getNameable(referencedTupleParts, resolvedTuplePart.getName()); if (referencedTuplePart != null) { Type resolvedTuplePartType = resolvedTuplePart.getType(); Type referencedTuplePartType = referencedTuplePart.getType(); installEquivalence(resolvedTuplePartType, referencedTuplePartType); } } } return; } if (referencedType instanceof LambdaType) { if (resolvedType instanceof LambdaType) { LambdaType referencedLambdaType = (LambdaType)referencedType; LambdaType resolvedLambdaType = (LambdaType)resolvedType; installEquivalence(resolvedLambdaType.getContextType(), referencedLambdaType.getContextType()); installEquivalence(resolvedLambdaType.getResultType(), referencedLambdaType.getResultType()); List<? extends Type> resolvedParameterTypes = resolvedLambdaType.getParameterTypes(); List<? extends Type> referencedParameterTypes = referencedLambdaType.getParameterTypes(); for (int i = 0; i < Math.min(resolvedParameterTypes.size(), referencedParameterTypes.size()); i++) { Type resolvedParameterType = resolvedParameterTypes.get(i); Type referencedParameterType = referencedParameterTypes.get(i); installEquivalence(resolvedParameterType, referencedParameterType); } } return; } return; } }