Use declared statements to resolve augments 51/100151/2
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 18 Mar 2022 18:37:28 +0000 (19:37 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Sat, 19 Mar 2022 10:30:39 +0000 (11:30 +0100)
When trying to map effective instantiated model back to our Generator
hierarchy we need to not get confused by namespaces. The simplest way
to do that is to pick out augmentations first -- as those are the only
ones what can actually differ in namespace. The rest can be taken care
of just based on localName, as we are dealing with
SchemaTreeEffectiveStatements.

In general we can make the connection by tracing back the path we have
taken towards the instantiation site when seeing an
AugmentEffectiveStatement and match it to the corresponding
AbstractAugmentGenerator. Normally we could do this via straight
comparison of AugmentEffectiveStatements, but unfortunately their
equality contract does not give us that.

The reason for that is that we reuse things across groupings, whereas
YANG parser creates separate instantiations -- hence this breaks down
with UsesAugmentGenerator. We deal with that by comparing the declared
view of the two statements -- and those are guaranteed to be unique.

JIRA: MDSAL-735
Change-Id: I4d8f0e50541b53620cc5b0a2170484e85e9cf717
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
15 files changed:
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractAugmentGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractCompositeGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AbstractExplicitGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AugmentResolver.java [new file with mode: 0644]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChildLookup.java [deleted file]
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChoiceGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/CompositeRuntimeTypeBuilder.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/IdentityGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/KeyGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/LeafGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/LeafListGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ModuleAugmentGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/OpaqueObjectGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/TypedefGenerator.java
binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/UsesAugmentGenerator.java

index d52d09632b0ace7f9401967a1b4611f5db1b165f..c25e6f867fb76accf8fc37c296569763271b150b 100644 (file)
@@ -11,13 +11,10 @@ import static com.google.common.base.Verify.verify;
 import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
-import com.google.common.collect.ImmutableList;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.binding.generator.impl.reactor.CollisionDomain.Member;
 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultAugmentRuntimeType;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
@@ -34,8 +31,6 @@ import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement.SchemaTreeNamespace;
-import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 
 /**
@@ -92,9 +87,7 @@ abstract class AbstractAugmentGenerator
         return otherIt.hasNext() ? -1 : 0;
     };
 
-    private SchemaTreeAwareEffectiveStatement<?, ?> targetStatement;
     private AbstractCompositeGenerator<?, ?> targetGen;
-    private Optional<AugmentRuntimeType> internalRuntimeType;
 
     AbstractAugmentGenerator(final AugmentEffectiveStatement statement, final AbstractCompositeGenerator<?, ?> parent) {
         super(statement, parent);
@@ -155,53 +148,23 @@ abstract class AbstractAugmentGenerator
         return builder.build();
     }
 
-    @NonNull List<CaseRuntimeType> augmentedCasesIn(final ChildLookup lookup, final ChoiceEffectiveStatement stmt) {
-        final var target = verifyNotNull(targetStatement);
-        if (!stmt.equals(target)) {
-            return List.of();
-        }
-
-        final var result = createBuilder(effectiveStatement(statement(), target))
-            .fillTypes(ChildLookup.of(target), this)
-            .getCaseChilden();
-        internalRuntimeType = Optional.empty();
-        return result;
+    boolean matchesInstantiated(final AugmentEffectiveStatement statement) {
+        return statement().equals(statement);
     }
 
-    @Nullable AugmentRuntimeType runtimeTypeIn(final ChildLookup lookup, final EffectiveStatement<?, ?> stmt) {
-        final var target = verifyNotNull(targetStatement);
-        if (!stmt.equals(target)) {
-            return null;
-        }
-        if (internalRuntimeType != null) {
-            return internalRuntimeType.orElseThrow();
-        }
-
-        final var result = verifyNotNull(createInternalRuntimeType(ChildLookup.of(target),
-            effectiveStatement(statement(), target)));
-        internalRuntimeType = Optional.of(result);
-        return result;
+    final void fillRuntimeCasesIn(final AugmentResolver resolver, final ChoiceEffectiveStatement stmt,
+            final List<CaseRuntimeType> toList) {
+        toList.addAll(createBuilder(effectiveIn(stmt)).populate(resolver, this).getCaseChilden());
     }
 
-    private static @NonNull AugmentEffectiveStatement effectiveStatement(final AugmentEffectiveStatement augment,
-            final SchemaTreeAwareEffectiveStatement<?, ?> target) {
-        final var stmts = augment.effectiveSubstatements();
-        final var builder = ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(stmts.size());
-        for (var child : stmts) {
-            if (child instanceof SchemaTreeEffectiveStatement) {
-                final var qname = ((SchemaTreeEffectiveStatement<?>) child).getIdentifier();
-                // FIXME: orElseThrow()?
-                target.get(SchemaTreeNamespace.class, qname).ifPresent(builder::add);
-            } else {
-                builder.add(child);
-            }
-        }
-        return new TargetAugmentEffectiveStatement(augment, target, builder.build());
+    final @NonNull AugmentRuntimeType runtimeTypeIn(final AugmentResolver resolver,
+            final EffectiveStatement<?, ?> stmt) {
+        verify(stmt instanceof SchemaTreeAwareEffectiveStatement, "Unexpected target statement %s", stmt);
+        return verifyNotNull(createInternalRuntimeType(resolver,
+            effectiveIn((SchemaTreeAwareEffectiveStatement<?, ?>) stmt)));
     }
 
-    final @Nullable AugmentRuntimeType getInternalRuntimeType() {
-        return verifyNotNull(internalRuntimeType, "Internal runtime not resolved in %s", this).orElse(null);
-    }
+    abstract @NonNull TargetAugmentEffectiveStatement effectiveIn(SchemaTreeAwareEffectiveStatement<?, ?> target);
 
     @Override
     final void addAsGetterMethod(final GeneratedTypeBuilderBase<?> builder, final TypeBuilderFactory builderFactory) {
@@ -230,10 +193,4 @@ abstract class AbstractAugmentGenerator
     final @NonNull AbstractCompositeGenerator<?, ?> targetGenerator() {
         return verifyNotNull(targetGen, "No target for %s", this);
     }
-
-    final void setTargetStatement(final EffectiveStatement<?, ?> targetStatement) {
-        verify(targetStatement instanceof SchemaTreeAwareEffectiveStatement, "Unexpected target statement %s",
-            targetStatement);
-        this.targetStatement = (SchemaTreeAwareEffectiveStatement<?, ?>) targetStatement;
-    }
 }
index 769830433f7ff6ebd94c6e29b5ef573818c9cdbc..a675e036566d1aa9a2f92137981714cb0c46a99c 100644 (file)
@@ -176,22 +176,15 @@ public abstract class AbstractCompositeGenerator<S extends EffectiveStatement<?,
     @Override
     final R createExternalRuntimeType(final Type type) {
         verify(type instanceof GeneratedType, "Unexpected type %s", type);
-
-        // FIXME: we should be able to use internal cache IFF when all augments end up being local to our statement
-        final var statement = statement();
-        return createBuilder(statement)
-            .fillTypes(ChildLookup.of(statement), this)
-            .build((GeneratedType) type);
+        return createBuilder(statement()).populate(new AugmentResolver(), this).build((GeneratedType) type);
     }
 
     abstract @NonNull CompositeRuntimeTypeBuilder<S, R> createBuilder(S statement);
 
     @Override
-    final R createInternalRuntimeType(final ChildLookup lookup, final S statement, final Type type) {
+    final R createInternalRuntimeType(final AugmentResolver resolver, final S statement, final Type type) {
         verify(type instanceof GeneratedType, "Unexpected type %s", type);
-        return createBuilder(statement)
-            .fillTypes(lookup.inStatement(statement), this)
-            .build((GeneratedType) type);
+        return createBuilder(statement).populate(resolver, this).build((GeneratedType) type);
     }
 
     @Override
index 5219378e39fdb1535008934212492f9cdf149410..39456cbbaab1575ac2f9222de8d7225bc618a1b8 100644 (file)
@@ -135,7 +135,7 @@ public abstract class AbstractExplicitGenerator<S extends EffectiveStatement<?,
      * @param stmt Statement for which to create the view
      * @return Internally-accessible RuntimeType, or {@code null} if not applicable
      */
-    final @Nullable R createInternalRuntimeType(final @NonNull ChildLookup lookup, final @NonNull S stmt) {
+    final @Nullable R createInternalRuntimeType(final @NonNull AugmentResolver resolver, final @NonNull S stmt) {
         // FIXME: cache requests: if we visited this statement, we obviously know what it entails. Note that we walk
         //        towards the original definition. As such, the cache may have to live in the generator we look up,
         //        but should operate on this statement to reflect lookups. This needs a bit of figuring out.
@@ -143,7 +143,7 @@ public abstract class AbstractExplicitGenerator<S extends EffectiveStatement<?,
         do {
             final var type = gen.runtimeJavaType();
             if (type != null) {
-                return createInternalRuntimeType(lookup, stmt, type);
+                return createInternalRuntimeType(resolver, stmt, type);
             }
 
             gen = gen.previous();
@@ -152,7 +152,7 @@ public abstract class AbstractExplicitGenerator<S extends EffectiveStatement<?,
         return null;
     }
 
-    abstract @NonNull R createInternalRuntimeType(@NonNull ChildLookup lookup, @NonNull S statement,
+    abstract @NonNull R createInternalRuntimeType(@NonNull AugmentResolver resolver, @NonNull S statement,
         @NonNull Type type);
 
     @Override
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AugmentResolver.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/AugmentResolver.java
new file mode 100644 (file)
index 0000000..db7f69f
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2022 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.reactor;
+
+import static java.util.Objects.requireNonNull;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.Mutable;
+import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
+
+/**
+ * Utility to resolve instantiated {@code augment} statements to their {@link AbstractAugmentGenerator} counterparts.
+ * This is essentially a stack of {@link AbstractCompositeGenerator}s which should be examined.
+ */
+final class AugmentResolver implements Mutable {
+    private final Deque<AbstractCompositeGenerator<?, ?>> stack = new ArrayDeque<>();
+
+    void enter(final AbstractCompositeGenerator<?, ?> generator) {
+        stack.push(requireNonNull(generator));
+    }
+
+    void exit() {
+        stack.pop();
+    }
+
+    @NonNull AbstractAugmentGenerator getAugment(final AugmentEffectiveStatement statement) {
+        for (var generator : stack) {
+            final var found = findAugment(generator, statement);
+            if (found != null) {
+                return found;
+            }
+        }
+        throw new IllegalStateException("Failed to resolve " + statement + " in " + stack);
+    }
+
+    private @Nullable AbstractAugmentGenerator findAugment(final AbstractCompositeGenerator<?, ?> generator,
+            final AugmentEffectiveStatement statement) {
+        for (var augment : generator.augments()) {
+            if (augment.matchesInstantiated(statement)) {
+                return augment;
+            }
+        }
+        for (var grouping : generator.groupings()) {
+            final var found = findAugment(grouping, statement);
+            if (found != null) {
+                return found;
+            }
+        }
+        return null;
+    }
+}
diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChildLookup.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/ChildLookup.java
deleted file mode 100644 (file)
index 083bf08..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (c) 2022 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.reactor;
-
-import static com.google.common.base.Verify.verify;
-import static com.google.common.base.Verify.verifyNotNull;
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.base.MoreObjects;
-import com.google.common.collect.ImmutableSet;
-import java.util.stream.Stream;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.concepts.Immutable;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.UsesEffectiveStatement;
-
-/**
- * Lookup context for dealing with namespace translation during execution of {@link AbstractCompositeGenerator}'s
- * createInternalRuntimeType(). It tracks which namespaces should be translated on account of crossing into source
- * {@code grouping} statement.
- */
-final class ChildLookup implements Immutable {
-    private final ImmutableSet<AugmentEffectiveStatement> validUsesAugments;
-    private final ImmutableSet<QNameModule> squashNamespaces;
-    private final QNameModule localNamespace;
-
-    private ChildLookup(final ImmutableSet<AugmentEffectiveStatement> validUsesAugments,
-            final ImmutableSet<QNameModule> squashNamespaces, final QNameModule localNamespace) {
-        this.validUsesAugments = requireNonNull(validUsesAugments);
-        this.squashNamespaces = requireNonNull(squashNamespaces);
-        this.localNamespace = localNamespace;
-        verify(localNamespace == null == squashNamespaces.isEmpty(), "Unexpected lookup state %s", this);
-    }
-
-    public static @NonNull ChildLookup of(final EffectiveStatement<?, ?> statement) {
-        return new ChildLookup(streamUsesAugments(statement).collect(ImmutableSet.toImmutableSet()), ImmutableSet.of(),
-            null);
-    }
-
-    @NonNull QName adjustQName(final @NonNull QName qname) {
-        return squashNamespaces.contains(qname.getModule()) ? qname.bindTo(verifyNotNull(localNamespace)) : qname;
-    }
-
-    boolean contains(final AugmentEffectiveStatement augment) {
-        return validUsesAugments.contains(augment);
-    }
-
-    @NonNull ChildLookup inStatement(final EffectiveStatement<?, ?> statememt) {
-        return hasUsesAugments(statememt)
-            ? new ChildLookup(concatUsesAugments(statememt), squashNamespaces, localNamespace) : this;
-    }
-
-    @NonNull ChildLookup inGrouping(final QName qname, final GroupingGenerator grouping) {
-        final var statement = grouping.statement();
-        final var grpNamespace = statement.argument().getModule();
-        final var itemNamespace = qname.getModule();
-
-        final ImmutableSet<QNameModule> newSquashNamespaces;
-        if (squashNamespaces.contains(itemNamespace)) {
-            newSquashNamespaces = squashNamespaces;
-        } else {
-            newSquashNamespaces = ImmutableSet.<QNameModule>builderWithExpectedSize(squashNamespaces.size() + 1)
-                .addAll(squashNamespaces).add(itemNamespace).build();
-        }
-
-        return new ChildLookup(hasUsesAugments(statement) ? concatUsesAugments(statement) : validUsesAugments,
-            newSquashNamespaces, grpNamespace);
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this).omitNullValues()
-            .add("augments", validUsesAugments)
-            .add("squash", squashNamespaces)
-            .add("local", localNamespace)
-            .toString();
-    }
-
-    private ImmutableSet<AugmentEffectiveStatement> concatUsesAugments(final EffectiveStatement<?, ?> stmt) {
-        final var concat = ImmutableSet.<AugmentEffectiveStatement>builder().addAll(validUsesAugments);
-        streamUsesAugments(stmt).forEach(concat::add);
-        return concat.build();
-    }
-
-    private static boolean hasUsesAugments(final EffectiveStatement<?, ?> stmt) {
-        return streamUsesAugments(stmt).findAny().isPresent();
-    }
-
-    private static Stream<AugmentEffectiveStatement> streamUsesAugments(final EffectiveStatement<?, ?> stmt) {
-        return stmt.streamEffectiveSubstatements(UsesEffectiveStatement.class)
-            .flatMap(uses -> uses.streamEffectiveSubstatements(AugmentEffectiveStatement.class));
-    }
-}
index 1b73a7d4d55be018dd55f98437c46d0770e0a535..f0290e4485522f9cfeb9be04c6e7f407baf5cc97 100644 (file)
@@ -9,7 +9,7 @@ package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
 import static com.google.common.base.Verify.verify;
 
-import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
 import java.util.List;
 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultChoiceRuntimeType;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
@@ -29,28 +29,25 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
  */
 final class ChoiceGenerator extends CompositeSchemaTreeGenerator<ChoiceEffectiveStatement, ChoiceRuntimeType> {
     static final class ChoiceBuilder extends CompositeRuntimeTypeBuilder<ChoiceEffectiveStatement, ChoiceRuntimeType> {
-        private ImmutableList<CaseRuntimeType> augmentedCases;
+        private final List<CaseRuntimeType> augmentedCases = new ArrayList<>();
 
         ChoiceBuilder(final ChoiceEffectiveStatement statement) {
             super(statement);
         }
 
         @Override
-        CompositeRuntimeTypeBuilder<ChoiceEffectiveStatement, ChoiceRuntimeType> fillTypes(
-                final ChildLookup lookup,
-                final AbstractCompositeGenerator<ChoiceEffectiveStatement, ChoiceRuntimeType> generator) {
-            fillAugmentedCases(lookup, generator.augments());
-            return super.fillTypes(lookup, generator);
+        void processAugment(final AugmentResolver resolver, final AbstractAugmentGenerator augment) {
+            augment.fillRuntimeCasesIn(resolver, statement(), augmentedCases);
         }
 
         @Override
-        boolean isAugmentedChild(final ChildLookup lookup, final QName qname) {
+        boolean isAugmentedChild(final QName qname) {
             for (var augmented : augmentedCases) {
                 if (qname.equals(augmented.statement().argument())) {
                     return true;
                 }
             }
-            return super.isAugmentedChild(lookup, qname);
+            return false;
         }
 
         @Override
@@ -60,14 +57,6 @@ final class ChoiceGenerator extends CompositeSchemaTreeGenerator<ChoiceEffective
             children.addAll(augmentedCases);
             return new DefaultChoiceRuntimeType(type, statement, children);
         }
-
-        private void fillAugmentedCases(final ChildLookup lookup, final List<AbstractAugmentGenerator> augments) {
-            final var builder = ImmutableList.<CaseRuntimeType>builder();
-            for (var augment : augments) {
-                builder.addAll(augment.augmentedCasesIn(lookup, statement()));
-            }
-            augmentedCases = builder.build();
-        }
     }
 
     ChoiceGenerator(final ChoiceEffectiveStatement statement, final AbstractCompositeGenerator<?, ?> parent) {
index 57af55851f2fd78581e2e03f00f73f42234a0113..763f04ab94e0e7ffd9527fa31d4bb981d3b81429 100644 (file)
@@ -15,7 +15,6 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
@@ -23,6 +22,8 @@ import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
 
 abstract class CompositeRuntimeTypeBuilder<S extends EffectiveStatement<?, ?>, R extends CompositeRuntimeType> {
@@ -34,10 +35,24 @@ abstract class CompositeRuntimeTypeBuilder<S extends EffectiveStatement<?, ?>, R
         this.statement = requireNonNull(statement);
     }
 
-    final @NonNull S statement() {
-        return statement;
+    final CompositeRuntimeTypeBuilder<S, R> populate(final AugmentResolver resolver,
+            final AbstractCompositeGenerator<S, R> generator) {
+        resolver.enter(generator);
+        try {
+            processGenerator(resolver, generator);
+        } finally {
+            resolver.exit();
+        }
+        return this;
+    }
+
+    final @NonNull R build(final @NonNull GeneratedType generatedType) {
+        return build(generatedType, statement, childTypes, augmentTypes);
     }
 
+    abstract @NonNull R build(GeneratedType type, S statement, List<RuntimeType> children,
+        List<AugmentRuntimeType> augments);
+
     final @NonNull List<CaseRuntimeType> getCaseChilden() {
         return childTypes.stream()
             .map(child -> {
@@ -47,27 +62,38 @@ abstract class CompositeRuntimeTypeBuilder<S extends EffectiveStatement<?, ?>, R
             .collect(Collectors.toUnmodifiableList());
     }
 
-    final @NonNull R build(final @NonNull GeneratedType generatedType) {
-        return build(generatedType, statement, childTypes, augmentTypes);
+    final @NonNull S statement() {
+        return statement;
     }
 
-    abstract @NonNull R build(GeneratedType type, S statement, List<RuntimeType> children,
-        List<AugmentRuntimeType> augments);
+    boolean isAugmentedChild(final QName qname) {
+        // Note we are dealing with two different kinds of augments and they behave differently with respect
+        // to namespaces. Top-level augments do not make an adjustment, while uses-augments do.
+        for (var augment : augmentTypes) {
+            if (augment.schemaTreeChild(qname) != null) {
+                return true;
+            }
+        }
+        return false;
+    }
 
-    CompositeRuntimeTypeBuilder<S, R> fillTypes(final ChildLookup lookup,
-            final AbstractCompositeGenerator<S, R> generator) {
+    void processAugment(final AugmentResolver resolver, final AbstractAugmentGenerator augment) {
+        augmentTypes.add(augment.runtimeTypeIn(resolver, statement));
+    }
+
+    private void processGenerator(final AugmentResolver resolver, final AbstractCompositeGenerator<S, R> generator) {
         // Figure out which augments are valid in target statement and record their RuntimeTypes.
         // We will pass the latter to create method. We will use the former to perform replacement lookups instead
         // of 'this.augments'. That is necessary because 'this.augments' holds all augments targeting the GeneratedType,
         // hence equivalent augmentations from differing places would match our lookup and the reverse search would be
         // lead astray.
         //
-        // Augments targeting 'choice' statement are handled by a separate class and need to be skipped here
-        if (!(generator instanceof ChoiceGenerator)) {
-            for (var augment : generator.augments()) {
-                final var augmentRuntimeType = augment.runtimeTypeIn(lookup, statement);
-                if (augmentRuntimeType != null) {
-                    augmentTypes.add(augmentRuntimeType);
+        // Note we should not do this for 'module' and 'uses' statements, as those are not valid augment targets. Of
+        // those two we only generate things for 'module'.
+        if (!(statement instanceof ModuleEffectiveStatement)) {
+            for (var stmt : statement.effectiveSubstatements()) {
+                if (stmt instanceof AugmentEffectiveStatement) {
+                    processAugment(resolver, resolver.getAugment((AugmentEffectiveStatement) stmt));
                 }
             }
         }
@@ -76,69 +102,51 @@ abstract class CompositeRuntimeTypeBuilder<S extends EffectiveStatement<?, ?>, R
         for (var stmt : statement.effectiveSubstatements()) {
             if (stmt instanceof SchemaTreeEffectiveStatement) {
                 final var child = (SchemaTreeEffectiveStatement<?>) stmt;
-                final var qname = child.getIdentifier();
 
                 // Try valid augments first: they should be empty most of the time and filter all the cases where we
                 // would not find the streamChild among our local and grouping statements. Note that unlike all others,
                 // such matches are not considered to be children in Binding DataObject tree, they are only considered
                 // such in the schema tree.
-                if (isAugmentedChild(lookup, qname)) {
-                    continue;
-                }
-
-                final var childRuntimeType = findChildRuntimeType(lookup, generator, child);
-                if (childRuntimeType != null) {
-                    childTypes.add(childRuntimeType);
-                }
-            }
-        }
-
-        return this;
-    }
-
-    @SuppressWarnings("unchecked")
-    final <X extends SchemaTreeEffectiveStatement<?>> @Nullable RuntimeType findChildRuntimeType(
-            final @NonNull ChildLookup lookup, final AbstractCompositeGenerator<?, ?> parent, final @NonNull X stmt) {
-        final var qname = stmt.getIdentifier();
-        // First try our local items without adjustment ...
-        @SuppressWarnings("rawtypes")
-        AbstractExplicitGenerator childGen = findChild(parent, qname);
-        if (childGen == null) {
-            // No luck, let's see if any of the groupings can find it
-            for (GroupingGenerator grouping : parent.groupings()) {
-                final var gen = grouping.findSchemaTreeGenerator(
-                    qname.bindTo(grouping.statement().argument().getModule()));
-                if (gen != null) {
-                    return findChildRuntimeType(lookup.inGrouping(qname, grouping), grouping, stmt);
+                //
+                // That is in general -- 'choice' statements are doing their own thing separately.
+                if (!isAugmentedChild(child.getIdentifier())) {
+                    final var childGen = verifyNotNull(findChildGenerator(generator, child.argument().getLocalName()),
+                        "Cannot find child for %s in %s", child, generator);
+                    final var childRuntimeType = childGen.createInternalRuntimeType(resolver, child);
+                    if (childRuntimeType != null) {
+                        childTypes.add(childRuntimeType);
+                    }
                 }
             }
-
-            // Finally attempt to find adjusted QName: this has to succeed
-            final var adjusted = lookup.adjustQName(qname);
-            childGen = verifyNotNull(findChild(parent, adjusted),
-                "Failed to find %s as %s in %s", stmt, adjusted, this);
         }
-
-        return childGen.createInternalRuntimeType(lookup, stmt);
     }
 
-    boolean isAugmentedChild(final ChildLookup lookup, final QName qname) {
-        // Note we are dealing with two different kinds of augments and they behave differently with respect
-        // to namespaces. Top-level augments do not make an adjustment, while uses-augments do.
-        return augmentTypes.stream().anyMatch(augment -> augment.schemaTreeChild(qname) != null);
-    }
-
-    private static @Nullable AbstractExplicitGenerator<?, ?> findChild(final AbstractCompositeGenerator<?, ?> parent,
-            final QName qname) {
+    // When we reach here we have dealt with all known augments in this scope, hence the only option is that the
+    // statement is either local or added via 'uses' -- in either case it has namespace equal to whatever the local
+    // namespace is and there can be no conflicts on QName.getLocalName(). That simplifies things a ton.
+    private static <S extends SchemaTreeEffectiveStatement<?>> AbstractExplicitGenerator<S, ?> findChildGenerator(
+            final AbstractCompositeGenerator<?, ?> parent, final String localName) {
+        // Search direct children first ...
         for (var child : parent) {
             if (child instanceof AbstractExplicitGenerator) {
-                final AbstractExplicitGenerator<?, ?> gen = (AbstractExplicitGenerator<?, ?>) child;
-                final EffectiveStatement<?, ?> stmt = gen.statement();
-                if (stmt instanceof SchemaTreeEffectiveStatement && qname.equals(stmt.argument())) {
+                @SuppressWarnings("unchecked")
+                final AbstractExplicitGenerator<S, ?> gen = (AbstractExplicitGenerator<S, ?>) child;
+                final EffectiveStatement<?, ?> genStmt = gen.statement();
+                if (genStmt instanceof SchemaTreeEffectiveStatement
+                    && localName.equals(((SchemaTreeEffectiveStatement<?>) genStmt).argument().getLocalName())) {
                     return gen;
                 }
             }
         }
+
+        // ... and groupings recursively last
+        for (var grouping : parent.groupings()) {
+            final AbstractExplicitGenerator<S, ?> found = findChildGenerator(grouping, localName);
+            if (found != null) {
+                return found;
+            }
+        }
+
         return null;
     }
 }
index ccd88efc57a6b49cc249e194e50f0fc76e315edf..95e7db5dabf26ebb8743a6324ea51dc3e4cb59f2 100644 (file)
@@ -84,8 +84,8 @@ public final class IdentityGenerator
     }
 
     @Override
-    IdentityRuntimeType createInternalRuntimeType(final ChildLookup lookup, final IdentityEffectiveStatement statement,
-            final Type type) {
+    IdentityRuntimeType createInternalRuntimeType(final AugmentResolver resolver,
+            final IdentityEffectiveStatement statement, final Type type) {
         // 'identity' statements are not part of schema tree and hence should never an internal reference
         throw new UnsupportedOperationException("Should never be called");
     }
index a45c1dcb35c8d74f920b9135e2af0271a4c02363..d1c59d5e65e0aba3bf0137845a73325d935b9c7b 100644 (file)
@@ -89,7 +89,7 @@ final class KeyGenerator extends AbstractExplicitGenerator<KeyEffectiveStatement
     }
 
     @Override
-    KeyRuntimeType createInternalRuntimeType(final ChildLookup lookup,final KeyEffectiveStatement statement,
+    KeyRuntimeType createInternalRuntimeType(final AugmentResolver resolver, final KeyEffectiveStatement statement,
             final Type type) {
         // The only reference to this runtime type is from ListGenerator which is always referencing the external type
         throw new UnsupportedOperationException("Should never be called");
index 233b785917f4b725c52fb64acbc78f526555efc4..6cdc66ea72f8eff534b0f3646c48ec5024c12d72 100644 (file)
@@ -26,7 +26,7 @@ final class LeafGenerator extends AbstractTypeAwareGenerator<LeafEffectiveStatem
     }
 
     @Override
-    LeafRuntimeType createInternalRuntimeType(final ChildLookup lookup, final LeafEffectiveStatement statement,
+    LeafRuntimeType createInternalRuntimeType(final AugmentResolver resolver, final LeafEffectiveStatement statement,
             final Type type) {
         return new DefaultLeafRuntimeType(type, statement);
     }
index aa6263a192696b724237e364020118151b64c883..a399972c8f825fb7ea5ba86898d98877560b0541 100644 (file)
@@ -42,8 +42,8 @@ final class LeafListGenerator
     }
 
     @Override
-    LeafListRuntimeType createInternalRuntimeType(final ChildLookup lookup, final LeafListEffectiveStatement statement,
-            final Type type) {
+    LeafListRuntimeType createInternalRuntimeType(final AugmentResolver resolver,
+            final LeafListEffectiveStatement statement, final Type type) {
         return new DefaultLeafListRuntimeType(type, statement);
     }
 }
index a04587e005be386c26d4c68c222becfe5dc87ff4..bf6964ec249035444bc48ebf3a0483389bf2d48a 100644 (file)
@@ -7,9 +7,13 @@
  */
 package org.opendaylight.mdsal.binding.generator.impl.reactor;
 
+import com.google.common.collect.ImmutableList;
 import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement.SchemaTreeNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
 
 /**
  * Generator corresponding to a {@code augment} statement used as a child of a {@code module} statement.
@@ -19,10 +23,24 @@ final class ModuleAugmentGenerator extends AbstractAugmentGenerator {
         super(statement, parent);
     }
 
-    @NonNull AugmentRequirement startLinkage(final GeneratorContext context) {
-        setTargetStatement(SchemaInferenceStack.of(context.getEffectiveModelContext())
-            .enterSchemaTree(statement().argument()));
+    @Override
+    TargetAugmentEffectiveStatement effectiveIn(final SchemaTreeAwareEffectiveStatement<?, ?> target) {
+        final var augment = statement();
+        final var stmts = augment.effectiveSubstatements();
+        final var builder = ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(stmts.size());
+        for (var child : stmts) {
+            if (child instanceof SchemaTreeEffectiveStatement) {
+                final var qname = ((SchemaTreeEffectiveStatement<?>) child).getIdentifier();
+                // FIXME: orElseThrow()?
+                target.get(SchemaTreeNamespace.class, qname).ifPresent(builder::add);
+            } else {
+                builder.add(child);
+            }
+        }
+        return new TargetAugmentEffectiveStatement(augment, target, builder.build());
+    }
 
+    @NonNull AugmentRequirement startLinkage(final GeneratorContext context) {
         return new AugmentRequirement(this,
             context.resolveModule(statement().argument().firstNodeIdentifier().getModule()));
     }
index 2e7da2abbb7cb98a78ec4d4ff54ff7b5e1636dc8..ce10cd1877d9c7f0b7d3a6fef67420ed444abf6d 100644 (file)
@@ -110,7 +110,7 @@ abstract class OpaqueObjectGenerator<S extends DataTreeEffectiveStatement<?>, R
     abstract @NonNull R createExternalRuntimeType(@NonNull GeneratedType type);
 
     @Override
-    final R createInternalRuntimeType(final ChildLookup lookup, final S statement, final Type type) {
+    final R createInternalRuntimeType(final AugmentResolver resolver, final S statement, final Type type) {
         verify(type instanceof GeneratedType, "Unexpected type %s", type);
         return createInternalRuntimeType(statement, (GeneratedType) type);
     }
index e3cfd4d5949e3399ba2d3966a8361e1c185447bb..bcebb15b340c720666d3eacdc6d126e98d45d7ef 100644 (file)
@@ -101,8 +101,8 @@ final class TypedefGenerator extends AbstractTypeObjectGenerator<TypedefEffectiv
     }
 
     @Override
-    TypedefRuntimeType createInternalRuntimeType(final ChildLookup lookup, final TypedefEffectiveStatement statement,
-            final Type type) {
+    TypedefRuntimeType createInternalRuntimeType(final AugmentResolver resolver,
+            final TypedefEffectiveStatement statement, final Type type) {
         // 'typedef' statements are not schema tree statements, they should not have internal references
         throw new UnsupportedOperationException("Should never be called");
     }
index 06c841d430043cc75bb140b449ca06eeb101dd86..dbb1e10a0f83165ce1aeae7807a76d47bdf2e1ec 100644 (file)
@@ -12,13 +12,10 @@ import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.ImmutableList;
-import java.util.List;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement.SchemaTreeNamespace;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
@@ -36,17 +33,6 @@ final class UsesAugmentGenerator extends AbstractAugmentGenerator {
             final AbstractCompositeGenerator<?, ?> parent) {
         super(statement, parent);
         this.uses = requireNonNull(uses);
-
-        // FIXME: use SchemaTreeAwareEffectiveStatement
-        var stmt = parent.statement();
-        for (var qname : statement.argument().getNodeIdentifiers()) {
-            final var tmp = stmt;
-            stmt = stmt.streamEffectiveSubstatements(SchemaTreeEffectiveStatement.class)
-                .filter(child -> qname.equals(child.argument()))
-                .findFirst()
-                .orElseThrow(() -> new IllegalStateException("Failed to find " + qname + " in " + tmp));
-        }
-        setTargetStatement(stmt);
     }
 
     void resolveGrouping(final UsesEffectiveStatement resolvedUses, final GroupingGenerator resolvedGrouping) {
@@ -68,50 +54,28 @@ final class UsesAugmentGenerator extends AbstractAugmentGenerator {
     }
 
     @Override
-    List<CaseRuntimeType> augmentedCasesIn(final ChildLookup lookup, final ChoiceEffectiveStatement stmt) {
-        final var result = super.augmentedCasesIn(lookup, stmt);
-        if (result != null) {
-            return result;
-        }
-        final var augment = statement();
-        if (!lookup.contains(augment)) {
-            return List.of();
-        }
-
-        final var effectiveStatement = effectiveStatement(augment, stmt);
-        return createBuilder(effectiveStatement)
-            .fillTypes(lookup.inStatement(effectiveStatement), this)
-            .getCaseChilden();
+    boolean matchesInstantiated(final AugmentEffectiveStatement statement) {
+        return super.matchesInstantiated(statement) || declared(statement()).equals(declared(statement));
     }
 
-    @Override
-    AugmentRuntimeType runtimeTypeIn(final ChildLookup lookup, final EffectiveStatement<?, ?> target) {
-        final var result = super.runtimeTypeIn(lookup, target);
-        if (result != null) {
-            return result;
-        }
-        final var augment = statement();
-        if (!lookup.contains(augment)) {
-            return null;
-        }
-
-        verify(target instanceof SchemaTreeAwareEffectiveStatement && target instanceof SchemaTreeEffectiveStatement,
-            "Unexpected statement %s", target);
-        final var effectiveStatement = effectiveStatement(augment, (SchemaTreeAwareEffectiveStatement<?, ?>) target);
-        return verifyNotNull(createInternalRuntimeType(lookup.inStatement(effectiveStatement), effectiveStatement));
+    private static AugmentStatement declared(final AugmentEffectiveStatement statement) {
+        // We are generating Augmentation interfaces on declared model, hence this is accurate
+        return verifyNotNull(statement.getDeclared(), " %s does not have a declared view", statement);
     }
 
-    private static @NonNull AugmentEffectiveStatement effectiveStatement(final AugmentEffectiveStatement augment,
-            final SchemaTreeAwareEffectiveStatement<?, ?> target) {
+    @Override
+    TargetAugmentEffectiveStatement effectiveIn(final SchemaTreeAwareEffectiveStatement<?, ?> target) {
         verify(target instanceof SchemaTreeEffectiveStatement, "Unexpected statement %s", target);
         // 'uses'/'augment': our children are binding to target's namespace
         final var targetNamespace = ((SchemaTreeEffectiveStatement<?>) target).argument().getModule();
 
+        final var augment = statement();
         final var stmts = augment.effectiveSubstatements();
         final var builder = ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(stmts.size());
         for (var stmt : stmts) {
             if (stmt instanceof SchemaTreeEffectiveStatement) {
                 final var qname = ((SchemaTreeEffectiveStatement<?>) stmt).getIdentifier().bindTo(targetNamespace);
+                // FIXME: orElseThrow()?
                 target.get(SchemaTreeNamespace.class, qname).ifPresent(builder::add);
             } else {
                 builder.add(stmt);