BUG-6522: create a dedicated extensions map
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / SourceSpecificContext.java
index 1d8c2ac6ed8387cc5a6d66568487f2c72e9f7d49..ec0ae036345ba92d841e49b648a2893c0798d63b 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
 import com.google.common.collect.Multimap;
 import java.net.URI;
 import java.util.ArrayList;
@@ -82,12 +83,13 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh
             .put(TypeUtils.INSTANCE_IDENTIFIER, new InstanceIdentifierSpecificationImpl.Definition())
             .build();
 
-    private final Multimap<ModelProcessingPhase, ModifierImpl> modifiers = HashMultimap.create();
     private final QNameToStatementDefinitionMap qNameToStmtDefMap = new QNameToStatementDefinitionMap();
+    private final Multimap<ModelProcessingPhase, ModifierImpl> modifiers = HashMultimap.create();
     private final PrefixToModuleMap prefixToModuleMap = new PrefixToModuleMap();
     private final BuildGlobalContext currentContext;
     private final StatementStreamSource source;
 
+    private Map<QName, StatementSupport<?, ?, ?>> definedExtensions = ImmutableMap.of();
     private Collection<NamespaceStorageNode> importedNamespaces = ImmutableList.of();
     private ModelProcessingPhase finishedPhase = ModelProcessingPhase.INIT;
     private ModelProcessingPhase inProgressPhase;
@@ -111,7 +113,7 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh
         StatementDefinitionContext<?, ?, ?> def = currentContext.getStatementDefinition(name);
 
         if (def == null) {
-            final StatementSupport<?, ?, ?> extension = qNameToStmtDefMap.get(name);
+            final StatementSupport<?, ?, ?> extension = definedExtensions.get(name);
             if (extension != null) {
                 def = new StatementDefinitionContext<>(extension);
             } else {
@@ -362,20 +364,28 @@ public class SourceSpecificContext implements NamespaceStorageNode, NamespaceBeh
         return prefixToModuleMap;
     }
 
+    private static <K, V> void addSupports(final Builder<K, V> builder, @Nullable final Map<K, V> supports) {
+        if (supports != null) {
+            builder.putAll(supports);
+        }
+    }
+
     private QNameToStatementDefinition stmtDef() {
         // regular YANG statements and extension supports added
         qNameToStmtDefMap.putAll(currentContext.getSupportsForPhase(inProgressPhase).getDefinitions());
 
-        // No further actions needed
-        if (inProgressPhase != ModelProcessingPhase.FULL_DECLARATION) {
-            return qNameToStmtDefMap;
-        }
-
         // We need to any and all extension statements which have been declared in the context
-        final Map<QName, StatementSupport<?, ?, ?>> extensions = currentContext.getAllFromNamespace(
-                StatementDefinitionNamespace.class);
-        if (extensions != null) {
-            extensions.forEach((qname, support) -> {
+        if (inProgressPhase == ModelProcessingPhase.FULL_DECLARATION) {
+            // We maintain this map for createDeclaredChild(), which calls out to global context first,
+            // hence there is no point in performing double lookups.
+            final Builder<QName, StatementSupport<?, ?, ?>> b = ImmutableMap.builder();
+            addSupports(b, getRoot().getAllFromLocalStorage(StatementDefinitionNamespace.class));
+            for (NamespaceStorageNode namespace : importedNamespaces) {
+                addSupports(b, namespace.getAllFromLocalStorage(StatementDefinitionNamespace.class));
+            }
+
+            definedExtensions = b.build();
+            definedExtensions.forEach((qname, support) -> {
                 final StatementSupport<?, ?, ?> existing = qNameToStmtDefMap.putIfAbsent(qname, support);
                 if (existing != null) {
                     LOG.debug("Source {} already defines statement {} as {}", source, qname, existing);