blob: f7b56200ed9b8f5c817ca540f7668f08ad888091 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2016 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.ocl.pivot.internal.ecore;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EGenericType;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.ENamedElement;
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.ETypeParameter;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.util.EcoreSwitch;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.pivot.internal.utilities.AliasAdapter;
import org.eclipse.ocl.pivot.internal.utilities.PivotConstantsInternal;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
/**
* Ecore2Moniker supports generation of a hierarchically derived moniker for
* an EModelElement. A moniker provides a unique repeatable readable id.
*/
public class Ecore2Moniker extends EcoreSwitch<Object> implements PivotConstantsInternal
{
public static String toString(EModelElement eElement) {
Ecore2Moniker moniker = new Ecore2Moniker(false);
moniker.appendElement(eElement);
String string = moniker.toString();
return string;
}
public static String toString(EGenericType eElement) {
Ecore2Moniker moniker = new Ecore2Moniker(false);
moniker.appendType(eElement);
String string = moniker.toString();
return string;
}
/**
* Moiniker detail; false for minimal uniqueness (omit template bounds, template
* parameter declarations, parameter names), true to show everything.
* <p>
* Ecore models (unlike Pivot models) are mutable so the moniker is computed on
* demand and may change if a name on the hierarchical path changes.
*/
protected boolean fullSignature;
private StringBuilder s = new StringBuilder();
private List<ETypeParameter> emittedParameters = null;
protected Ecore2Moniker(boolean fullSignature) {
this.fullSignature = fullSignature;
}
protected void append(String string) {
s.append(string != null ? string : "null"); //$NON-NLS-1$
}
protected void appendBounds(List<? extends EGenericType> bounds) {
String prefix = "";
for (@NonNull EGenericType bound : ClassUtil.nullFree(bounds)) {
s.append(prefix);
prefix = "|"; // No example available
EGenericType eLowerBound = bound.getELowerBound();
if (eLowerBound != null) {
s.append(" >= "); // No example available
appendType(eLowerBound);
}
EGenericType eUpperBound = bound.getEUpperBound();
if (eUpperBound != null) {
s.append(" <= "); // No example available
appendType(eUpperBound);
}
EClassifier eClassifier = bound.getEClassifier();
if (eClassifier != null) {
s.append(" extends ");
appendType(bound);
}
else {
assert bound.getETypeArguments().isEmpty();
assert bound.getERawType() == null;
}
assert bound.getETypeParameter() == null;
}
}
protected void appendElement(EModelElement eElement) {
if (eElement != null) {
int classifierID = eElement.eClass().getClassifierID();
doSwitch(classifierID, eElement);
}
}
protected Object doInPackageSwitch1(EModelElement theEObject) {
int classifierID = theEObject.eClass().getClassifierID();
return doSwitch(classifierID, theEObject);
}
protected void appendName(ENamedElement eNamedElement) {
append(eNamedElement.getName());
}
protected void appendParameters(List<EParameter> parameters) {
s.append(PARAMETER_PREFIX);
String prefix = ""; //$NON-NLS-1$
for (EParameter eParameter : parameters) {
s.append(prefix);
appendType(eParameter.getEGenericType());
if (fullSignature) {
s.append(":");
s.append(eParameter.getName());
}
prefix = PARAMETER_SEPARATOR;
}
s.append(PARAMETER_SUFFIX);
}
protected void appendParent(EObject eElement, String parentSeparator) {
EObject parent = eElement != null ? eElement.eContainer() : null;
if (parent instanceof EModelElement) {
boolean wasFullSignature = fullSignature;
fullSignature = false;
appendElement((EModelElement) parent);
fullSignature = wasFullSignature;
}
else if (parent instanceof EGenericType) {
appendParent(parent, parentSeparator);
}
append(parentSeparator);
}
protected void appendType(EGenericType eGenericType) {
ETypeParameter eTypeParameter = eGenericType.getETypeParameter();
EClassifier eClassifier = eGenericType.getEClassifier();
if (eClassifier != null) {
appendParent(eClassifier, MONIKER_SCOPE_SEPARATOR);
append(eClassifier.getName());
appendTypeArguments(eGenericType.getETypeArguments(), eClassifier.getETypeParameters());
}
else if (eTypeParameter != null){
appendElement(eTypeParameter);
assert eGenericType.getETypeArguments().size() == 0;
}
else {
EStructuralFeature eContainingFeature = eGenericType.eContainingFeature();
if (s.length() == 0) {
appendParent(eGenericType, MONIKER_SCOPE_SEPARATOR);
s.append(WILDCARD_INDICATOR);
}
else if (eContainingFeature == EcorePackage.Literals.EGENERIC_TYPE__ETYPE_ARGUMENTS) {
EGenericType eContainer = (EGenericType)eGenericType.eContainer();
List<?> eTypeArguments = (List<?>) eContainer.eGet(eContainingFeature);
int index = eTypeArguments.indexOf(eGenericType);
EClassifier unspecializedClassifier = eContainer.getEClassifier();
appendElement(unspecializedClassifier);
s.append(BINDINGS_PREFIX);
List<ETypeParameter> eTypeParameters = unspecializedClassifier.getETypeParameters();
eTypeParameter = eTypeParameters.get(index);
appendName(eTypeParameter);
s.append(MONIKER_SCOPE_SEPARATOR);
s.append(WILDCARD_INDICATOR);
s.append(index);
}
else {
s.append(WILDCARD_INDICATOR);
}
assert eGenericType.getETypeArguments().size() == 0;
}
}
protected void appendTypeArguments(List<EGenericType> eTypeArguments, List<ETypeParameter> eTypeParameters) {
assert eTypeArguments.size() == eTypeParameters.size();
if (!eTypeArguments.isEmpty()) {
s.append(TEMPLATE_BINDING_PREFIX);
String prefix = ""; //$NON-NLS-1$
for (int i = 0; i < eTypeArguments.size(); i++) {
s.append(prefix);
appendType(eTypeArguments.get(i));
if (fullSignature) {
s.append(":");
appendTypeParameter(eTypeParameters.get(i));
}
prefix = TEMPLATE_BINDING_SEPARATOR;
}
s.append(TEMPLATE_BINDING_SUFFIX);
}
}
protected void appendTypeParameter(ETypeParameter eTypeParameter) {
if (emittedParameters == null) {
emittedParameters = new ArrayList<ETypeParameter>();
}
emittedParameters.add(eTypeParameter);
appendName(eTypeParameter);
if (fullSignature) {
appendBounds(eTypeParameter.getEBounds());
}
}
protected void appendTypeParameters(List<ETypeParameter> eTypeParameters) {
if (!eTypeParameters.isEmpty()) {
s.append(TEMPLATE_SIGNATURE_PREFIX);
String prefix = ""; //$NON-NLS-1$
for (ETypeParameter eTypeParameter : eTypeParameters) {
s.append(prefix);
appendTypeParameter(eTypeParameter);
prefix = TEMPLATE_SIGNATURE_SEPARATOR;
}
s.append(TEMPLATE_SIGNATURE_SUFFIX);
}
}
protected void appendTypes(List<EGenericType> eTypes) {
String prefix = ""; //$NON-NLS-1$
for (EGenericType eType : eTypes) {
s.append(prefix);
appendType(eType);
prefix = TEMPLATE_SIGNATURE_SEPARATOR;
}
}
@Override
public Object caseEAnnotation(EAnnotation eElement) {
appendParent(eElement, MONIKER_SCOPE_SEPARATOR);
s.append("'");
append(eElement.getSource());
s.append("'");
Object container = eElement.eContainer().eGet(eElement.eContainingFeature());
if (container instanceof List<?>) {
int index = 0;
for (Object object : (List<?>)container) {
if (object == eElement) {
break;
}
if (object instanceof EAnnotation) {
String source = ((EAnnotation)object).getSource();
if ((source != null) && source.equals(eElement.getSource())) {
index++;
}
}
}
if (index > 0) {
s.append(index);
}
}
return true;
}
@Override
public Object caseEClassifier(EClassifier eElement) {
caseENamedElement(eElement);
appendTypeParameters(eElement.getETypeParameters());
return true;
}
@Override
public Object caseENamedElement(ENamedElement eElement) {
appendParent(eElement, MONIKER_SCOPE_SEPARATOR);
appendName(eElement);
return true;
}
@Override
public Object caseEOperation(EOperation eElement) {
caseENamedElement(eElement);
appendTypeParameters(eElement.getETypeParameters());
appendParameters(eElement.getEParameters());
if (fullSignature) {
List<EGenericType> eGenericExceptions = eElement.getEGenericExceptions();
if (eGenericExceptions.size() > 0) {
append(" throws ");
appendTypes(eGenericExceptions);
}
}
return true;
}
@Override
public Object caseEPackage(EPackage eElement) {
String alias = AliasAdapter.getAlias(eElement);
if (alias != null) {
append(alias);
return true;
}
return caseENamedElement(eElement);
}
@Override
public Object caseETypeParameter(ETypeParameter eElement) {
if (!hasEmitted(eElement)) {
if (toString().length() < MONIKER_OVERFLOW_LIMIT) {
appendParent(eElement, TEMPLATE_PARAMETER_PREFIX);
}
else {
append(OVERFLOW_MARKER);
}
}
appendName(eElement);
return true;
}
protected boolean hasEmitted(ETypeParameter eTypeParameter) {
return (emittedParameters != null) && emittedParameters.contains(eTypeParameter);
}
@Override
public String toString() {
return s.toString();
}
}