Reformulate StatementContextFactory.createEffective()
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / EffectiveStmtUtils.java
index 9f8787b32e5e9c4be5912a67408653c310b98c89..f093e387f3622fb9b0f29748d7a3fa9ef35bf41c 100644 (file)
@@ -5,29 +5,34 @@
  * 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.parser.rfc7950.stmt;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Optional;
 import java.util.Set;
-import org.opendaylight.yangtools.yang.common.QName;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.model.api.ElementCountConstraint;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.MaxElementsEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.MinElementsEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
 
 @Beta
 public final class EffectiveStmtUtils {
@@ -35,32 +40,40 @@ public final class EffectiveStmtUtils {
     private static final String UNBOUNDED_STR = "unbounded";
 
     private EffectiveStmtUtils() {
-        throw new UnsupportedOperationException("Utility class");
+        // Hidden on purpose
     }
 
     public static SourceException createNameCollisionSourceException(final StmtContext<?, ?, ?> ctx,
-            final EffectiveStatement<?, ?> effectiveStatement) {
-        return new SourceException(ctx.getStatementSourceReference(),
+            final StatementSourceReference ref, final EffectiveStatement<?, ?> effectiveStatement) {
+        return new SourceException(ref,
             "Error in module '%s': cannot add '%s'. Node name collision: '%s' already declared.",
-            ctx.getRoot().getStatementArgument(),
-            effectiveStatement.argument(),
-            effectiveStatement.argument());
+            ctx.getRoot().rawStatementArgument(), effectiveStatement.argument(), effectiveStatement.argument());
     }
 
     public static Optional<ElementCountConstraint> createElementCountConstraint(final EffectiveStatement<?, ?> stmt) {
+        return createElementCountConstraint(
+            stmt.findFirstEffectiveSubstatementArgument(MinElementsEffectiveStatement.class).orElse(null),
+            stmt.findFirstEffectiveSubstatementArgument(MaxElementsEffectiveStatement.class).orElse(null));
+    }
+
+    public static Optional<ElementCountConstraint> createElementCountConstraint(
+            final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
+        return createElementCountConstraint(
+            BaseQNameStatementSupport.findFirstArgument(substatements, MinElementsEffectiveStatement.class, null),
+            BaseQNameStatementSupport.findFirstArgument(substatements, MaxElementsEffectiveStatement.class, null));
+    }
+
+    private static Optional<ElementCountConstraint> createElementCountConstraint(
+            final @Nullable Integer min, final @Nullable String max) {
         final Integer minElements;
-        final Optional<Integer> min = stmt.findFirstEffectiveSubstatementArgument(MinElementsEffectiveStatement.class);
-        if (min.isPresent()) {
-            final Integer m = min.get();
-            minElements = m > 0 ? m : null;
+        if (min != null) {
+            minElements = min > 0 ? min : null;
         } else {
             minElements = null;
         }
 
         final Integer maxElements;
-        final String max = stmt.findFirstEffectiveSubstatementArgument(MaxElementsEffectiveStatement.class)
-                .orElse(UNBOUNDED_STR);
-        if (!UNBOUNDED_STR.equals(max)) {
+        if (max != null && !UNBOUNDED_STR.equals(max)) {
             final Integer m = Integer.valueOf(max);
             maxElements = m < Integer.MAX_VALUE ? m : null;
         } else {
@@ -70,7 +83,6 @@ public final class EffectiveStmtUtils {
         return ElementCountConstraint.forNullable(minElements, maxElements);
     }
 
-
     /**
      * Checks whether supplied type has any of specified default values marked
      * with an if-feature. This method creates mutable copy of supplied set of
@@ -129,8 +141,8 @@ public final class EffectiveStmtUtils {
         while (iter.hasNext() && !defaultValues.isEmpty()) {
             final EffectiveStatement<?, ?> effectiveSubstatement = iter.next();
             if (YangStmtMapping.BIT.equals(effectiveSubstatement.statementDefinition())) {
-                final QName bitQName = (QName) effectiveSubstatement.argument();
-                if (defaultValues.remove(bitQName.getLocalName()) && containsIfFeature(effectiveSubstatement)) {
+                final String bitName = (String) effectiveSubstatement.argument();
+                if (defaultValues.remove(bitName) && containsIfFeature(effectiveSubstatement)) {
                     return true;
                 }
             } else if (YangStmtMapping.ENUM.equals(effectiveSubstatement.statementDefinition())
@@ -154,4 +166,36 @@ public final class EffectiveStmtUtils {
         }
         return false;
     }
+
+    public static void checkUniqueGroupings(final StmtContext<?, ?, ?> ctx,
+            final Collection<? extends EffectiveStatement<?, ?>> statements, final StatementSourceReference ref) {
+        checkUniqueNodes(ctx, statements, GroupingDefinition.class, ref);
+    }
+
+    public static void checkUniqueTypedefs(final StmtContext<?, ?, ?> ctx,
+            final Collection<? extends EffectiveStatement<?, ?>> statements, final StatementSourceReference ref) {
+        final Set<Object> typedefs = new HashSet<>();
+        for (EffectiveStatement<?, ?> stmt : statements) {
+            if (stmt instanceof TypedefEffectiveStatement
+                    && !typedefs.add(((TypedefEffectiveStatement) stmt).getTypeDefinition())) {
+                throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, ref, stmt);
+            }
+        }
+    }
+
+    public static void checkUniqueUses(final StmtContext<?, ?, ?> ctx,
+            final Collection<? extends EffectiveStatement<?, ?>> statements, final StatementSourceReference ref) {
+        checkUniqueNodes(ctx, statements, UsesNode.class, ref);
+    }
+
+    private static void checkUniqueNodes(final StmtContext<?, ?, ?> ctx,
+            final Collection<? extends EffectiveStatement<?, ?>> statements, final Class<?> type,
+            final StatementSourceReference ref) {
+        final Set<Object> nodes = new HashSet<>();
+        for (EffectiveStatement<?, ?> stmt : statements) {
+            if (type.isInstance(stmt) && !nodes.add(stmt)) {
+                throw EffectiveStmtUtils.createNameCollisionSourceException(ctx, ref, stmt);
+            }
+        }
+    }
 }