Merge "Bug 2997: Fixed instanceof checks to use interfaces"
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / YangParserImpl.java
index 7948158f4dee6b277493d8d2451395d3ee6b3d19..5684c045d5a08d1412b48bfdf3db5a28f2b7e21d 100644 (file)
@@ -15,10 +15,8 @@ import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.f
 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.processAugmentation;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.TypeUtils.resolveType;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.TypeUtils.resolveTypeUnion;
-
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
 import com.google.common.collect.HashBiMap;
 import com.google.common.io.ByteSource;
 import java.io.File;
@@ -35,6 +33,7 @@ import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.NavigableMap;
 import java.util.Set;
 import java.util.TreeMap;
 import javax.annotation.concurrent.Immutable;
@@ -47,11 +46,17 @@ import org.opendaylight.yangtools.antlrv4.code.gen.YangParser;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser;
 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
@@ -87,7 +92,6 @@ import org.slf4j.LoggerFactory;
 @Immutable
 public final class YangParserImpl implements YangContextParser {
     private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
-    private static final Splitter COLON_SPLITTER = Splitter.on(':');
     private static final YangParserImpl INSTANCE = new YangParserImpl();
 
     public static YangParserImpl getInstance() {
@@ -137,7 +141,7 @@ public final class YangParserImpl implements YangContextParser {
 
         // module builders sorted by dependencies
         List<ModuleBuilder> sortedBuilders = ModuleDependencySort.sort(resolved);
-        LinkedHashMap<URI, TreeMap<Date, ModuleBuilder>> modules = resolveModulesWithImports(sortedBuilders, null);
+        Map<URI, TreeMap<Date, ModuleBuilder>> modules = resolveModulesWithImports(sortedBuilders, null);
         Collection<Module> unsorted = build(modules).values();
         Set<Module> result = new LinkedHashSet<>(
                 ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
@@ -229,9 +233,9 @@ public final class YangParserImpl implements YangContextParser {
         return resolveSchemaContext(result);
     }
 
-    private static LinkedHashMap<URI, TreeMap<Date, ModuleBuilder>> resolveModulesWithImports(final List<ModuleBuilder> sorted,
+    private static Map<URI, TreeMap<Date, ModuleBuilder>> resolveModulesWithImports(final List<ModuleBuilder> sorted,
             final SchemaContext context) {
-        final LinkedHashMap<URI, TreeMap<Date, ModuleBuilder>> modules = orderModules(sorted);
+        final Map<URI, TreeMap<Date, ModuleBuilder>> modules = orderModules(sorted);
         for (ModuleBuilder module : sorted) {
             if (module != null) {
                 for (ModuleImport imp : module.getImports().values()) {
@@ -477,7 +481,7 @@ public final class YangParserImpl implements YangContextParser {
             final Map<String, TreeMap<Date, ModuleBuilder>> submodules) {
         Map<String, Date> includes = module.getIncludedModules();
         for (Map.Entry<String, Date> entry : includes.entrySet()) {
-            TreeMap<Date, ModuleBuilder> subs = submodules.get(entry.getKey());
+            NavigableMap<Date, ModuleBuilder> subs = submodules.get(entry.getKey());
             if (subs == null) {
                 throw new YangParseException("Failed to find references submodule " + entry.getKey() + " in module "
                         + module.getName());
@@ -559,8 +563,8 @@ public final class YangParserImpl implements YangContextParser {
      *            topologically sorted modules
      * @return modules ordered by namespace and revision
      */
-    private static LinkedHashMap<URI, TreeMap<Date, ModuleBuilder>> orderModules(final List<ModuleBuilder> modules) {
-        final LinkedHashMap<URI, TreeMap<Date, ModuleBuilder>> result = new LinkedHashMap<>();
+    private static Map<URI, TreeMap<Date, ModuleBuilder>> orderModules(final List<ModuleBuilder> modules) {
+        final Map<URI, TreeMap<Date, ModuleBuilder>> result = new LinkedHashMap<>();
         for (final ModuleBuilder builder : modules) {
             if (builder == null) {
                 continue;
@@ -709,6 +713,7 @@ public final class YangParserImpl implements YangContextParser {
         resolveUsesForNodes(modules);
         resolveAugments(modules);
         resolveIdentities(modules);
+        checkChoiceCasesForDuplicityQNames(modules);
 
         // build
         final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
@@ -967,6 +972,7 @@ public final class YangParserImpl implements YangContextParser {
                         "Error in module {} at line {}: Unsupported augment target: {}. Augmentation process skipped.",
                         module.getName(), augment.getLine(), potentialTargetNode);
                 augment.setResolved(true);
+                augment.setUnsupportedTarget(true);
                 return true;
             }
         } else {
@@ -1022,7 +1028,8 @@ public final class YangParserImpl implements YangContextParser {
         }
     }
 
-    private void resolveIdentity(final ModuleBuilder module, final IdentitySchemaNodeBuilder identity) {
+    private void resolveIdentity(final ModuleBuilder module,
+            final IdentitySchemaNodeBuilder identity) {
         final String baseIdentityName = identity.getBaseIdentityName();
         if (baseIdentityName != null) {
             IdentitySchemaNodeBuilder result = null;
@@ -1030,15 +1037,34 @@ public final class YangParserImpl implements YangContextParser {
                 final int line = identity.getLine();
                 String[] splittedBase = baseIdentityName.split(":");
                 if (splittedBase.length > 2) {
-                    throw new YangParseException(module.getName(), line, "Failed to parse identityref base: "
-                            + baseIdentityName);
+                    throw new YangParseException(module.getName(), line,
+                            "Failed to parse identityref base: "
+                                    + baseIdentityName);
                 }
                 String prefix = splittedBase[0];
                 String name = splittedBase[1];
-                ModuleBuilder dependentModule = BuilderUtils.getModuleByPrefix(module, prefix);
-                result = BuilderUtils.findIdentity(dependentModule.getAddedIdentities(), name);
+
+                if (prefix.equals(module.getPrefix())
+                        && name.equals(identity.getQName().getLocalName())) {
+                    throw new YangParseException(module.getName(),
+                            identity.getLine(),
+                            "Failed to parse base, identity name equals base identity name: "
+                                    + baseIdentityName);
+                }
+
+                ModuleBuilder dependentModule = BuilderUtils.getModuleByPrefix(
+                        module, prefix);
+                result = BuilderUtils.findIdentity(
+                        dependentModule.getAddedIdentities(), name);
             } else {
-                result = BuilderUtils.findIdentity(module.getAddedIdentities(), baseIdentityName);
+                if (baseIdentityName.equals(identity.getQName().getLocalName())) {
+                    throw new YangParseException(module.getName(),
+                            identity.getLine(),
+                            "Failed to parse base, identity name equals base identity name: "
+                                    + baseIdentityName);
+                }
+                result = BuilderUtils.findIdentity(module.getAddedIdentities(),
+                        baseIdentityName);
             }
             identity.setBaseIdentity(result);
         }
@@ -1223,4 +1249,73 @@ public final class YangParserImpl implements YangContextParser {
         return null;
     }
 
+
+    /**
+     * Traverse through modules and check if choice has choice cases with the
+     * same qname.
+     *
+     * @param modules
+     *            all loaded modules
+     */
+    private void checkChoiceCasesForDuplicityQNames(final Map<URI, TreeMap<Date, ModuleBuilder>> modules) {
+        for (Map.Entry<URI, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+            for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
+                final ModuleBuilder moduleBuilder = childEntry.getValue();
+                final Module module = moduleBuilder.build();
+                final List<ChoiceSchemaNode> allChoicesFromModule = getChoicesFrom(module);
+
+                for (ChoiceSchemaNode choiceNode : allChoicesFromModule) {
+                    findDuplicityNodesIn(choiceNode, module, moduleBuilder, modules);
+                }
+            }
+        }
+    }
+
+    private void findDuplicityNodesIn(final ChoiceSchemaNode choiceNode, final Module module, final ModuleBuilder moduleBuilder,
+            final Map<URI, TreeMap<Date, ModuleBuilder>> modules) {
+        final Set<QName> duplicityTestSet = new HashSet<QName>();
+
+        for (ChoiceCaseNode choiceCaseNode : choiceNode.getCases()) {
+
+            for (DataSchemaNode childSchemaNode : choiceCaseNode.getChildNodes()) {
+                if (!duplicityTestSet.add(childSchemaNode.getQName())) {
+                    final Optional<SchemaNodeBuilder> schemaNodeBuilder = BuilderUtils.findSchemaNodeInModule(childSchemaNode.getPath(), moduleBuilder);
+                    final String nameOfSchemaNode = childSchemaNode.getQName().getLocalName();
+                    int lineOfSchemaNode = 0;
+
+                    if (schemaNodeBuilder.isPresent()) {
+                        lineOfSchemaNode = schemaNodeBuilder.get().getLine();
+                    }
+                    throw new YangParseException(module.getName(), lineOfSchemaNode,
+                            String.format("Choice has two nodes case with same qnames - %s", nameOfSchemaNode));
+                }
+            }
+        }
+    }
+
+    private List<ChoiceSchemaNode> getChoicesFrom(final Module module) {
+        final List<ChoiceSchemaNode> allChoices = new ArrayList<ChoiceSchemaNode>();
+
+        for (DataSchemaNode dataSchemaNode : module.getChildNodes()) {
+            findChoicesIn(dataSchemaNode, allChoices);
+        }
+        return allChoices;
+    }
+
+    private void findChoicesIn(final SchemaNode schemaNode, final Collection<ChoiceSchemaNode> choiceNodes) {
+        if (schemaNode instanceof ContainerSchemaNode) {
+            final ContainerSchemaNode contSchemaNode = (ContainerSchemaNode) schemaNode;
+            for (DataSchemaNode dataSchemaNode : contSchemaNode.getChildNodes()) {
+                findChoicesIn(dataSchemaNode, choiceNodes);
+            }
+        } else if (schemaNode instanceof ListSchemaNode) {
+            final ListSchemaNode listSchemaNode = (ListSchemaNode) schemaNode;
+            for (DataSchemaNode dataSchemaNode : listSchemaNode.getChildNodes()) {
+                findChoicesIn(dataSchemaNode, choiceNodes);
+            }
+        } else if (schemaNode instanceof ChoiceSchemaNode) {
+            choiceNodes.add((ChoiceSchemaNode) schemaNode);
+        }
+    }
+
 }