You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/05/30 15:18:38 UTC
[groovy] 09/11: return unmodifiable collections and other minor
refactoring
This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 3f2f3d4b0680a03a833215429cea7e52196a27e1
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri May 29 10:02:06 2020 -0500
return unmodifiable collections and other minor refactoring
(cherry picked from commit 435280d495242cbbbd7148a2b0d72cdc6ac4d35f)
---
.../java/org/codehaus/groovy/ast/ImportNode.java | 65 +++---
.../java/org/codehaus/groovy/ast/ModuleNode.java | 231 ++++++++++-----------
.../codehaus/groovy/control/CompilationUnit.java | 10 +-
.../{Groovy4193Bug.groovy => Groovy4193.groovy} | 19 +-
4 files changed, 161 insertions(+), 164 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/ast/ImportNode.java b/src/main/java/org/codehaus/groovy/ast/ImportNode.java
index df249bb..d5d3f50 100644
--- a/src/main/java/org/codehaus/groovy/ast/ImportNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/ImportNode.java
@@ -18,12 +18,12 @@
*/
package org.codehaus.groovy.ast;
-import org.objectweb.asm.Opcodes;
+import static java.util.Objects.requireNonNull;
/**
- * Represents an import statement of a single class
+ * Represents an import statement.
*/
-public class ImportNode extends AnnotatedNode implements Opcodes {
+public class ImportNode extends AnnotatedNode {
private final ClassNode type;
private final String alias;
@@ -33,13 +33,13 @@ public class ImportNode extends AnnotatedNode implements Opcodes {
private final boolean isStatic;
/**
- * Represent an import of an entire package, i.e. import package.Classname
+ * An import of a single type, i.e. {@code import pack.Type} or {@code import pack.Type as Alias}
*
- * @param type the referenced class
+ * @param type the type reference
* @param alias optional alias
*/
- public ImportNode(ClassNode type, String alias) {
- this.type = type;
+ public ImportNode(final ClassNode type, final String alias) {
+ this.type = requireNonNull(type);
this.alias = alias;
this.isStar = false;
this.isStatic = false;
@@ -48,26 +48,26 @@ public class ImportNode extends AnnotatedNode implements Opcodes {
}
/**
- * Represent an import of an entire package, i.e. import package.*
+ * An import of all types in a package, i.e. {@code import pack.*}
*
* @param packageName the name of the package
*/
- public ImportNode(String packageName) {
+ public ImportNode(final String packageName) {
this.type = null;
this.alias = null;
this.isStar = true;
this.isStatic = false;
- this.packageName = packageName;
+ this.packageName = requireNonNull(packageName);
this.fieldName = null;
}
/**
- * Represent a static import of a Class, i.e. import static package.Classname.*
+ * An import of all static members of a type, i.e. {@code import static pack.Type.*}
*
- * @param type the referenced class
+ * @param type the type reference
*/
- public ImportNode(ClassNode type) {
- this.type = type;
+ public ImportNode(final ClassNode type) {
+ this.type = requireNonNull(type);
this.alias = null;
this.isStar = true;
this.isStatic = true;
@@ -76,24 +76,25 @@ public class ImportNode extends AnnotatedNode implements Opcodes {
}
/**
- * Represent a static import of a field or method, i.e. import static package.Classname.name
+ * An import of a static field or method of a type, i.e. {@code import static pack.Type.name} or {@code import static pack.Type.name as alias}
*
- * @param type the referenced class
+ * @param type the type reference
* @param fieldName the field name
* @param alias optional alias
*/
- public ImportNode(ClassNode type, String fieldName, String alias) {
- this.type = type;
+ public ImportNode(final ClassNode type, final String fieldName, final String alias) {
+ this.type = requireNonNull(type);
this.alias = alias;
this.isStar = false;
this.isStatic = true;
this.packageName = null;
- this.fieldName = fieldName;
+ this.fieldName = requireNonNull(fieldName);
}
/**
* @return the text display of this import
*/
+ @Override
public String getText() {
String typeName = getClassName();
if (isStar && !isStatic) {
@@ -114,14 +115,6 @@ public class ImportNode extends AnnotatedNode implements Opcodes {
return "import " + typeName + " as " + alias;
}
- public String getPackageName() {
- return packageName;
- }
-
- public String getFieldName() {
- return fieldName;
- }
-
public boolean isStar() {
return isStar;
}
@@ -134,15 +127,23 @@ public class ImportNode extends AnnotatedNode implements Opcodes {
return alias;
}
- public ClassNode getType() {
- return type;
+ public String getClassName() {
+ return (type == null ? null : type.getName());
}
- public String getClassName() {
- return type == null ? null : type.getName();
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ public String getPackageName() {
+ return packageName;
}
- public void visit(GroovyCodeVisitor visitor) {
+ public ClassNode getType() {
+ return type;
}
+ @Override
+ public void visit(final GroovyCodeVisitor visitor) {
+ }
}
diff --git a/src/main/java/org/codehaus/groovy/ast/ModuleNode.java b/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
index f305aea..7fcdfc6 100644
--- a/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
@@ -19,13 +19,7 @@
package org.codehaus.groovy.ast;
import groovy.lang.Binding;
-import org.codehaus.groovy.ast.expr.ArgumentListExpression;
-import org.codehaus.groovy.ast.expr.ClassExpression;
-import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
-import org.codehaus.groovy.ast.expr.MethodCallExpression;
-import org.codehaus.groovy.ast.expr.VariableExpression;
import org.codehaus.groovy.ast.stmt.BlockStatement;
-import org.codehaus.groovy.ast.stmt.ExpressionStatement;
import org.codehaus.groovy.ast.stmt.Statement;
import org.codehaus.groovy.classgen.GeneratorContext;
import org.codehaus.groovy.control.SourceUnit;
@@ -45,6 +39,15 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.callX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.classX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.params;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+
/**
* Represents a module, which consists typically of a class declaration
* but could include some imports, some statements and multiple classes
@@ -67,24 +70,15 @@ public class ModuleNode extends ASTNode implements Opcodes {
private ClassNode scriptDummy;
private String mainClassName;
private final BlockStatement statementBlock = new BlockStatement();
- private final Parameter[] SCRIPT_CONTEXT_CTOR = {new Parameter(ClassHelper.BINDING_TYPE, "context")};
- public ModuleNode (SourceUnit context ) {
+ public ModuleNode(final SourceUnit context) {
this.context = context;
}
- public ModuleNode (CompileUnit unit) {
+ public ModuleNode(final CompileUnit unit) {
this.unit = unit;
}
- public BlockStatement getStatementBlock() {
- return statementBlock;
- }
-
- public List<MethodNode> getMethods() {
- return methods;
- }
-
public List<ClassNode> getClasses() {
if (createClassForStatements && (!statementBlock.isEmpty() || !methods.isEmpty() || isPackageInfo())) {
ClassNode mainClass = createStatementsClass();
@@ -94,11 +88,11 @@ public class ModuleNode extends ASTNode implements Opcodes {
mainClass.setModule(this);
addToCompileUnit(mainClass);
}
- return classes;
+ return /*Collections.unmodifiableList(*/classes/*)*/; // modified by MacroClassTransform
}
- private boolean isPackageInfo() {
- return context != null && context.getName() != null && context.getName().endsWith("package-info.groovy");
+ public List<MethodNode> getMethods() {
+ return Collections.unmodifiableList(methods);
}
public List<ImportNode> getImports() {
@@ -106,53 +100,63 @@ public class ModuleNode extends ASTNode implements Opcodes {
}
public List<ImportNode> getStarImports() {
- return starImports;
+ return Collections.unmodifiableList(starImports);
+ }
+
+ public Map<String, ImportNode> getStaticImports() {
+ return Collections.unmodifiableMap(staticImports);
+ }
+
+ public Map<String, ImportNode> getStaticStarImports() {
+ return Collections.unmodifiableMap(staticStarImports);
}
/**
* @param alias the name of interest
- * @return the class node for the given alias or null if none is available
+ * @return the import type for the given alias or null if none is available
*/
- public ClassNode getImportType(String alias) {
- ImportNode importNode = imports.get(alias);
- return importNode == null ? null : importNode.getType();
+ public ClassNode getImportType(final String alias) {
+ ImportNode node = getImport(alias);
+ return (node != null ? node.getType() : null);
}
/**
* @param alias the name of interest
* @return the import node for the given alias or null if none is available
*/
- public ImportNode getImport(String alias) {
+ public ImportNode getImport(final String alias) {
return imports.get(alias);
}
- public void addImport(String alias, ClassNode type) {
+ public void addImport(final String alias, final ClassNode type) {
addImport(alias, type, Collections.emptyList());
}
- public void addImport(String alias, ClassNode type, List<AnnotationNode> annotations) {
+ public void addImport(final String alias, final ClassNode type, final List<AnnotationNode> annotations) {
ImportNode importNode = new ImportNode(type, alias);
- imports.put(alias, importNode);
importNode.addAnnotations(annotations);
+ imports.put(alias, importNode);
+
storeLastAddedImportNode(importNode);
}
- public void addStarImport(String packageName) {
+ public void addStarImport(final String packageName) {
addStarImport(packageName, Collections.emptyList());
}
- public void addStarImport(String packageName, List<AnnotationNode> annotations) {
+ public void addStarImport(final String packageName, final List<AnnotationNode> annotations) {
ImportNode importNode = new ImportNode(packageName);
importNode.addAnnotations(annotations);
starImports.add(importNode);
+
storeLastAddedImportNode(importNode);
}
- public void addStaticImport(ClassNode type, String fieldName, String alias) {
+ public void addStaticImport(final ClassNode type, final String fieldName, final String alias) {
addStaticImport(type, fieldName, alias, Collections.emptyList());
}
- public void addStaticImport(ClassNode type, String fieldName, String alias, List<AnnotationNode> annotations) {
+ public void addStaticImport(final ClassNode type, final String fieldName, final String alias, final List<AnnotationNode> annotations) {
ImportNode node = new ImportNode(type, fieldName, alias);
node.addAnnotations(annotations);
ImportNode prev = staticImports.put(alias, node);
@@ -160,43 +164,47 @@ public class ModuleNode extends ASTNode implements Opcodes {
staticImports.put(prev.toString(), prev);
staticImports.put(alias, staticImports.remove(alias));
}
+
storeLastAddedImportNode(node);
}
- public void addStaticStarImport(String name, ClassNode type) {
+ public void addStaticStarImport(final String name, final ClassNode type) {
addStaticStarImport(name, type, Collections.emptyList());
}
- public void addStaticStarImport(String name, ClassNode type, List<AnnotationNode> annotations) {
+ public void addStaticStarImport(final String name, final ClassNode type, final List<AnnotationNode> annotations) {
ImportNode node = new ImportNode(type);
node.addAnnotations(annotations);
staticStarImports.put(name, node);
+
storeLastAddedImportNode(node);
}
- public void addStatement(Statement node) {
+ public void addStatement(final Statement node) {
statementBlock.addStatement(node);
}
- public void addClass(ClassNode node) {
- if(classes.isEmpty()) mainClassName = node.getName();
+ public void addClass(final ClassNode node) {
+ if (classes.isEmpty())
+ mainClassName = node.getName();
classes.add(node);
node.setModule(this);
addToCompileUnit(node);
}
- private void addToCompileUnit(ClassNode node) {
+ private void addToCompileUnit(final ClassNode node) {
// register the new class with the compile unit
if (unit != null) {
unit.addClass(node);
}
}
- public void addMethod(MethodNode node) {
+ public void addMethod(final MethodNode node) {
methods.add(node);
}
- public void visit(GroovyCodeVisitor visitor) {
+ @Override
+ public void visit(final GroovyCodeVisitor visitor) {
}
public String getPackageName() {
@@ -207,26 +215,20 @@ public class ModuleNode extends ASTNode implements Opcodes {
return packageNode;
}
- // TODO don't allow override?
- public void setPackage(PackageNode packageNode) {
- this.packageNode = packageNode;
- }
-
- // TODO don't allow override?
- public void setPackageName(String packageName) {
- this.packageNode = new PackageNode(packageName);
+ public boolean hasPackage() {
+ return (packageNode != null);
}
- public boolean hasPackageName(){
- return packageNode != null && packageNode.getName() != null;
+ public void setPackage(final PackageNode packageNode) {
+ this.packageNode = packageNode;
}
- public boolean hasPackage(){
- return this.packageNode != null;
+ public boolean hasPackageName() {
+ return (packageNode != null && packageNode.getName() != null);
}
- public SourceUnit getContext() {
- return context;
+ public void setPackageName(final String packageName) {
+ setPackage(new PackageNode(packageName));
}
/**
@@ -236,11 +238,11 @@ public class ModuleNode extends ASTNode implements Opcodes {
if (context != null) {
return context.getName();
} else {
- return this.description;
+ return description;
}
}
- public void setDescription(String description) {
+ public void setDescription(final String description) {
this.description = description;
}
@@ -248,12 +250,20 @@ public class ModuleNode extends ASTNode implements Opcodes {
return unit;
}
- void setUnit(CompileUnit unit) {
+ void setUnit(final CompileUnit unit) {
this.unit = unit;
}
+ public SourceUnit getContext() {
+ return context;
+ }
+
+ private boolean isPackageInfo() {
+ return context != null && context.getName() != null && context.getName().endsWith("package-info.groovy");
+ }
+
public ClassNode getScriptClassDummy() {
- if (scriptDummy!=null) {
+ if (scriptDummy != null) {
setScriptBaseClassFromConfig(scriptDummy);
return scriptDummy;
}
@@ -282,7 +292,7 @@ public class ModuleNode extends ASTNode implements Opcodes {
return classNode;
}
- private void setScriptBaseClassFromConfig(ClassNode cn) {
+ private void setScriptBaseClassFromConfig(final ClassNode cn) {
String baseClassName = null;
if (unit != null) {
baseClassName = unit.getConfig().getScriptBaseClass();
@@ -312,15 +322,17 @@ public class ModuleNode extends ASTNode implements Opcodes {
"main",
ACC_PUBLIC | ACC_STATIC,
ClassHelper.VOID_TYPE,
- new Parameter[] { new Parameter(ClassHelper.STRING_TYPE.makeArray(), "args")},
+ params(param(ClassHelper.STRING_TYPE.makeArray(), "args")),
ClassNode.EMPTY_ARRAY,
- new ExpressionStatement(
- new MethodCallExpression(
- new ClassExpression(ClassHelper.make(InvokerHelper.class)),
+ stmt(
+ callX(
+ classX(ClassHelper.make(InvokerHelper.class)),
"runScript",
- new ArgumentListExpression(
- new ClassExpression(classNode),
- new VariableExpression("args"))))));
+ args(classX(classNode), varX("args"))
+ )
+ )
+ )
+ );
MethodNode methodNode = new MethodNode("run", ACC_PUBLIC, ClassHelper.OBJECT_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, statementBlock);
methodNode.setIsScriptBody();
@@ -332,39 +344,25 @@ public class ModuleNode extends ASTNode implements Opcodes {
// A script's contextual constructor should call it's super class' contextual constructor, if it has one.
// In practice this will always be true because currently this visitor is run before the AST transformations
// (like @BaseScript) that could change this. But this is cautious and anticipates possible compiler changes.
- if (classNode.getSuperClass().getDeclaredConstructor(SCRIPT_CONTEXT_CTOR) != null) {
- stmt = new ExpressionStatement(
- new ConstructorCallExpression(ClassNode.SUPER,
- new ArgumentListExpression(
- new VariableExpression("context"))));
+ if (classNode.getSuperClass().getDeclaredConstructor(params(param(ClassHelper.BINDING_TYPE, "context"))) != null) {
+ stmt = stmt(ctorX(ClassNode.SUPER, args(varX("context"))));
} else {
// Fallback for non-standard base "script" classes with no context (Binding) constructor.
- stmt = new ExpressionStatement(
- new MethodCallExpression(
- new VariableExpression("super"),
- "setBinding",
- new ArgumentListExpression(
- new VariableExpression("context"))));
+ stmt = stmt(callX(varX("super"), "setBinding", args(varX("context"))));
}
classNode.addConstructor(
ACC_PUBLIC,
- new Parameter[] { new Parameter(ClassHelper.make(Binding.class), "context")},
+ params(param(ClassHelper.make(Binding.class), "context")),
ClassNode.EMPTY_ARRAY,
stmt);
- for (MethodNode node : methods) {
- int modifiers = node.getModifiers();
- if ((modifiers & ACC_ABSTRACT) != 0) {
- throw new RuntimeException(
- "Cannot use abstract methods in a script, they are only available inside classes. Method: "
- + node.getName());
+ for (MethodNode method : methods) {
+ if (method.isAbstract()) {
+ throw new RuntimeException("Cannot use abstract methods in a script" +
+ ", they are only available inside classes. Method: " + method.getName());
}
- // br: the old logic seems to add static to all def f().... in a script, which makes enclosing
- // inner classes (including closures) in a def function difficult. Comment it out.
- node.setModifiers(modifiers /*| ACC_STATIC*/);
-
- classNode.addMethod(node);
+ classNode.addMethod(method);
}
return classNode;
}
@@ -372,11 +370,11 @@ public class ModuleNode extends ASTNode implements Opcodes {
/*
* If a main method is provided by user, account for it under run() as scripts generate their own 'main' so they can run.
*/
- private void handleMainMethodIfPresent(List methods) {
+ private void handleMainMethodIfPresent(final List<MethodNode> methods) {
boolean found = false;
- for (Iterator iter = methods.iterator(); iter.hasNext();) {
- MethodNode node = (MethodNode) iter.next();
- if(node.getName().equals("main")) {
+ for (Iterator<MethodNode> iter = methods.iterator(); iter.hasNext();) {
+ MethodNode node = iter.next();
+ if (node.getName().equals("main")) {
if (node.isStatic() && node.getParameters().length == 1) {
boolean retTypeMatches, argTypeMatches;
ClassNode argType = node.getParameters()[0].getType();
@@ -385,14 +383,14 @@ public class ModuleNode extends ASTNode implements Opcodes {
argTypeMatches = (argType.equals(ClassHelper.OBJECT_TYPE) || argType.getName().contains("String[]"));
retTypeMatches = (retType == ClassHelper.VOID_TYPE || retType == ClassHelper.OBJECT_TYPE);
- if(retTypeMatches && argTypeMatches) {
- if(found) {
+ if (retTypeMatches && argTypeMatches) {
+ if (found) {
throw new RuntimeException("Repetitive main method found.");
} else {
found = true;
}
// if script has both loose statements as well as main(), then main() is ignored
- if(statementBlock.isEmpty()) {
+ if (statementBlock.isEmpty()) {
addStatement(node.getCode());
}
iter.remove();
@@ -437,21 +435,20 @@ public class ModuleNode extends ASTNode implements Opcodes {
return classes.isEmpty() && statementBlock.getStatements().isEmpty();
}
- public void sortClasses(){
+ public void sortClasses() {
if (isEmpty()) return;
- List<ClassNode> classes = getClasses();
- LinkedList<ClassNode> sorted = new LinkedList<>();
- int level=1;
- while (!classes.isEmpty()) {
- for (Iterator<ClassNode> cni = classes.iterator(); cni.hasNext();) {
- ClassNode cn = cni.next();
- ClassNode sn = cn;
- for (int i=0; sn!=null && i<level; i++) sn = sn.getSuperClass();
- if (sn!=null && sn.isPrimaryClassNode()) continue;
- cni.remove();
- sorted.addLast(cn);
+ List<ClassNode> sorted = new LinkedList<>(), todo = getClasses();
+ int level = 1;
+ while (!todo.isEmpty()) {
+ for (Iterator<ClassNode> it = todo.iterator(); it.hasNext(); ) {
+ ClassNode cn = it.next(), sc = cn;
+
+ for (int i = 0; sc != null && i < level; i += 1) sc = sc.getSuperClass();
+ if (sc != null && sc.isPrimaryClassNode()) continue;
+ sorted.add(cn);
+ it.remove();
}
- level++;
+ level += 1;
}
this.classes = sorted;
}
@@ -460,18 +457,10 @@ public class ModuleNode extends ASTNode implements Opcodes {
return importsResolved;
}
- public void setImportsResolved(boolean importsResolved) {
+ public void setImportsResolved(final boolean importsResolved) {
this.importsResolved = importsResolved;
}
- public Map<String, ImportNode> getStaticImports() {
- return staticImports;
- }
-
- public Map<String, ImportNode> getStaticStarImports() {
- return staticStarImports;
- }
-
// This method only exists as a workaround for GROOVY-6094
// In order to keep binary compatibility
private void storeLastAddedImportNode(final ImportNode node) {
@@ -483,4 +472,8 @@ public class ModuleNode extends ASTNode implements Opcodes {
public String getMainClassName() {
return mainClassName;
}
+
+ public BlockStatement getStatementBlock() {
+ return statementBlock;
+ }
}
diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 02e4f1c..24d52e1 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -112,12 +112,12 @@ public class CompilationUnit extends ProcessingUnit {
}
}
- /** Controls behavior of {@link #classgen} and other routines. */
+ /** Controls behavior of {@link #classgen()} and other routines. */
protected boolean debug;
/** True after the first {@link #configure(CompilerConfiguration)} operation. */
protected boolean configured;
- /** A callback for use during {@link #classgen} */
+ /** A callback for use during {@link #classgen()} */
protected ClassgenCallback classgenCallback;
/** A callback for use during {@link #compile()} */
protected ProgressCallback progressCallback;
@@ -219,7 +219,9 @@ public class CompilationUnit extends ProcessingUnit {
}
}, Phases.SEMANTIC_ANALYSIS);
- addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> TraitComposer.doExtendTraits(classNode, source, this), Phases.CANONICALIZATION);
+ addPhaseOperation((final SourceUnit source, final GeneratorContext context, final ClassNode classNode) -> {
+ TraitComposer.doExtendTraits(classNode, source, this);
+ }, Phases.CANONICALIZATION);
addPhaseOperation(source -> {
List<ClassNode> classes = source.getAST().getClasses();
@@ -447,7 +449,7 @@ public class CompilationUnit extends ProcessingUnit {
}
/**
- * @return the class loader for loading AST transformations
+ * Returns the class loader for loading AST transformations.
*/
public GroovyClassLoader getTransformLoader() {
return Optional.ofNullable(getASTTransformationsContext().getTransformLoader()).orElseGet(this::getClassLoader);
diff --git a/src/test/groovy/bugs/Groovy4193Bug.groovy b/src/test/groovy/bugs/Groovy4193.groovy
similarity index 74%
rename from src/test/groovy/bugs/Groovy4193Bug.groovy
rename to src/test/groovy/bugs/Groovy4193.groovy
index 6db3096..63195a6 100644
--- a/src/test/groovy/bugs/Groovy4193Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4193.groovy
@@ -18,15 +18,16 @@
*/
package groovy.bugs
-import groovy.test.GroovyTestCase
+import groovy.transform.CompileStatic
import org.codehaus.groovy.ast.ImportNode
+import org.junit.Test
-class Groovy4193Bug extends GroovyTestCase {
- void testNPEOnImportNode() {
- def imp = new ImportNode(null, "GROOVY-4193")
-
- assertNull imp.className // no NPE
-
- assertNotNull imp.text // no NPE
+@CompileStatic
+final class Groovy4193 {
+ @Test
+ void testImportNodeGetClassNameForNullType() {
+ def imp = new ImportNode('GROOVY-4193')
+ assert imp.className == null // no NPE
+ assert imp.text != null // no NPE
}
-}
\ No newline at end of file
+}