You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2019/11/17 03:00:53 UTC
[groovy] branch master updated: GROOVY-8446: Antlr2: syntax error
for void[] or void...
This is an automated email from the ASF dual-hosted git repository.
emilles 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 d99605b GROOVY-8446: Antlr2: syntax error for void[] or void...
d99605b is described below
commit d99605b902ab3748641e44c3e768cfd072e5e75f
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Nov 16 21:00:47 2019 -0600
GROOVY-8446: Antlr2: syntax error for void[] or void...
NOTE: Antlr4 parser does not recognize "void[]" or "void..." as types;
the JUnit tests can be switched to the new parser if/when it does.
---
.../codehaus/groovy/antlr/AntlrParserPlugin.java | 341 ++++++++-------------
src/test/groovy/bugs/Groovy8446.groovy | 67 ++++
.../apache/groovy/parser/antlr4/AstBuilder.java | 3 +
3 files changed, 204 insertions(+), 207 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java b/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java
index c6e6f87..99da22d 100644
--- a/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java
+++ b/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java
@@ -127,14 +127,14 @@ import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import static org.codehaus.groovy.ast.tools.GeneralUtils.nullX;
+import static org.codehaus.groovy.runtime.DefaultGroovyMethods.last;
/**
- * A parser plugin which adapts the JSR Antlr Parser to the Groovy runtime
+ * A parser plugin which adapts the JSR Antlr Parser to the Groovy runtime.
*/
@Deprecated
public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, GroovyTokenTypes {
@@ -142,6 +142,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
private static class AnonymousInnerClassCarrier extends Expression {
ClassNode innerClass;
+ @Override
public Expression transformExpression(ExpressionTransformer transformer) {
return null;
}
@@ -180,15 +181,15 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
protected AST ast;
private ClassNode classNode;
private MethodNode methodNode;
- private String[] tokenNames;
- private boolean enumConstantBeingDef = false;
- private boolean forStatementBeingDef = false;
- private boolean annotationBeingDef = false;
- private boolean firstParamIsVarArg = false;
- private boolean firstParam = false;
-
- public /*final*/ Reduction parseCST(final SourceUnit sourceUnit, Reader reader) throws CompilationFailedException {
- final SourceBuffer sourceBuffer = new SourceBuffer();
+ protected String[] tokenNames;
+ private boolean enumConstantBeingDef;
+ private boolean forStatementBeingDef;
+ private boolean annotationBeingDef;
+ private boolean firstParamIsVarArg;
+ private boolean firstParam;
+
+ public Reduction parseCST(SourceUnit sourceUnit, Reader reader) throws CompilationFailedException {
+ SourceBuffer sourceBuffer = new SourceBuffer();
transformCSTIntoAST(sourceUnit, reader, sourceBuffer);
processAST();
return outputAST(sourceUnit, sourceBuffer);
@@ -199,8 +200,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
setController(sourceUnit);
- // TODO find a way to inject any GroovyLexer/GroovyRecognizer
-
UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(reader, sourceBuffer);
UnicodeLexerSharedInputState inputState = new UnicodeLexerSharedInputState(unicodeReader);
GroovyLexer lexer = new GroovyLexer(inputState);
@@ -238,12 +237,10 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
}
public Reduction outputAST(final SourceUnit sourceUnit, final SourceBuffer sourceBuffer) {
- AccessController.doPrivileged((PrivilegedAction) () -> {
+ return AccessController.doPrivileged((PrivilegedAction<Reduction>) () -> {
outputASTInVariousFormsIfNeeded(sourceUnit, sourceBuffer);
return null;
});
-
- return null; //new Reduction(Tpken.EOF);
}
private void outputASTInVariousFormsIfNeeded(SourceUnit sourceUnit, SourceBuffer sourceBuffer) {
@@ -251,7 +248,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
String formatProp = System.getProperty("ANTLR.AST".toLowerCase()); // uppercase to hide from jarjar
if ("xml".equals(formatProp)) {
- saveAsXML(sourceUnit.getName(), ast);
+ XStreamUtils.serialize(sourceUnit.getName() + ".antlr", ast);
}
// 'pretty printer' output of AST
@@ -307,10 +304,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
}
}
- private static void saveAsXML(String name, AST ast) {
- XStreamUtils.serialize(name+".antlr", ast);
- }
-
public ModuleNode buildAST(SourceUnit sourceUnit, ClassLoader classLoader, Reduction cst) throws ParserException {
setClassLoader(classLoader);
makeModule();
@@ -321,7 +314,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
}
// set the script source position
-
ClassNode scriptClassNode = output.getScriptClassDummy();
if (scriptClassNode != null) {
List<Statement> statements = output.getStatementBlock().getStatements();
@@ -334,15 +326,15 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
scriptClassNode.setLastLineNumber(lastStatement.getLastLineNumber());
}
}
- }
- catch (ASTRuntimeException e) {
+ } catch (ASTRuntimeException e) {
throw new ASTParserException(e.getMessage() + ". File: " + sourceUnit.getName(), e);
}
+ ast = null;
return output;
}
/**
- * Converts the Antlr AST to the Groovy AST
+ * Converts the Antlr AST to the Groovy AST.
*/
protected void convertGroovy(AST node) {
while (node != null) {
@@ -378,10 +370,8 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
annotationDef(node);
break;
- default: {
- Statement statement = statement(node);
- output.addStatement(statement);
- }
+ default:
+ output.addStatement(statement(node));
}
node = node.getNextSibling();
}
@@ -397,9 +387,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
processAnnotations(annotations, node);
node = node.getNextSibling();
}
- String name = qualifiedName(node);
- // TODO should we check package node doesn't already exist? conflict?
- PackageNode packageNode = setPackage(name, annotations);
+ PackageNode packageNode = setPackage(qualifiedName(node), annotations);
configureAST(packageNode, packageDef);
}
@@ -417,11 +405,13 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
node = node.getNextSibling();
}
+ ImportNode imp;
String alias = null;
+ AST aliasNode = null;
if (isType(LITERAL_as, node)) {
//import is like "import Foo as Bar"
node = node.getFirstChild();
- AST aliasNode = node.getNextSibling();
+ aliasNode = node.getNextSibling();
alias = identifier(aliasNode);
}
@@ -431,6 +421,8 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
ClassNode type = ClassHelper.make(name);
configureAST(type, importNode);
addImport(type, name, alias, annotations);
+ imp = last(output.getImports());
+ configureAST(imp, importNode);
return;
}
@@ -444,14 +436,17 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
ClassNode type = ClassHelper.make(packageName);
configureAST(type, importNode);
addStaticStarImport(type, packageName, annotations);
+ imp = output.getStaticStarImports().get(packageName);
+ configureAST(imp, importNode);
} else {
// import is like "import foo.*"
addStarImport(packageName, annotations);
+ imp = last(output.getStarImports());
+ configureAST(imp, importNode);
}
- if (alias != null) throw new GroovyBugError(
- "imports like 'import foo.* as Bar' are not " +
- "supported and should be caught by the grammar");
+ if (alias != null)
+ throw new GroovyBugError("imports like 'import foo.* as Bar' are not supported and should be caught by the grammar");
} else {
String name = identifier(nameNode);
if (isStatic) {
@@ -460,18 +455,22 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
ClassNode type = ClassHelper.make(packageName);
configureAST(type, importNode);
addStaticImport(type, name, alias, annotations);
+ imp = output.getStaticImports().get(alias == null ? name : alias);
+ configureAST(imp, importNode);
} else {
// import is like "import foo.Bar"
ClassNode type = ClassHelper.make(packageName + "." + name);
configureAST(type, importNode);
addImport(type, name, alias, annotations);
+ imp = last(output.getImports());
+ configureAST(imp, importNode);
}
}
} finally {
// we're using node metadata here in order to fix GROOVY-6094
// without breaking external APIs
Object node = output.getNodeMetaData(ImportNode.class);
- if (node!=null && node!=ImportNode.class) {
+ if (node != null && node != ImportNode.class) {
configureAST((ImportNode)node, importNode);
}
output.removeNodeMetaData(ImportNode.class);
@@ -607,7 +606,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
protected Expression anonymousInnerClassDef(AST node) {
ClassNode oldNode = classNode;
ClassNode outerClass = getClassOrScript(oldNode);
- String innerClassName = outerClass.getName() + '$' + (anonymousClassCount(outerClass) + 1);
+ String innerClassName = outerClass.getName() + "$" + (anonymousClassCount(outerClass) + 1);
if (enumConstantBeingDef) {
classNode = new EnumConstantClassNode(outerClass, innerClassName, Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE);
} else {
@@ -615,14 +614,15 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
}
((InnerClassNode) classNode).setAnonymous(true);
classNode.setEnclosingMethod(methodNode);
+ configureAST(classNode, node);
assertNodeType(OBJBLOCK, node);
objectBlock(node);
- output.addClass(classNode);
+
AnonymousInnerClassCarrier ret = new AnonymousInnerClassCarrier();
ret.innerClass = classNode;
+ output.addClass(classNode);
classNode = oldNode;
-
return ret;
}
@@ -768,10 +768,11 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
String enumName = (classNode != null ? name : dot(getPackageName(), name));
ClassNode enumClass = EnumHelper.makeEnumNode(enumName, modifiers, interfaces, classNode);
enumClass.setSyntheticPublic(syntheticPublic);
- ClassNode oldNode = classNode;
enumClass.addAnnotations(annotations);
+ configureAST(enumClass, enumNode);
+
+ ClassNode oldNode = classNode;
classNode = enumClass;
- configureAST(classNode, enumNode);
assertNodeType(OBJBLOCK, node);
objectBlock(node);
classNode = oldNode;
@@ -923,9 +924,10 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
if ((modifiers & Opcodes.ACC_ABSTRACT) == 0) {
if (node == null) {
throw new ASTRuntimeException(methodDef, "You defined a method without a body. Try adding a body, or declare it abstract.");
+ } else {
+ assertNodeType(SLIST, node);
+ code = statementList(node);
}
- assertNodeType(SLIST, node);
- code = statementList(node);
} else if (node != null) {
if (classNode != null && classNode.isAnnotationDefinition()) {
code = statement(node);
@@ -1046,7 +1048,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
initialValue = getDefaultValueForPrimitive(type);
}
-
FieldNode fieldNode = new FieldNode(name, modifiers, type, classNode, initialValue);
fieldNode.addAnnotations(annotations);
configureAST(fieldNode, fieldDef);
@@ -1162,7 +1163,8 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
ClassNode type = ClassHelper.DYNAMIC_TYPE;
if (isType(TYPE, node)) {
type = makeTypeWithArguments(node);
- if (variableParameterDef) type = type.makeArray();
+ if (variableParameterDef)
+ type = makeArray(type, node);
node = node.getNextSibling();
}
@@ -1289,8 +1291,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
protected AnnotationNode annotation(AST annotationNode) {
annotationBeingDef = true;
AST node = annotationNode.getFirstChild();
- String name = qualifiedName(node);
- AnnotationNode annotatedNode = new AnnotationNode(ClassHelper.make(name));
+ AnnotationNode annotatedNode = new AnnotationNode(ClassHelper.make(qualifiedName(node)));
configureAST(annotatedNode, annotationNode);
while (true) {
node = node.getNextSibling();
@@ -1310,7 +1311,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return annotatedNode;
}
-
// Statements
//-------------------------------------------------------------------------
@@ -1396,10 +1396,10 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
protected Statement statementListNoChild(AST node, AST alternativeConfigureNode) {
BlockStatement block = siblingsToBlockStatement(node);
// alternativeConfigureNode is used only to set the source position
- if (node != null) {
- configureAST(block, node);
- } else {
+ if (alternativeConfigureNode != null) {
configureAST(block, alternativeConfigureNode);
+ } else if (node != null) {
+ configureAST(block, node);
}
return block;
}
@@ -1606,15 +1606,13 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
Expression expression = expression(node);
Statement defaultStatement = EmptyStatement.INSTANCE;
- List list = new ArrayList();
+ List<CaseStatement> caseStatements = new ArrayList<>();
for (node = node.getNextSibling(); isType(CASE_GROUP, node); node = node.getNextSibling()) {
Statement tmpDefaultStatement;
AST child = node.getFirstChild();
if (isType(LITERAL_case, child)) {
- List cases = new LinkedList();
// default statement can be grouped with previous case
- tmpDefaultStatement = caseStatements(child, cases);
- list.addAll(cases);
+ tmpDefaultStatement = caseStatements(child, caseStatements);
} else {
tmpDefaultStatement = statement(child.getNextSibling());
}
@@ -1629,13 +1627,13 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
if (node != null) {
unknownAST(node);
}
- SwitchStatement switchStatement = new SwitchStatement(expression, list, defaultStatement);
+ SwitchStatement switchStatement = new SwitchStatement(expression, caseStatements, defaultStatement);
configureAST(switchStatement, switchNode);
return switchStatement;
}
- protected Statement caseStatements(AST node, List cases) {
- List<Expression> expressions = new LinkedList<>();
+ protected Statement caseStatements(AST node, List<CaseStatement> cases) {
+ List<Expression> expressions = new ArrayList<>();
Statement statement = EmptyStatement.INSTANCE;
Statement defaultStatement = EmptyStatement.INSTANCE;
AST nextSibling = node;
@@ -1652,10 +1650,9 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
statement = statement(nextSibling);
}
}
- Iterator iterator = expressions.iterator();
- while (iterator.hasNext()) {
- Expression expr = (Expression) iterator.next();
- Statement stmt;
+ for (Iterator<Expression> iterator = expressions.iterator(); iterator.hasNext(); ) {
+ Expression expr = iterator.next();
+ CaseStatement stmt;
if (iterator.hasNext()) {
stmt = new CaseStatement(expr, EmptyStatement.INSTANCE);
} else {
@@ -1721,9 +1718,9 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
protected List<CatchStatement> catchStatement(AST catchNode) {
AST node = catchNode.getFirstChild();
- List<CatchStatement> catches = new LinkedList<>();
+ List<CatchStatement> catches = new ArrayList<>();
if (MULTICATCH == node.getType()) {
- final AST multicatches = node.getFirstChild();
+ AST multicatches = node.getFirstChild();
if (multicatches.getType() != MULTICATCH_TYPES) {
// catch (e)
// catch (def e)
@@ -1734,7 +1731,8 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
catches.add(answer);
} else {
// catch (Exception e)
- // catch (Exception1 | Exception2 e)
+ // catch (java.lang.Exception e)
+ // catch (Exception1 | foo.bar.Exception2 e)
AST exceptionNodes = multicatches.getFirstChild();
String variable = identifier(multicatches.getNextSibling());
while (exceptionNodes != null) {
@@ -1772,7 +1770,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return whileStatement;
}
-
// Expressions
//-------------------------------------------------------------------------
@@ -1800,7 +1797,8 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
int type = node.getType();
switch (type) {
case EXPR:
- return expression(node.getFirstChild());
+ Expression expression = expression(node.getFirstChild());
+ return expression;
case ELIST:
return expressionList(node);
@@ -1861,10 +1859,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
case SPREAD_MAP_ARG:
return spreadMapExpression(node);
- // commented out of groovy.g due to non determinisms
- //case MEMBER_POINTER_DEFAULT:
- // return defaultMethodPointerExpression(node);
-
case MEMBER_POINTER:
return methodPointerExpression(node);
@@ -1880,14 +1874,15 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
case TYPECAST:
return castExpression(node);
- // literals
-
case LITERAL_true:
return literalExpression(node, Boolean.TRUE);
+
case LITERAL_false:
return literalExpression(node, Boolean.FALSE);
+
case LITERAL_null:
return literalExpression(node, null);
+
case STRING_LITERAL:
return literalExpression(node, node.getText());
@@ -1921,23 +1916,19 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
case UNARY_PLUS:
return unaryPlusExpression(node);
- // Prefix expressions
case INC:
return prefixExpression(node, Types.PLUS_PLUS);
case DEC:
return prefixExpression(node, Types.MINUS_MINUS);
- // Postfix expressions
case POST_INC:
return postfixExpression(node, Types.PLUS_PLUS);
case POST_DEC:
return postfixExpression(node, Types.MINUS_MINUS);
-
// Binary expressions
-
case ASSIGN:
return binaryExpression(Types.ASSIGN, node);
@@ -1968,18 +1959,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
case GE:
return binaryExpression(Types.COMPARE_GREATER_THAN_EQUAL, node);
- /**
- * TODO treble equal?
- return binaryExpression(Types.COMPARE_IDENTICAL, node);
-
- case ???:
- return binaryExpression(Types.LOGICAL_AND_EQUAL, node);
-
- case ???:
- return binaryExpression(Types.LOGICAL_OR_EQUAL, node);
-
- */
-
case LAND:
return binaryExpression(Types.LOGICAL_AND, node);
@@ -2004,42 +1983,36 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
case BXOR_ASSIGN:
return binaryExpression(Types.BITWISE_XOR_EQUAL, node);
-
case PLUS:
return binaryExpression(Types.PLUS, node);
case PLUS_ASSIGN:
return binaryExpression(Types.PLUS_EQUAL, node);
-
case MINUS:
return binaryExpression(Types.MINUS, node);
case MINUS_ASSIGN:
return binaryExpression(Types.MINUS_EQUAL, node);
-
case STAR:
return binaryExpression(Types.MULTIPLY, node);
case STAR_ASSIGN:
return binaryExpression(Types.MULTIPLY_EQUAL, node);
-
case STAR_STAR:
return binaryExpression(Types.POWER, node);
case STAR_STAR_ASSIGN:
return binaryExpression(Types.POWER_EQUAL, node);
-
case DIV:
return binaryExpression(Types.DIVIDE, node);
case DIV_ASSIGN:
return binaryExpression(Types.DIVIDE_EQUAL, node);
-
case MOD:
return binaryExpression(Types.MOD, node);
@@ -2074,7 +2047,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
case REGEX_MATCH:
return binaryExpression(Types.MATCH_REGEX, node);
-
// Ranges
case RANGE_INCLUSIVE:
return rangeExpression(node, true);
@@ -2089,7 +2061,9 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return binaryExpression(Types.KEYWORD_IN, node);
case ANNOTATION:
- return new AnnotationConstantExpression(annotation(node));
+ expression = new AnnotationConstantExpression(annotation(node));
+ configureAST(expression, node);
+ return expression;
case CLOSURE_LIST:
return closureListExpression(node);
@@ -2125,7 +2099,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
private ClosureListExpression closureListExpression(AST node) {
isClosureListExpressionAllowedHere(node);
AST exprNode = node.getFirstChild();
- List<Expression> list = new LinkedList<>();
+ List<Expression> list = new ArrayList<>();
while (exprNode != null) {
if (isType(EXPR, exprNode)) {
Expression expr = expression(exprNode);
@@ -2184,7 +2158,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return variableExpression;
}
- protected Expression literalExpression(AST node, Object value) {
+ protected ConstantExpression literalExpression(AST node, Object value) {
ConstantExpression constantExpression = new ConstantExpression(value, value instanceof Boolean);
configureAST(constantExpression, node);
return constantExpression;
@@ -2232,16 +2206,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return methodPointerExpression;
}
-/* commented out due to groovy.g non-determinisms
- protected Expression defaultMethodPointerExpression(AST node) {
- AST exprNode = node.getFirstChild();
- String methodName = exprNode.toString();
- MethodPointerExpression methodPointerExpression = new MethodPointerExpression(null, methodName);
- configureAST(methodPointerExpression, node);
- return methodPointerExpression;
- }
-*/
-
protected Expression listExpression(AST listNode) {
List<Expression> expressions = new ArrayList<>();
AST elist = listNode.getFirstChild();
@@ -2264,11 +2228,8 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return listExpression;
}
- /**
- * Typically only used for map constructors I think?
- */
protected Expression mapExpression(AST mapNode) {
- List expressions = new ArrayList();
+ List<MapEntryExpression> entryExpressions = new ArrayList<>();
AST elist = mapNode.getFirstChild();
if (elist != null) { // totally empty in the case of [:]
assertNodeType(ELIST, elist);
@@ -2279,15 +2240,15 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
break; // legal cases
case SPREAD_ARG:
assertNodeType(SPREAD_MAP_ARG, node);
- break; // helpful error
+ break;
default:
assertNodeType(LABELED_ARG, node);
- break; // helpful error
+ break;
}
- expressions.add(mapEntryExpression(node));
+ entryExpressions.add(mapEntryExpression(node));
}
}
- MapExpression mapExpression = new MapExpression(expressions);
+ MapExpression mapExpression = new MapExpression(entryExpressions);
configureAST(mapExpression, mapNode);
return mapExpression;
}
@@ -2311,7 +2272,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
}
}
-
protected Expression instanceofExpression(AST node) {
AST leftNode = node.getFirstChild();
Expression leftExpression = expression(leftNode);
@@ -2340,7 +2300,9 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
AST rightNode = leftNode.getNextSibling();
ClassNode type = makeTypeWithArguments(rightNode);
- return CastExpression.asExpression(type, leftExpression);
+ CastExpression asExpression = CastExpression.asExpression(type, leftExpression);
+ configureAST(asExpression, node);
+ return asExpression;
}
protected Expression castExpression(AST castNode) {
@@ -2356,7 +2318,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return castExpression;
}
-
protected Expression indexExpression(AST indexNode) {
AST bracket = indexNode.getFirstChild();
AST leftNode = bracket.getNextSibling();
@@ -2476,6 +2437,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
if (property instanceof VariableExpression) {
VariableExpression ve = (VariableExpression) property;
property = new ConstantExpression(ve.getName());
+ property.setSourcePosition(ve);
}
PropertyExpression propertyExpression = new PropertyExpression(leftExpression, property, node.getType() != DOT);
@@ -2531,8 +2493,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
objectExpression = VariableExpression.SUPER_EXPRESSION;
}
} else if (isPrimitiveTypeLiteral(selector)) {
- throw new ASTRuntimeException(selector, "Primitive type literal: " + selector.getText()
- + " cannot be used as a method name");
+ throw new ASTRuntimeException(selector, "Primitive type literal: " + selector.getText() + " cannot be used as a method name");
} else if (isType(SELECT_SLOT, selector)) {
Expression field = expression(selector.getFirstChild(), true);
AttributeExpression attributeExpression = new AttributeExpression(objectExpression, field, node.getType() != DOT);
@@ -2551,7 +2512,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
objectExpression = expression(selector, true);
}
- // if node text is found to be "super"/"this" when a method call is being processed, it is a
+ // if node text is found to be "super"/"this" when a method call is being processed, it is a
// call like this(..)/super(..) after the first statement, which shouldn't be allowed. GROOVY-2836
if (selector.getText().equals("this") || selector.getText().equals("super")) {
if (!(annotationBeingDef && selector.getText().equals("super"))) {
@@ -2606,7 +2567,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
if (expressionNode == null) {
throw new ASTRuntimeException(elist, "No expression for the array constructor call");
}
- List size = arraySizeExpression(expressionNode);
+ List<Expression> size = arraySizeExpression(expressionNode);
ArrayExpression arrayExpression = new ArrayExpression(type, null, size);
configureAST(arrayExpression, constructorCallNode);
return arrayExpression;
@@ -2643,8 +2604,8 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return null;
}
- protected List arraySizeExpression(AST node) {
- List list;
+ protected List<Expression> arraySizeExpression(AST node) {
+ List<Expression> list;
Expression size = null;
if (isType(ARRAY_DECLARATOR, node)) {
AST right = node.getNextSibling();
@@ -2660,7 +2621,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
list = arraySizeExpression(child);
} else {
size = expression(node);
- list = new ArrayList();
+ list = new ArrayList<>();
}
list.add(size);
return list;
@@ -2678,7 +2639,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
}
protected Expression arguments(AST elist) {
- List expressionList = new ArrayList();
+ List expressionList = new ArrayList<>();
// FIXME: all labeled arguments should follow any unlabeled arguments
boolean namedArguments = false;
for (AST node = elist; node != null; node = node.getNextSibling()) {
@@ -2724,19 +2685,17 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
}
}
- private static void checkDuplicateNamedParams(AST elist, List expressionList) {
+ private static void checkDuplicateNamedParams(AST elist, List<MapEntryExpression> expressionList) {
if (expressionList.isEmpty()) return;
Set<String> namedArgumentNames = new HashSet<>();
- for (Object expression : expressionList) {
- MapEntryExpression meExp = (MapEntryExpression) expression;
+ for (MapEntryExpression meExp : expressionList) {
if (meExp.getKeyExpression() instanceof ConstantExpression) {
String argName = meExp.getKeyExpression().getText();
if (!namedArgumentNames.contains(argName)) {
namedArgumentNames.add(argName);
} else {
- throw new ASTRuntimeException(elist, "Duplicate named parameter '" + argName
- + "' found.");
+ throw new ASTRuntimeException(elist, "Duplicate named parameter '" + argName + "' found.");
}
}
}
@@ -2835,6 +2794,8 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
protected Expression unaryPlusExpression(AST unaryPlusExpr) {
AST node = unaryPlusExpr.getFirstChild();
+ UnaryPlusExpression unaryPlusExpression = new UnaryPlusExpression(expression(node));
+ configureAST(unaryPlusExpression, unaryPlusExpr);
switch (node.getType()) {
case NUM_DOUBLE:
case NUM_FLOAT:
@@ -2842,11 +2803,9 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
case NUM_BIG_INT:
case NUM_INT:
case NUM_LONG:
- return expression(node);
+ return unaryPlusExpression.getExpression();
default:
- UnaryPlusExpression unaryPlusExpression = new UnaryPlusExpression(expression(node));
- configureAST(unaryPlusExpression, unaryPlusExpr);
return unaryPlusExpression;
}
}
@@ -2870,8 +2829,8 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
}
protected Expression gstring(AST gstringNode) {
- List strings = new ArrayList();
- List values = new ArrayList();
+ List<ConstantExpression> strings = new ArrayList<>();
+ List<Expression> values = new ArrayList<>();
StringBuilder buffer = new StringBuilder();
@@ -2908,12 +2867,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return gStringExpression;
}
- protected ClassNode type(AST typeNode) {
- // TODO intern types?
- // TODO configureAST(...)
- return buildName(typeNode.getFirstChild());
- }
-
public static String qualifiedName(AST qualifiedNameNode) {
if (isType(IDENT, qualifiedNameNode)) {
return qualifiedNameNode.getText();
@@ -3000,7 +2953,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
private List<GenericsType> getTypeArgumentsList(AST node) {
assertNodeType(TYPE_ARGUMENTS, node);
- List<GenericsType> typeArgumentList = new LinkedList<>();
+ List<GenericsType> typeArgumentList = new ArrayList<>();
AST typeArgument = node.getFirstChild();
while (typeArgument != null) {
@@ -3016,58 +2969,60 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
AST boundsRoot = rn.getNextSibling();
if (boundsRoot == null) return null;
assertNodeType(boundType, boundsRoot);
- LinkedList bounds = new LinkedList();
- for (AST boundsNode = boundsRoot.getFirstChild();
- boundsNode != null;
- boundsNode = boundsNode.getNextSibling()
- ) {
- ClassNode bound = null;
- bound = makeTypeWithArguments(boundsNode);
+ List<ClassNode> bounds = new ArrayList<>();
+ for (AST boundsNode = boundsRoot.getFirstChild(); boundsNode != null; boundsNode = boundsNode.getNextSibling()) {
+ ClassNode bound = makeTypeWithArguments(boundsNode);
configureAST(bound, boundsNode);
bounds.add(bound);
}
if (bounds.isEmpty()) return null;
- return (ClassNode[]) bounds.toArray(ClassNode.EMPTY_ARRAY);
+ return bounds.toArray(ClassNode.EMPTY_ARRAY);
}
protected GenericsType[] makeGenericsType(AST rootNode) {
AST typeParameter = rootNode.getFirstChild();
- LinkedList ret = new LinkedList();
+ List<GenericsType> generics = new ArrayList<>();
assertNodeType(TYPE_PARAMETER, typeParameter);
while (isType(TYPE_PARAMETER, typeParameter)) {
- AST typeNode = typeParameter.getFirstChild();
- ClassNode type = makeType(typeParameter);
-
- GenericsType gt = new GenericsType(type, makeGenericsBounds(typeNode, TYPE_UPPER_BOUNDS), null);
+ GenericsType gt = new GenericsType(makeType(typeParameter), makeGenericsBounds(typeParameter.getFirstChild(), TYPE_UPPER_BOUNDS), null);
configureAST(gt, typeParameter);
+ generics.add(gt);
- ret.add(gt);
typeParameter = typeParameter.getNextSibling();
}
- return (GenericsType[]) ret.toArray(GenericsType.EMPTY_ARRAY);
+ return generics.toArray(GenericsType.EMPTY_ARRAY);
}
protected ClassNode makeType(AST typeNode) {
ClassNode answer = ClassHelper.DYNAMIC_TYPE;
AST node = typeNode.getFirstChild();
if (node != null) {
- if (isType(INDEX_OP, node) || isType(ARRAY_DECLARATOR, node)) {
- answer = makeType(node).makeArray();
+ if (isType(ARRAY_DECLARATOR, node) || isType(INDEX_OP, node)) {
+ answer = makeArray(makeTypeWithArguments(node), node);
} else {
checkTypeArgs(node, false);
answer = ClassHelper.make(qualifiedName(node));
if (answer.isUsingGenerics()) {
- ClassNode newAnswer = ClassHelper.makeWithoutCaching(answer.getName());
- newAnswer.setRedirect(answer);
- answer = newAnswer;
+ ClassNode proxy = ClassHelper.makeWithoutCaching(answer.getName());
+ proxy.setRedirect(answer);
+ answer = proxy;
}
+ configureAST(answer, node);
}
- configureAST(answer, node);
}
return answer;
}
+ private ClassNode makeArray(ClassNode elementType, AST node) {
+ if (elementType.equals(ClassHelper.VOID_TYPE)) {
+ throw new ASTRuntimeException(node.getFirstChild(), "void[] is an invalid type");
+ }
+ ClassNode arrayType = elementType.makeArray();
+ configureAST(arrayType, node);
+ return arrayType;
+ }
+
private boolean checkTypeArgs(AST node, boolean seenTypeArgs) {
if (isType(IDENT, node) && seenTypeArgs) {
throw new ASTRuntimeException(node, "Unexpected type arguments found prior to: " + qualifiedName(node));
@@ -3083,44 +3038,22 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return seenTypeArgs;
}
- /**
- * Performs a name resolution to see if the given name is a type from imports,
- * aliases or newly created classes
- */
- /*protected String resolveTypeName(String name, boolean safe) {
- if (name == null) {
- return null;
- }
- return resolveNewClassOrName(name, safe);
- }*/
-
- /**
- * Extracts an identifier from the Antlr AST and then performs a name resolution
- * to see if the given name is a type from imports, aliases or newly created classes
- */
protected ClassNode buildName(AST node) {
if (isType(TYPE, node)) {
node = node.getFirstChild();
}
- ClassNode answer = null;
- if (isType(DOT, node) || isType(OPTIONAL_DOT, node)) {
- answer = ClassHelper.make(qualifiedName(node));
- } else if (isPrimitiveTypeLiteral(node)) {
- answer = ClassHelper.make(node.getText());
- } else if (isType(INDEX_OP, node) || isType(ARRAY_DECLARATOR, node)) {
- AST child = node.getFirstChild();
- answer = buildName(child).makeArray();
- configureAST(answer, node);
- return answer;
+ String name;
+ if (isType(ARRAY_DECLARATOR, node) || isType(INDEX_OP, node)) {
+ return makeArray(buildName(node.getFirstChild()), node);
+ } else if (isType(DOT, node) || isType(OPTIONAL_DOT, node)) {
+ name = qualifiedName(node);
} else {
- String identifier = node.getText();
- answer = ClassHelper.make(identifier);
+ name = node.getText();
}
+ ClassNode answer = ClassHelper.make(name);
AST nextSibling = node.getNextSibling();
- if (isType(INDEX_OP, nextSibling) || isType(ARRAY_DECLARATOR, node)) {
- answer = answer.makeArray();
- configureAST(answer, node);
- return answer;
+ if (isType(ARRAY_DECLARATOR, nextSibling) || isType(INDEX_OP, nextSibling)) {
+ return makeArray(answer, node);
} else {
configureAST(answer, node);
return answer;
@@ -3161,11 +3094,9 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return identifier(node);
}
-
// Helper methods
//-------------------------------------------------------------------------
-
/**
* Returns true if the modifiers flags contain a visibility modifier
*/
@@ -3175,16 +3106,13 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
protected void configureAST(ASTNode node, AST ast) {
if (ast == null)
- throw new ASTRuntimeException(ast, "PARSER BUG: Tried to configure " + node.getClass().getName() + " with null Node");
- node.setColumnNumber(ast.getColumn());
+ throw new ASTRuntimeException(ast, "PARSER BUG: Tried to configure " + node.getClass().getName() + " with null AST");
node.setLineNumber(ast.getLine());
+ node.setColumnNumber(ast.getColumn());
if (ast instanceof GroovySourceAST) {
- node.setLastColumnNumber(((GroovySourceAST) ast).getColumnLast());
node.setLastLineNumber(((GroovySourceAST) ast).getLineLast());
+ node.setLastColumnNumber(((GroovySourceAST) ast).getColumnLast());
}
-
- // TODO we could one day store the Antlr AST on the Groovy AST
- // node.setCSTNode(ast);
}
protected static Token makeToken(int typeCode, AST node) {
@@ -3196,7 +3124,6 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
return child != null ? child.getText() : null;
}
-
public static boolean isType(int typeCode, AST node) {
return node != null && node.getType() == typeCode;
}
diff --git a/src/test/groovy/bugs/Groovy8446.groovy b/src/test/groovy/bugs/Groovy8446.groovy
new file mode 100644
index 0000000..a6a9ccd
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy8446.groovy
@@ -0,0 +1,67 @@
+/*
+ * 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 groovy.bugs
+
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.antlr.AntlrParserPluginFactory
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.shouldFail
+
+@CompileStatic
+final class Groovy8446 {
+
+ private GroovyShell shell = new GroovyShell(
+ new CompilerConfiguration(pluginFactory: new AntlrParserPluginFactory()))
+
+ @Test
+ void testVoidArray0() {
+ shell.evaluate '''
+ class C {
+ Void[] m() {}
+ }
+ println 'parsed'
+ '''
+ }
+
+ @Test
+ void testVoidArray1() {
+ def err = shouldFail {
+ shell.evaluate '''
+ class C {
+ void[] m() {}
+ }
+ '''
+ }
+ assert err =~ /void\[\] is an invalid type/
+ }
+
+ @Test
+ void testVoidArray2() {
+ def err = shouldFail {
+ shell.evaluate '''
+ class C {
+ def meth(void... args) {}
+ }
+ '''
+ }
+ assert err =~ /void\[\] is an invalid type|void is not allowed here/
+ }
+}
diff --git a/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java b/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
index 580f23d..33e794e 100644
--- a/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/subprojects/parser-antlr4/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -4114,6 +4114,9 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov
}
private ClassNode createArrayType(ClassNode elementType) {
+ if (ClassHelper.VOID_TYPE.equals(elementType)) {
+ throw this.createParsingFailedException("void[] is an invalid type", elementType);
+ }
return elementType.makeArray();
}