| /******************************************************************************* |
| * Copyright (c) 2010, 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.ocl.xtext.base.as2cs; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.log4j.Logger; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EFactory; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.impl.BasicEObjectImpl; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.ocl.pivot.CollectionType; |
| import org.eclipse.ocl.pivot.CompletePackage; |
| import org.eclipse.ocl.pivot.Element; |
| import org.eclipse.ocl.pivot.MapType; |
| import org.eclipse.ocl.pivot.Model; |
| import org.eclipse.ocl.pivot.NamedElement; |
| import org.eclipse.ocl.pivot.Namespace; |
| import org.eclipse.ocl.pivot.Package; |
| import org.eclipse.ocl.pivot.PivotPackage; |
| import org.eclipse.ocl.pivot.Property; |
| import org.eclipse.ocl.pivot.TemplateSignature; |
| import org.eclipse.ocl.pivot.Type; |
| import org.eclipse.ocl.pivot.TypedElement; |
| import org.eclipse.ocl.pivot.VoidType; |
| import org.eclipse.ocl.pivot.internal.manager.Orphanage; |
| import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager; |
| import org.eclipse.ocl.pivot.internal.manager.PrecedenceManager; |
| import org.eclipse.ocl.pivot.internal.utilities.AbstractConversion; |
| import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal; |
| import org.eclipse.ocl.pivot.internal.utilities.PivotConstantsInternal; |
| import org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal; |
| import org.eclipse.ocl.pivot.util.Visitable; |
| import org.eclipse.ocl.pivot.utilities.ClassUtil; |
| import org.eclipse.ocl.pivot.utilities.NameUtil; |
| import org.eclipse.ocl.pivot.utilities.PivotConstants; |
| import org.eclipse.ocl.pivot.utilities.PivotUtil; |
| import org.eclipse.ocl.pivot.utilities.URIUtil; |
| import org.eclipse.ocl.pivot.values.Unlimited; |
| import org.eclipse.ocl.xtext.base.as2cs.AS2CS.Factory; |
| import org.eclipse.ocl.xtext.base.utilities.BaseCSResource; |
| import org.eclipse.ocl.xtext.basecs.AnnotationCS; |
| import org.eclipse.ocl.xtext.basecs.BaseCSFactory; |
| import org.eclipse.ocl.xtext.basecs.BaseCSPackage; |
| import org.eclipse.ocl.xtext.basecs.ClassCS; |
| import org.eclipse.ocl.xtext.basecs.ConstraintCS; |
| import org.eclipse.ocl.xtext.basecs.DetailCS; |
| import org.eclipse.ocl.xtext.basecs.ElementCS; |
| import org.eclipse.ocl.xtext.basecs.ImportCS; |
| import org.eclipse.ocl.xtext.basecs.ModelElementCS; |
| import org.eclipse.ocl.xtext.basecs.MultiplicityBoundsCS; |
| import org.eclipse.ocl.xtext.basecs.MultiplicityCS; |
| import org.eclipse.ocl.xtext.basecs.MultiplicityStringCS; |
| import org.eclipse.ocl.xtext.basecs.NamedElementCS; |
| import org.eclipse.ocl.xtext.basecs.PackageCS; |
| import org.eclipse.ocl.xtext.basecs.PathElementCS; |
| import org.eclipse.ocl.xtext.basecs.PathElementWithURICS; |
| import org.eclipse.ocl.xtext.basecs.PathNameCS; |
| import org.eclipse.ocl.xtext.basecs.RootCS; |
| import org.eclipse.ocl.xtext.basecs.StructuralFeatureCS; |
| import org.eclipse.ocl.xtext.basecs.TemplateBindingCS; |
| import org.eclipse.ocl.xtext.basecs.TemplateSignatureCS; |
| import org.eclipse.ocl.xtext.basecs.TypedElementCS; |
| import org.eclipse.ocl.xtext.basecs.TypedRefCS; |
| import org.eclipse.ocl.xtext.basecs.TypedTypeRefCS; |
| |
| public class AS2CSConversion extends AbstractConversion implements PivotConstantsInternal |
| { |
| private static final Logger logger = Logger.getLogger(AS2CSConversion.class); |
| |
| protected final @NonNull AS2CS converter; |
| protected final @NonNull BaseDeclarationVisitor defaultDeclarationVisitor; |
| protected final @NonNull BaseReferenceVisitor defaultExpressionVisitor; |
| protected final @NonNull BaseReferenceVisitor defaultReferenceVisitor; |
| |
| private org.eclipse.ocl.pivot.Class scope = null; |
| |
| private final @NonNull Map<@NonNull EClass, @NonNull BaseDeclarationVisitor> declarationVisitorMap = new HashMap<>(); |
| private final @NonNull Map<EClass, BaseReferenceVisitor> expressionVisitorMap = new HashMap<>(); |
| private final @NonNull Map<@NonNull EClass, @NonNull BaseReferenceVisitor> referenceVisitorMap = new HashMap<>(); |
| private Map<@NonNull Namespace, @NonNull List<@NonNull String>> importedNamespaces = null; |
| |
| /** |
| * The CS Resource currently being converted. |
| */ |
| private @Nullable BaseCSResource csResource = null;; |
| |
| public AS2CSConversion(@NonNull AS2CS converter) { |
| super(converter.getEnvironmentFactory()); |
| this.converter = converter; |
| this.defaultDeclarationVisitor = converter.createDefaultDeclarationVisitor(this); |
| this.defaultExpressionVisitor = converter.createDefaultExpressionVisitor(this); |
| this.defaultReferenceVisitor = converter.createDefaultReferenceVisitor(this); |
| } |
| |
| protected void addBooleanQualifier(@NonNull List<@NonNull String> qualifiers, @NonNull DetailCS csDetail, @NonNull String csString) { |
| EList<String> values = csDetail.getValues(); |
| if ((values.size() == 1) && Boolean.valueOf(values.get(0))) { |
| qualifiers.add(csString); |
| } |
| else { |
| qualifiers.add("!" + csString); |
| } |
| } |
| |
| public void createImports(@NonNull RootCS documentCS, @NonNull Map<@NonNull Namespace, @NonNull List<@NonNull String>> importedNamespaces) { |
| BaseCSResource csResource = (BaseCSResource) ClassUtil.nonNullState(documentCS.eResource()); |
| AliasAnalysis.dispose(csResource); // Force reanalysis |
| EnvironmentFactoryInternal environmentFactory = PivotUtilInternal.findEnvironmentFactory(csResource); |
| if (environmentFactory == null) { |
| throw new IllegalStateException("No EnvironmentFactory"); |
| } |
| PivotMetamodelManager metamodelManager = environmentFactory.getMetamodelManager(); |
| AliasAnalysis aliasAnalysis = null; |
| URI csURI = csResource.getURI(); |
| List<@NonNull ImportCS> imports = new ArrayList<>(); |
| List<@NonNull Namespace> sortedImportedNamespaces = new ArrayList<>(importedNamespaces.keySet()); |
| Collections.sort(sortedImportedNamespaces, NameUtil.NAMEABLE_COMPARATOR); |
| for (@NonNull Namespace importedNamespace : sortedImportedNamespaces) { |
| if (importedNamespace instanceof org.eclipse.ocl.pivot.Package){ |
| Package pivotPackage = metamodelManager.getCompletePackage((org.eclipse.ocl.pivot.Package)importedNamespace).getPrimaryPackage(); |
| // ModelElementCS csElement = createMap.get(importedPackage); |
| // if ((csElement != null) && (csElement.eResource() == xtextResource)) { |
| // continue; // Don't import defined packages |
| // } |
| if (metamodelManager.getLibraries().contains(pivotPackage)) { |
| continue; |
| } |
| } |
| List<@NonNull String> aliases = importedNamespaces.get(importedNamespace); |
| if ((aliases == null) || aliases.isEmpty()) { |
| if (aliasAnalysis == null) { |
| aliasAnalysis = AliasAnalysis.getAdapter(csResource, environmentFactory); |
| } |
| String alias = aliasAnalysis.getAlias(importedNamespace, null); |
| aliases = alias != null ? Collections.singletonList(alias) : Collections.emptyList(); |
| } |
| EObject eObject = importedNamespace.getESObject(); |
| String importURI = null; |
| if (eObject instanceof EPackage) { |
| EPackage ePackage = (EPackage)eObject; |
| Resource resource = ePackage.eResource(); |
| if (ClassUtil.isRegistered(resource)) { |
| importURI = ePackage.getNsURI(); |
| } |
| } |
| if (importURI == null) { |
| URI fullURI = EcoreUtil.getURI(eObject != null ? eObject : importedNamespace); |
| URI deresolvedURI = URIUtil.deresolve(fullURI, csURI, true, true, false); |
| importURI = deresolvedURI.toString(); |
| } |
| for (@NonNull String alias : aliases) { |
| ImportCS importCS = BaseCSFactory.eINSTANCE.createImportCS(); |
| importCS.setName(alias); |
| PathNameCS csPathName = BaseCSFactory.eINSTANCE.createPathNameCS(); |
| importCS.setOwnedPathName(csPathName); |
| List<PathElementCS> csPath = csPathName.getOwnedPathElements(); |
| PathElementWithURICS csSimpleRef = BaseCSFactory.eINSTANCE.createPathElementWithURICS(); |
| csPath.add(csSimpleRef); |
| csSimpleRef.setReferredElement(importedNamespace); |
| csSimpleRef.setUri(importURI); |
| importCS.setPivot(importedNamespace); |
| imports.add(importCS); |
| } |
| } |
| if (aliasAnalysis != null) { |
| aliasAnalysis.dispose(); |
| } |
| aliasAnalysis = AliasAnalysis.getAdapter(csResource, metamodelManager.getEnvironmentFactory()); |
| for (@NonNull ImportCS csImport : imports) { |
| Namespace namespace = csImport.getReferredNamespace(); |
| String alias = csImport.getName(); |
| if ((namespace != null) && (alias == null)) { |
| alias = aliasAnalysis.getAlias(namespace, null); |
| if (alias == null) { |
| String hint = null; |
| if (namespace instanceof org.eclipse.ocl.pivot.Package) { |
| hint = ((org.eclipse.ocl.pivot.Package)namespace).getNsPrefix(); |
| } |
| if (hint == null) { |
| String name = namespace.getName(); |
| if (name.length() > 0) { |
| hint = name.substring(0, 1).toLowerCase() + name.substring(1); |
| } |
| } |
| if (hint != null) { |
| alias = aliasAnalysis.getAlias(namespace, hint); |
| } |
| } |
| if (alias != null) { |
| csImport.setName(alias); |
| } |
| } |
| } |
| Collections.sort(imports, new Comparator<@NonNull ImportCS>() |
| { |
| @Override |
| public int compare(@NonNull ImportCS o1, @NonNull ImportCS o2) { |
| Namespace ns1 = o1.getReferredNamespace(); |
| Namespace ns2 = o2.getReferredNamespace(); |
| int d1 = PivotUtil.getContainmentDepth(ns1); |
| int d2 = PivotUtil.getContainmentDepth(ns2); |
| if (d1 != d2) { |
| return d1 - d2; |
| } |
| String n1 = o1.getName(); |
| String n2 = o2.getName(); |
| return n1.compareTo(n2); |
| } |
| }); |
| for (@NonNull ImportCS csImport : imports) { |
| String alias = csImport.getName(); |
| if (alias.length() == 0) { |
| csImport.setName(null); |
| } |
| } |
| documentCS.getOwnedImports().addAll(imports); |
| } |
| |
| public @NonNull MultiplicityCS createMultiplicityCS(int lower, int upper, boolean isNullFree) { |
| String stringValue = null; |
| if (lower == 0) { |
| if (upper == 1) { |
| stringValue = "?"; |
| } |
| else if (upper == -1) { |
| stringValue = "*"; |
| } |
| // else if (upper == -2) { |
| // stringValue = "0..?"; |
| // } |
| } |
| else if (lower == 1) { |
| if (upper == -1) { |
| stringValue = "+"; |
| } |
| } |
| MultiplicityCS csMultiplicity; |
| if (stringValue != null) { |
| MultiplicityStringCS csMultiplicityString = BaseCSFactory.eINSTANCE.createMultiplicityStringCS(); |
| csMultiplicityString.setStringBounds(stringValue); |
| csMultiplicity = csMultiplicityString; |
| } |
| else { |
| MultiplicityBoundsCS csMultiplicityBounds = BaseCSFactory.eINSTANCE.createMultiplicityBoundsCS(); |
| if (lower != 1) { |
| csMultiplicityBounds.setLowerBound(lower); |
| } |
| if (upper != lower) { |
| csMultiplicityBounds.setUpperBound(upper); |
| } |
| csMultiplicity = csMultiplicityBounds; |
| } |
| csMultiplicity.setIsNullFree(isNullFree); |
| return csMultiplicity; |
| } |
| |
| public @Nullable BaseCSResource getCSResource() { |
| return csResource; |
| } |
| |
| public @NonNull AS2CS getConverter() { |
| return converter; |
| } |
| |
| public @Nullable BaseDeclarationVisitor getDeclarationVisitor(@NonNull EClass eClass) { |
| BaseDeclarationVisitor declarationVisitor = declarationVisitorMap.get(eClass); |
| if ((declarationVisitor == null) && !declarationVisitorMap.containsKey(eClass)) { |
| Factory factory = converter.getFactory(eClass); |
| if (factory != null) { |
| declarationVisitor = factory.createDeclarationVisitor(this); |
| } |
| else { |
| declarationVisitor = defaultDeclarationVisitor; |
| } |
| declarationVisitorMap.put(eClass, declarationVisitor); |
| } |
| return declarationVisitor; |
| } |
| |
| public @Nullable BaseReferenceVisitor getExpressionVisitor(@NonNull EClass eClass, @Nullable Namespace scope) { |
| if (scope == null) { |
| BaseReferenceVisitor expressionVisitor = expressionVisitorMap.get(eClass); |
| if ((expressionVisitor == null) && !expressionVisitorMap.containsKey(eClass)) { |
| Factory factory = converter.getFactory(eClass); |
| if (factory != null) { |
| expressionVisitor = factory.createExpressionVisitor(this, null); |
| } |
| else { |
| expressionVisitor = defaultExpressionVisitor; |
| } |
| expressionVisitorMap.put(eClass, expressionVisitor); |
| } |
| return expressionVisitor; |
| } |
| else { |
| Factory factory = converter.getFactory(eClass); |
| if (factory != null) { |
| return factory.createExpressionVisitor(this, scope); |
| } |
| else { |
| return defaultExpressionVisitor; |
| } |
| } |
| } |
| |
| public @NonNull PrecedenceManager getPrecedenceManager() { |
| return metamodelManager.getPrecedenceManager(); |
| } |
| |
| public @Nullable BaseReferenceVisitor getReferenceVisitor(@NonNull EClass eClass, @Nullable Namespace scope) { |
| if (scope == null) { |
| BaseReferenceVisitor referenceVisitor = referenceVisitorMap.get(eClass); |
| if ((referenceVisitor == null) && !referenceVisitorMap.containsKey(eClass)) { |
| Factory factory = converter.getFactory(eClass); |
| if (factory != null) { |
| referenceVisitor = factory.createReferenceVisitor(this, null); |
| } |
| else { |
| referenceVisitor = defaultReferenceVisitor; |
| } |
| referenceVisitorMap.put(eClass, referenceVisitor); |
| } |
| return referenceVisitor; |
| } |
| else { |
| Factory factory = converter.getFactory(eClass); |
| if (factory != null) { |
| return factory.createReferenceVisitor(this, scope); |
| } |
| else { |
| return defaultReferenceVisitor; |
| } |
| } |
| } |
| |
| public org.eclipse.ocl.pivot.Class getScope() { |
| return scope; |
| } |
| |
| protected @NonNull List<@NonNull TemplateBindingCS> getTemplateBindings(ElementCS csElement) { |
| List<@NonNull TemplateBindingCS> csTemplateBindings; |
| // EObject container = csElement.eContainer(); |
| // if (container instanceof ElementCS) { |
| // csTemplateBindings = getTemplateBindings((ElementCS) container); |
| // } |
| // else { |
| csTemplateBindings = new ArrayList<>(); |
| // } |
| if (csElement instanceof TypedTypeRefCS) { |
| TypedTypeRefCS csTemplateableElement = (TypedTypeRefCS)csElement; |
| TemplateBindingCS csTemplateBinding = csTemplateableElement.getOwnedBinding(); |
| if (csTemplateBinding != null) { |
| csTemplateBindings.add(csTemplateBinding); |
| } |
| } |
| return csTemplateBindings; |
| } |
| |
| public void importNamespace(@NonNull Namespace importNamespace, @Nullable String alias) { |
| Namespace primaryNamespace = metamodelManager.getPrimaryElement(importNamespace); |
| List<@NonNull String> aliases = importedNamespaces.get(primaryNamespace); |
| if (aliases == null) { |
| aliases = new ArrayList<>(); |
| importedNamespaces.put(primaryNamespace, aliases); |
| } |
| if ((alias != null) && !aliases.contains(alias)) { |
| aliases.add(alias); |
| } |
| } |
| |
| protected <@NonNull T extends ClassCS> T refreshClassifier(@NonNull Class<T> csClass, /*@NonNull*/ EClass csEClass, org.eclipse.ocl.pivot.@NonNull Class object) { |
| T csElement = refreshNamedElement(csClass, csEClass, object); |
| List<@NonNull ConstraintCS> csInvariants = visitDeclarations(ConstraintCS.class, object.getOwnedInvariants(), null); |
| for (@NonNull ConstraintCS csInvariant : csInvariants) { |
| csInvariant.setStereotype(PivotConstants.INVARIANT_NAME); |
| } |
| refreshList(csElement.getOwnedConstraints(), csInvariants); |
| TemplateSignature ownedTemplateSignature = object.getOwnedSignature(); |
| if (ownedTemplateSignature != null) { |
| csElement.setOwnedSignature(visitDeclaration(TemplateSignatureCS.class, ownedTemplateSignature)); |
| } |
| if (object.eIsSet(PivotPackage.Literals.CLASS__INSTANCE_CLASS_NAME)) { |
| csElement.setInstanceClassName(object.getInstanceClassName()); |
| } |
| else { |
| csElement.eUnset(BaseCSPackage.Literals.CLASS_CS__INSTANCE_CLASS_NAME); |
| } |
| return csElement; |
| } |
| |
| public <@NonNull T extends ModelElementCS> T refreshElement(@NonNull Class<T> csClass, /*@NonNull*/ EClass csEClass, @NonNull Element object) { |
| assert csClass == csEClass.getInstanceClass(); |
| EFactory eFactoryInstance = csEClass.getEPackage().getEFactoryInstance(); |
| ModelElementCS csElement = (ModelElementCS) eFactoryInstance.create(csEClass); |
| if (!csClass.isAssignableFrom(csElement.getClass())) { |
| throw new ClassCastException(); |
| } |
| csElement.setPivot(object); |
| @SuppressWarnings("unchecked") |
| T castElement = (T) csElement; |
| return castElement; |
| } |
| |
| public <@NonNull T extends NamedElementCS> T refreshNamedElement(@NonNull Class<T> csClass, /*@NonNull */EClass csEClass, @NonNull NamedElement object) { |
| return refreshNamedElement(csClass, csEClass, object, "«null»"); |
| } |
| |
| public <@NonNull T extends NamedElementCS> T refreshNamedElement(@NonNull Class<T> csClass, /*@NonNull */EClass csEClass, @NonNull NamedElement object, @Nullable String replacementNameForNull) { |
| T csElement = refreshElement(csClass, csEClass, object); |
| String name = object.getName(); |
| if (name == null) { |
| name = replacementNameForNull; |
| } |
| csElement.setName(name); |
| refreshList(csElement.getOwnedAnnotations(), visitDeclarations(AnnotationCS.class, object.getOwnedAnnotations(), null)); |
| return csElement; |
| } |
| |
| /** |
| * Assign a sequence of one or more path elements to csPathName that identify element with respect |
| * to scope. |
| * <br> |
| * For example A::B::C::D::E with respect to A::B::C::X::Y is D::E. |
| * <br> |
| * Validation is performed to check that the shortened name resolves to the same |
| * element. |
| * <br> |
| * For example if there is also an A::B::C::X::D::E, the scope is shortened to A::B so |
| * that the result is C::D::E. |
| */ |
| public void refreshPathName(@NonNull PathNameCS csPathName, @NonNull Element element, @Nullable Namespace scope) {//, @Nullable Resource csResource) { |
| Namespace safeScope = scope; |
| Element primaryElement = metamodelManager.getPrimaryElement(element); |
| if ((safeScope != null) && (primaryElement instanceof Type)) { |
| String name = ((Type)primaryElement).getName(); |
| for (EObject eObject = safeScope; eObject != null; eObject = eObject.eContainer()) { |
| if (eObject instanceof Namespace) { |
| safeScope = (Namespace) eObject; |
| } |
| if (eObject instanceof org.eclipse.ocl.pivot.Package) { |
| CompletePackage completePackage = metamodelManager.getCompletePackage((org.eclipse.ocl.pivot.Package)eObject); |
| org.eclipse.ocl.pivot.Class memberType = completePackage.getMemberType(name); |
| if (memberType == primaryElement) { |
| if ((eObject != scope) && (eObject != PivotUtil.getContainingPackage(scope))) { |
| eObject = eObject.eContainer(); // If eObject is needed in path, optional scope is its container |
| } |
| if (eObject instanceof Namespace) { |
| safeScope = (Namespace) eObject; |
| } |
| break; |
| } |
| } |
| } |
| } |
| List<PathElementCS> csPath = csPathName.getOwnedPathElements(); |
| csPath.clear(); // FIXME re-use |
| PathElementCS csSimpleRef = BaseCSFactory.eINSTANCE.createPathElementCS(); |
| csPath.add(csSimpleRef); |
| csSimpleRef.setReferredElement(primaryElement); |
| BaseCSResource csResource2 = this.csResource; |
| if ((csResource2 == null) || (csResource2.isPathable(primaryElement) == null)) { |
| return; |
| } |
| for (EObject eContainer = primaryElement.eContainer(); eContainer instanceof Element; eContainer = eContainer.eContainer()) { |
| if (eContainer instanceof Model) { |
| return; // Skip root package |
| } |
| if ((eContainer instanceof org.eclipse.ocl.pivot.Package) && Orphanage.isTypeOrphanage((org.eclipse.ocl.pivot.Package)eContainer)) { |
| return; // Skip orphan package |
| } |
| if (eContainer instanceof TemplateSignature) { |
| continue; // Skip signature |
| } |
| for (EObject aScope = safeScope; aScope != null; aScope = aScope.eContainer()) { |
| if (metamodelManager.getPrimaryElement(aScope) == metamodelManager.getPrimaryElement(eContainer)) { // If element ancestor is scope or an ancestor |
| return; // no need for further qualification |
| } |
| } |
| csSimpleRef = BaseCSFactory.eINSTANCE.createPathElementCS(); |
| csPath.add(0, csSimpleRef); |
| csSimpleRef.setReferredElement((Element) eContainer); |
| } |
| } |
| |
| public void refreshQualifiers(List<String> qualifiers, String string, boolean polarity) { |
| for (String qualifier : qualifiers) { |
| if (qualifier.equals(string)) { |
| if (!polarity) { |
| qualifiers.remove(qualifier); |
| } |
| return; |
| } |
| } |
| if (polarity) { |
| qualifiers.add(string); |
| } |
| } |
| |
| public void refreshQualifiers(@NonNull List<@NonNull String> qualifiers, @NonNull String trueString, @NonNull String falseString, @Nullable Boolean polarity) { |
| boolean isFalse = false; |
| boolean isTrue = false; |
| for (String qualifier : qualifiers) { |
| if (qualifier.equals(trueString)) { |
| if (isTrue || (polarity != Boolean.TRUE)) { |
| qualifiers.remove(qualifier); |
| } |
| isTrue = true; |
| } |
| if (qualifier.equals(falseString)) { |
| if (isTrue || (polarity != Boolean.FALSE)) { |
| qualifiers.remove(qualifier); |
| } |
| isFalse = true; |
| } |
| } |
| if (polarity == Boolean.TRUE) { |
| if (!isTrue) { |
| qualifiers.add(trueString); |
| } |
| } |
| else if (polarity == Boolean.FALSE) { |
| if (!isFalse) { |
| qualifiers.add(falseString); |
| } |
| } |
| } |
| |
| // FIXME BUG 496148 this is biased to use of e.g. {ordered} for OCLinEcore |
| public <@NonNull T extends StructuralFeatureCS> T refreshStructuralFeature(@NonNull Class<T> csClass, /*@NonNull */EClass csEClass, @NonNull Property object) { |
| T csElement = refreshTypedElement(csClass, csEClass, object); |
| refreshQualifiers(csElement.getQualifiers(), "derived", object.isIsDerived()); |
| refreshQualifiers(csElement.getQualifiers(), "readonly", object.isIsReadOnly()); |
| refreshQualifiers(csElement.getQualifiers(), "static", object.isIsStatic()); |
| refreshQualifiers(csElement.getQualifiers(), "transient", object.isIsTransient()); |
| refreshQualifiers(csElement.getQualifiers(), "unsettable", object.isIsUnsettable()); |
| refreshQualifiers(csElement.getQualifiers(), "volatile", object.isIsVolatile()); |
| csElement.setDefault(object.getDefaultValueString()); |
| return csElement; |
| } |
| |
| // FIXME BUG 496148 this is biased to use of e.g. {ordered} for OCLinEcore |
| public <@NonNull T extends TypedElementCS> T refreshTypedElement(@NonNull Class<T> csClass, /*@NonNull */EClass csEClass, @NonNull TypedElement object) { |
| T csElement = refreshNamedElement(csClass, csEClass, object); |
| final Type type = object.getType(); |
| final Type elementType; |
| boolean isEMap = (type instanceof MapType) && (((MapType)type).getEntryClass() != null); |
| if (isEMap) { |
| elementType = ((MapType)type).getEntryClass(); |
| } |
| else if ((type instanceof CollectionType) && (((CollectionType)type).getUnspecializedElement() != standardLibrary.getCollectionType())) { |
| PivotUtil.debugWellContainedness(type); |
| elementType = ((CollectionType)type).getElementType(); |
| } |
| else if (type instanceof VoidType) { |
| elementType = null; |
| } |
| else { |
| elementType = type; |
| } |
| if (elementType != null) { |
| PivotUtil.debugWellContainedness(elementType); |
| TypedRefCS typeRef = visitReference(TypedRefCS.class, elementType, null); |
| csElement.setOwnedType(typeRef); |
| } |
| else { |
| csElement.setOwnedType(null); |
| } |
| TypedRefCS csTypeRef = csElement.getOwnedType(); |
| if (csTypeRef != null) { |
| boolean isNullFree ; |
| int lower; |
| int upper; |
| if (isEMap) { |
| isNullFree = true; |
| lower = object.isIsRequired() ? 1 : 0; |
| upper = -1; |
| List<@NonNull String> qualifiers = ClassUtil.nullFree(csElement.getQualifiers()); |
| // refreshQualifiers(qualifiers, "composes", object.isIsComposite()); |
| refreshQualifiers(qualifiers, "ordered", "!ordered", Boolean.TRUE); // sic; Ecore idiom |
| refreshQualifiers(qualifiers, "unique", "!unique", Boolean.TRUE); |
| } |
| else if ((type instanceof CollectionType) && (((CollectionType)type).getUnspecializedElement() != standardLibrary.getCollectionType())) { |
| CollectionType collectionType = (CollectionType)type; |
| isNullFree = collectionType.isIsNullFree(); |
| lower = collectionType.getLower().intValue(); |
| Number upper2 = collectionType.getUpper(); |
| upper = upper2 instanceof Unlimited ? -1 : upper2.intValue(); |
| List<@NonNull String> qualifiers = ClassUtil.nullFree(csElement.getQualifiers()); |
| refreshQualifiers(qualifiers, "ordered", "!ordered", collectionType.isOrdered() ? Boolean.TRUE : null); |
| refreshQualifiers(qualifiers, "unique", "!unique", collectionType.isUnique() ? null : Boolean.FALSE); |
| } |
| else { |
| isNullFree = false; |
| lower = object.isIsRequired() ? 1 : 0; |
| upper = 1; |
| } |
| MultiplicityCS csMultiplicity = createMultiplicityCS(lower, upper, isNullFree); |
| csTypeRef.setOwnedMultiplicity(csMultiplicity); |
| } |
| return csElement; |
| } |
| |
| public org.eclipse.ocl.pivot.Class setScope(org.eclipse.ocl.pivot.Class object) { |
| org.eclipse.ocl.pivot.Class savedScope = scope; |
| this.scope = object; |
| return savedScope; |
| } |
| |
| /** |
| * Sequence the update passes to make the pivot match the CS. |
| */ |
| public void update(@NonNull BaseCSResource csResource) { |
| this.csResource = csResource; |
| // Map<Resource, Map<Namespace, List<String>>> imports = new HashMap<Resource, Map<Namespace, List<String>>>(); |
| // |
| // Perform the pre-order traversal to create the CS for each declaration. A |
| // separate reference pass is not needed since references are to the pivot model. |
| // |
| importedNamespaces = new HashMap<>(); |
| Resource asResource = converter.getASResource(csResource); |
| if (asResource != null) { |
| List<@NonNull PackageCS> list = visitDeclarations(PackageCS.class, asResource.getContents(), null); |
| refreshList(csResource.getContents(), list); |
| if (importedNamespaces != null) { |
| defaultDeclarationVisitor.postProcess(csResource, importedNamespaces); |
| } |
| // imports.put(csResource, importedNamespaces); |
| } |
| } |
| |
| public <T extends ElementCS> @Nullable T visitDeclaration(@NonNull Class<T> csClass, @Nullable EObject eObject) { |
| if (eObject == null) { |
| return null; |
| } |
| @SuppressWarnings("null") @NonNull EClass eClass = eObject.eClass(); |
| BaseDeclarationVisitor declarationVisitor = getDeclarationVisitor(eClass); |
| if ((declarationVisitor == null) || !(eObject instanceof Visitable)) { |
| logger.warn("Unsupported declaration " + eClass.getName()); |
| return null; |
| } |
| ElementCS csElement = ((Visitable)eObject).accept(declarationVisitor); |
| @SuppressWarnings("unchecked") |
| T castElement = (T) csElement; |
| return castElement; |
| } |
| |
| public <T extends ElementCS, @Nullable V extends EObject> @Nullable List<@NonNull T> visitDeclarationAsList(@NonNull Class<T> csClass, V eObject) { |
| if (eObject == null) { |
| return null; |
| } |
| @Nullable T csElement = visitDeclaration(csClass, eObject); |
| if (csElement == null) { |
| return null; |
| } |
| return Collections.singletonList(csElement); |
| } |
| |
| public @NonNull <T extends ElementCS, V extends EObject> List<T> visitDeclarations(@NonNull Class<T> csClass, /*@NonNull*/ Iterable<V> eObjects, AS2CS.@Nullable Predicate<V> predicate) { |
| assert eObjects != null; |
| List<T> csElements = new ArrayList<>(); |
| for (V eObject : eObjects) { |
| if ((eObject != null) && ((predicate == null) || predicate.filter(eObject))) { |
| @Nullable T csElement = visitDeclaration(csClass, eObject); |
| if (csElement != null) { |
| csElements.add(csElement); |
| } |
| } |
| } |
| return csElements; |
| } |
| |
| public @Nullable <T extends ElementCS> T visitReference(@NonNull Class<T> csClass, @NonNull EObject eObject, @Nullable Namespace scope) { |
| @SuppressWarnings("null") @NonNull EClass eClass = eObject.eClass(); |
| BaseReferenceVisitor referenceVisitor = getReferenceVisitor(eClass, scope); |
| if ((referenceVisitor == null) || !(eObject instanceof Visitable)) { |
| logger.warn("Unsupported reference " + eObject.eClass().getName()); |
| return null; |
| } |
| if (eObject.eIsProxy()) { |
| logger.warn("Unresolved reference " + ((BasicEObjectImpl)eObject).eProxyURI()); |
| return null; |
| } |
| ElementCS csElement = ((Visitable)eObject).accept(referenceVisitor); |
| if (csElement == null) { |
| return null; |
| } |
| if (!csClass.isAssignableFrom(csElement.getClass())) { |
| logger.error("CS " + csElement.getClass().getName() + "' element is not a '" + csClass.getName() + "'"); //$NON-NLS-1$ |
| return null; |
| } |
| @SuppressWarnings("unchecked") |
| T castElement = (T) csElement; |
| return castElement; |
| } |
| |
| public @NonNull <T extends ElementCS, V extends EObject> List<T> visitReferences(@NonNull Class<T> csClass, /*@NonNull*/ Iterable<? extends V> eObjects, AS2CS.@Nullable Predicate<V> predicate) { |
| assert eObjects != null; |
| List<T> csElements = new ArrayList<>(); |
| for (V eObject : eObjects) { |
| if ((eObject != null) && ((predicate == null) || predicate.filter(eObject))) { |
| @Nullable T csElement = visitReference(csClass, eObject, null); |
| if (csElement != null) { |
| csElements.add(csElement); |
| } |
| } |
| } |
| return csElements; |
| } |
| } |