Fix NPE when parsing deviation from submodule 84/103284/1
authorRuslan Kashapov <ruslan.kashapov@pantheon.tech>
Tue, 15 Nov 2022 15:41:31 +0000 (17:41 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 16 Nov 2022 21:01:43 +0000 (22:01 +0100)
If the deviation statement is used in a submodule, we need to lookup up
the corresponding module, otherwise we will not find the correct
namespace.

JIRA: YANGTOOLS-1448
Change-Id: Iaf2e1d6526a9f268a6c0a3835e1bfdfafa05fffe
Signed-off-by: Ruslan Kashapov <ruslan.kashapov@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit 274de5b85ab4626c0ba6f79c38e8dd2e5b0eddcb)
(cherry picked from commit 049a6ac5bbc8d535a15bcad8c6fc879e2c533881)

parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/meta/DeviationStatementSupport.java
parser/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/YT1448Test.java [new file with mode: 0644]
parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/invalid/foo-submodule.yang [new file with mode: 0644]
parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/invalid/foo.yang [new file with mode: 0644]
parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/valid/bar.yang [new file with mode: 0644]
parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/valid/foo-submodule.yang [new file with mode: 0644]
parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/valid/foo.yang [new file with mode: 0644]

index efc4f30e4f4545f538fd298b622d31f78048cbe7..8526ca040cf36a07ac3496c122441275627f225d 100644 (file)
@@ -7,9 +7,10 @@
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.meta;
 
+import static com.google.common.base.Verify.verifyNotNull;
+
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
-import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
@@ -17,6 +18,7 @@ import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DeviationEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DeviationStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatementDecorators;
 import org.opendaylight.yangtools.yang.model.ri.stmt.DeclaredStatements;
 import org.opendaylight.yangtools.yang.model.ri.stmt.EffectiveStatements;
@@ -29,6 +31,7 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
+import org.opendaylight.yangtools.yang.parser.spi.source.BelongsToPrefixToModuleCtx;
 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
 
 public final class DeviationStatementSupport
@@ -53,9 +56,17 @@ public final class DeviationStatementSupport
     public void onFullDefinitionDeclared(final Mutable<Absolute, DeviationStatement, DeviationEffectiveStatement> ctx) {
         super.onFullDefinitionDeclared(ctx);
 
-        final QNameModule currentModule = ctx.getFromNamespace(ModuleCtxToModuleQName.class, ctx.getRoot());
-        final QNameModule targetModule = Iterables.getLast(ctx.getArgument().getNodeIdentifiers()).getModule();
+        StmtContext<?, ?, ?> root = ctx.getRoot();
+        if (root.producesDeclared(SubmoduleStatement.class)) {
+            // root is submodule, we need to find the module we belong to. We can rely on there being exactly one
+            // belongs-to statement, enforced SubmoduleStatementSupport's validator.
+            root = Iterables.getOnlyElement(
+                root.getAllFromNamespace(BelongsToPrefixToModuleCtx.class).values());
+        }
 
+        final var currentModule = verifyNotNull(ctx.getFromNamespace(ModuleCtxToModuleQName.class, root),
+            "Failed to find QName for %s", root);
+        final var targetModule = Iterables.getLast(ctx.getArgument().getNodeIdentifiers()).getModule();
         if (currentModule.equals(targetModule)) {
             throw new InferenceException(ctx,
                     "Deviation must not target the same module as the one it is defined in: %s", currentModule);
diff --git a/parser/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/YT1448Test.java b/parser/yang-parser-rfc7950/src/test/java/org/opendaylight/yangtools/yang/stmt/YT1448Test.java
new file mode 100644 (file)
index 0000000..404b46c
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022 PANTHEON.tech s.r.o. 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.yangtools.yang.stmt;
+
+import static org.hamcrest.CoreMatchers.startsWith;
+
+import org.junit.Test;
+
+public class YT1448Test extends AbstractYangTest {
+
+    @Test
+    public void deviationFromSubmodule() {
+        assertEffectiveModelDir("/bugs/YT1448/valid");
+    }
+
+    @Test
+    public void deviationFromSubmoduleTargetedOwnModule() {
+        assertInferenceExceptionDir("/bugs/YT1448/invalid",
+                startsWith("Deviation must not target the same module as the one it is defined in"));
+    }
+}
diff --git a/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/invalid/foo-submodule.yang b/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/invalid/foo-submodule.yang
new file mode 100644 (file)
index 0000000..3d8ac91
--- /dev/null
@@ -0,0 +1,13 @@
+submodule foo-submodule {
+  yang-version 1.1;
+
+  belongs-to foo {
+    prefix foo;
+  }
+
+  revision 2020-10-21;
+
+  deviation "/foo:object/foo:items/foo:boolean" {
+    deviate not-supported ;
+  }
+}
diff --git a/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/invalid/foo.yang b/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/invalid/foo.yang
new file mode 100644 (file)
index 0000000..c3cf60e
--- /dev/null
@@ -0,0 +1,25 @@
+module foo {
+  yang-version 1.1;
+  namespace "urn:test:foo";
+  prefix foo;
+
+  include foo-submodule;
+
+  revision 2022-02-22;
+
+  container object {
+    list items {
+      key "name";
+      leaf name {
+        type string;
+      }
+      leaf str {
+        type string;
+      }
+      leaf boolean {
+        type boolean;
+      }
+    }
+  }
+
+}
diff --git a/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/valid/bar.yang b/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/valid/bar.yang
new file mode 100644 (file)
index 0000000..23a192d
--- /dev/null
@@ -0,0 +1,22 @@
+module bar {
+  yang-version 1.1;
+  namespace "urn:test:bar";
+  prefix bar;
+
+  revision 2022-02-22;
+
+  container object {
+    list items {
+      key "name";
+      leaf name {
+        type string;
+      }
+      leaf str {
+        type string;
+      }
+      leaf boolean {
+        type boolean;
+      }
+    }
+  }
+}
diff --git a/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/valid/foo-submodule.yang b/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/valid/foo-submodule.yang
new file mode 100644 (file)
index 0000000..2ed4aa8
--- /dev/null
@@ -0,0 +1,17 @@
+submodule foo-submodule {
+  yang-version 1.1;
+
+  belongs-to foo {
+    prefix foo;
+  }
+
+  import bar {
+    prefix bar;
+  }
+
+  revision 2020-10-21;
+
+  deviation "/bar:object/bar:items/bar:boolean" {
+    deviate not-supported ;
+  }
+}
diff --git a/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/valid/foo.yang b/parser/yang-parser-rfc7950/src/test/resources/bugs/YT1448/valid/foo.yang
new file mode 100644 (file)
index 0000000..a29b6d7
--- /dev/null
@@ -0,0 +1,19 @@
+module foo {
+  yang-version 1.1;
+  namespace "urn:test:foo";
+  prefix foo;
+
+  include foo-submodule;
+
+  revision 2022-02-22;
+
+  container object {
+    list items {
+      key "name";
+      leaf name {
+        type string;
+      }
+    }
+  }
+
+}