Introduce yangtools.binding.meta
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / ReactorStmtCtx.java
index f2a33e9f74734d631569f2b56760e7a9af73b7f5..c875f520a722df8be92841844ad03caf8593cf7f 100644 (file)
@@ -16,24 +16,22 @@ import com.google.common.base.VerifyException;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
 import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.model.api.source.SourceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.ConfigEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.DeviationStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
-import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStatementState;
 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
@@ -41,14 +39,12 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.ExecutionOrder;
-import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ParserNamespace;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementFactory;
 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;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
-import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -60,7 +56,7 @@ import org.slf4j.LoggerFactory;
  * @param <E> Effective Statement representation
  */
 abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
-        extends NamespaceStorageSupport implements Mutable<A, D, E>, Current<A, D> {
+        extends AbstractNamespaceStorage implements Mutable<A, D, E>, Current<A, D> {
     private static final Logger LOG = LoggerFactory.getLogger(ReactorStmtCtx.class);
 
     /**
@@ -156,25 +152,18 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     // hence improve memory layout.
     private byte flags;
 
-    // Flag for use by AbstractResumedStatement, ReplicaStatementContext and InferredStatementContext. Each of them
-    // uses it to indicated a different condition. This is hiding in the alignment shadow created by
-    // 'isSupportedToBuildEffective'.
-    // FIXME: move this out once we have JDK15+
-    private boolean boolFlag;
-
     ReactorStmtCtx() {
         // Empty on purpose
     }
 
     ReactorStmtCtx(final ReactorStmtCtx<A, D, E> original) {
         isSupportedToBuildEffective = original.isSupportedToBuildEffective;
-        boolFlag = original.boolFlag;
         flags = original.flags;
     }
 
     // Used by ReplicaStatementContext only
     ReactorStmtCtx(final ReactorStmtCtx<A, D, E> original, final Void dummy) {
-        boolFlag = isSupportedToBuildEffective = original.isSupportedToBuildEffective;
+        isSupportedToBuildEffective = original.isSupportedToBuildEffective;
         flags = original.flags;
     }
 
@@ -195,8 +184,8 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     public abstract Collection<? extends @NonNull StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements();
 
     @Override
-    public final Registry getBehaviourRegistry() {
-        return getRoot().getBehaviourRegistryImpl();
+    final <K, V> NamespaceAccess<K, V> accessNamespace(final ParserNamespace<K, V> type) {
+        return getRoot().getSourceContext().accessNamespace(type);
     }
 
     @Override
@@ -236,8 +225,8 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
     @Override
     public final QName moduleName() {
-        final RootStatementContext<?, ?, ?> root = getRoot();
-        return QName.create(StmtContextUtils.getRootModuleQName(root), root.getRawArgument());
+        final var root = getRoot();
+        return QName.create(StmtContextUtils.getModuleQName(root), root.getRawArgument());
     }
 
     //
@@ -299,16 +288,12 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
     private String refString() {
         final int current = refcount;
-        switch (current) {
-            case REFCOUNT_DEFUNCT:
-                return "DEFUNCT";
-            case REFCOUNT_SWEEPING:
-                return "SWEEPING";
-            case REFCOUNT_SWEPT:
-                return "SWEPT";
-            default:
-                return String.valueOf(refcount);
-        }
+        return switch (current) {
+            case REFCOUNT_DEFUNCT -> "DEFUNCT";
+            case REFCOUNT_SWEEPING -> "SWEEPING";
+            case REFCOUNT_SWEPT -> "SWEPT";
+            default -> String.valueOf(refcount);
+        };
     }
 
     /**
@@ -320,30 +305,33 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
     //
     //
-    // NamespaceStorageSupport/Mutable integration methods. Keep these together.
+    // AbstractNamespaceStorage/Mutable integration methods. Keep these together.
     //
     //
 
     @Override
-    public final <K, V, T extends K, N extends ParserNamespace<K, V>> V namespaceItem(final Class<@NonNull N> type,
-            final T key) {
-        return getBehaviourRegistry().getNamespaceBehaviour(type).getFrom(this, key);
+    public StorageType getStorageType() {
+        // Common to all subclasses except RootStatementContext
+        return StorageType.STATEMENT_LOCAL;
     }
 
     @Override
-    public final <K, V, N extends ParserNamespace<K, V>> Map<K, V> namespace(final Class<@NonNull N> type) {
-        return getNamespace(type);
+    public final <K, V> V namespaceItem(final ParserNamespace<K, V> namespace, final K key) {
+        return accessNamespace(namespace).valueFrom(this, key);
     }
 
     @Override
-    public final <K, V, N extends ParserNamespace<K, V>>
-            Map<K, V> localNamespacePortion(final Class<@NonNull N> type) {
-        return getLocalNamespace(type);
+    public final <K, V> Map<K, V> namespace(final ParserNamespace<K, V> namespace) {
+        return getNamespace(namespace);
     }
 
     @Override
-    protected <K, V, N extends ParserNamespace<K, V>> void onNamespaceElementAdded(final Class<N> type, final K key,
-            final V value) {
+    public final <K, V> Map<K, V> localNamespacePortion(final ParserNamespace<K, V> namespace) {
+        return getLocalNamespace(namespace);
+    }
+
+    @Override
+    protected <K, V> void onNamespaceElementAdded(final ParserNamespace<K, V> type, final K key, final V value) {
         // definition().onNamespaceElementAdded(this, type, key, value);
     }
 
@@ -409,8 +397,8 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
      * @return Built effective stateue
      */
     abstract @NonNull E createInferredEffective(@NonNull StatementFactory<A, D, E> factory,
-        @NonNull InferredStatementContext<A, D, E> ctx, Stream<? extends StmtContext<?, ?, ?>> declared,
-        Stream<? extends StmtContext<?, ?, ?>> effective);
+        @NonNull InferredStatementContext<A, D, E> ctx, Stream<? extends ReactorStmtCtx<?, ?, ?>> declared,
+        Stream<? extends ReactorStmtCtx<?, ?, ?>> effective);
 
     /**
      * Attach an effective copy of this statement. This essentially acts as a map, where we make a few assumptions:
@@ -472,7 +460,7 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
     //
     //
 
-    // Non-final form ImplicitStmtCtx
+    // Non-final for ImplicitStmtCtx/InferredStatementContext
     @Override
     public boolean isSupportedToBuildEffective() {
         return isSupportedToBuildEffective;
@@ -480,7 +468,7 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
     @Override
     public final void setUnsupported() {
-        this.isSupportedToBuildEffective = false;
+        isSupportedToBuildEffective = false;
     }
 
     @Override
@@ -494,16 +482,10 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
             return true;
         }
 
-        /*
-         * If parent is supported, we need to check if-features statements of this context.
-         */
-        if (isParentSupportedByFeatures()) {
-            // If the set of supported features has not been provided, all features are supported by default.
-            final Set<QName> supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class, Empty.value());
-            if (supportedFeatures == null || StmtContextUtils.checkFeatureSupport(this, supportedFeatures)) {
-                flags |= SET_SUPPORTED_BY_FEATURES;
-                return true;
-            }
+        // If parent is supported, we need to check if-features statements of this context.
+        if (isParentSupportedByFeatures() && computeSupportedByFeatures()) {
+            flags |= SET_SUPPORTED_BY_FEATURES;
+            return true;
         }
 
         // Either parent is not supported or this statement is not supported
@@ -511,6 +493,14 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
         return false;
     }
 
