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/12 14:10:53 UTC

[groovy] branch GROOVY_3_0_X updated: GROOVY-9522: Throwing NPE when I use ternary operator with something special (#1246)

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


The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
     new e65eeb6  GROOVY-9522: Throwing NPE when I use ternary operator with something special (#1246)
e65eeb6 is described below

commit e65eeb69cc22ae435f408028cdc18d0970b1d306
Author: Daniel.Sun <su...@apache.org>
AuthorDate: Tue May 12 22:02:04 2020 +0800

    GROOVY-9522: Throwing NPE when I use ternary operator with something special (#1246)
    
    (cherry picked from commit 553f52c5403f873fae7b9b66872d48a8cbb54a20)
---
 src/antlr/GroovyParser.g4                          | 46 ++++++++++++++++++++--
 .../apache/groovy/parser/antlr4/AstBuilder.java    | 18 ++++-----
 .../groovy/parser/antlr4/GroovyParserTest.groovy   |  4 ++
 .../src/test/resources/bugs/BUG-GROOVY-9522.groovy | 37 +++++++++++++++++
 4 files changed, 93 insertions(+), 12 deletions(-)

diff --git a/src/antlr/GroovyParser.g4 b/src/antlr/GroovyParser.g4
index 29f347c..47b212c 100644
--- a/src/antlr/GroovyParser.g4
+++ b/src/antlr/GroovyParser.g4
@@ -1008,6 +1008,13 @@ options { baseContext = primary; }
     |   parExpression                                                                       #parenPrmrAlt
     ;
 
+namedArgPrimary
+options { baseContext = primary; }
+    :   identifier                                                                          #identifierPrmrAlt
+    |   literal                                                                             #literalPrmrAlt
+    |   gstring                                                                             #gstringPrmrAlt
+    ;
+
 commandPrimary
 options { baseContext = primary; }
     :   identifier                                                                          #identifierPrmrAlt
@@ -1047,6 +1054,12 @@ options { baseContext = mapEntry; }
     |   MUL COLON nls expression
     ;
 
+namedArg
+options { baseContext = mapEntry; }
+    :   namedArgLabel COLON nls expression
+    |   MUL COLON nls expression
+    ;
+
 mapEntryLabel
     :   keywords
     |   primary
@@ -1058,6 +1071,12 @@ options { baseContext = mapEntryLabel; }
     |   namedPropertyArgPrimary
     ;
 
+namedArgLabel
+options { baseContext = mapEntryLabel; }
+    :   keywords
+    |   namedArgPrimary
+    ;
+
 /**
  *  t 0: general creation; 1: non-static inner class creation
  */
@@ -1100,30 +1119,51 @@ typeArgumentsOrDiamond
     ;
 
 arguments
-    :   LPAREN enhancedArgumentList? COMMA? rparen
+    :   LPAREN enhancedArgumentListInPar? COMMA? rparen
     ;
 
 argumentList
-options { baseContext = enhancedArgumentList; }
-    :   argumentListElement
+options { baseContext = enhancedArgumentListInPar; }
+    :   firstArgumentListElement
         (   COMMA nls
             argumentListElement
         )*
     ;
 
 enhancedArgumentList
+options { baseContext = enhancedArgumentListInPar; }
+    :   firstEnhancedArgumentListElement
+        (   COMMA nls
+            enhancedArgumentListElement
+        )*
+    ;
+
+enhancedArgumentListInPar
     :   enhancedArgumentListElement
         (   COMMA nls
             enhancedArgumentListElement
         )*
     ;
 
+firstArgumentListElement
+options { baseContext = enhancedArgumentListElement; }
+    :   expressionListElement[true]
+    |   namedArg
+    ;
+
 argumentListElement
 options { baseContext = enhancedArgumentListElement; }
     :   expressionListElement[true]
     |   namedPropertyArg
     ;
 
+firstEnhancedArgumentListElement
+options { baseContext = enhancedArgumentListElement; }
+    :   expressionListElement[true]
+    |   standardLambdaExpression
+    |   namedArg
+    ;
+
 enhancedArgumentListElement
     :   expressionListElement[true]
     |   standardLambdaExpression
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 b366212..d5f80d1 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
@@ -201,8 +201,8 @@ import static org.apache.groovy.parser.antlr4.GroovyLangParser.ElementValuePairs
 import static org.apache.groovy.parser.antlr4.GroovyLangParser.ElementValuesContext;
 import static org.apache.groovy.parser.antlr4.GroovyLangParser.EmptyDimsContext;
 import static org.apache.groovy.parser.antlr4.GroovyLangParser.EmptyDimsOptContext;
-import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnhancedArgumentListContext;
 import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnhancedArgumentListElementContext;
+import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnhancedArgumentListInParContext;
 import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnhancedForControlContext;
 import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnhancedStatementExpressionContext;
 import static org.apache.groovy.parser.antlr4.GroovyLangParser.EnumConstantContext;
@@ -2018,7 +2018,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
 
     @Override
     public Expression visitCommandExpression(CommandExpressionContext ctx) {
-        boolean hasArgumentList = asBoolean(ctx.enhancedArgumentList());
+        boolean hasArgumentList = asBoolean(ctx.enhancedArgumentListInPar());
         boolean hasCommandArgument = asBoolean(ctx.commandArgument());
 
         if (visitingArrayInitializerCnt > 0 && (hasArgumentList || hasCommandArgument)) {
@@ -2042,7 +2042,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
         MethodCallExpression methodCallExpression = null;
 
         if (hasArgumentList) {
-            Expression arguments = this.visitEnhancedArgumentList(ctx.enhancedArgumentList());
+            Expression arguments = this.visitEnhancedArgumentListInPar(ctx.enhancedArgumentListInPar());
 
             if (baseExpr instanceof PropertyExpression) { // e.g. obj.a 1, 2
                 methodCallExpression =
@@ -2104,7 +2104,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
 
         Expression primaryExpr = (Expression) this.visit(ctx.primary());
 
-        if (asBoolean(ctx.enhancedArgumentList())) { // e.g. x y a b
+        if (asBoolean(ctx.enhancedArgumentListInPar())) { // e.g. x y a b
             if (baseExpr instanceof PropertyExpression) { // the branch should never reach, because a.b.c will be parsed as a path expression, not a method call
                 throw createParsingFailedException("Unsupported command argument: " + ctx.getText(), ctx);
             }
@@ -2114,7 +2114,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
                     new MethodCallExpression(
                             baseExpr,
                             this.createConstantExpression(primaryExpr),
-                            this.visitEnhancedArgumentList(ctx.enhancedArgumentList())
+                            this.visitEnhancedArgumentListInPar(ctx.enhancedArgumentListInPar())
                     );
             methodCallExpression.setImplicitThis(false);
 
@@ -2493,19 +2493,19 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
 
     @Override
     public Expression visitArguments(ArgumentsContext ctx) {
-        if (asBoolean(ctx) && asBoolean(ctx.COMMA()) && !asBoolean(ctx.enhancedArgumentList())) {
+        if (asBoolean(ctx) && asBoolean(ctx.COMMA()) && !asBoolean(ctx.enhancedArgumentListInPar())) {
             throw createParsingFailedException("Expression expected", ctx.COMMA());
         }
 
-        if (!asBoolean(ctx) || !asBoolean(ctx.enhancedArgumentList())) {
+        if (!asBoolean(ctx) || !asBoolean(ctx.enhancedArgumentListInPar())) {
             return new ArgumentListExpression();
         }
 
-        return configureAST(this.visitEnhancedArgumentList(ctx.enhancedArgumentList()), ctx);
+        return configureAST(this.visitEnhancedArgumentListInPar(ctx.enhancedArgumentListInPar()), ctx);
     }
 
     @Override
-    public Expression visitEnhancedArgumentList(EnhancedArgumentListContext ctx) {
+    public Expression visitEnhancedArgumentListInPar(EnhancedArgumentListInParContext ctx) {
         if (!asBoolean(ctx)) {
             return null;
         }
diff --git a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
index cf841e5..83e63f9 100644
--- a/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
+++ b/subprojects/parser-antlr4/src/test/groovy/org/apache/groovy/parser/antlr4/GroovyParserTest.groovy
@@ -462,4 +462,8 @@ final class GroovyParserTest extends GroovyTestCase {
     void "test groovy core - GROOVY-9507"() {
         doTest('bugs/BUG-GROOVY-9507.groovy');
     }
+
+    void "test groovy core - GROOVY-9522"() {
+        doTest('bugs/BUG-GROOVY-9522.groovy');
+    }
 }
diff --git a/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-9522.groovy b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-9522.groovy
new file mode 100644
index 0000000..2b4e332
--- /dev/null
+++ b/subprojects/parser-antlr4/src/test/resources/bugs/BUG-GROOVY-9522.groovy
@@ -0,0 +1,37 @@
+/*
+ *  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.
+ */
+
+static String a() {
+    null
+}
+
+static String b() {
+    ''
+}
+
+def x = a() ? [b(), a()].join(',') : b()
+def x = a() ? [b(), a()] : b()
+def x = a() ? ([b(), a()]).join(',') : b()
+
+x == ''
+
+ds = DB_DATASOURCE.newInstance(
+        (DB_DS_KEY): DB_URL_PREFIX + getMethodName(),
+        user: DB_USER,
+        password: DB_PASSWORD)