/******************************************************************************* * 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.analyzer; import java.math.BigDecimal; import java.math.BigInteger; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.examples.codegen.cgmodel.CGBoxExp; import org.eclipse.ocl.examples.codegen.cgmodel.CGCallExp; import org.eclipse.ocl.examples.codegen.cgmodel.CGCatchExp; import org.eclipse.ocl.examples.codegen.cgmodel.CGCollectionExp; import org.eclipse.ocl.examples.codegen.cgmodel.CGCollectionPart; import org.eclipse.ocl.examples.codegen.cgmodel.CGEcoreExp; import org.eclipse.ocl.examples.codegen.cgmodel.CGGuardExp; import org.eclipse.ocl.examples.codegen.cgmodel.CGIterationCallExp; import org.eclipse.ocl.examples.codegen.cgmodel.CGOperationCallExp; import org.eclipse.ocl.examples.codegen.cgmodel.CGOppositePropertyCallExp; import org.eclipse.ocl.examples.codegen.cgmodel.CGPropertyCallExp; import org.eclipse.ocl.examples.codegen.cgmodel.CGString; import org.eclipse.ocl.examples.codegen.cgmodel.CGThrowExp; 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.pivot.BagType; import org.eclipse.ocl.pivot.CollectionLiteralExp; import org.eclipse.ocl.pivot.CollectionRange; import org.eclipse.ocl.pivot.CollectionType; import org.eclipse.ocl.pivot.Element; import org.eclipse.ocl.pivot.ExpressionInOCL; import org.eclipse.ocl.pivot.IntegerLiteralExp; import org.eclipse.ocl.pivot.Iteration; import org.eclipse.ocl.pivot.LiteralExp; import org.eclipse.ocl.pivot.LoopExp; import org.eclipse.ocl.pivot.Operation; import org.eclipse.ocl.pivot.OperationCallExp; import org.eclipse.ocl.pivot.OppositePropertyCallExp; import org.eclipse.ocl.pivot.OrderedSetType; import org.eclipse.ocl.pivot.Property; import org.eclipse.ocl.pivot.PropertyCallExp; import org.eclipse.ocl.pivot.RealLiteralExp; import org.eclipse.ocl.pivot.SequenceType; import org.eclipse.ocl.pivot.SetType; import org.eclipse.ocl.pivot.StringLiteralExp; import org.eclipse.ocl.pivot.Type; import org.eclipse.ocl.pivot.TypeExp; import org.eclipse.ocl.pivot.UnlimitedNaturalLiteralExp; import org.eclipse.ocl.pivot.VariableDeclaration; import org.eclipse.ocl.pivot.VariableExp; import org.eclipse.ocl.pivot.ids.ClassId; import org.eclipse.ocl.pivot.ids.CollectionTypeId; import org.eclipse.ocl.pivot.ids.DataTypeId; import org.eclipse.ocl.pivot.ids.ElementId; import org.eclipse.ocl.pivot.ids.EnumerationId; import org.eclipse.ocl.pivot.ids.EnumerationLiteralId; import org.eclipse.ocl.pivot.ids.IdVisitor; import org.eclipse.ocl.pivot.ids.LambdaTypeId; import org.eclipse.ocl.pivot.ids.MapTypeId; import org.eclipse.ocl.pivot.ids.NestedPackageId; import org.eclipse.ocl.pivot.ids.NestedTypeId; import org.eclipse.ocl.pivot.ids.NsURIPackageId; import org.eclipse.ocl.pivot.ids.OclInvalidTypeId; import org.eclipse.ocl.pivot.ids.OclVoidTypeId; import org.eclipse.ocl.pivot.ids.OperationId; import org.eclipse.ocl.pivot.ids.PackageId; import org.eclipse.ocl.pivot.ids.PrimitiveTypeId; import org.eclipse.ocl.pivot.ids.PropertyId; import org.eclipse.ocl.pivot.ids.RootPackageId; import org.eclipse.ocl.pivot.ids.TemplateBinding; import org.eclipse.ocl.pivot.ids.TemplateParameterId; import org.eclipse.ocl.pivot.ids.TemplateableTypeId; import org.eclipse.ocl.pivot.ids.TuplePartId; import org.eclipse.ocl.pivot.ids.TupleTypeId; import org.eclipse.ocl.pivot.ids.TypeId; import org.eclipse.ocl.pivot.ids.UnspecifiedId; import org.eclipse.ocl.pivot.utilities.ClassUtil; import org.eclipse.ocl.pivot.utilities.Nameable; import org.eclipse.ocl.pivot.utilities.PivotConstants; import org.eclipse.ocl.pivot.values.CollectionValue; import org.eclipse.ocl.pivot.values.IntegerRange; import org.eclipse.ocl.pivot.values.IntegerValue; import org.eclipse.ocl.pivot.values.InvalidValue; import org.eclipse.ocl.pivot.values.RealValue; /** * A NameManager provides suggestions for names and maintains caches of used names so that model elements are consistently * named without collisions. */ public class NameManager { public static final String BAG_NAME_HINT_PREFIX = "BAG"; public static final String COLLECTION_NAME_HINT_PREFIX = "COL"; public static final String DEFAULT_NAME_PREFIX = "symbol"; // public static final String ID_NAME_HINT_PREFIX = "TID"; public static final String EXPRESSION_IN_OCL_NAME_HINT_PREFIX = PivotConstants.RESULT_NAME; public static final String INTEGER_NAME_HINT_PREFIX = "INT_"; public static final String INVALID_NAME_HINT_PREFIX = "IVE_"; public static final String ITERATION_NAME_HINT_PREFIX = ""; public static final String OPERATION_NAME_HINT_PREFIX = "OP_"; public static final String OPERATION_CALL_EXP_NAME_HINT_PREFIX = ""; //"RES_"; public static final String ORDERED_SET_NAME_HINT_PREFIX = "ORD"; public static final String PROPERTY_NAME_HINT_PREFIX = ""; public static final String REAL_NAME_HINT_PREFIX = "REA_"; public static final String RANGE_NAME_HINT_PREFIX = "RNG"; public static final String SEQUENCE_NAME_HINT_PREFIX = "SEQ"; public static final String SET_NAME_HINT_PREFIX = "SET"; public static final String STRING_NAME_HINT_PREFIX = "STR_"; public static final int STRING_NAME_HINT_LIMIT = 64; public static final String TYPE_NAME_HINT_PREFIX = "TYP_"; public static final String VARIABLE_DECLARATION_NAME_HINT_PREFIX = ""; /** * Names that will not be allocated to temporary variables. * <p> * This Set is public and unsynchronized. Clients may change it in arbitrary ways at their own risk. * <p> * It is strongly recommended that clients do no more than add additional names. */ public static final Set<String> reservedJavaNames = new HashSet<String>(); { reservedJavaNames.add("Boolean"); reservedJavaNames.add("Character"); reservedJavaNames.add("Class"); reservedJavaNames.add("Double"); reservedJavaNames.add("Float"); reservedJavaNames.add("Integer"); reservedJavaNames.add("List"); reservedJavaNames.add("Long"); reservedJavaNames.add("Map"); reservedJavaNames.add("Package"); reservedJavaNames.add("String"); reservedJavaNames.add("boolean"); reservedJavaNames.add("byte"); reservedJavaNames.add("char"); reservedJavaNames.add("double"); reservedJavaNames.add("float"); reservedJavaNames.add("int"); reservedJavaNames.add("long"); reservedJavaNames.add("short"); reservedJavaNames.add("void"); reservedJavaNames.add("abstract"); // FIXME Exploit CodeGenUtil.getJavaReservedWords() reservedJavaNames.add("assert"); reservedJavaNames.add("break"); reservedJavaNames.add("case"); reservedJavaNames.add("catch"); reservedJavaNames.add("class"); reservedJavaNames.add("const"); reservedJavaNames.add("continue"); reservedJavaNames.add("default"); reservedJavaNames.add("do"); reservedJavaNames.add("else"); reservedJavaNames.add("enum"); reservedJavaNames.add("extends"); reservedJavaNames.add("final"); reservedJavaNames.add("finally"); reservedJavaNames.add("for"); reservedJavaNames.add("goto"); reservedJavaNames.add("if"); reservedJavaNames.add("implements"); reservedJavaNames.add("import"); reservedJavaNames.add("instanceof"); reservedJavaNames.add("interface"); reservedJavaNames.add("native"); reservedJavaNames.add("new"); reservedJavaNames.add("package"); reservedJavaNames.add("private"); reservedJavaNames.add("protected"); reservedJavaNames.add("public"); reservedJavaNames.add("return"); reservedJavaNames.add("static"); reservedJavaNames.add("strictfp"); reservedJavaNames.add("switch"); reservedJavaNames.add("synchronized"); reservedJavaNames.add("throw"); reservedJavaNames.add("throws"); reservedJavaNames.add("transient"); reservedJavaNames.add("try"); reservedJavaNames.add("volatile"); reservedJavaNames.add("while"); reservedJavaNames.add("false"); reservedJavaNames.add("null"); reservedJavaNames.add("super"); reservedJavaNames.add("this"); reservedJavaNames.add("true"); } public static @NonNull IdVisitor<String> idVisitor = new IdVisitor<String>() { @Override public @NonNull String visitClassId(@NonNull ClassId id) { return "CLSSid_" + id.getName(); } @Override public @NonNull String visitCollectionTypeId(@NonNull CollectionTypeId id) { CollectionTypeId generalizedId = id.getGeneralizedId(); String idPrefix; if (generalizedId == TypeId.BAG) { idPrefix = "BAG_"; } else if (generalizedId == TypeId.ORDERED_SET) { idPrefix = "ORD_"; } else if (generalizedId == TypeId.SEQUENCE) { idPrefix = "SEQ_"; } else if (generalizedId == TypeId.SET) { idPrefix = "SET_"; } else { idPrefix = "COL_"; } if (generalizedId == id) { return idPrefix; } else { return idPrefix + id.getElementTypeId().accept(this); } } @Override public @NonNull String visitDataTypeId(@NonNull DataTypeId id) { return "DATAid_" + id.getName(); } @Override public @NonNull String visitEnumerationId(@NonNull EnumerationId id) { return "ENUMid_" + id.getName(); } @Override public @NonNull String visitEnumerationLiteralId(@NonNull EnumerationLiteralId id) { return "ELITid_" + id.getName(); } @Override public @NonNull String visitInvalidId(@NonNull OclInvalidTypeId id) { return "INVid"; } @Override public @NonNull String visitLambdaTypeId(@NonNull LambdaTypeId id) { return "LAMBid_" + id.getName(); } @Override public @NonNull String visitMapTypeId(@NonNull MapTypeId id) { MapTypeId generalizedId = id.getGeneralizedId(); String idPrefix = "MAP_"; if (generalizedId == id) { return idPrefix; } else { return idPrefix + id.getKeyTypeId().accept(this) + id.getValueTypeId().accept(this); } } @Override public @NonNull String visitNestedPackageId(@NonNull NestedPackageId id) { return "PACKid_" + id.getName(); } @Override public @NonNull String visitNsURIPackageId(@NonNull NsURIPackageId id) { return "PACKid_" + id.getNsURI(); } @Override public @NonNull String visitNullId(@NonNull OclVoidTypeId id) { return "NULLid"; } @Override public @NonNull String visitOperationId(@NonNull OperationId id) { return "OPid_" + id.getName(); } @Override public @NonNull String visitPrimitiveTypeId(@NonNull PrimitiveTypeId id) { return "PRIMid_" + id.getName(); } @Override public @NonNull String visitPropertyId(@NonNull PropertyId id) { return "PROPid_" + id.getName(); } @Override public @NonNull String visitRootPackageId(@NonNull RootPackageId id) { return "PACKid_" + id.getName(); } @Override public @NonNull String visitTemplateBinding(@NonNull TemplateBinding id) { return "BINDid_"; } @Override public @NonNull String visitTemplateParameterId(@NonNull TemplateParameterId id) { return "TMPLid_"; } @Override public @NonNull String visitTemplateableTypeId(@NonNull TemplateableTypeId id) { return "TYPEid_"; } @Override public @NonNull String visitTuplePartId(@NonNull TuplePartId id) { return "PARTid_"; } @Override public @NonNull String visitTupleTypeId(@NonNull TupleTypeId id) { return "TUPLid_"; } @Override public @NonNull String visitUnspecifiedId(@NonNull UnspecifiedId id) { return "UNSPid_"; } }; protected static void appendJavaCharacters(StringBuilder s, String string) { for (int i = 0; i < string.length(); i++) { char c = string.charAt(i); if (Character.isJavaIdentifierPart(c)) { s.append(c); } else { s.append('_'); } } } protected static void appendJavaCharacters(StringBuilder s, String string, int iMax) { for (int i = 0; i < Math.min(iMax, string.length()); i++) { char c = string.charAt(i); if (Character.isJavaIdentifierPart(c)) { s.append(c); } else { s.append('_'); } } } /** * Return a valid Java identifier based on nameHint. hasPrefix may be true to indicate that the * caller will supply an additional valid prefix relieving this routine of the need to avoid * leading numeric characters. * <p> * This is not intended to be a reversible algorithm; just to provide something reasonably readable. */ private static @NonNull String getValidJavaIdentifier(@NonNull String nameHint, boolean hasPrefix, @Nullable Object anObject) { if (nameHint.equals("<")) { return("lt"); } else if (nameHint.equals("<=")) { return("le"); } else if (nameHint.equals("=")) { return("eq"); } else if (nameHint.equals("<>")) { return("ne"); } else if (nameHint.equals(">=")) { return("ge"); } else if (nameHint.equals(">")) { return("gt"); } else if (nameHint.equals("+")) { return("sum"); } else if (nameHint.equals("-")) { return((anObject instanceof Operation) && ((Operation)anObject).getOwnedParameters().size() <= 0 ? "neg" : "diff"); } else if (nameHint.equals("*")) { return("prod"); } else if (nameHint.equals("/")) { return("quot"); } else if (nameHint.equals("1_")) { return("_1"); } else if (nameHint.equals("2_")) { return("_2"); } StringBuilder s = new StringBuilder(); Character prefix = null; int length = nameHint.length(); for (int i = 0; i < length; i++) { char c = nameHint.charAt(i); if (((i == 0) && !hasPrefix) ? Character.isJavaIdentifierStart(c) : Character.isJavaIdentifierPart(c)) { if (prefix != null) { s.append(prefix); prefix = null; } s.append(c); } else { if (c == '*') { s.append("_a"); } else if (c == ':') { s.append("_c"); } else if (c == '.') { if (prefix != null) { s.append(prefix); prefix = null; } } else if (c == ')') { s.append("_e"); } else if (c == '>') { s.append("_g"); } else if (c == '<') { s.append("_l"); } else if (c == '-') { s.append("_m"); } else if (c == '(') { s.append("_o"); } else if (c == '+') { s.append("_p"); } else if (c == '=') { s.append("_q"); } else if (c == '/') { s.append("_s"); } else { s.append('_' + Integer.toString(c)); } prefix = '_'; } } return s.toString(); } public class Context { private final @Nullable Context context; // Pushed context private final @NonNull Map<String, Object> name2object; // User of each name, null if name ambiguous private final @NonNull Map<Object, String> object2name; // Unambiguous name for each object, null if not determined private Map<String, Integer> name2counter; // Auto-generation counter for each colliding name // private boolean frozen = false; // Set true once pushed public Context() { this.context = null; this.name2object = new HashMap<String, Object>(); this.object2name = new HashMap<Object, String>(); this.name2counter = null; } public Context(@NonNull Context context) { this.context = context; this.name2object = new HashMap<String, Object>(context.name2object); this.object2name = new HashMap<Object, String>(context.object2name); this.name2counter = context.name2counter != null ? new HashMap<String, Integer>(context.name2counter) : null; // context.frozen = true; } public @NonNull Context createNestedContext() { return new Context(this); } public @NonNull Context getContext() { return ClassUtil.nonNullState(context); } protected @NonNull String getGlobalUniqueName(@Nullable Object anObject, @Nullable String... nameHints) { if (context != null) { return context.getGlobalUniqueName(anObject, nameHints); } else { return getUniqueName(anObject, nameHints); } } public @NonNull String getSymbolName(@Nullable Object anObject, @Nullable String... nameHints) { if ((nameHints != null) && (nameHints.length > 0) && (nameHints[0] != null)) { return getUniqueName(anObject, nameHints); } else { return getUniqueName(anObject, anObject != null ? getNameHint(anObject) : null); } } /** * Return a unique name using some nameHints to suggest preferred names and allocate that name to anObject. * <p> * If anObject is non-null, any already allocated name is returned rather than allocating another name. * <p> * If anObject is null, the returned name is allocated to no object; not to the null value. * <p> * If nameHints is null a default name is generated. * <p> */ public @NonNull String getUniqueName(@Nullable Object anObject, @Nullable String... nameHints) { if ((anObject instanceof RealValue) && !(anObject instanceof InvalidValue)) { anObject = ((RealValue)anObject).asNumber(); } if (anObject != null) { String knownName = object2name.get(anObject); if (knownName != null) { return knownName; } } String lastResort = null; if (nameHints != null) { for (String nameHint : nameHints) { if (nameHint != null) { String validHint = getValidJavaIdentifier(nameHint, false, anObject); if (!reservedJavaNames.contains(validHint) || ((anObject instanceof CGValuedElement) && isNative((CGValuedElement)anObject))) { if (anObject != null) { Object oldElement = name2object.get(validHint); if (oldElement == anObject) { return validHint; } if ((oldElement == null) && !name2object.containsKey(validHint)) { install(validHint, anObject); return validHint; } } else { if (!name2object.containsKey(validHint)) { install(validHint, anObject); return validHint; } } if (lastResort == null) { lastResort = validHint; } } } } } if (lastResort == null) { lastResort = DEFAULT_NAME_PREFIX; } if (name2counter == null) { name2counter = new HashMap<String, Integer>(); } Integer counter = name2counter.get(lastResort); int count = counter != null ? counter : 0; for ( ; true; count++) { String attempt = lastResort + "_" + Integer.toString(count); if (!name2object.containsKey(attempt)) { // Assumes that reserved names do not end in _ count install(attempt, anObject); name2counter.put(lastResort, ++count); return attempt; } } } private void install(@NonNull String name, @Nullable Object anObject) { //FIXME assert !frozen; assert !(anObject instanceof RealValue) || (anObject instanceof InvalidValue); name2object.put(name, anObject); if (anObject != null) { object2name.put(anObject, name); } } private boolean isNative(@NonNull CGValuedElement cgElement) { TypeId asTypeId = cgElement.getASTypeId(); if (asTypeId instanceof NestedTypeId) { PackageId packageId = ((NestedTypeId)asTypeId).getParent(); if ((packageId instanceof RootPackageId) && ((RootPackageId)packageId).getName().contains("://")) { // e.g. java:// return true; } } return false; } /** * Reserve name for use by anObject. If anObject is null, the reservation is for an unspecified object not for the null value. * public @NonNull String reserveName(@NonNull String name, @Nullable Object anObject) { assert !frozen; assert !(anObject instanceof RealValue); String validJavaIdentifier = getUniqueName(anObject, getValidJavaIdentifier(name, true, anObject)); Object oldElement = name2object.put(validJavaIdentifier, anObject); // FIXME redundant assert (oldElement == null) || (oldElement == anObject); return validJavaIdentifier; } */ } private @NonNull Context context = new Context(); public NameManager() {} public @NonNull Context createNestedContext() { return new Context(context); } public @NonNull String getExplicitName(@Nullable Object anObject) { if (anObject == null) { return "null"; } else if (anObject instanceof Boolean) { return ((Boolean)anObject).booleanValue() ? "true" : "false"; } else { return "<null-" + anObject.getClass().getSimpleName() + ">"; } } public @NonNull String getGlobalSymbolName(@Nullable Object anObject, @Nullable String... nameHints) { if ((nameHints != null) && (nameHints.length > 0)) { return getGlobalUniqueName(anObject, nameHints); } else { return getGlobalUniqueName(anObject, anObject != null ? getNameHint(anObject) : null); } } protected @NonNull String getGlobalUniqueName(@Nullable Object anObject, @Nullable String... nameHints) { return context.getGlobalUniqueName(anObject, nameHints); } protected String getIterationNameHint(@NonNull Iteration anIteration) { @SuppressWarnings("null") @NonNull String string = anIteration.getName(); return ITERATION_NAME_HINT_PREFIX + getValidJavaIdentifier(string, ITERATION_NAME_HINT_PREFIX.length() > 0, anIteration); } protected String getKindHint(@NonNull String kind) { if (TypeId.BAG_NAME.equals(kind)) { return BAG_NAME_HINT_PREFIX; } else if (TypeId.ORDERED_SET_NAME.equals(kind)) { return ORDERED_SET_NAME_HINT_PREFIX; } else if (TypeId.SEQUENCE_NAME.equals(kind)) { return SEQUENCE_NAME_HINT_PREFIX; } else if (TypeId.SET_NAME.equals(kind)) { return SET_NAME_HINT_PREFIX; } else { return COLLECTION_NAME_HINT_PREFIX; } } /** * Return a suggestion for the name of anObject. * <p> * The returned name is not guaranteed to be unique. Uniqueness is enforced when the hint is passed to getSymbolName(). */ public @Nullable String getNameHint(@NonNull Object anObject) { if (anObject instanceof CGValuedElement) { anObject = ((CGValuedElement)anObject).getNamedValue(); } if (anObject instanceof CollectionLiteralExp) { Type type = ((CollectionLiteralExp)anObject).getType(); return type != null ? getTypeNameHint(type) : null; } else if (anObject instanceof CollectionRange) { return RANGE_NAME_HINT_PREFIX; } else if (anObject instanceof CGCollectionPart) { return RANGE_NAME_HINT_PREFIX; } else if (anObject instanceof InvalidValue) { return INVALID_NAME_HINT_PREFIX; } else if (anObject instanceof CollectionValue) { String kind = ((CollectionValue)anObject).getKind(); return kind != null ? getKindHint(kind) : null; } else if (anObject instanceof CGCollectionExp) { String kind = ((CGCollectionExp)anObject).getName(); return kind != null ? getKindHint(kind) : null; } else if (anObject instanceof ElementId) { String nameHint = ((ElementId)anObject).accept(idVisitor); return nameHint; } else if (anObject instanceof ExpressionInOCL) { return EXPRESSION_IN_OCL_NAME_HINT_PREFIX; } else if (anObject instanceof IntegerLiteralExp) { Number numberSymbol = ((IntegerLiteralExp)anObject).getIntegerSymbol(); return numberSymbol != null ? getNumericNameHint(numberSymbol) : null; } else if (anObject instanceof IntegerRange) { return RANGE_NAME_HINT_PREFIX; } else if (anObject instanceof IntegerValue) { Number numberSymbol = ((IntegerValue)anObject).asNumber(); return getNumericNameHint(numberSymbol); } else if (anObject instanceof LoopExp) { Iteration referredIteration = ((LoopExp)anObject).getReferredIteration(); return referredIteration != null ? getIterationNameHint(referredIteration) : null; } else if (anObject instanceof Number) { return getNumericNameHint((Number)anObject); } else if (anObject instanceof Operation) { return getOperationNameHint((Operation)anObject); } else if (anObject instanceof OperationCallExp) { Operation referredOperation = ((OperationCallExp)anObject).getReferredOperation(); return referredOperation != null ? getOperationCallExpNameHint(referredOperation) : null; } else if (anObject instanceof OppositePropertyCallExp) { Property referredOppositeProperty = ((OppositePropertyCallExp)anObject).getReferredProperty(); Property referredProperty = referredOppositeProperty != null ? referredOppositeProperty.getOpposite() : null; return referredProperty != null ? getPropertyNameHint(referredProperty) : null; } else if (anObject instanceof PropertyCallExp) { Property referredProperty = ((PropertyCallExp)anObject).getReferredProperty(); return referredProperty != null ? getPropertyNameHint(referredProperty) : null; } else if (anObject instanceof CGCallExp) { if (anObject instanceof CGOppositePropertyCallExp) { Property referredOppositeProperty = ((OppositePropertyCallExp)((CGOppositePropertyCallExp)anObject).getAst()).getReferredProperty(); Property referredProperty = referredOppositeProperty != null ? referredOppositeProperty.getOpposite() : null; return referredProperty != null ? getPropertyNameHint(referredProperty) : null; } else if (anObject instanceof CGPropertyCallExp) { Property referredProperty = ((PropertyCallExp)((CGPropertyCallExp)anObject).getAst()).getReferredProperty(); return referredProperty != null ? getPropertyNameHint(referredProperty) : null; } else if (anObject instanceof CGIterationCallExp) { Iteration referredIteration = ((LoopExp)((CGIterationCallExp)anObject).getAst()).getReferredIteration(); return referredIteration != null ? getIterationNameHint(referredIteration) : null; } else if (anObject instanceof CGOperationCallExp) { Operation referredOperation = ((OperationCallExp)((CGOperationCallExp)anObject).getAst()).getReferredOperation(); return referredOperation != null ? getOperationCallExpNameHint(referredOperation) : null; } else if (anObject instanceof CGBoxExp) { return "BOXED_" + ((CGBoxExp)anObject).getSourceValue().getValueName(); } else if (anObject instanceof CGEcoreExp) { return "ECORE_" + ((CGEcoreExp)anObject).getSourceValue().getValueName(); } else if (anObject instanceof CGUnboxExp) { return "UNBOXED_" + ((CGUnboxExp)anObject).getSourceValue().getValueName(); } else if (anObject instanceof CGCatchExp) { return "CAUGHT_" + ((CGCatchExp)anObject).getSourceValue().getValueName(); } else if (anObject instanceof CGGuardExp) { return "GUARDED_" + ((CGGuardExp)anObject).getSourceValue().getValueName(); } else if (anObject instanceof CGThrowExp) { return "THROWN_" + ((CGThrowExp)anObject).getSourceValue().getValueName(); } else { return null; } } else if (anObject instanceof RealLiteralExp) { Number numberSymbol = ((RealLiteralExp)anObject).getRealSymbol(); return numberSymbol != null ? getNumericNameHint(numberSymbol) : null; } else if (anObject instanceof RealValue) { Number numberSymbol = ((RealValue)anObject).asNumber(); return getNumericNameHint(numberSymbol); } else if (anObject instanceof String) { return getStringNameHint((String)anObject); } else if (anObject instanceof CGString) { String stringValue = ((CGString)anObject).getStringValue(); return stringValue != null ? getStringNameHint(stringValue) : null; } else if (anObject instanceof StringLiteralExp) { String stringSymbol = ((StringLiteralExp)anObject).getStringSymbol(); return stringSymbol != null ? getStringNameHint(stringSymbol) : null; } else if (anObject instanceof Type) { return getTypeNameHint((Type)anObject); } else if (anObject instanceof CGTypeId) { Element type = ((CGTypeId)anObject).getAst(); return (type instanceof Type) ? getTypeNameHint((Type) type) : null; } else if (anObject instanceof TypeExp) { Type referredType = ((TypeExp)anObject).getType(); return referredType != null ? getTypeNameHint(referredType) : null; } // else if (anObject instanceof TypeValue) { // DomainType referredType = ((TypeValue)anObject).getInstanceType(); // return getTypeNameHint(referredType); // } else if (anObject instanceof UnlimitedNaturalLiteralExp) { Number numberSymbol = ((UnlimitedNaturalLiteralExp)anObject).getUnlimitedNaturalSymbol(); return numberSymbol != null ? getNumericNameHint(numberSymbol) : null; } else if (anObject instanceof VariableExp) { VariableDeclaration referredVariable = ((VariableExp)anObject).getReferredVariable(); return referredVariable != null ? getVariableDeclarationNameHint(referredVariable) : null; } else if (anObject instanceof LiteralExp) { return "literal"; } else if (anObject instanceof Nameable) { String name = ((Nameable)anObject).getName(); return name != null ? getValidJavaIdentifier(name, false, anObject) : null; } else { return null; } } protected String getNumericNameHint(@NonNull Number aNumber) { @SuppressWarnings("null") @NonNull String string = aNumber.toString(); if ((aNumber instanceof BigInteger) || (aNumber instanceof Long) || (aNumber instanceof Integer) || (aNumber instanceof Short)) { return INTEGER_NAME_HINT_PREFIX + string; } else if ((aNumber instanceof BigDecimal) || (aNumber instanceof Double) || (aNumber instanceof Float)) { return REAL_NAME_HINT_PREFIX + getValidJavaIdentifier(string, REAL_NAME_HINT_PREFIX.length() > 0, aNumber); } else { return null; } } protected String getOperationNameHint(@NonNull Operation anOperation) { @SuppressWarnings("null") @NonNull String string = anOperation.toString(); return OPERATION_NAME_HINT_PREFIX + getValidJavaIdentifier(string, OPERATION_NAME_HINT_PREFIX.length() > 0, anOperation); } protected String getOperationCallExpNameHint(@NonNull Operation anOperation) { @SuppressWarnings("null") @NonNull String string = anOperation.getName(); return OPERATION_CALL_EXP_NAME_HINT_PREFIX + getValidJavaIdentifier(string, OPERATION_CALL_EXP_NAME_HINT_PREFIX.length() > 0, anOperation); } protected String getPropertyNameHint(@NonNull Property aProperty) { @SuppressWarnings("null") @NonNull String string = aProperty.getName(); return PROPERTY_NAME_HINT_PREFIX + getValidJavaIdentifier(string, PROPERTY_NAME_HINT_PREFIX.length() > 0, aProperty); } protected String getStringNameHint(@NonNull String aString) { @NonNull String string = aString.length() > STRING_NAME_HINT_LIMIT ? aString.substring(0, STRING_NAME_HINT_LIMIT) : aString; return STRING_NAME_HINT_PREFIX + getValidJavaIdentifier(string, STRING_NAME_HINT_PREFIX.length() > 0, aString); } protected String getTypeNameHint(@NonNull Type aType) { if (aType instanceof CollectionType) { if (aType instanceof OrderedSetType) { return ORDERED_SET_NAME_HINT_PREFIX; } else if (aType instanceof SetType) { return SET_NAME_HINT_PREFIX; } else if (aType instanceof SequenceType) { return SEQUENCE_NAME_HINT_PREFIX; } else if (aType instanceof BagType) { return BAG_NAME_HINT_PREFIX; } else { return COLLECTION_NAME_HINT_PREFIX; } } @SuppressWarnings("null") @NonNull String string = aType.toString(); return TYPE_NAME_HINT_PREFIX + getValidJavaIdentifier(string, TYPE_NAME_HINT_PREFIX.length() > 0, aType); } protected String getVariableDeclarationNameHint(@NonNull VariableDeclaration aVariableDeclaration) { String string = ClassUtil.nonNullModel(aVariableDeclaration.getName()); return VARIABLE_DECLARATION_NAME_HINT_PREFIX + getValidJavaIdentifier(string, VARIABLE_DECLARATION_NAME_HINT_PREFIX.length() > 0, aVariableDeclaration); } /** * Reserve name for use by anObject. If anObject is null, the reservation is for an unspecified object not for the null value. */ public @NonNull String reserveName(@NonNull String name, @Nullable Object anObject) { return context.getSymbolName(anObject, name); } }