diff --git a/.gitignore b/.gitignore index 378350451..e8b7dfc37 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ plugin.xml_gen .checkstyle .classpath rosetta-profiling/dependency-reduced-pom.xml +rosetta-profiling/reports/ **/.settings **/src-gen/ diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/DeepPathUtilGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/DeepPathUtilGenerator.xtend index 70ea93b0e..5a386c5f1 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/DeepPathUtilGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/DeepPathUtilGenerator.xtend @@ -99,6 +99,7 @@ class DeepPathUtilGenerator { } private def JavaStatementBuilder deepFeatureToStatement(Data choiceType, JavaVariable inputParameter, Attribute deepFeature, Map> recursiveDeepFeaturesMap, JavaScope scope) { + val deepFeatureHasMeta = !deepFeature.metaAnnotations.empty val attrs = choiceType.allNonOverridesAttributes val receiverType = new RDataType(choiceType) var JavaStatementBuilder acc = JavaExpression.NULL @@ -122,13 +123,13 @@ class DeepPathUtilGenerator { } else { (attrType as RDataType).data.allNonOverridesAttributes.findFirst[name.equals(deepFeature.name)] } - attrVar.featureCall(attrType, actualFeature, needsToGoDownDeeper, scope, true) + attrVar.featureCall(attrType, actualFeature, needsToGoDownDeeper, scope, !deepFeatureHasMeta) } new JavaIfThenElseBuilder(it, deepFeatureExpr, currAcc, typeUtil) ] ] } - val resultType = deepFeature.toExpandedAttribute.toMultiRegularJavaType + val resultType = deepFeature.toExpandedAttribute.toMultiMetaOrRegularJavaType acc.addCoercions(resultType, scope) } } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/ExpressionGenerator.xtend b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/ExpressionGenerator.xtend index 7acb96649..be9a5a406 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/ExpressionGenerator.xtend +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/generator/java/expression/ExpressionGenerator.xtend @@ -100,6 +100,7 @@ import org.eclipse.xtend2.lib.StringConcatenationClient import org.eclipse.xtext.EcoreUtil2 import static extension com.regnosys.rosetta.generator.java.enums.EnumHelper.convertValues +import static extension com.regnosys.rosetta.generator.util.RosettaAttributeExtensions.* import com.regnosys.rosetta.types.RObjectFactory import javax.inject.Inject import com.regnosys.rosetta.rosetta.expression.RosettaConstructorExpression @@ -128,7 +129,6 @@ import java.time.ZonedDateTime import com.regnosys.rosetta.rosetta.expression.RosettaDeepFeatureCall import com.regnosys.rosetta.rosetta.expression.DefaultOperation import com.regnosys.rosetta.generator.java.statement.builder.JavaConditionalExpression -import com.regnosys.rosetta.rosetta.RosettaSymbol class ExpressionGenerator extends RosettaExpressionSwitch { @@ -278,7 +278,11 @@ class ExpressionGenerator extends RosettaExpressionSwitchmap("«feature.name.toFirstUpper»", «recordUtil.recordFeatureToLambda(receiverType as RRecordType, feature, scope)»)''' + '''.<«resultItemType»>map("«feature.name.toFirstUpper»", «recordUtil.recordFeatureToLambda(receiverType as RRecordType, feature, scope)»)''' default: throw new UnsupportedOperationException("Unsupported feature type of " + feature?.class?.name) } @@ -411,7 +415,7 @@ class ExpressionGenerator extends RosettaExpressionSwitch currency -> scheme val feature = if (receiver instanceof RosettaFeatureCall) { receiver.feature + } else if (receiver instanceof RosettaDeepFeatureCall) { + receiver.feature } else if (receiver instanceof RosettaSymbolReference) { receiver.symbol } diff --git a/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/DeepFeatureCallUtil.java b/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/DeepFeatureCallUtil.java index 33ea481af..f865e9fb6 100644 --- a/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/DeepFeatureCallUtil.java +++ b/rosetta-lang/src/main/java/com/regnosys/rosetta/utils/DeepFeatureCallUtil.java @@ -1,21 +1,15 @@ package com.regnosys.rosetta.utils; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; import javax.inject.Inject; +import com.google.common.collect.Iterables; import com.regnosys.rosetta.RosettaExtensions; import com.regnosys.rosetta.rosetta.RosettaCardinality; import com.regnosys.rosetta.rosetta.expression.OneOfOperation; -import com.regnosys.rosetta.rosetta.expression.RosettaDeepFeatureCall; import com.regnosys.rosetta.rosetta.expression.RosettaExpression; import com.regnosys.rosetta.rosetta.expression.RosettaImplicitVariable; import com.regnosys.rosetta.rosetta.simple.Attribute; @@ -27,9 +21,7 @@ public class DeepFeatureCallUtil { private final RosettaTypeProvider typeProvider; - private final CardinalityProvider cardinalityProvider; - private final RosettaExtensions ext; @Inject @@ -78,23 +70,13 @@ public Map findDeepFeatureMap(RDataType type) { return result; } private void intersect(Map featuresMapToModify, Map otherFeatureMap) { - featuresMapToModify.entrySet().removeIf(entry -> { - String attrName = entry.getKey(); - Attribute otherAttr = otherFeatureMap.get(attrName); - if (otherAttr != null) { - Attribute attr = entry.getValue(); - if (match(attr, otherAttr)) { - return false; - } - } - return true; - }); + intersectButRetainAttribute(featuresMapToModify, otherFeatureMap, null); } private void intersectButRetainAttribute(Map featuresMapToModify, Map otherFeatureMap, Attribute attributeToRetain) { featuresMapToModify.entrySet().removeIf(entry -> { String attrName = entry.getKey(); Attribute attr = entry.getValue(); - if (attributeToRetain.equals(attr)) { + if (attr.equals(attributeToRetain)) { return false; } Attribute otherAttr = otherFeatureMap.get(attrName); @@ -105,6 +87,15 @@ private void intersectButRetainAttribute(Map featuresMapToMod } return true; }); + // Make sure we don't give back an attribute with metadata if not all of them have it. + for (Map.Entry e : featuresMapToModify.entrySet()) { + String name = e.getKey(); + Attribute currFeature = e.getValue(); + Attribute otherFeature = otherFeatureMap.get(name); + if (otherFeature != null && !Iterables.isEmpty(ext.metaAnnotations(currFeature)) && Iterables.isEmpty(ext.metaAnnotations(otherFeature))) { + e.setValue(otherFeature); + } + } } private void merge(Map featuresMapToModify, Map otherFeatureMap) { otherFeatureMap.forEach((name, attr) -> { @@ -112,6 +103,9 @@ private void merge(Map featuresMapToModify, Map> id + a ->> id -> scheme '''.generateCode val classes = code.compileToClasses @@ -203,7 +203,7 @@ class FunctionGeneratorTest { }) }) - assertEquals("abc123", test.invokeFunc(String, #[aB])) + assertEquals("myScheme", test.invokeFunc(String, #[aB])) } @Test diff --git a/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaValidatorTest.xtend b/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaValidatorTest.xtend index 01b81579f..ee3912003 100644 --- a/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaValidatorTest.xtend +++ b/rosetta-testing/src/test/java/com/regnosys/rosetta/validation/RosettaValidatorTest.xtend @@ -32,7 +32,32 @@ class RosettaValidatorTest implements RosettaIssueCodes { @Inject extension ExpressionParser @Test - def void testCannotAccessMetaFeatureAfterDeepFeatureCall() { + def void testCannotAccessUncommonMetaFeatureOfDeepFeatureCall() { + val model = ''' + type A: + a string (1..1) + [metadata scheme] + + type B: + a string (1..1) + + type C: + a string (1..1) + [metadata scheme] + + choice ABC: + A + B + C + '''.parseRosettaWithNoIssues + + "abc ->> a -> scheme" + .parseExpression(#[model], #["abc ABC (1..1)"]) + .assertError(ROSETTA_FEATURE_CALL, Diagnostic.LINKING_DIAGNOSTIC, "Couldn't resolve reference to RosettaFeature 'scheme'.") + } + + @Test + def void testCanAccessMetaFeatureAfterDeepFeatureCall() { val context = ''' type A: b B (0..1) @@ -60,7 +85,7 @@ class RosettaValidatorTest implements RosettaIssueCodes { "a ->> id -> scheme" .parseExpression(#[context], #["a A (1..1)"]) - .assertError(ROSETTA_FEATURE_CALL, Diagnostic.LINKING_DIAGNOSTIC, "Couldn't resolve reference to RosettaFeature 'scheme'.") + .assertNoIssues } @Test