From: Robert Varga Date: Tue, 13 Jun 2023 14:57:25 +0000 (+0200) Subject: Fix code generation with leafrefs pointing to optional members X-Git-Tag: v12.0.0~73 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=756d61f430ee651a06adb69138d25b5a2a3648a7;p=mdsal.git Fix code generation with leafrefs pointing to optional members When we have a typedef which points to a location disabled by if-feature, we need to accept this fact -- but do not allow that typedef to be referenced. JIRA: MDSAL-829 Change-Id: Ibde28faa2f96904dc16fcc6f5a922edc6bcffebb Signed-off-by: Robert Varga --- diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java index 3afca47a8a..7a5849c36c 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractTypeObjectGenerator.java @@ -372,11 +372,7 @@ abstract class AbstractTypeObjectGenerator, R .map(context::resolveIdentity) .collect(Collectors.toUnmodifiableList())); } else if (TypeDefinitions.LEAFREF.equals(arg)) { - final AbstractTypeObjectGenerator targetGenerator = context.resolveLeafref( - type.findFirstEffectiveSubstatementArgument(PathEffectiveStatement.class).orElseThrow()); - checkArgument(targetGenerator != this, "Effective model contains self-referencing leaf %s", - statement().argument()); - refType = TypeReference.leafRef(targetGenerator); + refType = resolveLeafref(context); } else if (TypeDefinitions.UNION.equals(arg)) { unionDependencies = new UnionDependencies(type, context); LOG.trace("Resolved union {} to dependencies {}", type, unionDependencies); @@ -391,6 +387,20 @@ abstract class AbstractTypeObjectGenerator, R LOG.trace("Resolved derived {} to generator {}", type, refType); } + private @NonNull TypeReference resolveLeafref(final GeneratorContext context) { + final AbstractTypeObjectGenerator targetGenerator; + try { + targetGenerator = context.resolveLeafref( + type.findFirstEffectiveSubstatementArgument(PathEffectiveStatement.class).orElseThrow()); + } catch (IllegalArgumentException e) { + return TypeReference.leafRef(e); + } + + checkArgument(targetGenerator != this, "Effective model contains self-referencing leaf %s", + statement().argument()); + return TypeReference.leafRef(targetGenerator); + } + private static boolean isBuiltinName(final QName typeName) { return YangConstants.RFC6020_YANG_MODULE.equals(typeName.getModule()); } diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypeReference.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypeReference.java index cde69a941a..bbd30ec9db 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypeReference.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypeReference.java @@ -15,7 +15,7 @@ import org.eclipse.jdt.annotation.Nullable; import org.opendaylight.mdsal.binding.model.api.Type; import org.opendaylight.mdsal.binding.model.ri.Types; -abstract class TypeReference { +abstract sealed class TypeReference { private static final class Identityref extends TypeReference { private final List referencedGenerators; @@ -43,7 +43,7 @@ abstract class TypeReference { } // Note: this is exposed only for legacy naming handling - abstract static class Leafref extends TypeReference { + abstract static sealed class Leafref extends TypeReference { private Leafref() { // Hidden on purpose } @@ -75,10 +75,27 @@ abstract class TypeReference { } } + private static final class FailedLeafref extends Leafref { + private final IllegalArgumentException cause; + + FailedLeafref(final IllegalArgumentException cause) { + this.cause = requireNonNull(cause); + } + + @Override + Type methodReturnType(final TypeBuilderFactory builderFactory) { + throw new UnsupportedOperationException("Cannot ascertain type", cause); + } + } + static @NonNull TypeReference leafRef(final @Nullable AbstractTypeObjectGenerator referencedGenerator) { return referencedGenerator == null ? UnresolvedLeafref.INSTANCE : new ResolvedLeafref(referencedGenerator); } + static @NonNull TypeReference leafRef(final @NonNull IllegalArgumentException cause) { + return new FailedLeafref(cause); + } + static @NonNull TypeReference identityRef(final List referencedGenerators) { return new Identityref(referencedGenerators); } diff --git a/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Bug4621Test.java b/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Bug4621Test.java index 4572f4dc9c..a452211133 100644 --- a/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Bug4621Test.java +++ b/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Bug4621Test.java @@ -7,19 +7,23 @@ */ package org.opendaylight.mdsal.binding.generator.impl; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThrows; import org.junit.Test; -import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; public class Bug4621Test { @Test public void testMissingLeafrefTarget() { - final EffectiveModelContext context = YangParserTestUtils.parseYangResource("/bug4621.yang"); - final IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, + final var context = YangParserTestUtils.parseYangResource("/bug4621.yang"); + final var uoe = assertThrows(UnsupportedOperationException.class, () -> DefaultBindingGenerator.generateFor(context)); - assertEquals("Failed to find leafref target /foo:neighbor/foo:mystring1", ex.getMessage()); + assertEquals("Cannot ascertain type", uoe.getMessage()); + final var cause = uoe.getCause(); + assertThat(cause, instanceOf(IllegalArgumentException.class)); + assertEquals("Failed to find leafref target /foo:neighbor/foo:mystring1", cause.getMessage()); } } \ No newline at end of file diff --git a/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/DefaultBindingGeneratorTest.java b/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/DefaultBindingGeneratorTest.java index d05186818d..dae49bfa42 100644 --- a/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/DefaultBindingGeneratorTest.java +++ b/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/DefaultBindingGeneratorTest.java @@ -213,7 +213,12 @@ public class DefaultBindingGeneratorTest { @Test public void javaTypeForSchemaDefinitionInvalidLeafrefPathTest() { final var ctx = YangParserTestUtils.parseYangResource("/unresolvable-leafref.yang"); - final var ex = assertThrows(IllegalArgumentException.class, () -> DefaultBindingGenerator.generateFor(ctx)); + + final var uoe = assertThrows(UnsupportedOperationException.class, + () -> DefaultBindingGenerator.generateFor(ctx)); + assertEquals("Cannot ascertain type", uoe.getMessage()); + final var ex = uoe.getCause(); + assertThat(ex, instanceOf(IllegalArgumentException.class)); assertEquals("Failed to find leafref target /somewhere/i/belong", ex.getMessage()); final var cause = ex.getCause(); assertThat(cause, instanceOf(IllegalArgumentException.class)); diff --git a/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/GeneratedTypesLeafrefTest.java b/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/GeneratedTypesLeafrefTest.java index e0175d363e..3d9bbd01f9 100644 --- a/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/GeneratedTypesLeafrefTest.java +++ b/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/GeneratedTypesLeafrefTest.java @@ -8,6 +8,7 @@ package org.opendaylight.mdsal.binding.generator.impl; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -22,7 +23,6 @@ import org.opendaylight.mdsal.binding.model.api.GeneratedType; import org.opendaylight.mdsal.binding.model.api.MethodSignature; import org.opendaylight.mdsal.binding.model.api.Type; import org.opendaylight.yangtools.yang.binding.contract.Naming; -import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; public class GeneratedTypesLeafrefTest { @@ -212,12 +212,15 @@ public class GeneratedTypesLeafrefTest { @Test public void testLeafrefInvalidPathResolving() { - final EffectiveModelContext context = YangParserTestUtils.parseYangResource( + final var context = YangParserTestUtils.parseYangResource( "/leafref-test-invalid-model/foo.yang"); assertEquals(1, context.getModules().size()); - IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, + final var uoe = assertThrows(UnsupportedOperationException.class, () -> DefaultBindingGenerator.generateFor(context)); - assertThat(ex.getMessage(), containsString("Failed to find leafref target")); + assertEquals("Cannot ascertain type", uoe.getMessage()); + final var cause = uoe.getCause(); + assertThat(cause, instanceOf(IllegalArgumentException.class)); + assertThat(cause.getMessage(), containsString("Failed to find leafref target")); } } \ No newline at end of file diff --git a/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal829Test.java b/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal829Test.java new file mode 100644 index 0000000000..9c77304381 --- /dev/null +++ b/binding/mdsal-binding-generator/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal829Test.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 PANTHEON.tech, s.r.o. 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 + */ +package org.opendaylight.mdsal.binding.generator.impl; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; + +import java.util.Set; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opendaylight.mdsal.binding.model.api.JavaTypeName; +import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; + +public class Mdsal829Test { + private static EffectiveModelContext CONTEXT; + + @BeforeClass + public static void beforeClass() { + CONTEXT = YangParserTestUtils.parseYangResource("/mdsal829.yang", Set.of()); + } + + @Test + public void testCompileTimeTypes() { + assertEquals(1, DefaultBindingGenerator.generateFor(CONTEXT).size()); + } + + @Test + public void testRunTimeTypes() { + final var types = BindingRuntimeTypesFactory.createTypes(CONTEXT); + assertSame(CONTEXT, types.getEffectiveModelContext()); + final var schema = types.findSchema( + JavaTypeName.create("org.opendaylight.yang.gen.v1.mdsal829.norev", "Mdsal829Data")).orElseThrow(); + assertNotNull(schema); + } +} diff --git a/binding/mdsal-binding-generator/src/test/resources/mdsal829.yang b/binding/mdsal-binding-generator/src/test/resources/mdsal829.yang new file mode 100644 index 0000000000..f8831276d4 --- /dev/null +++ b/binding/mdsal-binding-generator/src/test/resources/mdsal829.yang @@ -0,0 +1,17 @@ +module mdsal829 { + namespace mdsal829; + prefix mdsal829; + + feature feat; + + typedef foo { + type leafref { + path /mdsal829:bar; + } + } + + leaf bar { + if-feature feat; + type string; + } +}