This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new dbd5453  GROOVY-9577: maintain insertion order of imports and retain 
duplicates
dbd5453 is described below

commit dbd54539291d49baf355e6b6e1afac0cc9c6b70e
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Fri May 29 11:28:04 2020 -0500

    GROOVY-9577: maintain insertion order of imports and retain duplicates
    
    - lazily create name to node map
---
 .../java/org/codehaus/groovy/ast/ModuleNode.java   | 13 +++---
 .../groovy/control/io/AbstractReaderSource.java    | 12 ++----
 .../org/codehaus/groovy/ast/ModuleNodeTest.java    | 46 +++++++++++++++-------
 .../groovy/syntax/parser/TestParserSupport.java    | 38 ------------------
 4 files changed, 44 insertions(+), 65 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/ModuleNode.java 
b/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
index 7fcdfc6..4cc6870 100644
--- a/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
@@ -32,12 +32,12 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
@@ -57,7 +57,7 @@ public class ModuleNode extends ASTNode implements Opcodes {
 
     private List<ClassNode> classes = new LinkedList<>();
     private final List<MethodNode> methods = new ArrayList<>();
-    private final Map<String, ImportNode> imports = new HashMap<>();
+    private final List<ImportNode> imports = new ArrayList<>();
     private final List<ImportNode> starImports = new ArrayList<>();
     private final Map<String, ImportNode> staticImports = new 
LinkedHashMap<>();
     private final Map<String, ImportNode> staticStarImports = new 
LinkedHashMap<>();
@@ -96,7 +96,7 @@ public class ModuleNode extends ASTNode implements Opcodes {
     }
 
     public List<ImportNode> getImports() {
-        return new ArrayList<>(imports.values());
+        return Collections.unmodifiableList(imports);
     }
 
     public List<ImportNode> getStarImports() {
@@ -125,7 +125,9 @@ public class ModuleNode extends ASTNode implements Opcodes {
      * @return the import node for the given alias or null if none is available
      */
     public ImportNode getImport(final String alias) {
-        return imports.get(alias);
+        Map<String, ImportNode> aliases = getNodeMetaData("import.aliases", x 
->
+            imports.stream().collect(Collectors.toMap(ImportNode::getAlias, n 
-> n, (n, m) -> m)));
+        return aliases.get(alias);
     }
 
     public void addImport(final String alias, final ClassNode type) {
@@ -135,8 +137,9 @@ public class ModuleNode extends ASTNode implements Opcodes {
     public void addImport(final String alias, final ClassNode type, final 
List<AnnotationNode> annotations) {
         ImportNode importNode = new ImportNode(type, alias);
         importNode.addAnnotations(annotations);
-        imports.put(alias, importNode);
+        imports.add(importNode);
 
+        removeNodeMetaData("import.aliases");
         storeLastAddedImportNode(importNode);
     }
 
diff --git 
a/src/main/java/org/codehaus/groovy/control/io/AbstractReaderSource.java 
b/src/main/java/org/codehaus/groovy/control/io/AbstractReaderSource.java
index c3a9d59..d31dd7b 100644
--- a/src/main/java/org/codehaus/groovy/control/io/AbstractReaderSource.java
+++ b/src/main/java/org/codehaus/groovy/control/io/AbstractReaderSource.java
@@ -29,15 +29,11 @@ import java.io.IOException;
  * provides common functionality.
  */
 public abstract class AbstractReaderSource implements ReaderSource {
-    protected CompilerConfiguration configuration;   // Configuration data
 
-    public AbstractReaderSource(CompilerConfiguration configuration) {
-        if (configuration == null) {
-            throw new IllegalArgumentException("Compiler configuration must 
not be null!");
-            // ... or more relaxed?
-            // configuration = CompilerConfiguration.DEFAULT;
-        }
-        this.configuration = configuration;
+    protected CompilerConfiguration configuration;
+
+    public AbstractReaderSource(final CompilerConfiguration configuration) {
+        this.configuration = configuration != null ? configuration : 
CompilerConfiguration.DEFAULT;
     }
 
     /**
diff --git a/src/test/org/codehaus/groovy/ast/ModuleNodeTest.java 
b/src/test/org/codehaus/groovy/ast/ModuleNodeTest.java
index e38a0c6..67d155f 100644
--- a/src/test/org/codehaus/groovy/ast/ModuleNodeTest.java
+++ b/src/test/org/codehaus/groovy/ast/ModuleNodeTest.java
@@ -18,31 +18,49 @@
  */
 package org.codehaus.groovy.ast;
 
-import org.codehaus.groovy.syntax.parser.TestParserSupport;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.junit.Test;
 
-import java.util.List;
+import static org.codehaus.groovy.control.ParserPlugin.buildAST;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 /**
- * Tests the ClassNode
+ * Tests for {@link ModuleNode}.
  */
-public class ModuleNodeTest extends TestParserSupport {
+public final class ModuleNodeTest {
 
+    @Test
     public void testStatementClass() {
-        ModuleNode module = parse("x = [1, 2, 3]; println(x)", 
"Cheese.groovy");
-        assertFalse("Should have statements", 
module.getStatementBlock().isEmpty());
+        ModuleNode mn = buildAST("x = [1, 2, 3]; println(x)", null, null, 
null);
 
-        List<ClassNode> classes = module.getClasses();
-        assertEquals("Number of classes", 1, classes.size());
-
-        ClassNode classNode = (ClassNode) classes.get(0);
-        assertEquals("Class name", "Cheese", classNode.getName());
+        assertEquals(1, mn.getClasses().size());
+        assertTrue(mn.getClasses().get(0).getName().startsWith("Script"));
+        assertFalse("Should have statements", 
mn.getStatementBlock().isEmpty());
     }
 
-    // GROOVY-9194
+    @Test // GROOVY-9194
     public void testScriptStartingWithHash() {
         ModuleNode mn = new ModuleNode((CompileUnit) null);
         mn.setDescription("#script.groovy");
-        ClassNode cn = mn.getScriptClassDummy();
-        assertEquals("Dummy class name should not be empty", "#script", 
cn.getName());
+
+        assertEquals("Dummy class name should not be empty", "#script", 
mn.getScriptClassDummy().getName());
+    }
+
+    @Test // GROOVY-9577
+    public void testDuplicateImports() {
+        //@formatter:off
+        String source =
+            "import java.lang.Object\n" +
+            "import java.lang.Object\n" +
+            "import java.lang.Object as X\n";
+        //@formatter:on
+        ModuleNode mn = buildAST(source, null, null, null);
+
+        assertEquals(3, mn.getImports().size());
+        assertEquals(3, mn.getImport("X").getLineNumber());
+        assertEquals(2, mn.getImport("Object").getLineNumber());
+        assertEquals("X", 
DefaultGroovyMethods.last(mn.getImports()).getAlias());
     }
 }
diff --git a/src/test/org/codehaus/groovy/syntax/parser/TestParserSupport.java 
b/src/test/org/codehaus/groovy/syntax/parser/TestParserSupport.java
deleted file mode 100644
index c1fa1f7..0000000
--- a/src/test/org/codehaus/groovy/syntax/parser/TestParserSupport.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.codehaus.groovy.syntax.parser;
-
-import groovy.test.GroovyTestCase;
-import org.codehaus.groovy.ast.ModuleNode;
-import org.codehaus.groovy.control.CompilationUnit;
-import org.codehaus.groovy.control.Phases;
-import org.codehaus.groovy.control.SourceUnit;
-
-/**
- * An abstract base class useful for AST parser related test cases
- */
-public abstract class TestParserSupport extends GroovyTestCase {
-    public ModuleNode parse(String text, String description) {
-        SourceUnit unit = SourceUnit.create(description, text);
-        CompilationUnit compUnit = new CompilationUnit();
-        compUnit.addSource(unit);
-        compUnit.compile(Phases.CONVERSION);
-        return unit.getAST();
-    }
-}

Reply via email to