+    /**
+     * Compute whether this statement is supported by features. Returned value is combined with
+     * {@link #isParentSupportedByFeatures()} and cached.
+     *
+     * @return {@code true} if the current feature set matches {@code if-feature} of this statement
+     */
+    abstract boolean computeSupportedByFeatures();
+
     protected abstract boolean isParentSupportedByFeatures();
 
     /**
@@ -593,36 +583,6 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
         return false;
     }
 
-    // These two exist only due to memory optimization, should live in AbstractResumedStatement.
-    final boolean fullyDefined() {
-        return boolFlag;
-    }
-
-    final void setFullyDefined() {
-        boolFlag = true;
-    }
-
-    // This exists only due to memory optimization, should live in ReplicaStatementContext. In this context the flag
-    // indicates the need to drop source's reference count when we are being swept.
-    final boolean haveSourceReference() {
-        return boolFlag;
-    }
-
-    // These three exist due to memory optimization, should live in InferredStatementContext. In this context the flag
-    // indicates whether or not this statement's substatement file was modified, i.e. it is not quite the same as the
-    // prototype's file.
-    final boolean isModified() {
-        return boolFlag;
-    }
-
-    final void setModified() {
-        boolFlag = true;
-    }
-
-    final void setUnmodified() {
-        boolFlag = false;
-    }
-
     // These two exist only for StatementContextBase. Since we are squeezed for size, with only a single bit available
     // in flags, we default to 'false' and only set the flag to true when we are absolutely sure -- and all other cases
     // err on the side of caution by taking the time to evaluate each substatement separately.
@@ -657,17 +617,17 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
         }
 
         final Object argument = argument();
-        if (argument instanceof QName) {
-            return ((QName) argument).getModule();
+        if (argument instanceof QName qname) {
+            return qname.getModule();
         }
-        if (argument instanceof String) {
+        if (argument instanceof String str) {
             // FIXME: This may yield illegal argument exceptions
-            return StmtContextUtils.qnameFromArgument(getOriginalCtx().orElse(this), (String) argument).getModule();
+            return StmtContextUtils.qnameFromArgument(getOriginalCtx().orElse(this), str).getModule();
         }
-        if (argument instanceof SchemaNodeIdentifier
+        if (argument instanceof SchemaNodeIdentifier sni
                 && (producesDeclared(AugmentStatement.class) || producesDeclared(RefineStatement.class)
                         || producesDeclared(DeviationStatement.class))) {
-            return ((SchemaNodeIdentifier) argument).lastNodeIdentifier().getModule();
+            return sni.lastNodeIdentifier().getModule();
         }
 
         return coerceParent().effectiveNamespace();
@@ -880,26 +840,26 @@ abstract class ReactorStmtCtx<A, D extends DeclaredStatement<A>, E extends Effec
 
     private byte calculateParentRefcount() {
         final ReactorStmtCtx<?, ?, ?> parent = getParentContext();
-        if (parent == null) {
-            return PARENTREF_ABSENT;
-        }
+        return parent == null ? PARENTREF_ABSENT : parent.refcountForChild();
+    }
 
+    private byte refcountForChild() {
         // A slight wrinkle here is that our machinery handles only PRESENT -> ABSENT invalidation and we can reach here
         // while inference is still ongoing and hence we may not have a complete picture about existing references. We
         // could therefore end up caching an ABSENT result and then that information becoming stale as a new reference
         // is introduced.
-        if (parent.executionOrder() < ExecutionOrder.EFFECTIVE_MODEL) {
+        if (executionOrder() < ExecutionOrder.EFFECTIVE_MODEL) {
             return PARENTREF_UNKNOWN;
         }
 
         // There are three possibilities:
-        // - REFCOUNT_NONE, in which case we need to search next parent
+        // - REFCOUNT_NONE, in which case we need to check if this statement or its parents are holding a reference
         // - negative (< REFCOUNT_NONE), meaning parent is in some stage of sweeping, hence it does not have
         //   a reference to us
         // - positive (> REFCOUNT_NONE), meaning parent has an explicit refcount which is holding us down
-        final int refs = parent.refcount;
+        final int refs = refcount;
         if (refs == REFCOUNT_NONE) {
-            return parent.parentRefcount();
+            return noImplictRef() && noParentRef() ? PARENTREF_ABSENT : PARENTREF_PRESENT;
         }
         return refs < REFCOUNT_NONE ? PARENTREF_ABSENT : PARENTREF_PRESENT;
     }