blob: aaf3519367d79a8b61c108ac1b8a7f42d0d65397 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2019 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - initial API and implementation
******************************************************************************/
package org.eclipse.qvtd.pivot.qvtimperative.evaluation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CollectionType;
import org.eclipse.ocl.pivot.CompleteClass;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.PrimitiveType;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.TypedElement;
import org.eclipse.ocl.pivot.ids.PropertyId;
import org.eclipse.ocl.pivot.internal.manager.MetamodelManagerInternal;
import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.EnvironmentFactory;
import org.eclipse.qvtd.pivot.qvtimperative.EntryPoint;
import org.eclipse.qvtd.pivot.qvtimperative.ImperativeTransformation;
import org.eclipse.qvtd.pivot.qvtimperative.Mapping;
import org.eclipse.qvtd.pivot.qvtimperative.SetStatement;
import org.eclipse.qvtd.pivot.qvtimperative.utilities.QVTimperativeUtil;
/**
* EntryPointsAnalysis accumulates salient characteristics of one or more entry points for a transformation
* prior to execution so that those characteristics can be exploited during execution.
* <p>
* Salient characteristics are:
* <br>
* - the source types of allInstances() calls
* - cache indexes of MiddleSetStatement/MiddlePropertyCallExp
*/
public class EntryPointsAnalysis
{
protected final @NonNull EnvironmentFactoryInternal environmentFactory;
protected final @NonNull ImperativeTransformation transformation;
/**
* Set of all types for which allInstances() is invoked.
*/
private final @NonNull Set<@NonNull CompleteClass> allInstancesCompleteClasses = new HashSet<>();
/**
* Map from navigable property to sequential index in any TypedModel.
*/
private final @NonNull Map<@NonNull Property, @NonNull Integer> property2cacheIndex = new HashMap<>();
/**
* Map from propertyAssignment to the cache index of an un-navigable lookup cache to be updated by the assignment.
*/
private final @NonNull Map<@NonNull SetStatement, @NonNull Integer> setStatement2cacheIndex = new HashMap<>();
/**
* Mappings that can be used as entry points.
*/
private final @NonNull Map<@NonNull EntryPoint, @NonNull EntryPointAnalysis> entryPoint2entryPointAnalysis = new HashMap<>();
/**
* Mapping and their entry points.
*/
private final @NonNull Map<@NonNull Mapping, @NonNull EntryPointAnalysis> mapping2entryPointAnalysis = new HashMap<>();
public EntryPointsAnalysis(@NonNull EnvironmentFactoryInternal environmentFactory, @NonNull ImperativeTransformation transformation) {
this.environmentFactory = environmentFactory;
this.transformation = transformation;
}
protected @NonNull Integer allocateCacheIndex(@Nullable OCLExpression sourceExpression, @NonNull Property navigableProperty) {
Integer cacheIndex = property2cacheIndex.get(navigableProperty);
if (cacheIndex == null) {
Integer size = property2cacheIndex.size();
property2cacheIndex.put(navigableProperty, size);
cacheIndex = size;
}
return cacheIndex;
}
protected void analyzeStatements(@NonNull Iterable<@NonNull SetStatement> setStatements) {
for (@NonNull SetStatement propertyAssignment : setStatements) {
Property navigableProperty = propertyAssignment.getTargetProperty();
if (navigableProperty != null) {
Integer cacheIndex = property2cacheIndex.get(navigableProperty);
if (cacheIndex != null) { // No need to set cacheIndex if it is never accessed by an OppositePropertyCallExp
setStatement2cacheIndex.put(propertyAssignment, cacheIndex);
}
}
}
}
public void analyzeTransformation() {
for (@NonNull EntryPoint iEntryPoint : QVTimperativeUtil.computeEntryPoints(transformation)) {
EntryPointAnalysis entryPointAnalysis = new EntryPointAnalysis(this, iEntryPoint);
entryPoint2entryPointAnalysis.put(iEntryPoint, entryPointAnalysis);
for (@NonNull Mapping mapping : QVTimperativeUtil.computeMappingClosure(iEntryPoint)) {
entryPointAnalysis.addMapping(mapping);
mapping2entryPointAnalysis.put(mapping, entryPointAnalysis);
}
}
assert !entryPoint2entryPointAnalysis.isEmpty();
for (@NonNull EntryPointAnalysis entryPointAnalysis : entryPoint2entryPointAnalysis.values()) {
entryPointAnalysis.analyze();
}
}
public void addAllInstancesClass(@NonNull TypedElement asExpression) {
Type asType = asExpression instanceof OCLExpression ? ((OCLExpression)asExpression).getTypeValue() : null;
if (asType == null) {
asType = asExpression.getType();
}
if (asType instanceof org.eclipse.ocl.pivot.Class) {
assert !(asType instanceof PrimitiveType);
assert !(asType instanceof CollectionType);
CompleteClass completeClass = environmentFactory.getCompleteModel().getCompleteClass(asType);
allInstancesCompleteClasses.add(completeClass);
}
}
public @NonNull Set<@NonNull CompleteClass> getAllInstancesCompleteClasses() {
return allInstancesCompleteClasses;
}
public @Nullable Integer getCacheIndex(@NonNull SetStatement setStatement) {
return setStatement2cacheIndex.get(setStatement);
}
public int getCacheIndexes() {
return property2cacheIndex.size();
}
public @NonNull Map<@NonNull Property, @NonNull Integer> getCaches() {
return property2cacheIndex;
}
// @Deprecated
// public @NonNull EntryPointAnalysis getDefaultEntryPointAnalysis() {
// return entryPoint2entryPointAnalysis.values().iterator().next();
// }
public @NonNull EnvironmentFactory getEnvironmentFactory() {
return environmentFactory;
}
public @NonNull Iterable<@NonNull EntryPointAnalysis> getEntryPointAnalyses() {
return entryPoint2entryPointAnalysis.values();
}
public @NonNull EntryPointAnalysis getEntryPointAnalysis(@NonNull EntryPoint entryPoint) {
return ClassUtil.nonNullState(entryPoint2entryPointAnalysis.get(entryPoint));
}
/**
* Return a Map from each instanceClasses to the subset of instanceClasses that are transitive superClasses of the particular instanceClass.
*/
public @NonNull Map<@NonNull CompleteClass, @Nullable List<@NonNull CompleteClass>> getInstancesCompleteClassAnalysis(@NonNull Iterable<@NonNull CompleteClass> instanceCompleteClasses) {
Map<@NonNull CompleteClass, @Nullable List<@NonNull CompleteClass>> instancesClassAnalysis = new HashMap<>();
for (@NonNull CompleteClass instanceCompleteClass : instanceCompleteClasses) {
instancesClassAnalysis.put(instanceCompleteClass, null);
}
for (@NonNull CompleteClass instanceCompleteClass : instancesClassAnalysis.keySet()) {
List<@NonNull CompleteClass> superInstanceCompleteClasses = new ArrayList<>();
superInstanceCompleteClasses.add(instanceCompleteClass);
for (@NonNull CompleteClass superCompleteClass : instanceCompleteClass.getProperSuperCompleteClasses()) {
if (instancesClassAnalysis.containsKey(superCompleteClass)) {
superInstanceCompleteClasses.add(superCompleteClass);
}
instancesClassAnalysis.put(instanceCompleteClass, superInstanceCompleteClasses);
}
}
return instancesClassAnalysis;
}
public @NonNull MetamodelManagerInternal getMetamodelManager() {
return environmentFactory.getMetamodelManager();
}
public @NonNull PropertyId @NonNull [] getPropertyIndex2propertyId() {
@NonNull PropertyId @NonNull [] propertyIndex2propertyId = new @NonNull PropertyId[property2cacheIndex.size()];
for (@NonNull Property property : property2cacheIndex.keySet()) {
Integer index = property2cacheIndex.get(property);
assert index != null;
propertyIndex2propertyId[index] = property.getPropertyId();
}
return propertyIndex2propertyId;
}
public @NonNull ImperativeTransformation getTransformation() {
return transformation;
}
@Override
public String toString() {
return entryPoint2entryPointAnalysis.keySet().toString();
}
}