| /******************************************************************************* |
| * Copyright (c) 2013, 2022 CEA LIST 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(CEA LIST) - Initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ocl.examples.codegen.analyzer; |
| |
| import java.util.List; |
| |
| import org.eclipse.emf.ecore.EClassifier; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.ocl.examples.codegen.calling.OperationCallingConvention; |
| import org.eclipse.ocl.examples.codegen.calling.PropertyCallingConvention; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGAssertNonNullExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGBoxExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGBuiltInIterationCallExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGCachedOperation; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGCachedOperationCallExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGCallExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGCastExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGEcoreExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGElement; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGExecutorType; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGGuardExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGIfExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGIsEqual2Exp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGIsEqualExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGIterationCallExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGIterator; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGLibraryIterateCallExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGLibraryIterationCallExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGLibraryOperation; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGModelFactory; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGNavigationCallExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGOperation; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGOperationCallExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGParameter; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGProperty; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGShadowPart; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGTypeExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGTypeId; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGUnboxExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGValuedElement; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGVariable; |
| import org.eclipse.ocl.examples.codegen.cgmodel.CGVariableExp; |
| import org.eclipse.ocl.examples.codegen.cgmodel.util.AbstractExtendingCGModelVisitor; |
| import org.eclipse.ocl.examples.codegen.generator.CodeGenerator; |
| import org.eclipse.ocl.examples.codegen.generator.TypeDescriptor; |
| import org.eclipse.ocl.examples.codegen.java.types.BoxedDescriptor; |
| import org.eclipse.ocl.examples.codegen.java.types.EcoreDescriptor; |
| import org.eclipse.ocl.examples.codegen.java.types.UnboxedDescriptor; |
| import org.eclipse.ocl.examples.codegen.utilities.CGUtil; |
| import org.eclipse.ocl.pivot.CallExp; |
| import org.eclipse.ocl.pivot.Element; |
| import org.eclipse.ocl.pivot.Type; |
| import org.eclipse.ocl.pivot.TypedElement; |
| import org.eclipse.ocl.pivot.ids.ElementId; |
| import org.eclipse.ocl.pivot.library.LibraryIteration; |
| import org.eclipse.ocl.pivot.library.iterator.IterateIteration; |
| |
| /** |
| * A BoxingAnalyzer performs a bottom up tree-traversal inserting: |
| * <p>CGBoxExp or CGUnboxExp whereever a conversion from boxed to unboxed or vice-versa is required. |
| * <p>CGCastExp whereever the apparent type is not available (e.g. Parameters passed as Object). |
| * <p>CGGuardExp whereever a non-null value is required. |
| * <p> |
| * No attempt at optimisation is made, since this can be performed by Common SubExpression Elimination. |
| * <p> |
| * <h2>Simple (both boxed and unboxed)</h2> |
| * Boolean, String, null, EObject (except Types) |
| * <h2>Boxed/Unboxed</h2> |
| * IntegerValue/Number, RealValue/Number, TypeValue/EObject, InvalidValue/Exception, CollectionValue/List |
| * <h2>Boxed</h2> |
| * TupleValue |
| * <h2>Boxed Protocol</h2> |
| * Executor/Library Iteration/Operation/PropertyCall |
| * <h2>Unboxed Protocol</h2> |
| * Ecore Operation/PropertyCall |
| */ |
| public class BoxingAnalyzer extends AbstractExtendingCGModelVisitor<@Nullable Object, @NonNull CodeGenAnalyzer> |
| { |
| protected final @NonNull CodeGenerator codeGenerator; |
| |
| public BoxingAnalyzer(@NonNull CodeGenAnalyzer analyzer) { |
| super(analyzer); |
| codeGenerator = analyzer.getCodeGenerator(); |
| } |
| |
| public @NonNull CodeGenAnalyzer getAnalyzer() { |
| return context; |
| } |
| |
| public @NonNull CodeGenerator getCodeGenerator() { |
| return codeGenerator; |
| } |
| |
| /** |
| * Return true if cgCallExp uses a safe navigation operator. |
| */ |
| public boolean isSafe(@NonNull CGCallExp cgCallExp) { |
| Element asElement = cgCallExp.getAst(); |
| return (asElement instanceof CallExp) && ((CallExp)asElement).isIsSafe(); |
| } |
| |
| /** |
| * Insert a CGAssertNonNullExp around cgChild. |
| */ |
| public @Nullable CGValuedElement rewriteAsAssertNonNulled(@Nullable CGValuedElement cgChild) { |
| if ((cgChild == null) || cgChild.isNonNull() /*|| (cgParent instanceof CGGuardExp)*/) { |
| return cgChild; |
| } |
| CGAssertNonNullExp cgAssertExp = CGModelFactory.eINSTANCE.createCGAssertNonNullExp(); |
| CGUtil.wrap(cgAssertExp, cgChild); |
| return cgAssertExp; |
| } |
| |
| /** |
| * Insert a CGBoxExp around cgChild. |
| */ |
| public @Nullable CGValuedElement rewriteAsBoxed(@Nullable CGValuedElement cgChild) { |
| if ((cgChild == null) || cgChild.isBoxed()) { |
| return cgChild; |
| } |
| CGTypeId cgTypeId = cgChild.getTypeId(); |
| ElementId elementId = cgTypeId.getElementId(); |
| if (elementId != null) { |
| BoxedDescriptor boxedDescriptor = codeGenerator.getBoxedDescriptor(elementId); |
| if (cgChild.isEcore()) { |
| EClassifier eClassifier = cgChild.getEcoreClassifier(); |
| Class<?> instanceClass = eClassifier != null ? eClassifier.getInstanceClass() : null; |
| EcoreDescriptor ecoreDescriptor = boxedDescriptor.getEcoreDescriptor(codeGenerator, instanceClass); |
| if (boxedDescriptor == ecoreDescriptor) { |
| return cgChild; |
| } |
| } |
| else { |
| UnboxedDescriptor unboxedDescriptor = boxedDescriptor.getUnboxedDescriptor(codeGenerator); |
| if (unboxedDescriptor == boxedDescriptor) { |
| return cgChild; |
| } |
| } |
| } |
| CGBoxExp cgBoxExp = CGModelFactory.eINSTANCE.createCGBoxExp(); |
| // NameResolution unboxedNameResolution = codeGenerator.getNameResolution(cgChild); |
| // NameVariant boxedNameVariant = codeGenerator.getBOXED_NameVariant(); |
| // NameResolution boxedNameResolution = unboxedNameResolution.addNameVariant(boxedNameVariant); |
| // boxedNameResolution.addCGElement(cgBoxExp); |
| CGUtil.wrap(cgBoxExp, cgChild); |
| return cgBoxExp; |
| } |
| |
| /** |
| * Insert a CGEcoreExp around cgChild. |
| */ |
| public @Nullable CGValuedElement rewriteAsEcore(@Nullable CGValuedElement cgChild, /*@NonNull*/ EClassifier eClassifier) { |
| if ((cgChild == null) || cgChild.isEcore()) { |
| return cgChild; |
| } |
| CGTypeId cgTypeId = cgChild.getTypeId(); |
| ElementId elementId = cgTypeId.getElementId(); |
| if (elementId != null) { |
| BoxedDescriptor boxedDescriptor = codeGenerator.getBoxedDescriptor(elementId); |
| // EClassifier eClassifier = cgChild.getEcoreClassifier(); |
| Class<?> instanceClass = eClassifier != null ? eClassifier.getInstanceClass() : null; |
| EcoreDescriptor ecoreDescriptor = boxedDescriptor.getEcoreDescriptor(codeGenerator, instanceClass); |
| if (cgChild.isUnboxed()) { |
| UnboxedDescriptor unboxedDescriptor = boxedDescriptor.getUnboxedDescriptor(codeGenerator); |
| if (ecoreDescriptor == unboxedDescriptor) { |
| return cgChild; |
| } |
| } |
| else { |
| if (ecoreDescriptor == boxedDescriptor) { |
| return cgChild; |
| } |
| } |
| } |
| CGEcoreExp cgEcoreExp = CGModelFactory.eINSTANCE.createCGEcoreExp(); |
| cgEcoreExp.setEClassifier(eClassifier); |
| CGUtil.wrap(cgEcoreExp, cgChild); |
| return cgEcoreExp; |
| } |
| |
| /** |
| * Insert a CGGuardExp around cgChild. |
| */ |
| public @Nullable CGValuedElement rewriteAsGuarded(@Nullable CGValuedElement cgChild, boolean isSafe, @NonNull String message) { |
| if ((cgChild == null) || cgChild.isNonNull() /*|| (cgParent instanceof CGGuardExp)*/) { |
| return cgChild; |
| } |
| CGGuardExp cgGuardExp = CGModelFactory.eINSTANCE.createCGGuardExp(); |
| cgGuardExp.setMessage(message); |
| cgGuardExp.setSafe(isSafe); |
| // Guard is a prefix IF so new new variable name required; just a copyable resolution.. |
| // NameResolution unguardedNameResolution = codeGenerator.getNameResolution(cgChild); |
| // NameResolution guardedNameResolution = unguardedNameResolution.addNameVariant(codeGenerator.getGUARDED_NameVariant()); |
| // unguardedNameResolution.addCGElement(cgGuardExp); // XXX GUARD is a prefix throw - no new variable |
| CGUtil.wrap(cgGuardExp, cgChild); |
| return cgGuardExp; |
| } |
| |
| /** |
| * Insert a CGCastExp around cgChild. |
| */ |
| protected CGValuedElement rewriteAsCast(@Nullable CGValuedElement/*CGVariableExp*/ cgChild) { |
| if (cgChild == null) { |
| return cgChild; |
| } |
| TypeDescriptor typeDescriptor = codeGenerator.getTypeDescriptor(cgChild); |
| if (typeDescriptor.getJavaClass() == Object.class) { |
| return cgChild; |
| } |
| TypedElement pivot = (TypedElement) cgChild.getAst(); |
| Type asType = pivot.getType(); |
| CGCastExp cgCastExp = CGModelFactory.eINSTANCE.createCGCastExp(); |
| CGUtil.wrap(cgCastExp, cgChild); |
| cgCastExp.setAst(pivot); |
| if (asType != null) { |
| CGExecutorType cgExecutorType = context.createExecutorType(asType); |
| cgCastExp.setExecutorType(cgExecutorType); |
| } |
| cgCastExp.setTypeId(codeGenerator.getAnalyzer().getCGTypeId(pivot.getTypeId())); |
| return cgCastExp; |
| } |
| |
| /** |
| * Insert a CGUnboxExp around cgChild. |
| */ |
| public @Nullable CGValuedElement rewriteAsUnboxed(@Nullable CGValuedElement cgChild) { |
| if ((cgChild == null) || cgChild.isUnboxed()) { |
| return cgChild; |
| } |
| CGTypeId cgTypeId = cgChild.getTypeId(); |
| ElementId elementId = cgTypeId.getElementId(); |
| if (elementId != null) { |
| // boolean maybePrimitive = codeGenerator.maybePrimitive(cgChild); |
| // TypeDescriptor boxedTypeDescriptor = codeGenerator.getTypeDescriptor(elementId, true, maybePrimitive); |
| // TypeDescriptor unboxedTypeDescriptor = codeGenerator.getTypeDescriptor(elementId, false, maybePrimitive); |
| TypeDescriptor boxedDescriptor = codeGenerator.getBoxedDescriptor(elementId); |
| TypeDescriptor unboxedDescriptor = boxedDescriptor.getUnboxedDescriptor(codeGenerator); |
| if (cgChild.isEcore()) { |
| EClassifier eClassifier = cgChild.getEcoreClassifier(); |
| Class<?> instanceClass = eClassifier != null ? eClassifier.getInstanceClass() : null; |
| EcoreDescriptor ecoreDescriptor = boxedDescriptor.getEcoreDescriptor(codeGenerator, instanceClass); |
| if ((unboxedDescriptor == ecoreDescriptor) || (ecoreDescriptor instanceof UnboxedDescriptor)) { |
| return cgChild; |
| } |
| } |
| else { |
| if (unboxedDescriptor == boxedDescriptor) { |
| return cgChild; |
| } |
| } |
| } |
| CGUnboxExp cgUnboxExp = CGModelFactory.eINSTANCE.createCGUnboxExp(); |
| CGUtil.wrap(cgUnboxExp, cgChild); |
| return cgUnboxExp; |
| } |
| |
| @Override |
| @Nullable |
| public Object visiting(@NonNull CGElement visitable) { |
| throw new UnsupportedOperationException(getClass().getSimpleName() + ": " + visitable.getClass().getSimpleName()); |
| } |
| |
| @Override |
| public @Nullable Object visitCGBuiltInIterationCallExp(@NonNull CGBuiltInIterationCallExp cgElement) { |
| super.visitCGBuiltInIterationCallExp(cgElement); |
| rewriteAsBoxed(rewriteAsGuarded(cgElement.getSource(), isSafe(cgElement), "source for '" + cgElement.getAsIteration() + "'")); |
| CGValuedElement cgBody = cgElement.getBody(); |
| if (cgBody.isRequired()) { |
| rewriteAsBoxed(rewriteAsGuarded(cgBody, false, "body for '" + cgElement.getAsIteration() + "'")); |
| } |
| else { |
| rewriteAsBoxed(cgBody); |
| } |
| return null; |
| } |
| |
| @Override |
| public @Nullable Object visitCGCachedOperation(@NonNull CGCachedOperation cgCachedOperation) { |
| super.visitCGCachedOperation(cgCachedOperation); |
| rewriteAsBoxed(cgCachedOperation.getBody()); |
| return null; |
| } |
| |
| @Override |
| public @Nullable Object visitCGCachedOperationCallExp(@NonNull CGCachedOperationCallExp cgElement) { |
| super.visitCGCachedOperationCallExp(cgElement); |
| assert cgElement.getCgThis() == null; |
| List<CGValuedElement> cgArguments = cgElement.getArguments(); |
| int iMax = cgArguments.size(); |
| for (int i = 0; i < iMax; i++) { // Avoid CME from rewrite |
| CGValuedElement cgArgument = cgArguments.get(i); |
| if (i == 0) { |
| rewriteAsGuarded(cgArgument, isSafe(cgElement), "source for '" + cgElement.getAsOperation() + "'"); |
| } |
| rewriteAsBoxed(cgArgument); |
| } |
| return null; |
| } |
| |
| /* @Override |
| public @Nullable Object visitCGConstrainedProperty(@NonNull CGConstrainedProperty cgProperty) { |
| super.visitCGConstrainedProperty(cgProperty); |
| if (cgProperty.isRequired()) { |
| CGValuedElement body = cgProperty.getBody(); |
| if (body != null) { |
| rewriteAsGuarded(body, false, "body for '" + cgProperty.getAst() + "'"); |
| } |
| } |
| return null; |
| } */ |
| |
| /* @Override |
| public @Nullable Object visitCGEcoreOperation(@NonNull CGEcoreOperation cgElement) { |
| super.visitCGEcoreOperation(cgElement); |
| CGValuedElement body = cgElement.getBody(); |
| if (body != null) { |
| rewriteAsEcore(body, cgElement.getEOperation().getEType()); |
| } |
| return null; |
| } */ |
| |
| /* @Override |
| public @Nullable Object visitCGEcoreOppositePropertyCallExp(@NonNull CGEcoreOppositePropertyCallExp cgElement) { |
| super.visitCGEcoreOppositePropertyCallExp(cgElement); |
| rewriteAsEcore(cgElement.getSource(), cgElement.getEStructuralFeature().getEType()); |
| if (cgElement.getEStructuralFeature().isMany()) { |
| rewriteAsAssertNonNulled(cgElement); |
| } |
| return null; |
| } */ |
| |
| /* @Override |
| public @Nullable Object visitCGEcorePropertyCallExp(@NonNull CGEcorePropertyCallExp cgElement) { |
| super.visitCGEcorePropertyCallExp(cgElement); |
| rewriteAsEcore(cgElement.getSource(), cgElement.getEStructuralFeature().getEContainingClass()); |
| if (cgElement.getEStructuralFeature().isMany()) { |
| rewriteAsAssertNonNulled(cgElement); |
| } |
| return null; |
| } */ |
| |
| /* @Override |
| public @Nullable Object visitCGExecutorOppositePropertyCallExp(@NonNull CGExecutorOppositePropertyCallExp cgElement) { |
| super.visitCGExecutorOppositePropertyCallExp(cgElement); |
| rewriteAsUnboxed(cgElement.getSource()); |
| CGTypedElement cgParent = (CGTypedElement) cgElement.getParent(); |
| if (cgParent != null) { |
| rewriteAsBoxed(cgElement); |
| } |
| return null; |
| } */ |
| |
| /* @Override |
| public @Nullable Object visitCGExecutorPropertyCallExp(@NonNull CGExecutorPropertyCallExp cgElement) { |
| super.visitCGExecutorPropertyCallExp(cgElement); |
| rewriteAsUnboxed(cgElement.getSource()); |
| CGTypedElement cgParent = (CGTypedElement) cgElement.getParent(); |
| if (cgParent != null) { |
| rewriteAsBoxed(cgElement); |
| } |
| return null; |
| } */ |
| |
| @Override |
| public @Nullable Object visitCGElement(@NonNull CGElement cgElement) { |
| for (@NonNull CGElement cgChild : cgElement.getChildren()) { |
| cgChild.accept(this); |
| } |
| return null; |
| } |
| |
| /* @Override |
| public @Nullable Object visitCGForeignProperty(@NonNull CGForeignProperty cgForeignProperty) { |
| super.visitCGForeignProperty(cgForeignProperty); |
| rewriteAsBoxed(cgForeignProperty.getBody()); |
| if (cgForeignProperty.isRequired()) { |
| CGValuedElement body = cgForeignProperty.getBody(); |
| if (body != null) { |
| rewriteAsGuarded(body, false, "body for '" + cgForeignProperty.getAst() + "'"); |
| } |
| } |
| return null; |
| } */ |
| |
| /* @Override |
| public @Nullable Object visitCGForeignPropertyCallExp(@NonNull CGForeignPropertyCallExp cgElement) { |
| return null; |
| } */ |
| |
| @Override |
| public @Nullable Object visitCGIfExp(@NonNull CGIfExp cgElement) { |
| super.visitCGIfExp(cgElement); |
| rewriteAsGuarded(cgElement.getCondition(), false, "if condition"); |
| CGValuedElement thenExpression = cgElement.getThenExpression(); |
| CGValuedElement elseExpression = cgElement.getElseExpression(); |
| if ((thenExpression != null) && (elseExpression != null)) { |
| boolean thenIsBoxed = thenExpression.isBoxed(); |
| boolean elseIsBoxed = elseExpression.isBoxed(); |
| if (thenIsBoxed != elseIsBoxed) { |
| if (thenIsBoxed) { |
| rewriteAsBoxed(cgElement.getElseExpression()); |
| } |
| else { |
| rewriteAsBoxed(cgElement.getThenExpression()); |
| } |
| } |
| } |
| return null; |
| } |
| |
| // @Override |
| // public @Nullable Object visitCGIndexExp(@NonNull CGIndexExp cgIndexExp) { |
| // return null; |
| // } |
| |
| @Override |
| public @Nullable Object visitCGIsEqualExp(@NonNull CGIsEqualExp cgElement) { |
| super.visitCGIsEqualExp(cgElement); |
| CGValuedElement cgSource = cgElement.getSource(); |
| CGValuedElement cgArgument = cgElement.getArgument(); |
| boolean sourceIsBoxed = cgSource.isBoxed(); |
| boolean argumentIsBoxed = cgArgument.isBoxed(); |
| if (sourceIsBoxed != argumentIsBoxed) { // FIXME also needs-boxing |
| if (!sourceIsBoxed) { |
| rewriteAsBoxed(cgSource); |
| } |
| if (!argumentIsBoxed) { |
| rewriteAsBoxed(cgArgument); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public @Nullable Object visitCGIsEqual2Exp(@NonNull CGIsEqual2Exp cgElement) { |
| super.visitCGIsEqual2Exp(cgElement); |
| CGValuedElement cgSource = cgElement.getSource(); |
| CGValuedElement cgArgument = cgElement.getArgument(); |
| boolean sourceIsBoxed = cgSource.isBoxed(); |
| boolean argumentIsBoxed = cgArgument.isBoxed(); |
| if (sourceIsBoxed != argumentIsBoxed) { // FIXME also needs-boxing |
| if (!sourceIsBoxed) { |
| rewriteAsBoxed(cgSource); |
| } |
| if (!argumentIsBoxed) { |
| rewriteAsBoxed(cgArgument); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public @Nullable Object visitCGLibraryIterateCallExp(@NonNull CGLibraryIterateCallExp cgElement) { |
| super.visitCGLibraryIterateCallExp(cgElement); |
| rewriteAsGuarded(cgElement.getSource(), isSafe(cgElement), "source for '" + cgElement.getAsIteration() + "'"); |
| rewriteAsBoxed(cgElement.getSource()); |
| LibraryIteration libraryIteration = cgElement.getLibraryIteration(); |
| if (!(libraryIteration instanceof IterateIteration)) { |
| rewriteAsBoxed(cgElement.getBody()); |
| } |
| return null; |
| } |
| |
| @Override |
| public @Nullable Object visitCGLibraryIterationCallExp(@NonNull CGLibraryIterationCallExp cgElement) { |
| super.visitCGLibraryIterationCallExp(cgElement); |
| rewriteAsGuarded(cgElement.getSource(), isSafe(cgElement), "source for '" + cgElement.getAsIteration() + "'"); |
| rewriteAsBoxed(cgElement.getSource()); |
| LibraryIteration libraryIteration = cgElement.getLibraryIteration(); |
| if (!(libraryIteration instanceof IterateIteration)) { |
| rewriteAsBoxed(cgElement.getBody()); |
| } |
| return null; |
| } |
| |
| /* @Override |
| public @Nullable Object visitCGLibraryOperation(@NonNull CGLibraryOperation cgLibraryOperation) { |
| super.visitCGLibraryOperation(cgLibraryOperation); |
| rewriteAsBoxed(cgLibraryOperation.getBody()); |
| return null; |
| } */ |
| |
| /* @Override |
| public @Nullable Object visitCGNativeOperation(@NonNull CGNativeOperation cgNativeOperation) { |
| super.visitCGNativeOperation(cgNativeOperation); |
| rewriteAsUnboxed(cgNativeOperation.getBody()); |
| return null; |
| } */ |
| |
| /* @Override |
| public @Nullable Object visitCGNativeProperty(@NonNull CGNativeProperty cgProperty) { |
| super.visitCGNativeProperty(cgProperty); |
| if (cgProperty.isRequired()) { |
| CGValuedElement body = cgProperty.getBody(); |
| if (body != null) { |
| rewriteAsGuarded(body, false, "body for '" + cgProperty.getAst() + "'"); |
| } |
| } |
| return null; |
| } */ |
| |
| /* @Override |
| public @Nullable Object visitCGNativePropertyCallExp(@NonNull CGNativePropertyCallExp cgElement) { |
| return super.visitCGNativePropertyCallExp(cgElement); |
| } */ |
| |
| @Override |
| public @Nullable Object visitCGNavigationCallExp(@NonNull CGNavigationCallExp cgNavigationCallExp) { |
| super.visitCGNavigationCallExp(cgNavigationCallExp); |
| PropertyCallingConvention callingConvention = cgNavigationCallExp.getReferredProperty().getCallingConvention(); |
| callingConvention.rewriteWithBoxingAndGuards(this, cgNavigationCallExp); |
| return null; |
| } |
| |
| @Override |
| public @Nullable Object visitCGOperation(@NonNull CGOperation cgOperation) { |
| super.visitCGOperation(cgOperation); |
| // if ("isAttribute".cgOperation(cgElement.getName())) { // XXX |
| // System.out.println("visitCGOperation for " + cgElement.getAst().toString()); |
| // } |
| OperationCallingConvention callingConvention = cgOperation.getCallingConvention(); |
| callingConvention.rewriteWithBoxingAndGuards(this, cgOperation); |
| return null; |
| } |
| |
| @Override |
| public @Nullable Object visitCGOperationCallExp(@NonNull CGOperationCallExp cgElement) { |
| super.visitCGOperationCallExp(cgElement);; |
| CGOperation cgOperation = cgElement.getReferredOperation(); |
| if ("specializeIn".equals(cgOperation.getName())) { |
| getClass(); // XXX |
| } |
| OperationCallingConvention callingConvention = cgOperation.getCallingConvention(); |
| callingConvention.rewriteWithBoxingAndGuards(this, cgElement); |
| return null; |
| |
| /* boolean isBoxed = callingConvention.isBoxed(); |
| boolean isEcore = callingConvention.isEcore(); |
| boolean isUnboxed = callingConvention.isUnboxed(); |
| assert isBoxed == cgElement.isBoxed(); |
| assert isEcore == cgElement.isEcore(); |
| assert isUnboxed == cgElement.isUnboxed(); |
| Operation referredOperation = cgElement.getReferredOperation(); |
| CGValuedElement cgThis = cgElement.getCgThis(); |
| // assert (cgThis == null) || cgThis.isEcore() || cgThis.isUnboxed(); |
| EOperation eOperation = null; |
| // |
| // Guard / cast source |
| // XXX cgThis / cgSource |
| if (isBoxed) { |
| boolean isStatic = cgThis != null; // XXXcallingConvention.isStatic(cgOperation); |
| if (isStatic) { |
| assert cgThis != null; |
| boolean sourceMayBeNull = false; |
| if (referredOperation != null) { // XXX cgOperation is non-null |
| OperationId operationId = referredOperation.getOperationId(); |
| sourceMayBeNull = context.hasOclVoidOperation(operationId); // FIXME redundant since LibraryOperationCallingConvention.createParaeters invokes hasOclVoidOperation |
| if (!sourceMayBeNull && cgThis.isNull()) { |
| // CGInvalid cgInvalid = context.getInvalid("null value1 for source parameter"); |
| CGInvalid cgInvalid = context.getInvalid("''" + referredOperation.getOwningClass().getName() + "'' rather than ''OclVoid'' value required"); |
| CGConstantExp cgLiteralExp = context.createCGConstantExp(CGUtil.getAST(cgElement), cgInvalid); |
| CGUtil.replace(cgElement, cgLiteralExp); |
| return null; |
| } |
| } |
| rewriteAsBoxed(cgThis); |
| if ((referredOperation != null) && !sourceMayBeNull && !cgThis.isNonNull()) { |
| // rewriteAsGuarded(cgThis, false, "value3 for source parameter"); |
| rewriteAsGuarded(cgThis, false, "''" + referredOperation.getOwningClass().getName() + "'' rather than ''OclVoid'' value required"); |
| } |
| } |
| } |
| else { |
| if (isEcore) { |
| eOperation = ((CGEcoreOperationCallExp)cgElement).getEOperation(); |
| rewriteAsEcore(cgThis, eOperation.getEContainingClass()); |
| if (eOperation.isMany()) { |
| rewriteAsAssertNonNulled(cgElement); |
| } |
| } |
| else { |
| rewriteAsUnboxed(cgThis); |
| } |
| if (!referredOperation.isIsStatic()) { |
| rewriteAsGuarded(cgElement.getCgThis(), isSafe(cgElement), "source for '" + referredOperation + "'"); |
| } |
| // rewriteAsGuarded(cgSource, isSafe(cgElement), "source for '" + cgElement.getReferredOperation() + "'"); |
| } |
| // |
| // Null check boxed arguments |
| // |
| // List<Parameter> ownedParameters = null; |
| List<CGParameter> cgParameters = cgOperation.getParameters(); |
| if (referredOperation != null) { // Null if a Java method ?? could check Method parameters |
| // ownedParameters = referredOperation.getOwnedParameters(); |
| if (isBoxed) { |
| List<CGValuedElement> cgArguments = cgElement.getCgArguments(); |
| int iMax = cgArguments.size(); |
| assert iMax == cgParameters.size(); |
| if (!referredOperation.isIsValidating()) { |
| for (int i = 0; i < iMax; i++) { // Avoid CME from rewrite |
| CGValuedElement cgArgument = cgArguments.get(i); |
| // Parameter asParameter = ownedParameters.get(i); |
| CGParameter cgParameter = cgParameters.get(i); |
| // if (asParameter.isIsRequired()) { |
| if (cgParameter.isRequired()) { |
| if (cgArgument.isNull()) { |
| // CGInvalid cgInvalid = context.getInvalid("null value2 for " + asParameter.getName() + " parameter"); |
| StringBuilder s= new StringBuilder(); |
| s.append("''"); |
| if (cgParameter.isIsSelf()) { |
| s.append(referredOperation.getOwningClass().getName()); |
| } |
| else { |
| s.append(cgParameter.getTypeId()); |
| } |
| s.append("'' rather than ''OclVoid'' value required"); |
| CGInvalid cgInvalid = context.getInvalid(s.toString()); |
| CGConstantExp cgLiteralExp = context.createCGConstantExp(CGUtil.getAST(cgElement), cgInvalid); |
| CGUtil.replace(cgElement, cgLiteralExp); |
| return null; |
| } |
| } |
| } |
| } |
| } |
| } |
| // |
| // Guard / cast arguments |
| // |
| List<EParameter> eParameters = null; |
| if (eOperation != null) { |
| eParameters = eOperation.getEParameters(); |
| } |
| List<CGValuedElement> cgArguments = cgElement.getCgArguments(); |
| int iMax = cgArguments.size(); |
| for (int i = 0; i < iMax; i++) { // Avoid CME from rewrite |
| CGValuedElement cgArgument = cgArguments.get(i); |
| CGParameter cgParameter = cgParameters.get(i); |
| if (isBoxed) { |
| rewriteAsBoxed(cgArgument); |
| // if (cgParameters != null) { |
| // Parameter asParameter = ownedParameters.get(i); |
| if (cgParameter.isRequired() && !cgArgument.isNonNull()) { |
| // rewriteAsGuarded(cgArgument, false, "value4 for " + asParameter.getName() + " parameter"); |
| rewriteAsGuarded(cgArgument, false, "''" + cgParameter.getTypeId() + "'' rather than ''OclVoid'' value required"); |
| } |
| // } |
| } |
| else if ((eParameters != null) && !cgParameter.isIsSelf()) { |
| EParameter eParameter = eParameters.get(i-1); |
| rewriteAsEcore(cgArgument, eParameter.getEType()); |
| } |
| else { |
| rewriteAsUnboxed(cgArgument); |
| } |
| } |
| return null; */ |
| } |
| |
| @Override |
| public @Nullable Object visitCGProperty(@NonNull CGProperty cgProperty) { |
| super.visitCGProperty(cgProperty); |
| // if ("isAttribute".cgOperation(cgElement.getName())) { |
| // System.out.println("visitCGOperation for " + cgElement.getAst().toString()); |
| // } |
| PropertyCallingConvention callingConvention = cgProperty.getCallingConvention(); |
| callingConvention.rewriteWithBoxingAndGuards(this, cgProperty); |
| return null; |
| } |
| |
| @Override |
| public @Nullable Object visitCGShadowPart(@NonNull CGShadowPart cgShadowPart) { |
| rewriteAsUnboxed(cgShadowPart.getInit()); |
| return super.visitCGShadowPart(cgShadowPart); |
| } |
| |
| @Override |
| public @Nullable Object visitCGTypeExp(@NonNull CGTypeExp cgTypeExp) { |
| super.visitCGTypeExp(cgTypeExp); |
| TypeDescriptor typeDescriptor = codeGenerator.getTypeDescriptor(cgTypeExp); |
| if (typeDescriptor.getJavaClass() != org.eclipse.ocl.pivot.Class.class) { |
| rewriteAsCast(cgTypeExp); // XXX |
| } |
| return null; |
| } |
| |
| @Override |
| public @Nullable Object visitCGVariableExp(@NonNull CGVariableExp cgElement) { |
| super.visitCGVariableExp(cgElement); |
| CGVariable referredVariable = cgElement.getReferredVariable(); |
| if (referredVariable instanceof CGIterator) { |
| CGIterator cgIterator = (CGIterator)referredVariable; |
| EObject cgOperation = cgIterator.eContainer(); |
| if ((cgOperation instanceof CGIterationCallExp) && !(cgOperation instanceof CGBuiltInIterationCallExp)) { |
| rewriteAsCast(cgElement); |
| } |
| } |
| else if (referredVariable instanceof CGParameter) { |
| CGParameter cgParameter = (CGParameter)referredVariable; |
| if (cgParameter.getAst() != null) { // Skip synthetic parameters such as executor |
| EObject cgOperation = cgParameter.eContainer(); |
| if (cgOperation instanceof CGLibraryOperation) { |
| rewriteAsCast(cgElement); |
| } |
| } |
| } |
| return null; |
| } |
| } |