/******************************************************************************* * Copyright (c) 2007, 2015 Borland Software Corporation 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: * Borland Software Corporation - initial API and implementation * Christopher Gerking - bug 289982 * Alex Paperno - bugs 424584 *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.ast.parser; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EDataType; import org.eclipse.emf.ecore.EEnum; import org.eclipse.emf.ecore.EEnumLiteral; import org.eclipse.emf.ecore.EModelElement; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EParameter; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EcoreFactory; import org.eclipse.emf.ecore.util.ExtendedMetaData; import org.eclipse.m2m.internal.qvt.oml.NLS; import org.eclipse.m2m.internal.qvt.oml.ast.binding.ASTSyntheticNode; import org.eclipse.m2m.internal.qvt.oml.ast.binding.ASTSyntheticNodeAccess; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtEnvironmentBase; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalEnv; import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtOperationalStdLibrary; import org.eclipse.m2m.internal.qvt.oml.compiler.CompiledUnit; import org.eclipse.m2m.internal.qvt.oml.cst.ConstructorCS; import org.eclipse.m2m.internal.qvt.oml.cst.ImportCS; import org.eclipse.m2m.internal.qvt.oml.cst.LibraryCS; import org.eclipse.m2m.internal.qvt.oml.cst.MappingDeclarationCS; import org.eclipse.m2m.internal.qvt.oml.cst.MappingExtensionCS; import org.eclipse.m2m.internal.qvt.oml.cst.MappingExtensionKindCS; import org.eclipse.m2m.internal.qvt.oml.cst.MappingMethodCS; import org.eclipse.m2m.internal.qvt.oml.cst.MappingModuleCS; import org.eclipse.m2m.internal.qvt.oml.cst.MappingQueryCS; import org.eclipse.m2m.internal.qvt.oml.cst.MappingRuleCS; import org.eclipse.m2m.internal.qvt.oml.cst.ModelTypeCS; import org.eclipse.m2m.internal.qvt.oml.cst.ModulePropertyCS; import org.eclipse.m2m.internal.qvt.oml.cst.ScopedNameCS; import org.eclipse.m2m.internal.qvt.oml.cst.TransformationHeaderCS; import org.eclipse.m2m.internal.qvt.oml.cst.UnitCS; import org.eclipse.m2m.internal.qvt.oml.emf.util.EmfUtil; import org.eclipse.m2m.internal.qvt.oml.expressions.ContextualProperty; import org.eclipse.m2m.internal.qvt.oml.expressions.DirectionKind; import org.eclipse.m2m.internal.qvt.oml.expressions.ImperativeOperation; import org.eclipse.m2m.internal.qvt.oml.expressions.ImportKind; import org.eclipse.m2m.internal.qvt.oml.expressions.MappingOperation; import org.eclipse.m2m.internal.qvt.oml.expressions.Module; import org.eclipse.m2m.internal.qvt.oml.expressions.ModuleImport; import org.eclipse.m2m.internal.qvt.oml.expressions.VarParameter; import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.ReturnExp; import org.eclipse.m2m.qvt.oml.ecore.ImperativeOCL.Typedef; import org.eclipse.ocl.Environment; import org.eclipse.ocl.cst.CSTNode; import org.eclipse.ocl.cst.CollectionTypeCS; import org.eclipse.ocl.cst.PathNameCS; import org.eclipse.ocl.cst.PrimitiveTypeCS; import org.eclipse.ocl.cst.SimpleNameCS; import org.eclipse.ocl.cst.TupleTypeCS; import org.eclipse.ocl.cst.TypeCS; import org.eclipse.ocl.cst.VariableCS; import org.eclipse.ocl.cst.impl.CSTNodeImpl; import org.eclipse.ocl.ecore.CallOperationAction; import org.eclipse.ocl.ecore.CollectionType; import org.eclipse.ocl.ecore.Constraint; import org.eclipse.ocl.ecore.SendSignalAction; import org.eclipse.ocl.expressions.OCLExpression; import org.eclipse.ocl.expressions.Variable; import org.eclipse.ocl.types.BagType; import org.eclipse.ocl.types.OrderedSetType; import org.eclipse.ocl.types.PrimitiveType; import org.eclipse.ocl.types.SequenceType; import org.eclipse.ocl.types.SetType; import org.eclipse.ocl.types.TupleType; import org.eclipse.ocl.util.TypeUtil; import org.eclipse.ocl.utilities.PredefinedType; import org.eclipse.ocl.utilities.UMLReflection; public class QvtOperationalParserUtil { private static final String NAMESPACE_SEPARATOR = "."; //$NON-NLS-1$ public static final String QVT_NAMESPACE_URI = "http://www.eclipse.org/m2m/1.0.0/QVT"; //$NON-NLS-1$ private static final String QVT_IS_ABSTRACT = "abstract"; //$NON-NLS-1$ private static final String QVT_IS_STATIC = "static"; //$NON-NLS-1$ private static final String QVT_INIT_EXPRESSION_URI = QVT_NAMESPACE_URI + "/initExp"; //$NON-NLS-1$ public static final String QVT_AUTOGEN_MODELPARAM_EXPRESSION_URI = QVT_NAMESPACE_URI + "/autoModelParam"; //$NON-NLS-1$ private static final String QVT_DEPRECATED = "deprecated"; //$NON-NLS-1$ private static final String QVT_UNSUPPORTED = "unsupported"; //$NON-NLS-1$ private QvtOperationalParserUtil() { } public static EClassifier getContextualType(ImperativeOperation operation) { VarParameter context = operation.getContext(); return context != null ? context.getEType() : null; } public static boolean isContextual(ImperativeOperation operation) { return getContextualType(operation) != null; } public static String getMappingStringRepresentation(MappingMethodCS operationCS) { MappingDeclarationCS mappingDeclarationCS = operationCS.getMappingDeclarationCS(); if(mappingDeclarationCS != null) { StringBuilder buf = new StringBuilder(); if(mappingDeclarationCS.getContextType() != null) { buf.append(QvtOperationalParserUtil.getStringRepresentation(mappingDeclarationCS.getContextType())); buf.append(EmfUtil.PATH_SEPARATOR); } if(mappingDeclarationCS.getSimpleNameCS() != null) { buf.append(mappingDeclarationCS.getSimpleNameCS().getValue()); } return buf.toString(); } return ""; //$NON-NLS-1$ } public static String getStringRepresentation(PathNameCS pathName, String pathSeparator) { return getStringRepresentation(pathName.getSimpleNames(), pathSeparator); } public static String getStringRepresentation(PathNameCS pathName) { return getStringRepresentation(pathName.getSimpleNames(), EmfUtil.PATH_SEPARATOR); } public static String getStringRepresentation(List<SimpleNameCS> pathName, String pathSeparator) { StringBuffer buffer = null; for (SimpleNameCS element : pathName) { if (buffer != null) { buffer.append(pathSeparator); } else { buffer = new StringBuffer(); } buffer.append(element.getValue()); } return buffer == null ? "" : buffer.toString(); //$NON-NLS-1$ } public static String getStringRepresentation(ScopedNameCS scopedNameCS) { StringBuilder buf = new StringBuilder(); if(scopedNameCS.getTypeCS() != null) { buf.append(getStringRepresentation(scopedNameCS.getTypeCS())); buf.append(EmfUtil.PATH_SEPARATOR); } if(scopedNameCS.getName() != null) { buf.append(scopedNameCS.getName()); } return buf.toString(); } public static String getStringRepresentation(TypeCS typeCS) { if (typeCS instanceof PrimitiveTypeCS) { return ((PrimitiveTypeCS) typeCS).getValue(); } else if (typeCS instanceof PathNameCS) { return getStringRepresentation((PathNameCS) typeCS, EmfUtil.PATH_SEPARATOR); } else if (typeCS instanceof CollectionTypeCS) { return ((CollectionTypeCS) typeCS).getCollectionTypeIdentifier().getName() + "(" + getStringRepresentation(((CollectionTypeCS) typeCS).getTypeCS()) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ } else if (typeCS instanceof TupleTypeCS) { StringBuffer result = new StringBuffer(); for (VariableCS var : ((TupleTypeCS) typeCS).getVariables()) { if (result.length() > 0) { result.append(","); //$NON-NLS-1$ } result.append(var.getName()); result.append(":"); //$NON-NLS-1$ result.append(getStringRepresentation(var.getTypeCS())); } return TupleType.SINGLETON_NAME + "(" + result.toString() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ } return ""; //$NON-NLS-1$ } public static void setInitExpression(EStructuralFeature moduleFeature, OCLExpression<EClassifier> expression) { if(expression == null) { // possible NPE caused by parsing errors => no AST expression produce return; } EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource(QVT_INIT_EXPRESSION_URI); annotation.getContents().add(expression); moduleFeature.getEAnnotations().add(annotation); } @SuppressWarnings("unchecked") public static OCLExpression<EClassifier> getInitExpression(EStructuralFeature feature) { EAnnotation annotation = feature.getEAnnotation(QVT_INIT_EXPRESSION_URI); if(annotation != null) { for (EObject referredObj : annotation.getContents()) { if(referredObj instanceof OCLExpression) { return (OCLExpression<EClassifier>)referredObj; } } } return null; } public static Module getOwningModule(ImperativeOperation operation) { if(operation.getEContainingClass() instanceof Module) { return (Module) operation.getEContainingClass(); } return null; } public static Module getOwningModule(EOperation operation) { EClassifier owner = operation.getEContainingClass(); if(owner == null) { return null; } // check for operations directly owned by a QVT moduleAST if(owner instanceof Module) { return (Module) owner; } EPackage owningPackage = owner.getEPackage(); if(owningPackage == null) { return null; } if(owner instanceof Typedef) { if(owningPackage instanceof Module) { return (Module) owningPackage; } // our QVT AST meta-model contains the additional operations via // typedef stored directly in the owning moduleAST // Additionally, support the nested 'additions' package as implemented by MDT OCL EPackage superOwner = owningPackage.getESuperPackage(); if(superOwner instanceof Module) { return (Module) superOwner; } } if(owningPackage instanceof Module) { // handles cases like plain EOperation on Model class in Stdlib return (Module)owningPackage; } return null; } public static List<EOperation> getOwnedOperations(Module module) { List<EOperation> result = new ArrayList<EOperation>(module.getEOperations().size()); for (EOperation operation : module.getEOperations()) { if(operation instanceof ImperativeOperation) { result.add(operation); } } return result; } public static void collectAllImports(CompiledUnit unit, Set<CompiledUnit> result) { for (CompiledUnit importedUnit : unit.getCompiledImports()) { if (!result.contains(importedUnit)) { collectAllImports(importedUnit, result); } result.add(importedUnit); } } public static void collectAllImports(Module module, Set<Module> result) { collectAllImportsByKind(module, result, null); } public static Set<Module> collectAllImportsByKind(Module module, Set<Module> result, ImportKind importKind) { if (result == null) { result = new HashSet<Module>(); } for (ModuleImport imp : module.getModuleImport()) { if (imp == null || imp.getImportedModule() == null) { continue; } if ((importKind == null) || (imp.getKind() == importKind)) { if (!result.contains(imp.getImportedModule())) { collectAllImportsByKind(imp.getImportedModule(), result, importKind); } result.add(imp.getImportedModule()); } } return result; } /** * Remark: accepts null types, but always returns <code>false</code> if any * of the type argument is <code>null</code> */ public static boolean isAssignableToFrom( Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env, EClassifier variableType, EClassifier initialiserType) { if (variableType == null) return false; if (initialiserType == null) return false; // handle primitive types if (variableType == env.getOCLStandardLibrary().getUnlimitedNatural()) { // FIXME - we should not have any special handling of OCL types // See related, https://bugs.eclipse.org/bugs/show_bug.cgi?id=260403 if (initialiserType == env.getOCLStandardLibrary().getInteger()) { return true; } } // FIXME - better be handled in OCL itself // check was added due to https://bugs.eclipse.org/bugs/show_bug.cgi?id=275824 if (variableType instanceof EDataType && initialiserType instanceof EDataType && variableType instanceof PredefinedType == false) { if (variableType.getInstanceClass() == initialiserType.getInstanceClass() && variableType.getInstanceClass() != null) { return true; } if (initialiserType instanceof EEnum && initialiserType == ExtendedMetaData.INSTANCE.getBaseType((EDataType) variableType )) { return true; } } return (TypeUtil.getRelationship(env, variableType, initialiserType) & UMLReflection.SUPERTYPE) != 0; } /** * Get the moduleAST simple name as the last element of possible qualified * name. * * @return the name string or empty string, of the moduleAST name sequence is * empty */ public static String getMappingModuleSimpleName(TransformationHeaderCS headerCS) { EList<SimpleNameCS> moduleName = headerCS.getPathNameCS().getSimpleNames(); if (moduleName.isEmpty()) { return ""; //$NON-NLS-1$ } return moduleName.get(moduleName.size()-1).getValue(); } public static boolean hasSimpleName(TransformationHeaderCS headerCS) { if(headerCS.getPathNameCS() != null) { return headerCS.getPathNameCS().getSimpleNames().size() <= 1; } return false; } public static String getMappingModuleQualifiedName(TransformationHeaderCS headerCS) { String namespace = getMappingModuleNamespace(headerCS); if(namespace == null || namespace.length() == 0) { return getMappingModuleSimpleName(headerCS); } return namespace + NAMESPACE_SEPARATOR + getMappingModuleSimpleName(headerCS); } /** * @return dot separated namespace or empty string. */ public static String getMappingModuleNamespace(TransformationHeaderCS headerCS) { StringBuilder unitNamespace = new StringBuilder(); EList<SimpleNameCS> moduleName = headerCS.getPathNameCS().getSimpleNames(); if (moduleName.size() > 1) { for (int i = 0, sz = moduleName.size(); i < sz - 1; i++) { if (i > 0) { unitNamespace.append(NAMESPACE_SEPARATOR); } unitNamespace.append(moduleName.get(i)); } } return unitNamespace.toString(); } public static boolean isTypeCast(final EOperation operation) { if (operation != null) { return PredefinedType.OCL_AS_TYPE_NAME.equals(operation.getName()); } return false; } // FIXME - to be removed => use getRelationShip(t1, t2) operation public static boolean isIncorrectCast(final EClassifier sourceType, final EClassifier targetType) { if (sourceType == null || targetType == null) { return false; // error should be reported in this case, not // warning } if (sourceType instanceof PrimitiveType && PrimitiveType.REAL_NAME.equals(((PrimitiveType<?>) sourceType).getName())) { return targetType instanceof PrimitiveType && PrimitiveType.INTEGER_NAME.equals(((PrimitiveType<?>) targetType).getName()); } if (sourceType instanceof SetType) { return !(targetType instanceof SetType); } if (sourceType instanceof BagType) { return !(targetType instanceof BagType); } if (sourceType instanceof SequenceType) { return !(targetType instanceof SequenceType); } if (sourceType instanceof OrderedSetType) { return !(targetType instanceof OrderedSetType || targetType instanceof SetType); } return false; } public static boolean validateAssignment(boolean isProperty, String leftName, EClassifier leftType, EClassifier rightType, boolean isIncremental, CSTNode lValueCS, CSTNode rValueCS, Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env) { if (isIncremental) { if (leftType instanceof CollectionType == false) { QvtOperationalUtil.reportError(env, NLS.bind(ValidationMessages.SemanticUtil_3, new Object[] { leftName }), lValueCS); return false; } EClassifier baseType = ((CollectionType) leftType).getElementType(); EClassifier actualType = rightType; if (actualType instanceof CollectionType) { actualType = ((CollectionType) actualType).getElementType(); } if (!isAssignableToFrom(env, baseType, actualType)) { QvtOperationalUtil.reportError(env, NLS.bind(ValidationMessages.SemanticUtil_5, new Object[] { leftName, QvtOperationalTypesUtil.getTypeFullName(baseType), QvtOperationalTypesUtil.getTypeFullName(actualType) }), rValueCS); return false; } } else if (isProperty && leftType instanceof CollectionType) { EClassifier baseType = ((CollectionType) leftType).getElementType(); EClassifier actualType = rightType; if (actualType instanceof CollectionType) { actualType = ((CollectionType) actualType).getElementType(); } if (!isAssignableToFrom(env, baseType, actualType)) { QvtOperationalUtil.reportError(env, NLS.bind(ValidationMessages.SemanticUtil_5, new Object[] { leftName, QvtOperationalTypesUtil.getTypeFullName(baseType), QvtOperationalTypesUtil.getTypeFullName(actualType) }), rValueCS); return false; } } else { if (!isAssignableToFrom(env, leftType, rightType)) { QvtOperationalUtil.reportError(env, NLS.bind(ValidationMessages.SemanticUtil_8, new Object[] { leftName, QvtOperationalTypesUtil.getTypeFullName(leftType), QvtOperationalTypesUtil.getTypeFullName(rightType) }), rValueCS); return false; } } return true; } /** * Checks if the given variable is allowed to be modified, reports an error in * case it is not. * * @param variable * the variable to be assigned a value or indirectly modified through * an owned property * @param varNodeCS * the pathname representing the left side of an assignment. It can be a simple name * representing a variable direct access or a path navigating to owned property. * @param varPathNamePropertyASTopt AST property element for a property if any available as the target for modification * * @return <code>true</code> if it can be modified, <code>false</code> * otherwise. */ public static boolean validateVariableModification(Variable<EClassifier, EParameter> variable, CSTNode varNodeCS, EStructuralFeature varPathNamePropertyASTopt, Environment<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> env, boolean isDirectModification) { EParameter representedParameter = variable.getRepresentedParameter(); if (representedParameter instanceof VarParameter) { VarParameter parameter = (VarParameter) representedParameter; // detect whether an [inout] parameter variable is to be assigned a new value boolean isInsideMapping = env.getContextOperation() instanceof MappingOperation; boolean isDirectInoutModification = parameter.getKind() == DirectionKind.INOUT && isDirectModification && isInsideMapping; boolean isDirectOutModificationOutsideInit = parameter.getKind() == DirectionKind.OUT && isDirectModification && isInsideMapping && (env instanceof QvtOperationalEnv) && !((QvtOperationalEnv)env).isWithinInitMappingSection(); boolean isContextualPropertyAccessed = varPathNamePropertyASTopt instanceof ContextualProperty; if(isDirectInoutModification) { QvtOperationalUtil.reportError(env, NLS.bind(ValidationMessages.QvtOperationalParserUtil_inoutParamAssignmentError, parameter.getName()), varNodeCS); return false; } if(isDirectOutModificationOutsideInit) { QvtOperationalUtil.reportError(env, NLS.bind(ValidationMessages.QvtOperationalParserUtil_outParamAssignmentError, parameter.getName()), varNodeCS); return false; } if (parameter.getKind() != DirectionKind.OUT && parameter.getKind() != DirectionKind.INOUT && isContextualPropertyAccessed == false) { QvtOperationalUtil.reportError(env, NLS.bind(ValidationMessages.inputParameterModificationError, variable.getName()), varNodeCS); return false; } } return true; } /** * Finds the first imperative operation named <code>main</code>. * <p> * Note: This method isolates the caller from the legacy QVT AST model incompatibility, * allowing a mapping to be the entry operation, while the OMG specification requires * EntryOperation only. */ public static ImperativeOperation getMainOperation(Module module) { if(module.getEntry() != null) { return module.getEntry(); } for (Iterator<EOperation> ruleIt = module.getEOperations().iterator(); ruleIt.hasNext();) { EOperation nextOperation = ruleIt.next(); if (QvtOperationalEnv.MAIN.equals(nextOperation.getName()) && nextOperation instanceof ImperativeOperation) { return (ImperativeOperation)nextOperation; } } return null; } public static boolean isOverloadableMapping(final EOperation op, final QvtOperationalEnv env) { EObject context = op.eContainer(); if (env.getUMLReflection().getOwningClassifier(op) instanceof Module) { // no context to overload return false; } return context instanceof EClass; } public static String safeGetMappingQualifiedName(QvtOperationalEnv env, ImperativeOperation operation) { if(operation != null) { StringBuilder buf = new StringBuilder(); EClassifier ctxType = getContextualType(operation); if(ctxType != null) { buf.append(safeGetQualifiedName(env, ctxType)); buf.append(EmfUtil.PATH_SEPARATOR); } if(operation.getName() != null) { buf.append(operation.getName()); } return buf.toString(); } return ""; //$NON-NLS-1$ } /** * Null-safe variant of {@link UMLReflection#getQualifiedName(Object)} * operation. * * @param type * a classifier that may be <code>null</code> * @param defaultValue * the default value if a non-null can not be derived * @return the name, or <code>defaultValue</code> if a non-null name can not be * derived */ public static String safeGetQualifiedName(QvtOperationalEnv env, EClassifier type, String defaultValue) { return safeGetQualifiedName(env.getUMLReflection(), type, defaultValue); } public static String safeGetQualifiedName( UMLReflection<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint> umlReflection, EClassifier type, String defaultValue) { if(type == null) { return defaultValue; } String result = defaultValue; if(type.getEPackage() == null) { result = umlReflection.getName(type); } else { try { result = umlReflection.getQualifiedName(type); } catch(RuntimeException e) { result = umlReflection.getName(type); } } return result != null ? result : defaultValue; } /** * Null-safe variant of {@link UMLReflection#getQualifiedName(Object)} * operation. * * @param type * a classifier that may be <code>null</code> * @return the name, or empty string if a non-null name can not be derived */ public static String safeGetQualifiedName(QvtOperationalEnv env, EClassifier type) { return safeGetQualifiedName(env, type, ""); //$NON-NLS-1$ } public static <T> T findParentElement(ReturnExp returnExp, Class<T> type) { T result = null; EObject parent = returnExp.eContainer(); while(parent != null) { if(type.isInstance(parent)) { result = (T) type.cast(parent); break; } parent = parent.eContainer(); } return result; } public static void markAsUnsupported(EModelElement element, String reason) { EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource(QVT_NAMESPACE_URI); annotation.getDetails().put(QVT_UNSUPPORTED, reason); element.getEAnnotations().add(annotation); } public static boolean isUnsupported(EModelElement element) { EAnnotation annotation = element.getEAnnotation(QVT_NAMESPACE_URI); if(annotation != null) { return annotation.getDetails().containsKey(QVT_UNSUPPORTED); } return false; } public static String getUnsupportedReason(EModelElement element) { EAnnotation annotation = element.getEAnnotation(QVT_NAMESPACE_URI); if(annotation != null) { return annotation.getDetails().get(QVT_UNSUPPORTED); } return null; } public static void markAsDeprecated(EModelElement element) { markAsDeprecated(element, null); } public static void markAsDeprecated(EModelElement element, String replacingReferenceOpt) { EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource(QVT_NAMESPACE_URI); annotation.getDetails().put(QVT_DEPRECATED, replacingReferenceOpt); element.getEAnnotations().add(annotation); } public static boolean isDeprecated(EModelElement element) { EAnnotation annotation = element.getEAnnotation(QVT_NAMESPACE_URI); return annotation != null && annotation.getDetails().containsKey(QVT_DEPRECATED); } public static String getDeprecatedBy(EModelElement element) { EAnnotation annotation = element.getEAnnotation(QVT_NAMESPACE_URI); if(annotation != null) { return annotation.getDetails().get(QVT_DEPRECATED); } return null; } static void markAsAbstractOperation(ImperativeOperation operation) { EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource(QVT_NAMESPACE_URI); annotation.getDetails().put(QVT_IS_ABSTRACT, Boolean.toString(true)); operation.getEAnnotations().add(annotation); } public static boolean isAbstractOperation(ImperativeOperation operation) { EAnnotation annotation = operation.getEAnnotation(QVT_NAMESPACE_URI); if(annotation != null) { String value = annotation.getDetails().get(QVT_IS_ABSTRACT); return Boolean.valueOf(value); } return false; } public static void markAsStaticOperation(EOperation operation) { EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation(); annotation.setSource(QVT_NAMESPACE_URI); annotation.getDetails().put(QVT_IS_STATIC, Boolean.toString(true)); operation.getEAnnotations().add(annotation); } public static boolean isStaticOperation(EOperation operation) { EAnnotation annotation = operation.getEAnnotation(QVT_NAMESPACE_URI); if(annotation != null) { String value = annotation.getDetails().get(QVT_IS_STATIC); return Boolean.valueOf(value); } return false; } public static CSTNode getPropertyProblemNode(EStructuralFeature feature, QvtOperationalEnv env) { CSTNode cstNode = env.getASTMapping(feature); if(cstNode instanceof ModulePropertyCS) { CSTNode nameCS = ((ModulePropertyCS)cstNode).getSimpleNameCS(); if(nameCS != null) { cstNode = nameCS; } } return cstNode; } public static CSTNode getMethodNameProblemNodeCS(MappingMethodCS methodCS) { MappingDeclarationCS mappingDeclCS = methodCS.getMappingDeclarationCS(); if(mappingDeclCS != null) { final int pos[] = {mappingDeclCS.getStartOffset(), mappingDeclCS.getEndOffset()}; if(mappingDeclCS.getContextType() != null) { pos[0] = mappingDeclCS.getContextType().getStartOffset(); pos[1] = mappingDeclCS.getContextType().getEndOffset(); } if(mappingDeclCS.getSimpleNameCS() != null) { pos[1] = mappingDeclCS.getSimpleNameCS().getEndOffset(); } return new CSTNodeImpl() { @Override public int getStartOffset() { return pos[0]; } @Override public int getEndOffset() { return pos[1]; } }; } return methodCS; } public static CSTNode getMethodHeaderProblemNodeCS(MappingMethodCS methodCS) { MappingDeclarationCS mappingDeclCS = methodCS.getMappingDeclarationCS(); if(mappingDeclCS != null) { final int pos[] = {mappingDeclCS.getStartOffset(), mappingDeclCS.getEndOffset()}; if(mappingDeclCS.getContextType() != null) { pos[1] = mappingDeclCS.getContextType().getEndOffset(); } if(mappingDeclCS.getSimpleNameCS() != null) { pos[1] = mappingDeclCS.getSimpleNameCS().getEndOffset(); } if(!mappingDeclCS.getParameters().isEmpty()) { pos[1] = mappingDeclCS.getParameters().get(mappingDeclCS.getParameters().size()-1).getEndOffset(); } if(!mappingDeclCS.getResult().isEmpty()) { pos[1] = mappingDeclCS.getResult().get(mappingDeclCS.getResult().size()-1).getEndOffset(); } return new CSTNodeImpl() { @Override public int getStartOffset() { return pos[0]; } @Override public int getEndOffset() { return pos[1]; } }; } return methodCS; } public static <T> Collection<T> selectDuplicateQualifiers(List<T> elements) { Set<T> result = null; for (T nextQualifier : elements) { if(Collections.frequency(elements, nextQualifier) > 1) { if(result == null) { result = new HashSet<T>(2); } result.add(nextQualifier); } } return (result != null) ? result : Collections.<T>emptySet(); } public static Module createModule(MappingModuleCS moduleCS) { String name = null; TransformationHeaderCS headerCS = moduleCS.getHeaderCS(); if(headerCS != null && headerCS.getPathNameCS() != null) { EList<SimpleNameCS> sequenceOfNames = headerCS.getPathNameCS().getSimpleNames(); if(!sequenceOfNames.isEmpty()) { name = sequenceOfNames.get(0).getValue(); } } Module module; if(moduleCS instanceof LibraryCS) { module = QvtOperationalStdLibrary.createLibrary(name); } else { module = QvtOperationalStdLibrary.INSTANCE.createTransformation(name); } moduleCS.setAst(module); if(headerCS != null) { ASTSyntheticNode astNode = ASTSyntheticNodeAccess.createASTNode(module); astNode.setStartPosition(headerCS.getStartOffset()); astNode.setEndPosition(headerCS.getEndOffset()); } return module; } public static List<ImportCS> getImports(UnitCS unitCS) { List<ImportCS> allImports = new ArrayList<ImportCS>(); allImports.addAll(unitCS.getImports()); for (MappingModuleCS nextModule : unitCS.getModules()) { allImports.addAll(nextModule.getImports()); } return allImports; } public static List<ModelTypeCS> getModelTypes(UnitCS unitCS) { List<ModelTypeCS> modelTypes = new ArrayList<ModelTypeCS>(); modelTypes.addAll(unitCS.getModelTypes()); for (MappingModuleCS nextModule : unitCS.getModules()) { modelTypes.addAll(nextModule.getMetamodels()); } return modelTypes; } public static String wrappInSeeErrorLogMessage(String message) { return NLS.bind(ValidationMessages.QvtOperationalVisitorCS_SeeErrorLogForDetails, message); } public static Variable<EClassifier, EParameter> getThisVariable(Module module) { for (Variable<EClassifier, EParameter> var : module.getOwnedVariable()) { if(QvtOperationalEnv.THIS.equals(var.getName())) { return var; } } return null; } public static boolean isExtendingEnv(QvtEnvironmentBase env, Module extended) { if(extended == null) { throw new IllegalArgumentException(); } for (QvtEnvironmentBase extEnv : env.getAllExtendedModules()) { if(extended == extEnv.getModuleContextType()) { return true; } } return false; } public static List<String> getSequenceOfNames(List<SimpleNameCS> names) { List<String> result = new ArrayList<String>(names.size()); for (SimpleNameCS nameCS : names) { result.add(nameCS.getValue()); } return result; } public static boolean hasOperationBody(MappingMethodCS methodCS) { return (methodCS instanceof MappingRuleCS && ((MappingRuleCS) methodCS).getMappingBody() != null) || (methodCS instanceof ConstructorCS && ((ConstructorCS) methodCS).getBody() != null) || (methodCS instanceof MappingQueryCS && ((MappingQueryCS) methodCS).getBody() != null) || (methodCS instanceof ConstructorCS && ((ConstructorCS) methodCS).getBody() != null); } public static boolean isDisjunctiveMappingOperation(MappingMethodCS methodCS) { for (MappingExtensionCS extensionCS : methodCS.getMappingDeclarationCS().getMappingExtension()) { if(extensionCS.getKind() == MappingExtensionKindCS.DISJUNCTS) { return true; } } return false; } }