blob: f7c6da94789c4d0e3d177ab346bad10493134a15 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2020 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.utilities;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.examples.codegen.cgmodel.CGBuiltInIterationCallExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGCallExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGClass;
import org.eclipse.ocl.examples.codegen.cgmodel.CGConstantExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGConstraint;
import org.eclipse.ocl.examples.codegen.cgmodel.CGElement;
import org.eclipse.ocl.examples.codegen.cgmodel.CGExecutorType;
import org.eclipse.ocl.examples.codegen.cgmodel.CGIterationCallExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGIterator;
import org.eclipse.ocl.examples.codegen.cgmodel.CGLetExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGModelFactory;
import org.eclipse.ocl.examples.codegen.cgmodel.CGParameter;
import org.eclipse.ocl.examples.codegen.cgmodel.CGTupleExp;
import org.eclipse.ocl.examples.codegen.cgmodel.CGTuplePart;
import org.eclipse.ocl.examples.codegen.cgmodel.CGTypeId;
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.pivot.Constraint;
import org.eclipse.ocl.pivot.OCLExpression;
import org.eclipse.ocl.pivot.StandardLibrary;
import org.eclipse.ocl.pivot.Type;
import org.eclipse.ocl.pivot.Variable;
import org.eclipse.ocl.pivot.VariableDeclaration;
import org.eclipse.ocl.pivot.evaluation.Executor;
import org.eclipse.ocl.pivot.ids.ElementId;
import org.eclipse.ocl.pivot.ids.IdResolver;
import org.eclipse.ocl.pivot.ids.OclVoidTypeId;
import org.eclipse.ocl.pivot.ids.PrimitiveTypeId;
import org.eclipse.ocl.pivot.ids.TemplateParameterId;
import org.eclipse.ocl.pivot.ids.TypeId;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
public class CGUtil
{
/**
* Simplify org.eclipse.jdt.annotation references that unnecessarily use long firm within a long firm.
* e.g. replace
*
* "X.Y.@org.eclipse.jdt.annotation.NonNull Z" by "@NonNull Z" if "X.Y.Z" is an import.
* "java.lang.@org.eclipse.jdt.annotation.NonNull Z" by "@NonNull Z".
* "Y.@org.eclipse.jdt.annotation.NonNull Z" by "Y.@NonNull Z"
*/
public static @NonNull String compressJDTannotations(@NonNull String classFileContent) {
final String ORG_ECLIPSE_JDT_ANNOTATION = org.eclipse.jdt.annotation.NonNull.class.getPackage().getName();
final String AT_ORG_ECLIPSE_JDT_ANNOTATION_DOT = "@" + ORG_ECLIPSE_JDT_ANNOTATION + ".";
Set<@NonNull String> reservedNames = new HashSet<>();
reservedNames.add("Byte");
reservedNames.add("Character");
reservedNames.add("Class");
reservedNames.add("Double");
reservedNames.add("Enum");
reservedNames.add("Error");
reservedNames.add("Exception");
reservedNames.add("Float");
reservedNames.add("Integer");
reservedNames.add("Long");
reservedNames.add("Math");
reservedNames.add("Object");
reservedNames.add("Package");
reservedNames.add("Process");
reservedNames.add("Short");
reservedNames.add("String");
try {
Set<@NonNull String> longImports = new HashSet<>();
BufferedReader reader = new BufferedReader(new StringReader(classFileContent));
StringBuilder s = new StringBuilder();
for (String line; (line = reader.readLine()) != null; ) {
if (line.startsWith("import ")) {
int index = line.indexOf(";");
if (index > 0) {
String longImport = line.substring(7, index).trim();
int lastIndex = longImport.lastIndexOf(".");
if (lastIndex > 0) {
String shortImport = longImport.substring(lastIndex+1);
assert shortImport != null;
if (!reservedNames.contains(shortImport)) {
longImports.add(longImport);
}
// String oldLongImport = shortImports.put(shortImport, longImport);
// if (oldLongImport != null) {
// shortImports.put(shortImport, shortImport);
// }
}
}
}
while (true) {
int prefixEnd = line.indexOf(AT_ORG_ECLIPSE_JDT_ANNOTATION_DOT);
if (prefixEnd < 0) {
break;
}
int prefixIndex = prefixEnd;
for (; prefixIndex > 0; --prefixIndex) {
char c = line.charAt(prefixIndex-1);
if ((c != '.') && !Character.isJavaIdentifierPart(c)) {
break;
}
}
String prefixName = line.substring(prefixIndex, prefixEnd-1);
int annotationStart = prefixEnd + AT_ORG_ECLIPSE_JDT_ANNOTATION_DOT.length();
int annotationEnd = annotationStart+1;
for (; true; ++annotationEnd) {
char c = line.charAt(annotationEnd);
if (!Character.isJavaIdentifierPart(c)) {
break;
}
}
String annotationName = line.substring(annotationStart, annotationEnd);
if (!longImports.contains(ORG_ECLIPSE_JDT_ANNOTATION + "." + annotationName)) {
break;
}
int suffixStart = annotationEnd;
for (; true; ++suffixStart) {
char c = line.charAt(suffixStart);
if (!Character.isWhitespace(c)) {
break;
}
}
int suffixEnd = suffixStart;
for (; true; ++suffixEnd) {
char c = line.charAt(suffixEnd);
if (!Character.isJavaIdentifierPart(c)) {
break;
}
}
String suffixName = line.substring(suffixStart, suffixEnd);
String importName = prefixName + "." + suffixName;
if (longImports.contains(importName) || importName.startsWith("java.lang.")) {
line = line.substring(0, prefixIndex) + "@" + line.substring(annotationStart, line.length());
}
else {
line = line.substring(0, prefixEnd) + "@" + line.substring(annotationStart, line.length());
break;
}
}
// if (!line.startsWith("import org.eclipse.ocl.pivot.Class;") && !line.startsWith("import org.eclipse.ocl.pivot.Package;")) {
s.append(line);
s.append("\n");
// }
}
return s.toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return classFileContent;
}
public static @NonNull CGParameter createCGParameter(@NonNull String name, @NonNull CGTypeId typeId) {
CGParameter cgParameter = CGModelFactory.eINSTANCE.createCGParameter();
cgParameter.setName(name);
cgParameter.setTypeId(typeId);
return cgParameter;
}
public static @NonNull CGIterator getAccumulator(@NonNull CGBuiltInIterationCallExp cgIterationCallExp) {
return ClassUtil.nonNullState(cgIterationCallExp.getAccumulator());
}
public static @NonNull OCLExpression getAST(@NonNull CGCallExp cgCallExp) {
return ClassUtil.nonNullState((OCLExpression)cgCallExp.getAst());
}
public static org.eclipse.ocl.pivot.@NonNull Class getAST(@NonNull CGClass cgClass) {
return ClassUtil.nonNullState((org.eclipse.ocl.pivot.Class)cgClass.getAst());
}
public static @NonNull Constraint getAST(@NonNull CGConstraint cgConstraint) {
return ClassUtil.nonNullState((Constraint)cgConstraint.getAst());
}
public static @NonNull Variable getAST(@NonNull CGIterator cgIterator) {
return ClassUtil.nonNullState((Variable)cgIterator.getAst());
}
public static @NonNull /*ParameterVariable*/ VariableDeclaration getAST(@NonNull CGParameter cgParameter) {
return ClassUtil.nonNullState((VariableDeclaration)cgParameter.getAst());
}
public static @NonNull List<@NonNull CGIterator> getCoIteratorsList(@NonNull CGIterationCallExp cgIterationCallExp) {
return ClassUtil.nullFree(cgIterationCallExp.getCoIterators());
}
public static @Nullable CGClass getContainingClass(@NonNull CGElement cgExpression) {
for (CGElement cgElement = cgExpression; cgElement != null; cgElement = cgElement.getParent()) {
if (cgElement instanceof CGClass) {
return (CGClass) cgElement;
}
}
return null;
}
public static @Nullable CGConstraint getContainingConstraint(@NonNull CGElement cgExpression) {
for (CGElement cgElement = cgExpression; cgElement != null; cgElement = cgElement.getParent()) {
if (cgElement instanceof CGConstraint) {
return (CGConstraint) cgElement;
}
}
return null;
}
/* public static @Nullable CGOperation getContainingOperation(@NonNull CGValuedElement cgExpression) {
for (CGElement cgElement = cgExpression; cgElement != null; cgElement = cgElement.getParent()) {
if (cgElement instanceof CGOperation) {
return (CGOperation) cgElement;
}
}
return null;
} */
public static @NonNull CGValuedElement getIn(@NonNull CGLetExp cgLetExp) {
return ClassUtil.nonNullState(cgLetExp.getIn());
}
public static @NonNull CGValuedElement getInit(@NonNull CGTuplePart cgTuplePart) {
return ClassUtil.nonNullState(cgTuplePart.getInit());
}
public static @NonNull CGValuedElement getInit(@NonNull CGVariable cgVariable) {
return ClassUtil.nonNullState(cgVariable.getInit());
}
public static @NonNull List<@NonNull CGIterator> getIteratorsList(@NonNull CGIterationCallExp cgIterationCallExp) {
return ClassUtil.nullFree(cgIterationCallExp.getIterators());
}
public static Iterable<@NonNull CGTuplePart> getParts(@NonNull CGTupleExp cgTupleExp) {
return ClassUtil.nullFree(cgTupleExp.getParts());
}
public static @NonNull CGValuedElement getReferredConstant(@NonNull CGConstantExp cgConstantExp) {
return ClassUtil.nonNullState(cgConstantExp.getReferredConstant());
}
public static @NonNull CGValuedElement getReferredVariable(@NonNull CGVariableExp cgVariableExp) {
return ClassUtil.nonNullState(cgVariableExp.getReferredVariable());
}
public static boolean isInlinedId(@NonNull ElementId elementId) {
return (elementId instanceof PrimitiveTypeId)
|| (elementId instanceof OclVoidTypeId)
|| (elementId instanceof TemplateParameterId);
}
public static @Nullable Boolean isKindOf(@NonNull CGValuedElement cgValue, @NonNull CGExecutorType executorType) {
CGTypeId referenceTypeId = executorType.getUnderlyingTypeId();
CGTypeId actualTypeId = cgValue.getTypeId();
// return referenceTypeId == actualTypeId ? Boolean.TRUE : null; // FIXME support conformance somehow
if (referenceTypeId == actualTypeId) {
return Boolean.TRUE;
}
Executor executor = PivotUtil.getExecutor(cgValue);
assert executor != null;
IdResolver idResolver = executor.getIdResolver();
StandardLibrary standardLibrary = executor.getStandardLibrary();
TypeId asReferenceTypeId = referenceTypeId.getASTypeId();
assert asReferenceTypeId != null;
TypeId asActualTypeId = actualTypeId.getASTypeId();
assert asActualTypeId != null;
Type asReferenceType = idResolver.getType(asReferenceTypeId);
Type asActualType = idResolver.getType(asActualTypeId);
if (asActualType.conformsTo(standardLibrary, asReferenceType)) {
return Boolean.TRUE; // Guaranteed conformance
}
else if (!asReferenceType.conformsTo(standardLibrary, asActualType)) {
return Boolean.FALSE; // Guaranteed non-conformance
}
else {
return null; // Run-time conformance test required
}
}
/**
* Return true if the testNameSuffix system property has been set to indicate tests are
* running under the supervision of the maven-surefire-plugin..
*/
public static boolean isMavenSurefire() {
String testNameSuffix = System.getProperty("testNameSuffix", "");
return (testNameSuffix != null) && testNameSuffix.startsWith("maven");
}
/**
* Return true if the testNameSuffix system property has been set to indicate tests are
* running under the supervision of the tycho-surefire-plugin..
*/
public static boolean isTychoSurefire() {
String testNameSuffix = System.getProperty("testNameSuffix", "");
return (testNameSuffix != null) && testNameSuffix.startsWith("tycho");
}
/**
* Replace oldElement by newElement and return oldElement which is orphaned by the replacement.
*/
public static @NonNull CGValuedElement replace(@NonNull CGValuedElement oldElement, @NonNull CGValuedElement newElement) {
assert !oldElement.isRequired() || !newElement.isNull();
EObject oldContainer = oldElement.eContainer();
// EObject newContainer = newElement.eContainer();
// assert (oldContainer != null) && (newContainer == null);
EcoreUtil.replace(oldElement, newElement);
assert oldElement.eContainer() == null;
assert newElement.eContainer() == oldContainer;
return oldElement;
}
/**
* Trim trailing spaces from lines.
*/
public static @NonNull String trimLines(@NonNull String classFileContent) {
try {
BufferedReader reader = new BufferedReader(new StringReader(classFileContent));
StringBuilder s = new StringBuilder();
for (String line; (line = reader.readLine()) != null; ) {
int len = line.length();
int i = len;
while ((i > 0) && Character.isWhitespace(line.charAt(i-1))) {
i--;
}
s.append(i < len ? line.substring(0, i) : line);
s.append("\n");
}
return s.toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return classFileContent;
}
/**
* Use wrapExp to wrap wrappedExp.
*/
public static void wrap(@NonNull CGCallExp wrapExp, @NonNull CGValuedElement wrappedExp) {
wrapExp.setTypeId(wrappedExp.getTypeId());
wrapExp.setAst(wrappedExp.getAst());
replace(wrappedExp, wrapExp);
wrapExp.setSource(wrappedExp);
}
}