| /******************************************************************************* |
| * Copyright (c) 2015, 2017 Willink Transformations 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 - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.qvtd.pivot.qvtcore.analysis; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.ocl.pivot.CollectionItem; |
| import org.eclipse.ocl.pivot.CollectionLiteralExp; |
| import org.eclipse.ocl.pivot.CollectionLiteralPart; |
| import org.eclipse.ocl.pivot.CollectionRange; |
| import org.eclipse.ocl.pivot.CollectionType; |
| import org.eclipse.ocl.pivot.Element; |
| import org.eclipse.ocl.pivot.ExpressionInOCL; |
| import org.eclipse.ocl.pivot.IfExp; |
| import org.eclipse.ocl.pivot.IterateExp; |
| import org.eclipse.ocl.pivot.Iteration; |
| import org.eclipse.ocl.pivot.IteratorExp; |
| import org.eclipse.ocl.pivot.LanguageExpression; |
| import org.eclipse.ocl.pivot.LetExp; |
| import org.eclipse.ocl.pivot.LiteralExp; |
| import org.eclipse.ocl.pivot.MapLiteralExp; |
| import org.eclipse.ocl.pivot.MapLiteralPart; |
| import org.eclipse.ocl.pivot.NavigationCallExp; |
| import org.eclipse.ocl.pivot.NullLiteralExp; |
| import org.eclipse.ocl.pivot.OCLExpression; |
| import org.eclipse.ocl.pivot.Operation; |
| import org.eclipse.ocl.pivot.OperationCallExp; |
| import org.eclipse.ocl.pivot.OppositePropertyCallExp; |
| import org.eclipse.ocl.pivot.Parameter; |
| import org.eclipse.ocl.pivot.PrimitiveType; |
| import org.eclipse.ocl.pivot.Property; |
| import org.eclipse.ocl.pivot.PropertyCallExp; |
| import org.eclipse.ocl.pivot.SelfType; |
| import org.eclipse.ocl.pivot.ShadowExp; |
| import org.eclipse.ocl.pivot.ShadowPart; |
| import org.eclipse.ocl.pivot.TemplateParameter; |
| import org.eclipse.ocl.pivot.TemplateSignature; |
| import org.eclipse.ocl.pivot.TemplateableElement; |
| import org.eclipse.ocl.pivot.TupleLiteralExp; |
| import org.eclipse.ocl.pivot.TupleLiteralPart; |
| import org.eclipse.ocl.pivot.TupleType; |
| import org.eclipse.ocl.pivot.Type; |
| import org.eclipse.ocl.pivot.TypeExp; |
| import org.eclipse.ocl.pivot.TypedElement; |
| import org.eclipse.ocl.pivot.Variable; |
| import org.eclipse.ocl.pivot.VariableDeclaration; |
| import org.eclipse.ocl.pivot.VariableExp; |
| import org.eclipse.ocl.pivot.ids.OperationId; |
| import org.eclipse.ocl.pivot.internal.manager.TemplateParameterSubstitutionVisitor; |
| import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal; |
| import org.eclipse.ocl.pivot.util.Visitable; |
| import org.eclipse.ocl.pivot.utilities.ClassUtil; |
| import org.eclipse.ocl.pivot.utilities.EnvironmentFactory; |
| import org.eclipse.ocl.pivot.utilities.MetamodelManager; |
| import org.eclipse.ocl.pivot.utilities.ParserException; |
| import org.eclipse.qvtd.pivot.qvtbase.Domain; |
| import org.eclipse.qvtd.pivot.qvtbase.Function; |
| import org.eclipse.qvtd.pivot.qvtbase.Predicate; |
| import org.eclipse.qvtd.pivot.qvtbase.Rule; |
| import org.eclipse.qvtd.pivot.qvtbase.Transformation; |
| import org.eclipse.qvtd.pivot.qvtbase.TypedModel; |
| import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil; |
| import org.eclipse.qvtd.pivot.qvtcore.Area; |
| import org.eclipse.qvtd.pivot.qvtcore.Assignment; |
| import org.eclipse.qvtd.pivot.qvtcore.BottomPattern; |
| import org.eclipse.qvtd.pivot.qvtcore.CoreDomain; |
| import org.eclipse.qvtd.pivot.qvtcore.GuardPattern; |
| import org.eclipse.qvtd.pivot.qvtcore.Mapping; |
| import org.eclipse.qvtd.pivot.qvtcore.NavigationAssignment; |
| import org.eclipse.qvtd.pivot.qvtcore.OppositePropertyAssignment; |
| import org.eclipse.qvtd.pivot.qvtcore.PropertyAssignment; |
| import org.eclipse.qvtd.pivot.qvtcore.RealizedVariable; |
| import org.eclipse.qvtd.pivot.qvtcore.VariableAssignment; |
| import org.eclipse.qvtd.pivot.qvtcore.util.AbstractExtendingQVTcoreVisitor; |
| import org.eclipse.qvtd.pivot.qvtcore.utilities.QVTcoreUtil; |
| |
| /** |
| * AbstractDomainUsageAnalysis provides shared functionality for the overall analysis and for nested operational analyses. |
| */ |
| public abstract class AbstractDomainUsageAnalysis extends AbstractExtendingQVTcoreVisitor<org.eclipse.qvtd.pivot.qvtcore.analysis.@NonNull DomainUsage, @NonNull EnvironmentFactory> implements DomainUsageAnalysis.Internal |
| { |
| private DomainUsage selfUsage = null; |
| protected final @NonNull Map<@NonNull Element, org.eclipse.qvtd.pivot.qvtcore.analysis.DomainUsage> element2usage = new HashMap<@NonNull Element, org.eclipse.qvtd.pivot.qvtcore.analysis.DomainUsage>(); |
| |
| protected AbstractDomainUsageAnalysis(@NonNull EnvironmentFactory environmentFactory) { |
| super(environmentFactory); |
| } |
| |
| @Override |
| public @Nullable DomainUsage basicGetUsage(@Nullable Element element) { |
| return element2usage.get(element); |
| } |
| |
| protected @NonNull DomainUsage doNavigationAssignment(@NonNull Property property, @NonNull NavigationAssignment object) { |
| DomainUsage slotUsage = visit(object.getSlotExpression()); |
| DomainUsage valueUsage = visit(object.getValue()); |
| DomainUsage knownSourceUsage = getRootAnalysis().property2containingClassUsage.get(property); |
| if (knownSourceUsage != null) { |
| DomainUsage knownTargetUsage = getRootAnalysis().getUsage(property); |
| assert knownTargetUsage != null; |
| intersection(knownSourceUsage, slotUsage); |
| intersection(knownTargetUsage, valueUsage); |
| return knownSourceUsage; //intersection(knownTargetUsage, valueUsage); |
| } |
| else { |
| return slotUsage; //intersection(slotUsage, valueUsage); |
| } |
| } |
| |
| protected @NonNull DomainUsage doNavigationCallExp(@NonNull Property property, @NonNull NavigationCallExp object) { |
| DomainUsage actualSourceUsage = visit(object.getOwnedSource()); |
| DomainUsage knownPropertyUsage = visit(property); |
| DomainUsage usage = knownPropertyUsage; |
| RootDomainUsageAnalysis rootAnalysis = getRootAnalysis(); |
| Property oppositeProperty = property.getOpposite(); |
| if (property.isIsComposite() // Composite properties have both ends in the sme domain |
| || ((oppositeProperty != null) && oppositeProperty.isIsComposite()) |
| || (property == rootAnalysis.getOclContainerProperty()) // FIXME ensure these are isComposite |
| || (property == rootAnalysis.getOclContentsProperty())) { |
| usage = intersection(usage, actualSourceUsage); |
| } |
| else if (!property.isIsImplicit() && !rootAnalysis.isDirty(property) // Simple input domain nodes cannot reference middle or output domains |
| && (usage.isMiddle() || usage.isOutput()) |
| && actualSourceUsage.isInput() && !actualSourceUsage.isMiddle() && !actualSourceUsage.isOutput()) { |
| usage = intersection(usage, actualSourceUsage); |
| } |
| return usage; |
| } |
| |
| protected @NonNull DomainUsage getAllInstancesUsage(@NonNull OperationCallExp object, @NonNull DomainUsage sourceUsage) { |
| return sourceUsage; |
| } |
| |
| protected @NonNull DomainUsage getDomainUsage(@Nullable EObject object) { |
| Domain domain = QVTcoreUtil.basicGetContainingDomain(object); |
| if (domain != null) { |
| return visit(domain.getTypedModel()); |
| } |
| else { |
| return getRootAnalysis().getMiddleUsage(); |
| } |
| } |
| |
| public @NonNull Map<@NonNull Element, org.eclipse.qvtd.pivot.qvtcore.analysis.DomainUsage> getElements2Usage() { |
| return element2usage; |
| } |
| |
| public @NonNull EnvironmentFactory getEnvironmentFactory() { |
| return context; |
| } |
| |
| protected abstract @NonNull RootDomainUsageAnalysis getRootAnalysis(); |
| |
| @Override |
| public @NonNull DomainUsage getUsage(@NonNull Element element) { |
| DomainUsage usage = element2usage.get(element); |
| if (usage == null) { |
| usage = element.accept(this); |
| // if ((usage == null) || usage.isNone()) { // FIXME debugging |
| // usage = element.accept(this); |
| // } |
| assert usage != null : "null usage for " + element.eClass().getName() + " " + element; |
| setUsage(element, usage); |
| } |
| return usage; |
| } |
| |
| public @NonNull DomainUsage intersection(@NonNull DomainUsage firstUsage, @NonNull DomainUsage secondUsage) { |
| int firstMask = ((DomainUsage.Internal)firstUsage).getMask(); |
| int secondMask = ((DomainUsage.Internal)secondUsage).getMask(); |
| if (firstMask == secondMask) { |
| if (firstUsage != secondUsage) { |
| if (!firstUsage.isConstant()) { |
| replace((DomainUsage.Internal) firstUsage, secondUsage); |
| return secondUsage; |
| } |
| else if (!secondUsage.isConstant()) { |
| replace((DomainUsage.Internal) secondUsage, firstUsage); |
| return firstUsage; |
| } |
| } |
| return firstUsage; |
| } |
| else { |
| int intersectionMask = firstMask & secondMask; |
| DomainUsage usage = getRootAnalysis().getValidUsage(intersectionMask); |
| if (usage != null) { |
| if ((usage != firstUsage) && !firstUsage.isConstant()) { |
| replace((DomainUsage.Internal) firstUsage, usage); |
| } |
| if ((usage != secondUsage) && !secondUsage.isConstant()) { |
| replace((DomainUsage.Internal) secondUsage, usage); |
| } |
| return usage; |
| } |
| else { |
| usage = getRootAnalysis().createVariableUsage(intersectionMask); |
| if (!firstUsage.isConstant()) { |
| replace((DomainUsage.Internal) firstUsage, usage); |
| } |
| if (!secondUsage.isConstant()) { |
| replace((DomainUsage.Internal) secondUsage, usage); |
| } |
| return usage; |
| } |
| } |
| } |
| |
| protected void popSelfUsage(@Nullable DomainUsage savedUsage) { |
| selfUsage = savedUsage; |
| } |
| |
| protected DomainUsage pushSelfUsage(@NonNull DomainUsage usage) { |
| DomainUsage oldUsage = selfUsage; |
| int usageMask = ((DomainUsage.Internal)usage).getMask(); |
| DomainUsage constantUsage = getRootAnalysis().getValidUsage(usageMask); |
| if (constantUsage == null) { |
| usage = getRootAnalysis().createVariableUsage(usageMask); |
| } |
| selfUsage = usage; |
| return oldUsage; |
| } |
| |
| protected void replace(DomainUsage.@NonNull Internal oldUsage, @NonNull DomainUsage newUsage) { |
| Iterable<Element> elements = oldUsage.getElements(); |
| if (elements != null) { |
| for (@SuppressWarnings("null")@NonNull Element element : elements) { |
| setUsage(element, newUsage); |
| } |
| } |
| } |
| |
| protected void setBoundVariablesUsages(@NonNull Rule rule) { |
| DomainUsage primitiveUsage = getRootAnalysis().getPrimitiveUsage(); |
| for (Domain domain : rule.getDomain()) { |
| if (domain instanceof CoreDomain) { |
| DomainUsage usage = visit(domain.getTypedModel()); |
| for (Variable variable : ((CoreDomain)domain).getGuardPattern().getVariable()) { |
| if (variable != null) { |
| DomainUsage variableUsage = visit(variable.getType()); |
| if (variableUsage != primitiveUsage) { |
| variableUsage = usage; |
| } |
| assert variableUsage != null; |
| setUsage(variable, variableUsage); |
| } |
| } |
| } |
| } |
| if (rule instanceof Mapping) { |
| DomainUsage middleUsage = getRootAnalysis().getMiddleUsage(); |
| for (Variable variable : ((Mapping)rule).getGuardPattern().getVariable()) { |
| if (variable != null) { |
| DomainUsage variableUsage = visit(variable.getType()); |
| // if (variableUsage != primitiveUsage) { |
| if (!variableUsage.isInput() && !variableUsage.isOutput() && !variableUsage.isPrimitive()) { |
| variableUsage = middleUsage; |
| } |
| assert variableUsage != null; |
| setUsage(variable, variableUsage); |
| } |
| } |
| } |
| } |
| |
| protected void setUsage(@NonNull Element element, @NonNull DomainUsage newUsage) { |
| // if (newUsage.isNone()) { |
| // element.toString(); |
| // } |
| // if ("s".equals(element.toString())) { |
| // element.toString(); |
| // } |
| element2usage.put(element, newUsage); |
| ((DomainUsage.Internal)newUsage).addUsedBy(element); |
| // System.out.println(" setUsage " + getClass().getSimpleName() + "@" + Integer.toHexString(System.identityHashCode(this)) |
| // + " : " + element.eClass().getName() + "@" + Integer.toHexString(System.identityHashCode(element)) |
| // + " <= " + newUsage |
| // ); |
| } |
| |
| @Override |
| public String toString() { |
| Map<@NonNull String, org.eclipse.qvtd.pivot.qvtcore.analysis.DomainUsage> map = new HashMap<@NonNull String, org.eclipse.qvtd.pivot.qvtcore.analysis.DomainUsage>(element2usage.size()); |
| List<@NonNull String> keys = new ArrayList<@NonNull String>(element2usage.size()); |
| for (Map.Entry<@NonNull Element, org.eclipse.qvtd.pivot.qvtcore.analysis.DomainUsage> entry : element2usage.entrySet()) { |
| Element element = entry.getKey(); |
| String key = element.eClass().getName() + " : " + element; |
| map.put(key, entry.getValue()); |
| keys.add(key); |
| } |
| Collections.sort(keys); |
| StringBuilder s = new StringBuilder(); |
| for (@NonNull String key : keys) { |
| DomainUsage usage = map.get(key); |
| if (s.length() > 0) { |
| s.append("\n"); |
| } |
| s.append(key); |
| s.append(" => "); |
| s.append(usage); |
| } |
| return s.toString(); |
| } |
| |
| public @NonNull DomainUsage union(@NonNull DomainUsage firstUsage, @NonNull DomainUsage secondUsage) { |
| int firstMask = ((DomainUsage.Internal)firstUsage).getMask(); |
| int secondMask = ((DomainUsage.Internal)secondUsage).getMask(); |
| int unionMask = firstMask | secondMask; |
| if ((unionMask == firstMask) && firstUsage.isConstant()) { |
| return firstUsage; |
| } |
| else if ((unionMask == secondMask) && secondUsage.isConstant()) { |
| return secondUsage; |
| } |
| else if (firstUsage.isConstant() && secondUsage.isConstant()) { |
| return getRootAnalysis().getConstantUsage(unionMask); |
| } |
| else { |
| return getRootAnalysis().createVariableUsage(unionMask); |
| } |
| } |
| |
| @Override |
| public @NonNull DomainUsage visit(@Nullable Element element) { |
| if (element == null) { |
| return getRootAnalysis().getAnyUsage(); |
| } |
| DomainUsage usage = element2usage.get(element); |
| if (usage == null) { |
| // if ("s : StmcMM::StateMachine[1]".equals(element.toString())) { |
| // element.toString(); |
| // } |
| usage = element.accept(this); |
| // if (usage == null) { // FIXME debugging |
| // usage = element.accept(this); |
| // } |
| assert usage != null : "null usage for " + element.eClass().getName() + " " + element; |
| setUsage(element, usage); |
| } |
| return usage; |
| } |
| |
| @Override |
| public @NonNull DomainUsage visiting(@NonNull Visitable visitable) { |
| throw new UnsupportedOperationException("Unsupported " + visitable.eClass().getName() + " for " + getClass().getSimpleName()); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitBottomPattern(@NonNull BottomPattern object) { |
| for (Variable variable : object.getVariable()) { |
| visit(variable); |
| } |
| for (RealizedVariable variable : object.getRealizedVariable()) { |
| visit(variable); |
| } |
| for (Assignment assignment : object.getAssignment()) { |
| visit(assignment); |
| } |
| for (Predicate predicate : object.getPredicate()) { |
| visit(predicate); |
| } |
| return getDomainUsage(object); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitClass(org.eclipse.ocl.pivot.@NonNull Class object) { |
| DomainUsage usage = getRootAnalysis().class2usage.get(object); |
| if (usage != null) { |
| return usage; |
| } |
| else { |
| return getRootAnalysis().getPrimitiveUsage(); |
| } |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitCollectionItem(@NonNull CollectionItem object) { |
| return visit(object.getOwnedItem()); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitCollectionLiteralExp(@NonNull CollectionLiteralExp object) { |
| DomainUsage usage = visit(((CollectionType)object.getType()).getElementType()); |
| // DomainUsage usage = getRootAnalysis().getAnyUsage(); |
| for (@SuppressWarnings("null")@NonNull CollectionLiteralPart part : object.getOwnedParts()) { |
| usage = intersection(usage, visit(part)); |
| } |
| return usage; |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitCollectionRange(@NonNull CollectionRange object) { |
| DomainUsage firstUsage = visit(object.getOwnedFirst()); |
| DomainUsage lastUsage = visit(object.getOwnedLast()); |
| return intersection(firstUsage, lastUsage); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitCollectionType(@NonNull CollectionType object) { |
| return visit(object.getElementType()); |
| } |
| @Override |
| public @NonNull DomainUsage visitCoreDomain(@NonNull CoreDomain object) { |
| DomainUsage usage = visit(object.getTypedModel()); |
| setUsage(object, usage); |
| visit(object.getGuardPattern()); |
| visit(object.getBottomPattern()); |
| return usage; |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitExpressionInOCL(@NonNull ExpressionInOCL object) { |
| OCLExpression ownedBody = object.getOwnedBody(); |
| if ((ownedBody == null) && (object.getBody() != null)) { |
| try { |
| ownedBody = context.getMetamodelManager().parseSpecification(object).getOwnedBody(); // FIXME why is this necessary |
| } catch (ParserException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| } |
| Variable ownedContext = object.getOwnedContext(); |
| if ((ownedContext != null) && (selfUsage != null)) { |
| setUsage(ownedContext, selfUsage); |
| } |
| else { |
| visit(ownedContext); |
| } |
| for (Variable parameter : object.getOwnedParameters()) { |
| visit(parameter); |
| } |
| visit(object.getOwnedResult()); |
| return visit(ownedBody); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitFunction(@NonNull Function object) { |
| for (@SuppressWarnings("null")@NonNull Parameter parameter : object.getOwnedParameters()) { |
| visit(parameter); |
| } |
| OCLExpression queryExpression = object.getQueryExpression(); |
| if (queryExpression != null) { |
| return visit(queryExpression); |
| } |
| else { |
| return visit(object.getType()); |
| } |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitIfExp(@NonNull IfExp object) { |
| @SuppressWarnings("unused") DomainUsage conditionUsage = visit(object.getOwnedCondition()); |
| DomainUsage thenUsage = visit(object.getOwnedThen()); |
| DomainUsage elseUsage = visit(object.getOwnedElse()); |
| return intersection(thenUsage, elseUsage); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitGuardPattern(@NonNull GuardPattern object) { |
| DomainUsage domainUsage = getDomainUsage(object); |
| // for (Variable variable : object.getVariable()) { // In visitTransformation |
| // setUsage(variable, domainUsage); |
| // } |
| for (Predicate predicate : object.getPredicate()) { |
| visit(predicate); |
| } |
| return domainUsage; |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitIterateExp(@NonNull IterateExp object) { |
| DomainUsage sourceUsage = visit(object.getOwnedSource()); |
| for (Variable iterator : object.getOwnedIterators()) { |
| if (iterator != null) { |
| setUsage(iterator, sourceUsage); |
| } |
| } |
| visit(object.getOwnedResult()); |
| @SuppressWarnings("unused") DomainUsage bodyUsage = visit(object.getOwnedBody()); |
| TemplateParameterSubstitutionVisitor visitor = new TemplateParameterSubstitutionVisitor((@NonNull EnvironmentFactoryInternal) context, object.getOwnedSource().getType(), null); |
| object.accept(visitor); |
| Iteration iteration = object.getReferredIteration(); |
| for (EObject eObject = iteration; eObject != null; eObject = eObject.eContainer()) { |
| if (eObject instanceof TemplateableElement) { |
| TemplateSignature ownedSignature = ((TemplateableElement)eObject).getOwnedSignature(); |
| if (ownedSignature != null) { |
| for (TemplateParameter templateParameter : ownedSignature.getOwnedParameters()) { |
| if (templateParameter != null) { |
| Type templateParameterType = visitor.get(templateParameter); |
| DomainUsage templateParameterUsage = visit(templateParameterType); |
| setUsage(templateParameter, templateParameterUsage); |
| } |
| } |
| } |
| } |
| } |
| return visit(iteration.getType()); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitIteratorExp(@NonNull IteratorExp object) { |
| DomainUsage sourceUsage = visit(object.getOwnedSource()); |
| for (Variable iterator : object.getOwnedIterators()) { |
| if (iterator != null) { |
| setUsage(iterator, sourceUsage); |
| } |
| } |
| @SuppressWarnings("unused") DomainUsage bodyUsage = visit(object.getOwnedBody()); |
| TemplateParameterSubstitutionVisitor visitor = new TemplateParameterSubstitutionVisitor((@NonNull EnvironmentFactoryInternal) context, object.getOwnedSource().getType(), null); |
| object.accept(visitor); |
| Iteration iteration = object.getReferredIteration(); |
| for (EObject eObject = iteration; eObject != null; eObject = eObject.eContainer()) { |
| if (eObject instanceof TemplateableElement) { |
| TemplateSignature ownedSignature = ((TemplateableElement)eObject).getOwnedSignature(); |
| if (ownedSignature != null) { |
| for (TemplateParameter templateParameter : ownedSignature.getOwnedParameters()) { |
| if (templateParameter != null) { |
| Type templateParameterType = visitor.get(templateParameter); |
| DomainUsage templateParameterUsage = visit(templateParameterType); |
| setUsage(templateParameter, templateParameterUsage); |
| } |
| } |
| } |
| } |
| } |
| return visit(iteration.getType()); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitLetExp(@NonNull LetExp object) { |
| visit(object.getOwnedVariable()); |
| return visit(object.getOwnedIn()); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitLiteralExp(@NonNull LiteralExp object) { |
| return getRootAnalysis().getPrimitiveUsage(); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitMapLiteralExp(@NonNull MapLiteralExp object) { |
| DomainUsage usage = getRootAnalysis().getAnyUsage(); |
| for (@SuppressWarnings("null")@NonNull MapLiteralPart part : object.getOwnedParts()) { |
| usage = intersection(usage, visit(part)); |
| } |
| return usage; |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitMapLiteralPart(@NonNull MapLiteralPart object) { |
| DomainUsage keyUsage = visit(object.getOwnedKey()); |
| DomainUsage valueUsage = visit(object.getOwnedValue()); |
| return intersection(keyUsage, valueUsage); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitNavigationAssignment(@NonNull NavigationAssignment object) { |
| Property property = QVTcoreUtil.getTargetProperty(object); |
| // if ("middleRoot.name := hsvRoot.name".equals(object.toString())) { |
| // property = object.getTargetProperty(); |
| // } |
| return doNavigationAssignment(property, object); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitNullLiteralExp(@NonNull NullLiteralExp object) { |
| return getRootAnalysis().createVariableUsage(getRootAnalysis().getAnyMask()); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitOperation(@NonNull Operation object) { |
| // System.out.println(" " + getClass().getSimpleName() + "@" + Integer.toHexString(System.identityHashCode(this)) + " : " + object); |
| DomainUsage savedUsage = pushSelfUsage(visit(object.getOwningClass())); |
| try { |
| for (@SuppressWarnings("null")@NonNull Parameter parameter : object.getOwnedParameters()) { |
| visit(parameter); |
| } |
| LanguageExpression bodyExpression = object.getBodyExpression(); |
| if (bodyExpression == null) { |
| return visit(object.getType()); |
| } |
| MetamodelManager metamodelManager = context.getMetamodelManager(); |
| try { |
| ExpressionInOCL parseSpecification = metamodelManager.parseSpecification(bodyExpression); |
| return visit(parseSpecification); |
| } catch (ParserException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| return visit(object.getType()); |
| } |
| // ownedBody = parseSpecification.getOwnedBody(); // FIXME why is this necessary |
| // LanguageExpression bodyExpression = object.getBodyExpression(); |
| } |
| finally { |
| popSelfUsage(savedUsage); |
| } |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitOperationCallExp(@NonNull OperationCallExp object) { |
| DomainUsage sourceUsage = visit(object.getOwnedSource()); |
| DomainUsage savedUsage = pushSelfUsage(sourceUsage); |
| try { |
| Operation operation = ClassUtil.nonNullState(object.getReferredOperation()); |
| RootDomainUsageAnalysis rootAnalysis = getRootAnalysis(); |
| OperationId operationId = operation.getOperationId(); |
| // |
| // Special case: usage of oclContainer()/oclContents() is unchanged from the usage of the source. |
| // |
| if ((operationId == rootAnalysis.getOclContainerId()) |
| || (operationId == rootAnalysis.getOclContentsId())) { |
| return sourceUsage; |
| } |
| String operationName = object.getReferredOperation().getName(); |
| if ("allInstances".equals(operationName)) { // FIXME BUG 487257 Revise this |
| return getAllInstancesUsage(object, sourceUsage); |
| } |
| // |
| // Special case: left/right of "="/"<>" have same usage. Result is primitive. |
| // |
| // if ((operationId == getRootAnalysis().getOclAnyEqualsOperationId()) |
| // || (operationId == getRootAnalysis().getOclAnyNotEqualsOperationId())) { |
| if ("=".equals(operationName) // FIXME BUG 487252 rationalize the derived operationIds |
| || "<>".equals(operationName)) { |
| DomainUsage rightUsage = visit(object.getOwnedArguments().get(0)); |
| intersection(sourceUsage, rightUsage); |
| return getRootAnalysis().getPrimitiveUsage(); |
| } |
| /* if ("oclAsType".equals(operationName) && !sourceUsage.isPrimitive()) { // FIX ME fudge for Adolfo's suspect EObjects |
| TemplateParameter templateParameter = operation.getType().isTemplateParameter(); |
| if (templateParameter != null) { |
| List<Parameter> ownedParameters = operation.getOwnedParameters(); |
| int iMax = Math.min(ownedParameters.size(), object.getOwnedArguments().size()); |
| for (int i = 0; i < iMax; i++) { |
| Parameter parameter = ownedParameters.get(i); |
| if (parameter.isIsTypeof() && (parameter.getType() == templateParameter)) { |
| OCLExpression argument = object.getOwnedArguments().get(i); |
| DomainUsage argumentUsage = visit(argument); |
| intersection(sourceUsage, argumentUsage); |
| } |
| } |
| } |
| return sourceUsage; |
| } */ |
| TemplateParameter templateParameter = operation.getType().isTemplateParameter(); |
| if (templateParameter != null) { // Handle e.g oclAsType() |
| List<Parameter> ownedParameters = operation.getOwnedParameters(); |
| int iMax = Math.min(ownedParameters.size(), object.getOwnedArguments().size()); |
| for (int i = 0; i < iMax; i++) { |
| Parameter parameter = ownedParameters.get(i); |
| if (parameter.isIsTypeof() && (parameter.getType() == templateParameter)) { |
| OCLExpression argument = object.getOwnedArguments().get(i); |
| DomainUsage argumentUsage = visit(argument); |
| return argumentUsage; |
| } |
| } |
| } |
| DomainUsageAnalysis analysis = rootAnalysis.getAnalysis(operation); |
| Map<DomainUsage, DomainUsage> referred2specialized = new HashMap<DomainUsage, DomainUsage>(); |
| List<@NonNull Parameter> ownedParameters = ClassUtil.nullFree(operation.getOwnedParameters()); |
| int iMax = Math.min(ownedParameters.size(), object.getOwnedArguments().size()); |
| for (int i = 0; i < iMax; i++) { |
| Parameter parameter = ownedParameters.get(i); |
| OCLExpression argument = object.getOwnedArguments().get(i); |
| DomainUsage referredParameterUsage = analysis.getUsage(parameter); |
| DomainUsage specializedParameterUsage; |
| if (referredParameterUsage.isConstant()) { |
| specializedParameterUsage = referredParameterUsage; |
| } |
| else { |
| specializedParameterUsage = referred2specialized.get(referredParameterUsage); |
| if (specializedParameterUsage == null) { |
| // specializedParameterUsage = new DomainUsageVariable(getRootAnalysis(), ((DomainUsage.Internal)referredParameterUsage).getMask()); |
| specializedParameterUsage = ((DomainUsage.Internal)referredParameterUsage).cloneVariable(); |
| referred2specialized.put(referredParameterUsage, specializedParameterUsage); |
| } |
| } |
| DomainUsage argumentUsage = visit(argument); |
| intersection(argumentUsage, specializedParameterUsage); |
| } |
| DomainUsage operationUsage = analysis.basicGetUsage(operation); |
| if ((operationUsage != null) && !operationUsage.isConstant()) { |
| // operationUsage = new DomainUsageVariable(getRootAnalysis(), ((DomainUsage.Internal)operationUsage).getMask()); |
| operationUsage = ((DomainUsage.Internal)operationUsage).cloneVariable(); |
| } |
| DomainUsage operationCallUsage = visit(object.getType()); |
| return /*operationUsage != null ? intersection(operationUsage, operationCallUsage) :*/ operationCallUsage; |
| } |
| finally { |
| popSelfUsage(savedUsage); |
| } |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitOppositePropertyAssignment(@NonNull OppositePropertyAssignment object) { |
| return visitNavigationAssignment(object); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitOppositePropertyCallExp(@NonNull OppositePropertyCallExp object) { |
| Property property = ClassUtil.nonNullState(object.getReferredProperty()); |
| Property oppositeProperty = ClassUtil.nonNullState(property.getOpposite()); |
| return doNavigationCallExp(oppositeProperty, object); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitParameter(@NonNull Parameter object) { |
| // Operation operation = object.getOwningOperation(); |
| // Map<Element, DomainUsage> map = analyzeOperation(operation); |
| // return map.get(object); |
| DomainUsage usage = visit(object.getType()); |
| return getRootAnalysis().getValidOrVariableUsage(usage); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitPredicate(@NonNull Predicate object) { |
| return visit(object.getConditionExpression()); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitPrimitiveType(@NonNull PrimitiveType object) { |
| return getRootAnalysis().getPrimitiveUsage(); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitProperty(@NonNull Property property) { |
| DomainUsage annotatedUsage = getRootAnalysis().getAnnotatedUsage(property); |
| DomainUsage superUsage = super.visitProperty(property); |
| if (annotatedUsage != null) { |
| return intersection(annotatedUsage, superUsage); |
| } |
| else { |
| return superUsage; |
| } |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitPropertyAssignment(@NonNull PropertyAssignment object) { |
| return visitNavigationAssignment(object); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitPropertyCallExp(@NonNull PropertyCallExp object) { |
| Property property = ClassUtil.nonNullState(object.getReferredProperty()); |
| return doNavigationCallExp(property, object); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitRealizedVariable(@NonNull RealizedVariable object) { |
| return getDomainUsage(object); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitRule(@NonNull Rule object) { |
| for (Domain domain : object.getDomain()) { |
| visit(domain); |
| } |
| return getRootAnalysis().getNoneUsage(); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitSelfType(@NonNull SelfType object) { |
| return ClassUtil.nonNullState(selfUsage); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitShadowExp(@NonNull ShadowExp object) { |
| DomainUsage usage = visit(object.getType()); |
| for (@SuppressWarnings("null")@NonNull ShadowPart part : object.getOwnedParts()) { |
| /*usage = intersection(usage,*/ visit(part); //); |
| } |
| return usage; |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitShadowPart(@NonNull ShadowPart object) { |
| visit(object.getOwnedInit()); |
| return visit(object.getType()); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitTemplateParameter(@NonNull TemplateParameter object) { |
| RootDomainUsageAnalysis rootAnalysis = getRootAnalysis(); |
| int anyMask = rootAnalysis.getAnyMask(); |
| DomainUsage usage = rootAnalysis.getValidUsage(anyMask); |
| if (usage == null) { |
| usage = rootAnalysis.createVariableUsage(anyMask); |
| } |
| return usage; |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitTransformation(@NonNull Transformation object) { |
| RootDomainUsageAnalysis rootAnalysis = getRootAnalysis(); |
| if (rootAnalysis != this) { |
| return rootAnalysis.getNoneUsage(); |
| } |
| // for (TypedModel typedModel : object.getModelParameter()) { -- done in analyzeTransformation |
| // visit(typedModel); |
| // } |
| // System.out.println(" " + getClass().getSimpleName() + "@" + Integer.toHexString(System.identityHashCode(this)) + " : " + object); |
| Variable ownedContext = QVTbaseUtil.getContextVariable(getEnvironmentFactory().getStandardLibrary(), object); |
| setUsage(ownedContext, getRootAnalysis().getNoneUsage()); |
| // |
| // Ensure all operations are analyzed even if not used. |
| // |
| for (Operation operation : object.getOwnedOperations()) { |
| if (operation != null) { |
| getRootAnalysis().analyzeOperation(operation); |
| } |
| } |
| // |
| // Define all bound variables so that they back propgate to resolve domain usage variables. |
| // |
| for (Rule rule : object.getRule()) { |
| if (rule != null) { |
| setBoundVariablesUsages(rule); |
| } |
| } |
| // |
| // Analyze the rest of the tree. |
| // |
| for (Rule rule : object.getRule()) { |
| visit(rule); |
| } |
| return getRootAnalysis().getNoneUsage(); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitTupleLiteralExp(@NonNull TupleLiteralExp object) { |
| DomainUsage usage = getRootAnalysis().getAnyUsage(); |
| for (@SuppressWarnings("null")@NonNull TupleLiteralPart part : object.getOwnedParts()) { |
| usage = intersection(usage, visit(part)); // FIXME need HYBRID |
| } |
| return usage; |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitTupleLiteralPart(@NonNull TupleLiteralPart object) { |
| return visit(object.getType()); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitTupleType(@NonNull TupleType object) { |
| DomainUsage usage = getRootAnalysis().getAnyUsage(); |
| for (@SuppressWarnings("null")@NonNull Property part : object.getOwnedProperties()) { |
| usage = intersection(usage, visit(part.getType())); |
| } |
| return usage; |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitType(@NonNull Type object) { |
| return getRootAnalysis().getPrimitiveUsage(); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitTypeExp(@NonNull TypeExp object) { |
| DomainUsage usage = visit(object.getReferredType()); |
| return getRootAnalysis().getValidOrVariableUsage(usage); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitTypedElement(@NonNull TypedElement object) { |
| return visit(object.getType()); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitTypedModel(@NonNull TypedModel object) { |
| RootDomainUsageAnalysis rootAnalysis = getRootAnalysis(); |
| if (rootAnalysis != this) { |
| return ClassUtil.nonNullState(rootAnalysis.basicGetUsage(object)); |
| } |
| return ClassUtil.nonNullState(element2usage.get(object)); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitVariable(@NonNull Variable object) { |
| OCLExpression ownedInit = object.getOwnedInit(); |
| if (ownedInit != null) { |
| return visit(ownedInit); |
| } |
| Area area = QVTcoreUtil.getContainingArea(object); |
| if (area instanceof Domain) { |
| return visit(area); |
| } |
| else { |
| return visit(object.getType()); |
| } |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitVariableAssignment(@NonNull VariableAssignment object) { |
| DomainUsage valueUsage = visit(object.getValue()); |
| DomainUsage variableUsage = visit(object.getTargetVariable()); |
| return intersection(variableUsage, valueUsage); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitVariableDeclaration(@NonNull VariableDeclaration object) { |
| return visit(object.getType()); |
| } |
| |
| @Override |
| public @NonNull DomainUsage visitVariableExp(@NonNull VariableExp object) { |
| VariableDeclaration referredVariable = object.getReferredVariable(); |
| DomainUsage usage = visit(referredVariable); |
| assert usage != null : referredVariable + " usage not defined"; |
| return usage; |
| } |
| } |