BUG-7025: make the parser tree immutable 93/47593/3
authorRobert Varga <rovarga@cisco.com>
Tue, 25 Oct 2016 16:04:37 +0000 (18:04 +0200)
committerAnil Belur <abelur@linuxfoundation.org>
Sun, 30 Oct 2016 11:41:47 +0000 (11:41 +0000)
This adds a post-processing phase, which walks the entire tree
and makes sure children are initialized to an ImmutableList.

This is essentially the same operation as running the tree
through org.antlr.v4.runtime.Parser.TrimToSizeListener, except
it also initializes empty lists to immutable collection and
uses a more efficient implementation for singletons.

Change-Id: I2cf484654158ce01bb9f7c2ac51a9866f88ae320
Signed-off-by: Robert Varga <rovarga@cisco.com>
(cherry picked from commit acba6c1723f31a8689812cf0bd6f058f688465d3)

yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/rfc6020/YangStatementSourceImpl.java

index 7644c38488b492b590d718e446686c9d19fea054..8a9e6ca1f29de84b227c3eb3aac8d0d583a6a29e 100644 (file)
@@ -7,13 +7,18 @@
  */
 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
 
+import com.google.common.collect.ImmutableList;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URISyntaxException;
 import org.antlr.v4.runtime.ANTLRInputStream;
 import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.ErrorNode;
+import org.antlr.v4.runtime.tree.ParseTreeListener;
 import org.antlr.v4.runtime.tree.ParseTreeWalker;
+import org.antlr.v4.runtime.tree.TerminalNode;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementLexer;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser;
 import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext;
@@ -37,6 +42,27 @@ import org.slf4j.LoggerFactory;
  */
 public final class YangStatementSourceImpl implements StatementStreamSource {
     private static final Logger LOG = LoggerFactory.getLogger(YangStatementSourceImpl.class);
+    private static final ParseTreeListener MAKE_IMMUTABLE_LISTENER = new ParseTreeListener() {
+        @Override
+        public void enterEveryRule(final ParserRuleContext ctx) {
+            // No-op
+        }
+
+        @Override
+        public void exitEveryRule(final ParserRuleContext ctx) {
+            ctx.children = ctx.children == null ? ImmutableList.of() : ImmutableList.copyOf(ctx.children);
+        }
+
+        @Override
+        public void visitTerminal(final TerminalNode node) {
+            // No-op
+        }
+
+        @Override
+        public void visitErrorNode(final ErrorNode node) {
+            // No-op
+        }
+    };
 
     private YangStatementParserListenerImpl yangStatementModelParser;
     private YangStatementParser.StatementContext statementContext;
@@ -121,6 +147,11 @@ public final class YangStatementSourceImpl implements StatementStreamSource {
         final StatementContext result = parser.statement();
         errorListener.validate();
 
+        // Walk the resulting tree and replace each children with an immutable list, lowering memory requirements
+        // and making sure the resulting tree will not get accidentally modified. An alternative would be to use
+        // org.antlr.v4.runtime.Parser.TrimToSizeListener, but that does not make the tree immutable.
+        ParseTreeWalker.DEFAULT.walk(MAKE_IMMUTABLE_LISTENER, result);
+
         return result;
     }