/******************************************************************************* * Copyright (c) 2013, 2015 CEA LIST 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(CEA LIST) - Initial API and implementation *******************************************************************************/ package org.eclipse.ocl.examples.codegen.java; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EOperation; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.examples.codegen.analyzer.BoxingAnalyzer; import org.eclipse.ocl.examples.codegen.analyzer.DependencyVisitor; import org.eclipse.ocl.examples.codegen.analyzer.FieldingAnalyzer; import org.eclipse.ocl.examples.codegen.analyzer.NameManager; import org.eclipse.ocl.examples.codegen.analyzer.ReferencesVisitor; import org.eclipse.ocl.examples.codegen.asm5.ASM5JavaAnnotationReader; import org.eclipse.ocl.examples.codegen.cgmodel.CGPackage; import org.eclipse.ocl.examples.codegen.cgmodel.CGTypeId; import org.eclipse.ocl.examples.codegen.cgmodel.CGValuedElement; import org.eclipse.ocl.examples.codegen.cse.CommonSubexpressionEliminator; import org.eclipse.ocl.examples.codegen.cse.GlobalPlace; import org.eclipse.ocl.examples.codegen.generator.AbstractCodeGenerator; import org.eclipse.ocl.examples.codegen.generator.AbstractGenModelHelper; import org.eclipse.ocl.examples.codegen.generator.GenModelHelper; import org.eclipse.ocl.examples.codegen.generator.TypeDescriptor; import org.eclipse.ocl.examples.codegen.java.iteration.AnyIteration2Java; import org.eclipse.ocl.examples.codegen.java.iteration.CollectIteration2Java; import org.eclipse.ocl.examples.codegen.java.iteration.CollectNestedIteration2Java; import org.eclipse.ocl.examples.codegen.java.iteration.ExistsIteration2Java; import org.eclipse.ocl.examples.codegen.java.iteration.ForAllIteration2Java; import org.eclipse.ocl.examples.codegen.java.iteration.IsUniqueIteration2Java; import org.eclipse.ocl.examples.codegen.java.iteration.IterateIteration2Java; import org.eclipse.ocl.examples.codegen.java.iteration.OneIteration2Java; import org.eclipse.ocl.examples.codegen.java.iteration.RejectIteration2Java; import org.eclipse.ocl.examples.codegen.java.iteration.SelectIteration2Java; 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.Id2BoxedDescriptorVisitor; import org.eclipse.ocl.examples.codegen.java.types.UnboxedDescriptor; import org.eclipse.ocl.examples.codegen.utilities.AbstractCGModelResourceFactory; import org.eclipse.ocl.examples.codegen.utilities.CGModelResource; import org.eclipse.ocl.examples.codegen.utilities.CGModelResourceFactory; import org.eclipse.ocl.pivot.Iteration; import org.eclipse.ocl.pivot.Operation; import org.eclipse.ocl.pivot.OperationCallExp; import org.eclipse.ocl.pivot.Property; import org.eclipse.ocl.pivot.ids.ElementId; import org.eclipse.ocl.pivot.internal.utilities.EnvironmentFactoryInternal; import org.eclipse.ocl.pivot.library.LibraryIteration; import org.eclipse.ocl.pivot.library.iterator.AnyIteration; import org.eclipse.ocl.pivot.library.iterator.CollectIteration; import org.eclipse.ocl.pivot.library.iterator.CollectNestedIteration; import org.eclipse.ocl.pivot.library.iterator.ExistsIteration; import org.eclipse.ocl.pivot.library.iterator.ForAllIteration; import org.eclipse.ocl.pivot.library.iterator.IsUniqueIteration; import org.eclipse.ocl.pivot.library.iterator.IterateIteration; import org.eclipse.ocl.pivot.library.iterator.OneIteration; import org.eclipse.ocl.pivot.library.iterator.RejectIteration; import org.eclipse.ocl.pivot.library.iterator.SelectIteration; import org.eclipse.ocl.pivot.utilities.ClassUtil; /** * OCL2JavaClass supports generation of the content of a JavaClassFile to * provide the polymorphic implementation of an ExpressionInOCL. */ public abstract class JavaCodeGenerator extends AbstractCodeGenerator { public static Map<Class<?>, Class<?>> javaPrimitiveClasses = new HashMap<Class<?>, Class<?>>(); public static Map<String, Class<?>> javaPrimitiveNames = new HashMap<String, Class<?>>(); { initPrimitive(boolean.class, Boolean.class); initPrimitive(byte.class, Byte.class); initPrimitive(char.class, Character.class); initPrimitive(double.class, Double.class); initPrimitive(float.class, Float.class); initPrimitive(int.class, Integer.class); initPrimitive(long.class, Long.class); initPrimitive(short.class, Short.class); } private static final @NonNull AbstractCGModelResourceFactory CG_RESOURCE_FACTORY = new AbstractCGModelResourceFactory(); /** * The known classes that templates may use in unqualified form. The list is * here in a Java form to reduce the impact of refactoring templates. */ public static final @NonNull Class<?>[] knownClasses = { java.lang.Class.class, java.lang.Object.class, java.lang.Package.class, java.util.Iterator.class, org.eclipse.ocl.pivot.internal.library.ecore.EcoreExecutorEnumeration.class, org.eclipse.ocl.pivot.internal.library.ecore.EcoreExecutorEnumerationLiteral.class, org.eclipse.ocl.pivot.internal.library.ecore.EcoreExecutorInvalidType.class, org.eclipse.ocl.pivot.internal.library.ecore.EcoreExecutorManager.class, org.eclipse.ocl.pivot.internal.library.ecore.EcoreExecutorPackage.class, org.eclipse.ocl.pivot.internal.library.ecore.EcoreExecutorProperty.class, org.eclipse.ocl.pivot.internal.library.ecore.EcoreExecutorType.class, org.eclipse.ocl.pivot.internal.library.ecore.EcoreExecutorVoidType.class, org.eclipse.ocl.pivot.internal.library.executor.ExecutorDoubleIterationManager.class, org.eclipse.ocl.pivot.internal.library.executor.ExecutorFragment.class, org.eclipse.ocl.pivot.internal.library.executor.ExecutorLambdaType.class, org.eclipse.ocl.pivot.internal.library.executor.ExecutorOperation.class, org.eclipse.ocl.pivot.internal.library.executor.ExecutorProperty.class, org.eclipse.ocl.pivot.internal.library.executor.ExecutorPropertyWithImplementation.class, org.eclipse.ocl.pivot.internal.library.executor.ExecutorSingleIterationManager.class, org.eclipse.ocl.pivot.internal.library.executor.ExecutorSpecializedType.class, org.eclipse.ocl.pivot.internal.library.executor.ExecutorStandardLibrary.class, org.eclipse.ocl.pivot.internal.library.executor.ExecutorType.class, org.eclipse.ocl.pivot.internal.library.executor.ExecutorTypeParameter.class, org.eclipse.ocl.pivot.CollectionType.class, org.eclipse.ocl.pivot.Element.class, org.eclipse.ocl.pivot.ParameterTypes.class, org.eclipse.ocl.pivot.PivotPackage.class, org.eclipse.ocl.pivot.Property.class, org.eclipse.ocl.pivot.StandardLibrary.class, org.eclipse.ocl.pivot.TupleType.class, org.eclipse.ocl.pivot.Type.class, org.eclipse.ocl.pivot.TypedElement.class, org.eclipse.ocl.pivot.TemplateParameters.class, org.eclipse.ocl.pivot.evaluation.Executor.class, org.eclipse.ocl.pivot.ids.ClassId.class, org.eclipse.ocl.pivot.ids.CollectionTypeId.class, org.eclipse.ocl.pivot.ids.DataTypeId.class, org.eclipse.ocl.pivot.ids.EnumerationId.class, org.eclipse.ocl.pivot.ids.IdManager.class, org.eclipse.ocl.pivot.ids.PackageId.class, org.eclipse.ocl.pivot.ids.PrimitiveTypeId.class, org.eclipse.ocl.pivot.ids.TemplateParameterId.class, org.eclipse.ocl.pivot.ids.TuplePartId.class, org.eclipse.ocl.pivot.ids.TupleTypeId.class, org.eclipse.ocl.pivot.ids.TypeId.class, org.eclipse.ocl.pivot.library.AbstractBinaryOperation.class, org.eclipse.ocl.pivot.library.AbstractProperty.class, org.eclipse.ocl.pivot.library.AbstractTernaryOperation.class, org.eclipse.ocl.pivot.library.AbstractUnaryOperation.class, org.eclipse.ocl.pivot.library.LibraryBinaryOperation.class, org.eclipse.ocl.pivot.library.LibraryIteration.class, org.eclipse.ocl.pivot.library.LibraryProperty.class, org.eclipse.ocl.pivot.library.LibraryTernaryOperation.class, org.eclipse.ocl.pivot.library.LibraryUnaryOperation.class, org.eclipse.ocl.pivot.messages.PivotMessages.class, org.eclipse.ocl.pivot.values.BagValue.class, org.eclipse.ocl.pivot.values.CollectionValue.class, org.eclipse.ocl.pivot.values.IntegerRange.class, org.eclipse.ocl.pivot.values.IntegerValue.class, org.eclipse.ocl.pivot.values.InvalidValue.class, org.eclipse.ocl.pivot.values.OrderedSetValue.class, org.eclipse.ocl.pivot.values.RealValue.class, org.eclipse.ocl.pivot.values.SequenceValue.class, org.eclipse.ocl.pivot.values.SetValue.class, org.eclipse.ocl.pivot.values.TupleValue.class, org.eclipse.ocl.pivot.values.UnlimitedValue.class, org.eclipse.ocl.pivot.values.Value.class, org.eclipse.ocl.pivot.values.InvalidValueException.class, org.eclipse.ocl.pivot.utilities.ClassUtil.class, org.eclipse.ocl.pivot.internal.utilities.PivotUtilInternal.class, org.eclipse.ocl.pivot.utilities.ValueUtil.class, org.eclipse.osgi.util.NLS.class }; public static void initPrimitive(Class<?> class1, Class<?> class2) { javaPrimitiveClasses.put(class1, class2); javaPrimitiveNames.put(class1.getName(), class2); } private /*@LazyNonNull*/ Id2EClassVisitor id2EClassVisitor = null; // protected final @NonNull Id2JavaInterfaceVisitor id2JavaInterfaceVisitor; private /*@LazyNonNull*/ Id2BoxedDescriptorVisitor id2BoxedDescriptorVisitor = null; private /*@LazyNonNull*/ GlobalPlace globalPlace = null; private @NonNull Map<ElementId, BoxedDescriptor> boxedDescriptors = new HashMap<ElementId, BoxedDescriptor>(); private /*@LazyNonNull*/ ASM5JavaAnnotationReader annotationReader = null; public JavaCodeGenerator(@NonNull EnvironmentFactoryInternal environmentFactory) { super(environmentFactory); } @Override public @NonNull BoxingAnalyzer createBoxingAnalyzer() { return new BoxingAnalyzer(getAnalyzer()); } @Override public @NonNull CommonSubexpressionEliminator createCommonSubexpressionEliminator() { return new CommonSubexpressionEliminator(this); } public @NonNull CG2JavaPreVisitor createCG2JavaPreVisitor() { return new CG2JavaPreVisitor(getGlobalContext()); } @Override public @NonNull DependencyVisitor createDependencyVisitor() { return new JavaDependencyVisitor(getAnalyzer(), getGlobalContext(), getGlobalPlace()); } @Override public @NonNull FieldingAnalyzer createFieldingAnalyzer() { return new FieldingAnalyzer(getAnalyzer()); } @Override protected @NonNull GenModelHelper createGenModelHelper() { return new AbstractGenModelHelper(metamodelManager); } protected @NonNull Id2EClassVisitor createId2EClassVisitor() { return new Id2EClassVisitor(metamodelManager); } protected @NonNull Id2BoxedDescriptorVisitor createId2BoxedDescriptorVisitor() { return new Id2BoxedDescriptorVisitor(this); } @Override protected @NonNull NameManager createNameManager() { return new NameManager(); } @Override @NonNull public ReferencesVisitor createReferencesVisitor() { return ReferencesVisitor.INSTANCE; } @Override public @NonNull BoxedDescriptor getBoxedDescriptor(@NonNull ElementId elementId) { BoxedDescriptor boxedDescriptor = boxedDescriptors.get(elementId); if (boxedDescriptor != null) { return boxedDescriptor; } boxedDescriptor = elementId.accept(getId2BoxedDescriptorVisitor()); assert boxedDescriptor != null; boxedDescriptors.put(elementId, boxedDescriptor); return boxedDescriptor; } public @NonNull CGModelResourceFactory getCGResourceFactory() { return CG_RESOURCE_FACTORY; } @Override public @Nullable String getConstantsClass() { return null; } @Override public @NonNull EcoreDescriptor getEcoreDescriptor(@NonNull ElementId elementId, @Nullable Class<?> instanceClass) { BoxedDescriptor boxedDescriptor = getBoxedDescriptor(elementId); return boxedDescriptor.getEcoreDescriptor(this, instanceClass); } @Override public abstract @NonNull JavaGlobalContext<? extends JavaCodeGenerator> getGlobalContext(); @Override public @NonNull GlobalPlace getGlobalPlace() { GlobalPlace globalPlace2 = globalPlace; if (globalPlace2 == null) { globalPlace = globalPlace2 = new GlobalPlace(getAnalyzer()); } return globalPlace2; } public @NonNull Id2BoxedDescriptorVisitor getId2BoxedDescriptorVisitor() { Id2BoxedDescriptorVisitor id2BoxedDescriptorVisitor2 = id2BoxedDescriptorVisitor; if (id2BoxedDescriptorVisitor2 == null) { id2BoxedDescriptorVisitor = id2BoxedDescriptorVisitor2 = createId2BoxedDescriptorVisitor(); } return id2BoxedDescriptorVisitor2; } public @NonNull Id2EClassVisitor getId2EClassVisitor() { Id2EClassVisitor id2EClassVisitor2 = id2EClassVisitor; if (id2EClassVisitor2 == null) { id2EClassVisitor = id2EClassVisitor2 = createId2EClassVisitor(); } return id2EClassVisitor2; } /** * Return true for an @NonNull annotation, false for an @Nullable annotation, null otherwise. */ public @Nullable Boolean getIsNonNull(@NonNull Method method) { if (annotationReader == null) { annotationReader = new ASM5JavaAnnotationReader(); } return annotationReader.getIsNonNull(method); } @Override public @Nullable Iteration2Java getIterationHelper(@NonNull Iteration asIteration) { LibraryIteration libraryIteration = (LibraryIteration) metamodelManager.getImplementation(asIteration); if (asIteration.getOwnedIterators().size() != 1) { return null; } if (libraryIteration instanceof AnyIteration) { return AnyIteration2Java.INSTANCE; } else if (libraryIteration instanceof CollectIteration) { return CollectIteration2Java.INSTANCE; } else if (libraryIteration instanceof CollectNestedIteration) { return CollectNestedIteration2Java.INSTANCE; } else if (libraryIteration instanceof ExistsIteration) { return ExistsIteration2Java.INSTANCE; } else if (libraryIteration instanceof ForAllIteration) { return ForAllIteration2Java.INSTANCE; } else if (libraryIteration instanceof IsUniqueIteration) { return IsUniqueIteration2Java.INSTANCE; } else if (libraryIteration instanceof IterateIteration) { return IterateIteration2Java.INSTANCE; } else if (libraryIteration instanceof OneIteration) { return OneIteration2Java.INSTANCE; } else if (libraryIteration instanceof RejectIteration) { return RejectIteration2Java.INSTANCE; } else if (libraryIteration instanceof SelectIteration) { return SelectIteration2Java.INSTANCE; } else { return null; } } public @Nullable Method getLeastDerivedMethod(@NonNull Class<?> requiredClass, @NonNull String getAccessor) { Method leastDerivedMethod = getLeastDerivedMethodInternal(requiredClass, getAccessor); if (leastDerivedMethod != null) { return leastDerivedMethod; } else { try { return requiredClass.getMethod(getAccessor); } catch (Throwable e) { return null; } } } private @Nullable Method getLeastDerivedMethodInternal(@NonNull Class<?> requiredClass, @NonNull String getAccessor) { Class<?> superClass = requiredClass.getSuperclass(); if (superClass != null) { try { Method lessDerivedSuperMethod = getLeastDerivedMethodInternal(superClass, getAccessor); if (lessDerivedSuperMethod != null) { return lessDerivedSuperMethod; } Method method = superClass.getMethod(getAccessor); if (method != null) { return method; } } catch (Throwable e) { } } for (@SuppressWarnings("null")@NonNull Class<?> superInterface : requiredClass.getInterfaces()) { Method lessDerivedSuperMethod = getLeastDerivedMethodInternal(superInterface, getAccessor); if (lessDerivedSuperMethod != null) { return lessDerivedSuperMethod; } try { Method method = superInterface.getMethod(getAccessor); if (method != null) { return method; } } catch (Throwable e) { } } return null; } @Override public @NonNull TypeDescriptor getTypeDescriptor(@NonNull CGValuedElement cgElement) { CGTypeId typeId = cgElement.getTypeId(); if (typeId == null) { typeId = cgElement.getTypeId(); } CGTypeId cgTypeId = ClassUtil.nonNullState(typeId); ElementId elementId = ClassUtil.nonNullState(cgTypeId.getElementId()); TypeDescriptor typeDescriptor = getBoxedDescriptor(elementId); if (cgElement.isEcore()) { EClassifier eClassifier = cgElement.getEcoreClassifier(); Class<?> instanceClass = eClassifier != null ? eClassifier.getInstanceClass() : null; typeDescriptor = typeDescriptor.getEcoreDescriptor(this, instanceClass); } else if (cgElement.isUnboxed()) { typeDescriptor = typeDescriptor.getUnboxedDescriptor(this); } if (maybePrimitive(cgElement)) { typeDescriptor = typeDescriptor.getPrimitiveDescriptor(); } return typeDescriptor; } @Override public @NonNull UnboxedDescriptor getUnboxedDescriptor(@NonNull ElementId elementId) { BoxedDescriptor boxedDescriptor = getBoxedDescriptor(elementId); return boxedDescriptor.getUnboxedDescriptor(this); } @Override public @Nullable Boolean isNonNull(@NonNull OperationCallExp asOperationCallExp) { Operation asOperation = asOperationCallExp.getReferredOperation(); EObject eOperation = asOperation.getESObject(); if (!(eOperation instanceof EOperation)) { return null; } CGTypeId cgTypeId = getAnalyzer().getTypeId(asOperation.getOwningClass().getTypeId()); ElementId elementId = ClassUtil.nonNullState(cgTypeId.getElementId()); TypeDescriptor requiredTypeDescriptor = getUnboxedDescriptor(elementId); String getAccessor = genModelHelper.getOperationAccessor(asOperation); Class<?> requiredJavaClass = requiredTypeDescriptor.hasJavaClass(); if (requiredJavaClass == null) { return null; } Method leastDerivedMethod = getLeastDerivedMethod(requiredJavaClass, getAccessor); if (leastDerivedMethod == null) { return null; } return getIsNonNull(leastDerivedMethod) == Boolean.TRUE; } @Override public @Nullable Boolean isNonNull(@NonNull Property asProperty) { EObject eStructuralFeature = asProperty.getESObject(); if (!(eStructuralFeature instanceof EStructuralFeature)) { return null; } CGTypeId cgTypeId = getAnalyzer().getTypeId(asProperty.getOwningClass().getTypeId()); ElementId elementId = ClassUtil.nonNullState(cgTypeId.getElementId()); TypeDescriptor requiredTypeDescriptor = getUnboxedDescriptor(elementId); String getAccessor = genModelHelper.getGetAccessor((EStructuralFeature)eStructuralFeature); Class<?> requiredJavaClass = requiredTypeDescriptor.hasJavaClass(); if (requiredJavaClass == null) { return null; } Method leastDerivedMethod = getLeastDerivedMethod(requiredJavaClass, getAccessor); if (leastDerivedMethod == null) { return null; } return getIsNonNull(leastDerivedMethod) == Boolean.TRUE; } @Override public boolean maybePrimitive(@NonNull CGValuedElement cgValue) { if (cgValue.getNamedValue().isCaught()) { return false; } else { return cgValue.isNonNull(); } } /** * Perform the overall optimization of the CG tree. */ protected void optimize(@NonNull CGPackage cgPackage) { CGModelResource resource = getCGResourceFactory().createResource(URI.createURI("cg.xmi")); resource.getContents().add(cgPackage); getAnalyzer().analyze(cgPackage); CG2JavaPreVisitor cg2PreVisitor = createCG2JavaPreVisitor(); cgPackage.accept(cg2PreVisitor); CommonSubexpressionEliminator cseEliminator = createCommonSubexpressionEliminator(); cseEliminator.optimize(cgPackage); } /** * After overall optimization, return a sorted list of global declarations. */ public @Nullable List<CGValuedElement> prepareGlobals() { DependencyVisitor dependencyVisitor = createDependencyVisitor(); Collection<CGValuedElement> globals = getGlobalContext().getGlobals(); for (CGValuedElement cgGlobal : globals) { assert cgGlobal.isGlobal(); } dependencyVisitor.visitAll(globals); List<CGValuedElement> sortedGlobals = getGlobalPlace().getSortedGlobals(dependencyVisitor); return sortedGlobals; } }