Bug 3670 (part 1/5): Use of new statement parser in yang-maven-plugin
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / Utils.java
index 1d6a8e84ff1e8f28d7fe34f20357d58e11a07ac0..6efbe5ffe776626eaaf72f71e1535659313a607b 100644 (file)
@@ -9,10 +9,10 @@ package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
 import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
 
-import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
-
 import com.google.common.base.CharMatcher;
 import com.google.common.base.Splitter;
+import com.google.common.collect.Iterables;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -22,16 +22,19 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+
 import javax.annotation.Nullable;
 import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
+
 import org.antlr.v4.runtime.tree.TerminalNode;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
 import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Deviation;
 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
@@ -43,10 +46,13 @@ import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Relative;
 import org.opendaylight.yangtools.yang.model.api.stmt.SubmoduleStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
 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.BelongsToPrefixToModuleName;
 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier;
+import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleIdentifierToModuleQName;
 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
@@ -61,8 +67,7 @@ public final class Utils {
 
     private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
     private static final CharMatcher DOUBLE_QUOTE_MATCHER = CharMatcher.is('"');
-    private static final CharMatcher SINGLE_QUOTE_MATCHER = CharMatcher
-            .is('\'');
+    private static final CharMatcher SINGLE_QUOTE_MATCHER = CharMatcher.is('\'');
 
     public static final QName EMPTY_QNAME = QName.create("empty", "empty");
 
@@ -75,8 +80,8 @@ public final class Utils {
     private Utils() {
     }
 
-    public static Collection<SchemaNodeIdentifier.Relative> transformKeysStringToKeyNodes(StmtContext<?, ?, ?> ctx, String
-            value) {
+    public static Collection<SchemaNodeIdentifier.Relative> transformKeysStringToKeyNodes(StmtContext<?, ?, ?> ctx,
+            String value) {
         Splitter keySplitter = Splitter.on(SEPARATOR).omitEmptyStrings().trimResults();
         List<String> keyTokens = keySplitter.splitToList(value);
 
@@ -89,8 +94,8 @@ public final class Utils {
 
         for (String keyToken : keyTokens) {
 
-            SchemaNodeIdentifier.Relative keyNode = (Relative) SchemaNodeIdentifier.Relative
-                    .create(false, Utils.qNameFromArgument(ctx, keyToken));
+            SchemaNodeIdentifier.Relative keyNode = (Relative) SchemaNodeIdentifier.Relative.create(false,
+                    Utils.qNameFromArgument(ctx, keyToken));
             keyNodes.add(keyNode);
         }
 
@@ -99,26 +104,29 @@ public final class Utils {
 
     public static List<String> splitPathToNodeNames(String path) {
 
-        Splitter keySplitter = Splitter.on(SEPARATOR_NODENAME)
-                .omitEmptyStrings().trimResults();
+        Splitter keySplitter = Splitter.on(SEPARATOR_NODENAME).omitEmptyStrings().trimResults();
         return keySplitter.splitToList(path);
     }
 
-    public static void validateXPath(String path) {
+    public static void validateXPath(final StmtContext<?, ?, ?> ctx, String path) {
 
         final XPath xPath = XPathFactory.newInstance().newXPath();
 
         try {
             xPath.compile(path);
         } catch (XPathExpressionException e) {
-            throw new IllegalArgumentException(
-                    "Argument is not valid XPath string", e);
+            throw new IllegalArgumentException(String.format("Argument %s is not valid XPath string at %s", path, ctx
+                    .getStatementSourceReference().toString()), e);
         }
     }
 
-    public static boolean isXPathAbsolute(String path) {
+    private static String trimSingleLastSlashFromXPath(final String path) {
+        return path.replaceAll("/$", "");
+    }
 
-        validateXPath(path);
+    public static boolean isXPathAbsolute(final StmtContext<?, ?, ?> ctx, String path) {
+
+        validateXPath(ctx, trimSingleLastSlashFromXPath(path));
 
         return path.matches(REGEX_PATH_ABS);
     }
@@ -143,8 +151,8 @@ public final class Utils {
         return null;
     }
 
-    public static boolean isValidStatementDefinition(PrefixToModule prefixes,
-            QNameToStatementDefinition stmtDef, QName identifier) {
+    public static boolean isValidStatementDefinition(PrefixToModule prefixes, QNameToStatementDefinition stmtDef,
+            QName identifier) {
         if (stmtDef.get(identifier) != null) {
             return true;
         } else {
@@ -154,16 +162,11 @@ public final class Utils {
             if (namesParts.length == 2) {
                 String prefix = namesParts[0];
                 String localName = namesParts[1];
-                if (prefixes != null
-                        && prefixes.get(prefix) != null
-                        && stmtDef
-                                .get(new QName(
-                                        YangConstants.RFC6020_YIN_NAMESPACE,
-                                        localName)) != null) {
+                if (prefixes != null && prefixes.get(prefix) != null
+                        && stmtDef.get(new QName(YangConstants.RFC6020_YIN_NAMESPACE, localName)) != null) {
                     return true;
                 } else {
-                    if (stmtDef.get(new QName(
-                            YangConstants.RFC6020_YIN_NAMESPACE, localName)) != null) {
+                    if (stmtDef.get(new QName(YangConstants.RFC6020_YIN_NAMESPACE, localName)) != null) {
                         return true;
                     }
                 }
@@ -172,12 +175,13 @@ public final class Utils {
         return false;
     }
 
-    public static Iterable<QName> parseXPath(StmtContext<?, ?, ?> ctx,
-            String path) {
+    public static Iterable<QName> parseXPath(StmtContext<?, ?, ?> ctx, String path) {
+
+        String trimmedPath = trimSingleLastSlashFromXPath(path);
 
-        validateXPath(path);
+        validateXPath(ctx, trimmedPath);
 
-        List<String> nodeNames = splitPathToNodeNames(path);
+        List<String> nodeNames = splitPathToNodeNames(trimmedPath);
         List<QName> qNames = new ArrayList<>();
 
         for (String nodeName : nodeNames) {
@@ -192,8 +196,7 @@ public final class Utils {
         return qNames;
     }
 
-    public static String stringFromStringContext(
-            final YangStatementParser.ArgumentContext context) {
+    public static String stringFromStringContext(final YangStatementParser.ArgumentContext context) {
         StringBuilder sb = new StringBuilder();
         List<TerminalNode> strings = context.STRING();
         if (strings.isEmpty()) {
@@ -236,14 +239,15 @@ public final class Utils {
             prefix = namesParts[0];
             localName = namesParts[1];
             qNameModule = getModuleQNameByPrefix(ctx, prefix);
-            //in case of unknown statement argument, we're not going to parse it
-            if (qNameModule == null && ctx.getPublicDefinition().getDeclaredRepresentationClass().isAssignableFrom
-                    (UnknownStatementImpl.class)) {
+            // in case of unknown statement argument, we're not going to parse it
+            if (qNameModule == null
+                    && ctx.getPublicDefinition().getDeclaredRepresentationClass()
+                    .isAssignableFrom(UnknownStatementImpl.class)) {
                 localName = value;
                 qNameModule = getRootModuleQName(ctx);
             }
-            //:FIXME test and verify this...
-            if(qNameModule == null && ctx.getTypeOfCopy() == StmtContext.TypeOfCopy.ADDED_BY_AUGMENTATION) {
+            if (qNameModule == null
+                    && Iterables.getLast(ctx.getCopyHistory()) == StmtContext.TypeOfCopy.ADDED_BY_AUGMENTATION) {
                 ctx = ctx.getOriginalCtx();
                 qNameModule = getModuleQNameByPrefix(ctx, prefix);
             }
@@ -253,33 +257,24 @@ public final class Utils {
         }
 
         if (qNameModule == null) {
-            throw new IllegalArgumentException("Error in module '"
-                    + ctx.getRoot().rawStatementArgument()
+            throw new IllegalArgumentException("Error in module '" + ctx.getRoot().rawStatementArgument()
                     + "': can not resolve QNameModule for '" + value + "'.");
         }
 
-        QNameModule resultQNameModule = qNameModule.getRevision() == null ? QNameModule
-                .create(qNameModule.getNamespace(),
-                        SimpleDateFormatUtil.DEFAULT_DATE_REV) : qNameModule;
+        QNameModule resultQNameModule = qNameModule.getRevision() == null ? QNameModule.create(
+                qNameModule.getNamespace(), SimpleDateFormatUtil.DEFAULT_DATE_REV) : qNameModule;
 
         return QName.create(resultQNameModule, localName);
     }
 
-    public static QNameModule getModuleQNameByPrefix(StmtContext<?, ?, ?> ctx,
-            String prefix) {
+    public static QNameModule getModuleQNameByPrefix(StmtContext<?, ?, ?> ctx, String prefix) {
         QNameModule qNameModule;
-        ModuleIdentifier impModIdentifier = ctx.getRoot().getFromNamespace(
-                ImpPrefixToModuleIdentifier.class, prefix);
-        qNameModule = ctx.getFromNamespace(ModuleIdentifierToModuleQName.class,
-                impModIdentifier);
-
-        if (qNameModule == null
-                && StmtContextUtils.producesDeclared(ctx.getRoot(),
-                        SubmoduleStatement.class)) {
-            String moduleName = ctx.getRoot().getFromNamespace(
-                    BelongsToPrefixToModuleName.class, prefix);
-            qNameModule = ctx.getFromNamespace(ModuleNameToModuleQName.class,
-                    moduleName);
+        ModuleIdentifier impModIdentifier = ctx.getRoot().getFromNamespace(ImpPrefixToModuleIdentifier.class, prefix);
+        qNameModule = ctx.getFromNamespace(ModuleIdentifierToModuleQName.class, impModIdentifier);
+
+        if (qNameModule == null && StmtContextUtils.producesDeclared(ctx.getRoot(), SubmoduleStatement.class)) {
+            String moduleName = ctx.getRoot().getFromNamespace(BelongsToPrefixToModuleName.class, prefix);
+            qNameModule = ctx.getFromNamespace(ModuleNameToModuleQName.class, moduleName);
         }
         return qNameModule;
     }
@@ -294,25 +289,19 @@ public final class Utils {
         QNameModule qNameModule = null;
 
         if (StmtContextUtils.producesDeclared(rootCtx, ModuleStatement.class)) {
-            qNameModule = rootCtx.getFromNamespace(
-                    ModuleCtxToModuleQName.class,
-                    rootCtx);
-        } else if (StmtContextUtils.producesDeclared(rootCtx,
-                SubmoduleStatement.class)) {
-            String belongsToModuleName = firstAttributeOf(ctx.getRoot()
-                    .declaredSubstatements(), BelongsToStatement.class);
-            qNameModule = rootCtx.getFromNamespace(
-                    ModuleNameToModuleQName.class, belongsToModuleName);
+            qNameModule = rootCtx.getFromNamespace(ModuleCtxToModuleQName.class, rootCtx);
+        } else if (StmtContextUtils.producesDeclared(rootCtx, SubmoduleStatement.class)) {
+            String belongsToModuleName = firstAttributeOf(ctx.getRoot().declaredSubstatements(),
+                    BelongsToStatement.class);
+            qNameModule = rootCtx.getFromNamespace(ModuleNameToModuleQName.class, belongsToModuleName);
         }
 
-        return qNameModule.getRevision() == null ? QNameModule.create(
-                qNameModule.getNamespace(),
+        return qNameModule.getRevision() == null ? QNameModule.create(qNameModule.getNamespace(),
                 SimpleDateFormatUtil.DEFAULT_DATE_REV) : qNameModule;
     }
 
     @Nullable
-    public static StatementContextBase<?, ?, ?> findNode(
-            StatementContextBase<?, ?, ?> rootStmtCtx,
+    public static StatementContextBase<?, ?, ?> findNode(StatementContextBase<?, ?, ?> rootStmtCtx,
             final Iterable<QName> path) {
 
         StatementContextBase<?, ?, ?> parent = rootStmtCtx;
@@ -320,8 +309,7 @@ public final class Utils {
         Iterator<QName> pathIter = path.iterator();
         while (pathIter.hasNext()) {
             QName nextPathQName = pathIter.next();
-            StatementContextBase<?, ?, ?> foundSubstatement = getSubstatementByQName(
-                    parent, nextPathQName);
+            StatementContextBase<?, ?, ?> foundSubstatement = getSubstatementByQName(parent, nextPathQName);
 
             if (foundSubstatement == null) {
                 return null;
@@ -336,13 +324,11 @@ public final class Utils {
         return null;
     }
 
-    public static StatementContextBase<?, ?, ?> getSubstatementByQName(
-            StatementContextBase<?, ?, ?> parent, QName nextPathQName) {
+    public static StatementContextBase<?, ?, ?> getSubstatementByQName(StatementContextBase<?, ?, ?> parent,
+            QName nextPathQName) {
 
-        Collection<StatementContextBase<?, ?, ?>> declaredSubstatement = parent
-                .declaredSubstatements();
-        Collection<StatementContextBase<?, ?, ?>> effectiveSubstatement = parent
-                .effectiveSubstatements();
+        Collection<StatementContextBase<?, ?, ?>> declaredSubstatement = parent.declaredSubstatements();
+        Collection<StatementContextBase<?, ?, ?>> effectiveSubstatement = parent.effectiveSubstatements();
 
         Collection<StatementContextBase<?, ?, ?>> allSubstatements = new LinkedList<>();
         allSubstatements.addAll(declaredSubstatement);
@@ -358,20 +344,18 @@ public final class Utils {
     }
 
     @Nullable
-    public static StatementContextBase<?, ?, ?> findNode(
-            StatementContextBase<?, ?, ?> rootStmtCtx,
+    public static StatementContextBase<?, ?, ?> findNode(StatementContextBase<?, ?, ?> rootStmtCtx,
             final SchemaNodeIdentifier node) {
         return findNode(rootStmtCtx, node.getPathFromRoot());
     }
 
     public static SchemaPath getSchemaPath(StmtContext<?, ?, ?> ctx) {
 
-        if(ctx == null) {
+        if (ctx == null) {
             return null;
         }
 
-        Iterator<StmtContext<?, ?, ?>> iteratorFromRoot = ctx
-                .getStmtContextsFromRoot().iterator();
+        Iterator<StmtContext<?, ?, ?>> iteratorFromRoot = ctx.getStmtContextsFromRoot().iterator();
 
         if (iteratorFromRoot.hasNext()) {
             iteratorFromRoot.next(); // skip root argument
@@ -383,8 +367,10 @@ public final class Utils {
             Object nextStmtArgument = nextStmtCtx.getStatementArgument();
             if (nextStmtArgument instanceof QName) {
                 QName qname = (QName) nextStmtArgument;
-                if (StmtContextUtils.producesDeclared(
-                        nextStmtCtx.getParentContext(), ChoiceStatement.class)
+                if (StmtContextUtils.producesDeclared(nextStmtCtx, UsesStatement.class)) {
+                    continue;
+                }
+                if (StmtContextUtils.producesDeclared(nextStmtCtx.getParentContext(), ChoiceStatement.class)
                         && isSupportedAsShorthandCase(nextStmtCtx)) {
                     qNamesFromRoot.add(qname);
                 }
@@ -392,14 +378,11 @@ public final class Utils {
             } else if (nextStmtArgument instanceof String) {
                 final QName qName = qNameFromArgument(ctx, (String) nextStmtArgument);
                 qNamesFromRoot.add(qName);
-            }
-            else if (StmtContextUtils.producesDeclared(nextStmtCtx,
-                    AugmentStatement.class)
+            } else if (StmtContextUtils.producesDeclared(nextStmtCtx, AugmentStatement.class)
                     && nextStmtArgument instanceof SchemaNodeIdentifier) {
-                addQNamesFromSchemaNodeIdentifierToList(qNamesFromRoot,
-                        (SchemaNodeIdentifier) nextStmtArgument);
-            } else if (nextStmtCtx.getPublicDefinition().getDeclaredRepresentationClass().isAssignableFrom
-                    (UnknownStatementImpl.class)) {
+                addQNamesFromSchemaNodeIdentifierToList(qNamesFromRoot, (SchemaNodeIdentifier) nextStmtArgument);
+            } else if (nextStmtCtx.getPublicDefinition().getDeclaredRepresentationClass()
+                    .isAssignableFrom(UnknownStatementImpl.class)) {
                 qNamesFromRoot.add(nextStmtCtx.getPublicDefinition().getStatementName());
             } else {
                 return SchemaPath.SAME;
@@ -410,22 +393,17 @@ public final class Utils {
         return schemaPath;
     }
 
-    private static boolean isSupportedAsShorthandCase(
-            StmtContext<?, ?, ?> statementCtx) {
+    private static boolean isSupportedAsShorthandCase(StmtContext<?, ?, ?> statementCtx) {
 
-        Collection<?> supportedCaseShorthands = statementCtx.getFromNamespace(
-                ValidationBundlesNamespace.class,
+        Collection<?> supportedCaseShorthands = statementCtx.getFromNamespace(ValidationBundlesNamespace.class,
                 ValidationBundleType.SUPPORTED_CASE_SHORTHANDS);
 
-        return supportedCaseShorthands == null
-                || supportedCaseShorthands.contains(statementCtx
-                        .getPublicDefinition());
+        return supportedCaseShorthands == null || supportedCaseShorthands.contains(statementCtx.getPublicDefinition());
     }
 
-    private static void addQNamesFromSchemaNodeIdentifierToList(
-            List<QName> qNamesFromRoot, SchemaNodeIdentifier augmentTargetPath) {
-        Iterator<QName> augmentTargetPathIterator = augmentTargetPath
-                .getPathFromRoot().iterator();
+    private static void addQNamesFromSchemaNodeIdentifierToList(List<QName> qNamesFromRoot,
+            SchemaNodeIdentifier augmentTargetPath) {
+        Iterator<QName> augmentTargetPathIterator = augmentTargetPath.getPathFromRoot().iterator();
         while (augmentTargetPathIterator.hasNext()) {
             qNamesFromRoot.add(augmentTargetPathIterator.next());
         }
@@ -437,16 +415,14 @@ public final class Utils {
         // suit this
         String deviateUpper = deviate.toUpperCase();
         if (Objects.equals(deviate, deviateUpper)) {
-            throw new IllegalArgumentException(String.format(
-                    "String %s is not valid deviate argument", deviate));
+            throw new IllegalArgumentException(String.format("String %s is not valid deviate argument", deviate));
         }
 
         // but Java enum is uppercase so we cannot use lowercase here
         try {
             return Deviation.Deviate.valueOf(deviateUpper);
         } catch (IllegalArgumentException e) {
-            throw new IllegalArgumentException(String.format(
-                    "String %s is not valid deviate argument", deviate), e);
+            throw new IllegalArgumentException(String.format("String %s is not valid deviate argument", deviate), e);
         }
     }
 
@@ -470,10 +446,8 @@ public final class Utils {
         return status;
     }
 
-    public static SchemaPath SchemaNodeIdentifierToSchemaPath(
-            SchemaNodeIdentifier identifier) {
-        return SchemaPath.create(identifier.getPathFromRoot(),
-                identifier.isAbsolute());
+    public static SchemaPath SchemaNodeIdentifierToSchemaPath(SchemaNodeIdentifier identifier) {
+        return SchemaPath.create(identifier.getPathFromRoot(), identifier.isAbsolute());
     }
 
 }