/*******************************************************************************
* Copyright (c) 2007, 2016 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 - bugs 302594, 310991, 397959, 425069, 475123, 477331
*******************************************************************************/
package org.eclipse.m2m.internal.qvt.oml.ast.env;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnumLiteral;
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.resource.Resource;
import org.eclipse.m2m.internal.qvt.oml.ast.env.QvtEnvironmentBase.CollisionStatus.CollisionKind;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalParserUtil;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.QvtOperationalUtil;
import org.eclipse.m2m.internal.qvt.oml.ast.parser.ValidationMessages;
import org.eclipse.m2m.internal.qvt.oml.compiler.BlackboxUnitResolver;
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.Library;
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.internal.qvt.oml.stdlib.QVTUMLReflection;
import org.eclipse.ocl.AmbiguousLookupException;
import org.eclipse.ocl.LookupException;
import org.eclipse.ocl.ecore.CallOperationAction;
import org.eclipse.ocl.ecore.Constraint;
import org.eclipse.ocl.ecore.EcoreEnvironment;
import org.eclipse.ocl.ecore.SendSignalAction;
import org.eclipse.ocl.expressions.Variable;
import org.eclipse.ocl.lpg.ProblemHandler;
import org.eclipse.ocl.lpg.ProblemHandler.Severity;
import org.eclipse.ocl.options.ParsingOptions;
import org.eclipse.ocl.types.VoidType;
import org.eclipse.ocl.util.TypeUtil;
import org.eclipse.ocl.utilities.TypedElement;
import org.eclipse.ocl.utilities.UMLReflection;
import lpg.runtime.ParseErrorCodes;
/**
* @since 2.0
*/
public abstract class QvtEnvironmentBase extends EcoreEnvironment implements QVTOEnvironment {
public static class CollisionStatus {
enum CollisionKind {
ALREADY_DEFINED,
VIRTUAL_METHOD_SUBTYPE,
OVERRIDES,
VIRTUAL_METHOD_SUPERTYPE
}
private CollisionKind fKind;
private EOperation fOperation;
CollisionStatus(EOperation operation, CollisionKind kind) {
fKind = kind;
fOperation = operation;
}
public CollisionKind getCollisionKind() {
return fKind;
}
public EOperation getOperation() {
return fOperation;
}
}
/**
* Special prefix for generated identifiers
*/
public static final String GENERATED_NAME_SPECIAL_PREFIX = "$"; //$NON-NLS-1$
private static final String TEMPORARY_NAME_GENERATOR_UNIQUE_PREFIX = GENERATED_NAME_SPECIAL_PREFIX + "temp_"; //$NON-NLS-1$
private int myTemporaryNameGeneratorInt = 0;
/*
* List of declared variables and implicit variables, including "self".
* Implicit variables are generated when there is an iterator without any
* iteration variable specified.
*/
private List<org.eclipse.ocl.ecore.Variable> myImplicitVars = new LinkedList<org.eclipse.ocl.ecore.Variable>();
private QVTUMLReflection fQVUMLReflection;
private List<QvtEnvironmentBase> fByAccess;
private List<QvtEnvironmentBase> fByExtension;
private List<QvtEnvironmentBase> fAllExtendedModuleEnvs;
private Map<URI, Set<String>> fImportedNativeLibs;
protected QvtEnvironmentBase(QvtEnvironmentBase parent) {
super(parent);
setOption(ParsingOptions.USE_BACKSLASH_ESCAPE_PROCESSING, true);
setLongIntOption();
}
@SuppressWarnings("deprecation")
protected QvtEnvironmentBase(EPackage.Registry reg, Resource resource) {
super(reg, resource);
setOption(ParsingOptions.USE_BACKSLASH_ESCAPE_PROCESSING, true);
setLongIntOption();
}
private void setLongIntOption() {
try {
if (ParsingOptions.class.getDeclaredField("USE_LONG_INTEGERS") != null) { //$NON-NLS-1$
setOption(ParsingOptions.USE_LONG_INTEGERS, true);
}
} catch (Exception e) {}
}
protected QvtEnvironmentBase(EPackage.Registry reg) {
this(reg, null);
}
public abstract Module getModuleContextType();
public void addImplicitVariableForProperties(String name, Variable<EClassifier, EParameter> elem) {
getUMLReflection().setName(elem, name);
addedVariable(name, elem, false);
}
@Override
protected void addedVariable(String name, Variable<EClassifier, EParameter> elem, boolean isExplicit) {
org.eclipse.ocl.ecore.Variable elemVar = (org.eclipse.ocl.ecore.Variable) elem;
if(!isExplicit) {
myImplicitVars.add(elemVar);
}
if(elemVar instanceof VarParameter == false && elemVar.eContainer() == null) {
if(getContextOperation() instanceof ImperativeOperation) {
ImperativeOperation imperativeOperation = (ImperativeOperation) getContextOperation();
if (imperativeOperation.getBody() != null) {
imperativeOperation.getBody().getVariable().add((org.eclipse.ocl.ecore.Variable)elemVar);
} else {
super.addedVariable(name, elemVar, isExplicit);
}
} else {
super.addedVariable(name, elemVar, isExplicit);
}
}
}
@Override
protected void removedVariable(String name, Variable<EClassifier, EParameter> variable, boolean isExplicit) {
if(!isExplicit) {
myImplicitVars.remove(variable);
}
super.removedVariable(name, variable, isExplicit);
}
public Collection<org.eclipse.ocl.ecore.Variable> getImplicitVariables() {
return Collections.unmodifiableCollection(myImplicitVars);
}
protected Variable<EClassifier, EParameter> localLookupImplicitSourceForOperation(String name, List<? extends TypedElement<EClassifier>> args) {
return super.lookupImplicitSourceForOperation(name, args);
}
@Override
public Variable<EClassifier, EParameter> lookupImplicitSourceForOperation(String name, List<? extends TypedElement<EClassifier>> args) {
try {
return tryLookupImplicitSourceForOperation(name, args);
} catch(LookupException e) {
// report resolution ambiguity
throw new RuntimeException(e);
}
}
public Variable<EClassifier, EParameter> tryLookupImplicitSourceForOperation(String name, List<? extends TypedElement<EClassifier>> args) throws LookupException {
Variable<EClassifier, EParameter> result = super.lookupImplicitSourceForOperation(name, args);
if(result == null) {
QvtEnvironmentBase rootEnv = getRootEnv();
if(rootEnv != this) {
// TODO - why not to call the root directly, do we want others to override?
return this.getInternalParent().lookupImplicitSourceForOperation(name, args);
}
List<Variable<EClassifier, EParameter>> ambiguous = new LinkedList<Variable<EClassifier,EParameter>>();
for (QvtEnvironmentBase nextExtendedEnv : rootEnv.getAllExtendedModules()) {
result = nextExtendedEnv.localLookupImplicitSourceForOperation(name, args);
if(result != null) {
ambiguous.add(result);
}
}
for (QvtEnvironmentBase nextAccessedEnv : rootEnv.getImportsByAccess()) {
Module importedModule = nextAccessedEnv.getModuleContextType();
if(importedModule instanceof Library) {
// there is a single default instance for libraries
// this cannot be done transformations which has an explicit instance
result = nextAccessedEnv.localLookupImplicitSourceForOperation(name, args);
if(result != null) {
ambiguous.add(result);
}
}
}
if (ambiguous.size() > 1) {
throw new AmbiguousLookupException(ValidationMessages.AmbiguousImplicitSourceLookup, ambiguous);
}
result = ambiguous.isEmpty() ? null : ambiguous.get(0);
}
return result;
}
// implements the interface method
private Variable<EClassifier, EParameter> lookupImplicitSourceForPropertyInternal(String name) {
Variable<EClassifier, EParameter> vdcl;
for (int i = myImplicitVars.size() - 1; i >= 0; i--) {
vdcl = myImplicitVars.get(i);
EClassifier owner = vdcl.getType();
if (owner != null) {
EStructuralFeature property = safeTryLookupPropertyInternal(owner, name);
if (property != null) {
// in case of extended modules, module properties are distributed across multiple owners without explicit supertyping
// => accept only if property is actually available on the owner, i.e. if the actual property owner is an explicit supertype of the owner
EClassifier actualPropertyOwner = getUMLReflection().getOwningClassifier(property);
if (TypeUtil.compatibleTypeMatch(this, owner, actualPropertyOwner)) {
return vdcl;
}
}
}
}
// try the "self" variable, last
vdcl = getSelfVariable();
if (vdcl != null) {
EClassifier owner = vdcl.getType();
if (owner != null) {
EStructuralFeature property = safeTryLookupPropertyInternal(owner, name);
if (property != null) {
return vdcl;
}
}
}
return null;
}
/**
* Wrapper for the "try" operation that doesn't throw, but just returns the
* first ambiguous match in case of ambiguity.
*/
private EStructuralFeature safeTryLookupPropertyInternal(EClassifier owner, String name) {
EStructuralFeature result = null;
try {
result = tryLookupProperty(owner, name);
} catch (LookupException e) {
if (!e.getAmbiguousMatches().isEmpty()) {
result = (EStructuralFeature) e.getAmbiguousMatches().get(0);
}
}
return result;
}
@Override
public Variable<EClassifier, EParameter> lookupImplicitSourceForProperty(String name) {
Variable<EClassifier, EParameter> result = lookupImplicitSourceForPropertyInternal(name);
if(result == null) {
QvtEnvironmentBase rootEnv = getRootEnv();
if(rootEnv != this) {
return this.getInternalParent().lookupImplicitSourceForProperty(name);
}
for (QvtEnvironmentBase nextSiblingEnv : rootEnv.getImportsByExtends()) {
result = nextSiblingEnv.lookupImplicitSourceForProperty(name);
if(result != null) {
return result;
}
}
for (QvtEnvironmentBase nextSiblingEnv : rootEnv.getImportsByAccess()) {
Module importedModule = nextSiblingEnv.getModuleContextType();
if(importedModule instanceof Library) {
// there is a single default instance for libraries
// this cannot be done transformations which has an explicit instance
result = nextSiblingEnv.lookupImplicitSourceForProperty(name);
if(result != null) {
break;
}
}
}
}
return result;
}
// FIXME - refactore this out
final QvtTypeResolverImpl getQVTTypeResolver() {
return (QvtTypeResolverImpl)getTypeResolver();
}
@Override
public QVTOTypeResolver getTypeResolver() {
return (QVTOTypeResolver)super.getTypeResolver();
}
public QVTOStandardLibrary getQVTStandardLibrary() {
return QvtOperationalStdLibrary.INSTANCE;
}
@Override
public List<EOperation> getAdditionalOperations(EClassifier classifier) {
if (classifier instanceof VoidType<?>) {
List<EOperation> result = new ArrayList<EOperation>();
getAllContextualOperations(result, this);
for (QvtEnvironmentBase nextImportedEnv : getImportsByExtends()) {
getAllContextualOperations(result, nextImportedEnv);
}
return result;
}
if(classifier instanceof org.eclipse.ocl.ecore.CollectionType) {
org.eclipse.ocl.ecore.CollectionType collectionType = (org.eclipse.ocl.ecore.CollectionType) classifier;
List<EOperation> result = new ArrayList<EOperation>();
getLocalAdditionalCollectionOperations(collectionType, result);
// look for imported collection operations
for (QvtEnvironmentBase nextImportedEnv : getImportsByExtends()) {
nextImportedEnv.getLocalAdditionalCollectionOperations(collectionType, result);
}
for (QvtEnvironmentBase nextImportedEnv : getImportsByAccess()) {
nextImportedEnv.getLocalAdditionalCollectionOperations(collectionType, result);
}
return result;
}
return super.getAdditionalOperations(classifier);
}
private void getAllContextualOperations(List<EOperation> result, QvtEnvironmentBase env) {
if (env.getModuleContextType() == null) {
return;
}
for (EOperation operation : env.getModuleContextType().getEOperations()) {
if (operation instanceof ImperativeOperation) {
ImperativeOperation imperative = (ImperativeOperation) operation;
if (QvtOperationalParserUtil.isContextual(imperative)) {
result.add(imperative);
}
}
}
}
private void getLocalAdditionalCollectionOperations(org.eclipse.ocl.ecore.CollectionType collectionType, List<EOperation> result) {
// OCLStandardLibrary<EClassifier> oclstdlib = getOCLStandardLibrary();
//
// EcorePackage typePackage = EcorePackage.eINSTANCE;
//
// EClass metaType = collectionType.eClass();
// EClassifier genericBaseType = null;
//
// if(metaType == typePackage.getCollectionType() && collectionType != oclstdlib.getCollection()) {
// genericBaseType = oclstdlib.getCollection();
// } else if(metaType == typePackage.getBagType() && collectionType != oclstdlib.getBag()) {
// genericBaseType = oclstdlib.getBag();
// } else if(metaType == typePackage.getSequenceType() && collectionType != oclstdlib.getSequence()) {
// genericBaseType = oclstdlib.getSequence();
// } else if(metaType == typePackage.getSetType() && collectionType != oclstdlib.getSet()) {
// genericBaseType = oclstdlib.getSet();
// } else if(metaType == typePackage.getOrderedSetType() && collectionType != oclstdlib.getOrderedSet()) {
// genericBaseType = oclstdlib.getOrderedSet();
// } else if(metaType == ImperativeOCLPackage.eINSTANCE.getListType() && collectionType != getQVTStandardLibrary().getList()) {
// genericBaseType = getQVTStandardLibrary().getList();
// } else if(metaType == ImperativeOCLPackage.eINSTANCE.getDictionaryType() && collectionType != getQVTStandardLibrary().getDictionary()) {
// genericBaseType = getQVTStandardLibrary().getDictionary();
// }
QvtTypeResolverImpl thisResolver = getQVTTypeResolver();
// if(genericBaseType != null) {
// thisResolver.getLocalCollectionAdditionalOperations((CollectionType)genericBaseType, result, false);
// }
thisResolver.getLocalCollectionAdditionalOperations(collectionType, result, true);
// Collection<EClassifier> allParents = OCLStandardLibraryUtil.getAllSupertypes(this, collectionType);
// for (EClassifier general : allParents) {
// org.eclipse.ocl.ecore.CollectionType generalCollection = (org.eclipse.ocl.ecore.CollectionType) general;
// thisResolver.getLocalCollectionAdditionalOperations(generalCollection, result, false);
// }
//
// if(metaType == ImperativeOCLPackage.eINSTANCE.getListType()) {
// // process the CollectionType super type
// // TODO - better to have MDT OCL to support #getAllSupertypes(...) operation in TypeChecker
// thisResolver.getLocalCollectionAdditionalOperations((CollectionType)oclstdlib.getCollection(), result, false);
// }
}
@Override
public UMLReflection<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint> getUMLReflection() {
Internal<EPackage, EClassifier, EOperation, EStructuralFeature, EEnumLiteral, EParameter, EObject, CallOperationAction, SendSignalAction, Constraint, EClass, EObject> parent = getInternalParent();
if(parent != null) {
return parent.getUMLReflection();
}
if(fQVUMLReflection == null) {
fQVUMLReflection = new QVTUMLReflection(super.getUMLReflection());
}
return fQVUMLReflection;
}
public void close() {
if (getInternalParent() == null) {
if (fQVUMLReflection != null) {
fQVUMLReflection.close();
}
if (this != QvtOperationalStdLibrary.INSTANCE.getEnvironment()) {
QvtOperationalStdLibrary.INSTANCE.getEnvironment().close();
}
}
}
public final void addImport(ImportKind kind, QvtEnvironmentBase importedEnv) {
QvtEnvironmentBase rootEnv = getRootEnv();
if(rootEnv != this) {
// propagate to the top level parent
rootEnv.addImport(kind, importedEnv);
return;
}
if(importedEnv == null || importedEnv == this || isOneOfParents(importedEnv)) {
throw new IllegalArgumentException("Illegal import environment: " + String.valueOf(importedEnv)); //$NON-NLS-1$
}
List<QvtEnvironmentBase> container;
if(kind == ImportKind.ACCESS) {
if(fByAccess == null) {
fByAccess = new UniqueEList<QvtEnvironmentBase>();
}
container = fByAccess;
} else {
if(fByExtension == null) {
fByExtension = new UniqueEList<QvtEnvironmentBase>();
}
container = fByExtension;
fAllExtendedModuleEnvs = null;
}
fImportedNativeLibs = null;
assert container != null;
container.add(importedEnv);
// reset cached all extended modules
}
public final List<QvtEnvironmentBase> getImportsByAccess() {
QvtEnvironmentBase rootEnv = getRootEnv();
if(rootEnv != this) {
return rootEnv.getImportsByAccess();
}
return fByAccess != null ? fByAccess : Collections.<QvtEnvironmentBase>emptyList();
}
public List<QvtEnvironmentBase> getAllExtendedModules() {
QvtEnvironmentBase rootEnv = getRootEnv();
if(rootEnv != this) {
return rootEnv.getAllExtendedModules();
}
if(fAllExtendedModuleEnvs == null) {
LinkedHashSet<QvtEnvironmentBase> result = new LinkedHashSet<QvtEnvironmentBase>();
List<QvtEnvironmentBase> importsByExtends = getImportsByExtends();
for (QvtEnvironmentBase nextImportedEnv : importsByExtends) {
result.add(nextImportedEnv);
result.addAll(nextImportedEnv.getAllExtendedModules());
}
// safety check for the case somebody in the hierarchy tries to extend us
result.remove(this);
fAllExtendedModuleEnvs = Collections.unmodifiableList(new ArrayList<QvtEnvironmentBase>(result));
}
return fAllExtendedModuleEnvs;
}
public final List<QvtEnvironmentBase> getImportsByExtends() {
QvtEnvironmentBase rootEnv = getRootEnv();
if(rootEnv != this) {
return rootEnv.getImportsByExtends();
}
return fByExtension != null ? fByExtension : Collections.<QvtEnvironmentBase>emptyList();
}
public Map<URI, Set<String>> getImportedNativeLibs() {
QvtEnvironmentBase rootEnv = getRootEnv();
if(rootEnv != this) {
return rootEnv.getImportedNativeLibs();
}
if(fImportedNativeLibs == null) {
Collection<QvtEnvironmentBase> imports = new LinkedHashSet<QvtEnvironmentBase>();
imports.addAll(getImportsByExtends());
imports.addAll(getImportsByAccess());
Map<URI, Set<String>> result = new LinkedHashMap<URI, Set<String>>(imports.size());
for (QvtEnvironmentBase sibling : imports) {
Module module = sibling.getModuleContextType();
if (module == null || module.eResource() == null) {
continue;
}
URI uri = module.eResource().getURI();
if (!BlackboxUnitResolver.isBlackboxUnitURI(uri)) {
continue;
}
Set<String> names = result.get(uri);
if (names == null) {
names = new LinkedHashSet<String>();
result.put(uri, names);
}
names.add(module.getName());
}
fImportedNativeLibs = Collections.unmodifiableMap(result);
}
return fImportedNativeLibs;
}
protected final CollisionStatus findCollidingOperation(EClassifier ownerType, ImperativeOperation operation) {
return doFindCollidingOperation(ownerType, operation);
}
private EOperation findMatchingFromExtended(Module extending, EOperation operation) {
Library stdLibModule = getQVTStandardLibrary().getStdLibModule();
EOperation result = null;
for (ModuleImport nextImport : extending.getModuleImport()) {
Module nextImportedModule = nextImport.getImportedModule();
if(nextImportedModule == stdLibModule) {
// no imperative operation declaration in stdlib
continue;
}
EList<EOperation> importedOpers = nextImportedModule.getEOperations();
String name = operation.getName();
if(name != null) {
for (EOperation nextImportedOper : importedOpers) {
if(name.equals(nextImportedOper.getName()) &&
matchParameters(nextImportedOper, operation)) {
// accept imported operation only if it has the same context type (fixed by bug 397959)
if (nextImportedOper instanceof ImperativeOperation &&
operation instanceof ImperativeOperation &&
!matchContext((ImperativeOperation) nextImportedOper, (ImperativeOperation) operation)) {
continue;
}
return nextImportedOper;
}
}
}
result = findMatchingFromExtended(nextImportedModule, operation);
if(result != null) {
return result;
}
}
return null;
}
private CollisionStatus doFindCollidingOperation(EClassifier ownerType, ImperativeOperation operation) {
CollisionStatus result = null;
EClassifier definingModule = getModuleContextType();
String operationName = getUMLReflection().getName(operation);
Set<EOperation> operations = new LinkedHashSet<EOperation>(TypeUtil.getOperations(this, ownerType));
boolean isContextual = !(ownerType == definingModule);
if(!isContextual) {
EOperation overridden = findMatchingFromExtended(getModuleContextType(), operation);
if(overridden != null) {
operations.add(overridden);
}
} else {
// collect additional operations defined for sub-types of the checked owner type,
// Note: those from super-types are included by MDT OCL TypeUtil.getOperations(...);
// => union forms the whole scope for potentially virtually called operation;
// all fAdditionalTypes ever defined goes through this check, so all applicable get into VTABLEs
getQVTTypeResolver().collectAdditionalOperationsInTypeHierarchy(ownerType, true, operations);
}
// filter overridden operations
Collection<EOperation> overrideCandidates = QvtOperationalUtil.filterOverriddenOperations(operations);
for (EOperation next : operations) {
if ((next != operation) &&
(getUMLReflection().getName(next).equals(operationName) &&
matchParameters(next, operation))) {
EClassifier nextOwner = getUMLReflection().getOwningClassifier(next);
if(nextOwner == null) {
// be tolerant to partially parsed operations
continue;
}
if(isContextual) {
int ownerRelation = TypeUtil.getRelationship(this, ownerType, nextOwner);
if((ownerRelation != UMLReflection.SAME_TYPE) && (UMLReflection.RELATED_TYPE & ownerRelation) != 0) {
// context types are different but part of a common type hierarchy
EClassifier nextReturnType = next.getEType();
EClassifier operationReturnType = operation.getEType();
if (nextReturnType != null && operationReturnType != null) {
int returnRelation = TypeUtil.getRelationship(this, operationReturnType, nextReturnType);
if ((ownerRelation & UMLReflection.SUPERTYPE) != 0) {
if ((returnRelation & UMLReflection.SUPERTYPE) == 0) {
if (QvtOperationalEnv.MAIN.equals(operationName)) {
// clashes with main(...) are handled separately
return null;
}
// report ill-formed return type for virtual operations
return new CollisionStatus(next, CollisionKind.VIRTUAL_METHOD_SUPERTYPE);
}
}
else if ((ownerRelation & UMLReflection.SUBTYPE) != 0) {
if ((returnRelation & UMLReflection.SUBTYPE) == 0) {
if (QvtOperationalEnv.MAIN.equals(operationName)) {
// clashes with main(...) are handled separately
return null;
}
// report ill-formed return type for virtual operations
return new CollisionStatus(next, CollisionKind.VIRTUAL_METHOD_SUBTYPE);
}
}
}
// assemble virtual table info
if(QvtOperationalUtil.isImperativeOperation(operation) && QvtOperationalUtil.isImperativeOperation(next)) {
VirtualTable sourceOperVtable = getVirtualTable(operation);
sourceOperVtable.addOperation(next);
// do not virtualize operation from the importing module in the imported module for import by access
if(!isImportedByAccess(next)) {
VirtualTable targetOperVtable = getVirtualTable(next);
targetOperVtable.addOperation(operation);
}
}
}
}
if(ownerType == nextOwner || !isContextual) {
if(definingModule != next.getEContainingClass()) {
// we try to override operation only from extended modules
if(isImportedByExtends(next) && overrideCandidates.contains(next)) {
result = new CollisionStatus(next, CollisionKind.OVERRIDES);
}
} else {
return new CollisionStatus(next, CollisionKind.ALREADY_DEFINED);
}
}
} // end of matching operation processing
}
return result;
}
private boolean isImportedByAccess(EOperation operation) {
Module definingModule = QvtOperationalParserUtil.getOwningModule(operation);
for (QvtEnvironmentBase nextImport : getImportsByAccess()) {
if(definingModule == nextImport.getModuleContextType()) {
return true;
}
}
return false;
}
private boolean isImportedByExtends(EOperation operation) {
Module definingModule = QvtOperationalParserUtil.getOwningModule(operation);
if(definingModule == null) {
return false;
}
for (QvtEnvironmentBase nextImport : getAllExtendedModules()) {
if(definingModule == nextImport.getModuleContextType()) {
return true;
}
}
return false;
}
private VirtualTable getVirtualTable(EOperation operation) {
return VirtualTableAdapter.getAdapter(operation, true).getVirtualTable();
}
/**
* Performs name ignoring match on given parameters.
*/
private boolean matchParameters(EOperation a, EOperation b) {
List<EParameter> aparms = getUMLReflection().getParameters(a);
List<EParameter> bparms = getUMLReflection().getParameters(b);
if (aparms.size() == bparms.size()) {
int count = aparms.size();
for (int i = 0; i < count; i++) {
EParameter aparm = aparms.get(i);
EParameter bparm = bparms.get(i);
if (!TypeUtil.exactTypeMatch(this, getUMLReflection().getOCLType(aparm), getUMLReflection().getOCLType(bparm))) {
return false;
}
}
return true;
}
return false;
}
/**
* Performs name ignoring match on given context types.
*/
private boolean matchContext(ImperativeOperation a, ImperativeOperation b) {
return getTypeChecker().exactTypeMatch(
getUMLReflection().getOCLType(a.getContext()),
getUMLReflection().getOCLType(b.getContext()));
}
private boolean isOneOfParents(EcoreEnvironment env) {
for (EcoreEnvironment parent = (EcoreEnvironment)env.getInternalParent(); parent != null;
parent = (EcoreEnvironment)parent.getInternalParent()) {
if(parent == env) {
return true;
}
}
return false;
}
protected QvtEnvironmentBase getRootEnv() {
QvtEnvironmentBase root = this;
while(root.getInternalParent() instanceof QvtEnvironmentBase) {
root = (QvtEnvironmentBase) root.getInternalParent();
}
return root;
}
public String generateTemporaryName() {
QvtEnvironmentBase rootEnv = getRootEnv();
String name;
do {
name = rootEnv.generateTemporaryNameInternal();
} while (lookup(name) != null);
return name;
}
public boolean isTemporaryElement(String name) {
return (name != null) && name.startsWith(TEMPORARY_NAME_GENERATOR_UNIQUE_PREFIX);
}
private String generateTemporaryNameInternal() {
myTemporaryNameGeneratorInt++;
return TEMPORARY_NAME_GENERATOR_UNIQUE_PREFIX + myTemporaryNameGeneratorInt;
}
@SuppressWarnings("restriction")
@Override
public void parserError(int errorCode, int leftToken, int rightToken, String tokenText) {
ProblemHandler problemHandler = getProblemHandler();
if (problemHandler == null) {
return;
}
int leftTokenLoc = (leftToken > rightToken ? rightToken : leftToken);
int rightTokenLoc = rightToken;
int startOffset = getParser().getIPrsStream().getStartOffset(leftTokenLoc);
int endOffset = getParser().getIPrsStream().getEndOffset(rightTokenLoc);
int line = leftTokenLoc >= 0 ? getParser().getIPrsStream().getLine(leftTokenLoc) : -1;
String message;
if (line <= 0) {
message = org.eclipse.ocl.internal.l10n.OCLMessages.InvalidOCL_ERROR_;
} else {
String locInfo = ""; //$NON-NLS-1$
String messageTemplate = ProblemHandler.ERROR_MESSAGES[errorCode].substring(4);
String inputText = '"' + getParser().computeInputString(startOffset, endOffset) + '"';
switch (errorCode) {
case ParseErrorCodes.EOF_CODE:
case ParseErrorCodes.MISPLACED_CODE:
case ParseErrorCodes.DELETION_CODE:
case ParseErrorCodes.INVALID_TOKEN_CODE:
message = org.eclipse.ocl.internal.l10n.OCLMessages.bind(
messageTemplate,
locInfo,
inputText);
break;
case ParseErrorCodes.MERGE_CODE:
case ParseErrorCodes.BEFORE_CODE:
case ParseErrorCodes.INSERTION_CODE:
case ParseErrorCodes.SUBSTITUTION_CODE: // includes SECONDARY_CODE
message = org.eclipse.ocl.internal.l10n.OCLMessages.bind(
messageTemplate,
new Object[]{
locInfo,
tokenText,
inputText
});
break;
case ParseErrorCodes.SCOPE_CODE:
if (leftToken != rightToken) {
message = org.eclipse.ocl.internal.l10n.OCLMessages.bind(messageTemplate, locInfo, tokenText);
problemHandler.parserProblem(Severity.ERROR, message, null, startOffset, getParser().getIPrsStream().getEndOffset(leftTokenLoc));
}
startOffset = getParser().getIPrsStream().getStartOffset(rightTokenLoc);
default:
message = org.eclipse.ocl.internal.l10n.OCLMessages.bind(messageTemplate, locInfo, tokenText);
break;
}
}
problemHandler.parserProblem(Severity.ERROR, message, null, startOffset, endOffset);
}
}