[500803] Suppress inlining if invoking a non-final operation
diff --git a/examples/org.eclipse.ocl.examples.codegen/src/org/eclipse/ocl/examples/codegen/analyzer/AS2CGVisitor.java b/examples/org.eclipse.ocl.examples.codegen/src/org/eclipse/ocl/examples/codegen/analyzer/AS2CGVisitor.java
index adb2c3f..84eb6c9 100644
--- a/examples/org.eclipse.ocl.examples.codegen/src/org/eclipse/ocl/examples/codegen/analyzer/AS2CGVisitor.java
+++ b/examples/org.eclipse.ocl.examples.codegen/src/org/eclipse/ocl/examples/codegen/analyzer/AS2CGVisitor.java
@@ -937,7 +937,7 @@
* Return all final operations directly referenced by opaqueExpression, or null if none.
* @since 1.3
*/
- protected @Nullable Set<@NonNull Operation> getReferencedFinalOperations(@NonNull FinalAnalysis finalAnalysis, @NonNull LanguageExpression specification) {
+ protected @Nullable Iterable<@NonNull Operation> getReferencedFinalOperations(@NonNull FinalAnalysis finalAnalysis, @NonNull LanguageExpression specification) {
ExpressionInOCL prototype = null;
try {
prototype = metamodelManager.parseSpecification(specification);
@@ -964,6 +964,33 @@
return referencedOperations;
}
+ protected @Nullable Iterable<@NonNull Operation> getReferencedNonFinalOperations(@NonNull FinalAnalysis finalAnalysis, @NonNull LanguageExpression specification) {
+ ExpressionInOCL prototype = null;
+ try {
+ prototype = metamodelManager.parseSpecification(specification);
+ }
+ catch (ParserException e) {
+ // FIXME log error
+ e.printStackTrace();
+ }
+ if (prototype == null) {
+ return null;
+ }
+ Set<@NonNull Operation> referencedOperations = null;
+ for (EObject crossReference : EcoreUtil.ExternalCrossReferencer.find(prototype).keySet()) {
+ if (crossReference instanceof Operation) {
+ Operation operation = (Operation) crossReference;
+ if (!finalAnalysis.isFinal(operation)) {
+ if (referencedOperations == null) {
+ referencedOperations = new HashSet<>();
+ }
+ referencedOperations.add(operation);
+ }
+ }
+ }
+ return referencedOperations;
+ }
+
@Deprecated
public @NonNull CGParameter getSelfParameter(@NonNull Variable aParameter) {
return getParameter(aParameter, null);
@@ -973,8 +1000,8 @@
* Return all final operations transitively referenced by opaqueExpression, or null if none.
* @since 1.3
*/
- protected void getTransitivelyReferencedFinalOperations(@NonNull Set<Operation> alreadyReferencedFinalOperations, @NonNull FinalAnalysis finalAnalysis, @NonNull LanguageExpression expressionInOCL) {
- Set<@NonNull Operation> newlyReferencedFinalOperations = getReferencedFinalOperations(finalAnalysis, expressionInOCL);
+ protected void getTransitivelyReferencedFinalOperations(@NonNull Set<@NonNull Operation> alreadyReferencedFinalOperations, @NonNull FinalAnalysis finalAnalysis, @NonNull LanguageExpression expressionInOCL) {
+ Iterable<@NonNull Operation> newlyReferencedFinalOperations = getReferencedFinalOperations(finalAnalysis, expressionInOCL);
if (newlyReferencedFinalOperations != null) {
for (@NonNull Operation newlyReferencedFinalOperation : newlyReferencedFinalOperations) {
if (alreadyReferencedFinalOperations.add(newlyReferencedFinalOperation)) {
@@ -1023,6 +1050,10 @@
if (referencedFinalOperations.contains(callExp.getReferredOperation())) {
return null; // Avoid an infinite inlining recursion.
}
+ Iterable<@NonNull Operation> referencedNonFinalOperations = getReferencedNonFinalOperations(finalAnalysis, specification);
+ if (referencedNonFinalOperations != null) {
+ return null; // Simple heavy heuristic
+ }
ExpressionInOCL asClone = createCopy(prototype);
OCLExpression asExpression = ClassUtil.nonNullState(asClone.getOwnedBody());
List<@NonNull OCLExpression> asArguments = ClassUtil.nullFree(callExp.getOwnedArguments());
diff --git a/examples/org.eclipse.ocl.examples.codegen/src/org/eclipse/ocl/examples/codegen/java/CG2JavaVisitor.java b/examples/org.eclipse.ocl.examples.codegen/src/org/eclipse/ocl/examples/codegen/java/CG2JavaVisitor.java
index 27f82f6..0fb3e47 100644
--- a/examples/org.eclipse.ocl.examples.codegen/src/org/eclipse/ocl/examples/codegen/java/CG2JavaVisitor.java
+++ b/examples/org.eclipse.ocl.examples.codegen/src/org/eclipse/ocl/examples/codegen/java/CG2JavaVisitor.java
@@ -500,64 +500,12 @@
protected void doCachedOperationBasicEvaluate(@NonNull CGOperation cgOperation) {
List<@NonNull CGParameter> cgParameters = ClassUtil.nullFree(cgOperation.getParameters());
- js.append("public ");
- // boolean cgOperationIsInvalid = cgOperation.getInvalidValue() != null;
- // js.appendIsCaught(!cgOperationIsInvalid, cgOperationIsInvalid);
- // js.append(" ");
- js.appendClassReference(cgOperation.isRequired() ? true : null, cgOperation);
- js.append(" evaluate(");
- boolean isFirst = true;
- for (@NonNull CGParameter cgParameter : cgParameters) {
- if (!isFirst) {
- js.append(", ");
- }
- js.appendDeclaration(cgParameter);
- isFirst = false;
- }
- js.append(") {\n");
- js.pushIndentation(null);
- js.append("return (");
- js.appendClassReference(null, cgOperation);
- js.append(")");
- js.append(JavaConstants.EVALUATION_CACHE_NAME);
- js.append(".getCachedEvaluationResult(this, caller, new ");
- js.appendIsRequired(false);
- js.append(" ");
- js.appendClassReference(Object.class);
- js.append("[]{");
- isFirst = true;
- for (@NonNull CGParameter cgParameter : cgParameters) {
- if (!isFirst) {
- js.append(", ");
- }
- js.appendValueName(cgParameter);
- isFirst = false;
- }
- js.append("});\n");
- js.popIndentation();
- js.append("}\n");
- }
-
- protected void doCachedOperationClassInstance(@NonNull Operation asOperation) {
- String name = getNativeOperationClassName(asOperation);
- js.append("protected final ");
- js.appendIsRequired(true);
- js.append(" ");
- js.append(name);
- js.append(" ");
- js.append(getNativeOperationInstanceName(asOperation));
- js.append(" = new ");
- js.append(name);
- js.append("();\n");
- }
-
- protected void doCachedOperationEvaluate(@NonNull CGOperation cgOperation) {
- List<@NonNull CGParameter> cgParameters = ClassUtil.nullFree(cgOperation.getParameters());
CGValuedElement body = getExpression(cgOperation.getBody());
appendAtOverride(cgOperation);
js.append("public ");
// boolean cgOperationIsInvalid = cgOperation.getInvalidValue() != null;
// js.appendIsCaught(!cgOperationIsInvalid, cgOperationIsInvalid);
+ js.appendIsRequired(false);
js.append(" ");
js.appendClassReference(Object.class);
js.append(" basicEvaluate(");
@@ -587,7 +535,7 @@
if (cgParameter.getASTypeId() instanceof CollectionTypeId) {
js.append("@SuppressWarnings(\"unchecked\") ");
}
- else {
+ else if (cgParameter.isRequired()) {
js.append("@SuppressWarnings(\"null\") ");
}
js.appendDeclaration(cgParameter);
@@ -600,6 +548,66 @@
js.append("}\n");
}
+ protected void doCachedOperationClassInstance(@NonNull Operation asOperation) {
+ String name = getNativeOperationClassName(asOperation);
+ js.append("protected final ");
+ js.appendIsRequired(true);
+ js.append(" ");
+ js.append(name);
+ js.append(" ");
+ js.append(getNativeOperationInstanceName(asOperation));
+ js.append(" = new ");
+ js.append(name);
+ js.append("();\n");
+ }
+
+ protected void doCachedOperationEvaluate(@NonNull CGOperation cgOperation) {
+ List<@NonNull CGParameter> cgParameters = ClassUtil.nullFree(cgOperation.getParameters());
+ Boolean isRequiredReturn = cgOperation.isRequired() ? true : null;
+ if (cgOperation.getASTypeId() instanceof CollectionTypeId) {
+ js.append("@SuppressWarnings(\"unchecked\")\n");
+ }
+ else if ((isRequiredReturn == Boolean.TRUE) && js.isUseNullAnnotations()) {
+ js.append("@SuppressWarnings(\"null\")\n");
+ }
+ js.append("public ");
+ // boolean cgOperationIsInvalid = cgOperation.getInvalidValue() != null;
+ // js.appendIsCaught(!cgOperationIsInvalid, cgOperationIsInvalid);
+ // js.append(" ");
+ js.appendClassReference(isRequiredReturn, cgOperation);
+ js.append(" evaluate(");
+ boolean isFirst = true;
+ for (@NonNull CGParameter cgParameter : cgParameters) {
+ if (!isFirst) {
+ js.append(", ");
+ }
+ js.appendDeclaration(cgParameter);
+ isFirst = false;
+ }
+ js.append(") {\n");
+ js.pushIndentation(null);
+ js.append("return (");
+ js.appendClassReference(isRequiredReturn, cgOperation);
+ js.append(")");
+ js.append(JavaConstants.EVALUATION_CACHE_NAME);
+ js.append(".getCachedEvaluationResult(this, caller, new ");
+ js.appendIsRequired(false);
+ js.append(" ");
+ js.appendClassReference(Object.class);
+ js.append("[]{");
+ isFirst = true;
+ for (@NonNull CGParameter cgParameter : cgParameters) {
+ if (!isFirst) {
+ js.append(", ");
+ }
+ js.appendValueName(cgParameter);
+ isFirst = false;
+ }
+ js.append("});\n");
+ js.popIndentation();
+ js.append("}\n");
+ }
+
protected boolean doClassMethods(@NonNull CGClass cgClass, boolean needsBlankLine) {
for (CGOperation cgOperation : cgClass.getOperations()) {
if (needsBlankLine) {
@@ -2149,9 +2157,9 @@
js.append("\n");
js.append("{\n");
js.pushIndentation(null);
- doCachedOperationEvaluate(cgOperation);
- js.append("\n");
doCachedOperationBasicEvaluate(cgOperation);
+ js.append("\n");
+ doCachedOperationEvaluate(cgOperation);
js.popIndentation();
js.append("}\n");
//