Do not access TypeNamespace during declared build 71/94071/1
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 5 Dec 2020 13:27:37 +0000 (14:27 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sat, 5 Dec 2020 13:28:46 +0000 (14:28 +0100)
We have a shadowing check here which is being executed at
buildDeclared() time. Move the check into an inference action,
so that we do not even go to statement build if it is violated.

JIRA: YANGTOOLS-1198
Change-Id: Ibb5d121862bc2d822c5919a3233ae790412e53f4
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/typedef/TypedefStatementSupport.java

index 2f534f9b38f4d8aaea61d3d701861d575bf266af..3eb0ccddeda6fa2f63e59ddb231035f5f63dc15d 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.typedef;
 import static com.google.common.base.Preconditions.checkState;
 
 import com.google.common.collect.ImmutableList;
+import java.util.Collection;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
@@ -25,6 +26,11 @@ import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStatementMix
 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.EffectiveStmtUtils;
 import org.opendaylight.yangtools.yang.parser.spi.TypeNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prerequisite;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
 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.StmtContextUtils;
@@ -61,13 +67,32 @@ public final class TypedefStatementSupport extends
     public void onFullDefinitionDeclared(final Mutable<QName, TypedefStatement, TypedefEffectiveStatement> stmt) {
         super.onFullDefinitionDeclared(stmt);
 
-        if (stmt != null) {
-            final Mutable<?, ?, ?> parent = stmt.getParentContext();
-            if (parent != null) {
-                // Shadowing check: make sure we do not trample on pre-existing definitions. This catches sibling
-                // declarations and parent declarations which have already been declared.
-                checkConflict(parent, stmt);
-                parent.addContext(TypeNamespace.class, stmt.getArgument(), stmt);
+        final Mutable<?, ?, ?> parent = stmt.getParentContext();
+        if (parent != null) {
+            // Shadowing check: make sure we do not trample on pre-existing definitions. This catches sibling
+            // declarations and parent declarations which have already been declared.
+            checkConflict(parent, stmt);
+            parent.addContext(TypeNamespace.class, stmt.getArgument(), stmt);
+
+            final StmtContext<?, ?, ?> grandParent = parent.getParentContext();
+            if (grandParent != null) {
+                // Shadowing check: make sure grandparent does not see a conflicting definition. This is required to
+                // ensure that a typedef in child scope does not shadow a typedef in parent scope which occurs later in
+                // the text. For that check we need the full declaration of our model.
+
+                final ModelActionBuilder action = stmt.newInferenceAction(ModelProcessingPhase.FULL_DECLARATION);
+                action.requiresCtx(grandParent.getRoot(), ModelProcessingPhase.FULL_DECLARATION);
+                action.apply(new InferenceAction() {
+                    @Override
+                    public void apply(final InferenceContext ctx) {
+                        checkConflict(grandParent, stmt);
+                    }
+
+                    @Override
+                    public void prerequisiteFailed(final Collection<? extends Prerequisite<?>> failed) {
+                        // No-op
+                    }
+                });
             }
         }
     }
@@ -80,13 +105,11 @@ public final class TypedefStatementSupport extends
     @Override
     protected TypedefStatement createDeclared(final StmtContext<QName, TypedefStatement, ?> ctx,
             final ImmutableList<? extends DeclaredStatement<?>> substatements) {
-        checkDeclared(ctx);
         return new RegularTypedefStatement(ctx.getArgument(), substatements);
     }
 
     @Override
     protected TypedefStatement createEmptyDeclared(final StmtContext<QName, TypedefStatement, ?> ctx) {
-        checkDeclared(ctx);
         return new EmptyTypedefStatement(ctx.getArgument());
     }
 
@@ -114,18 +137,6 @@ public final class TypedefStatementSupport extends
         SourceException.throwIf(existing != null, stmt, "Duplicate name for typedef %s", arg);
     }
 
-    private static void checkDeclared(final StmtContext<QName, TypedefStatement, ?> ctx) {
-        // Shadowing check: make sure grandparent does not see a conflicting definition. This is required to ensure
-        // that a typedef in child scope does not shadow a typedef in parent scope which occurs later in the text.
-        final StmtContext<?, ?, ?> parent = ctx.getParentContext();
-        if (parent != null) {
-            final StmtContext<?, ?, ?> grandParent = parent.getParentContext();
-            if (grandParent != null) {
-                checkConflict(grandParent, ctx);
-            }
-        }
-    }
-
     private static int computeFlags(final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
         return new FlagsBuilder()
                 .setStatus(findFirstArgument(substatements, StatusEffectiveStatement.class, Status.CURRENT))