This is an automated email from the ASF dual-hosted git repository. paulk pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 4cafae822961b51775b49d3b7201b20939e967b1 Author: Paul King <pa...@asert.com.au> AuthorDate: Fri May 24 11:45:47 2019 +1000 GROOVY-9141: add null check for classNode when checking for abstract method with body (tweaks) --- .../codehaus/groovy/antlr/AntlrParserPlugin.java | 9 +++-- src/test/groovy/bugs/Groovy9141.groovy | 38 ++++++++++++++-------- .../apache/groovy/parser/antlr4/AstBuilder.java | 6 ++-- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java b/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java index 81ac6a4..dee0a95 100644 --- a/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java +++ b/src/main/java/org/codehaus/groovy/antlr/AntlrParserPlugin.java @@ -921,12 +921,11 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy modifiers &= ~Opcodes.ACC_SYNTHETIC; methodNode = new MethodNode(name, modifiers, returnType, parameters, exceptions, code); if ((modifiers & Opcodes.ACC_ABSTRACT) == 0) { - if (node != null) { - assertNodeType(SLIST, node); - code = statementList(node); - } else { - throw new ASTRuntimeException(methodDef, "You defined a method without body. Try adding a body, or declare it abstract."); + if (node == null) { + throw new ASTRuntimeException(methodDef, "You defined a method without a body. Try adding a body, or declare it abstract."); } + assertNodeType(SLIST, node); + code = statementList(node); } else if (node != null) { if (classNode != null && classNode.isAnnotationDefinition()) { code = statement(node); diff --git a/src/test/groovy/bugs/Groovy9141.groovy b/src/test/groovy/bugs/Groovy9141.groovy index 32dd3a4..0889d36 100644 --- a/src/test/groovy/bugs/Groovy9141.groovy +++ b/src/test/groovy/bugs/Groovy9141.groovy @@ -20,27 +20,39 @@ package groovy.bugs import gls.CompilableTestSupport import groovy.transform.CompileStatic +import org.codehaus.groovy.control.CompilerConfiguration + +import static org.codehaus.groovy.control.ParserVersion.V_2 @CompileStatic final class Groovy9141 extends CompilableTestSupport { + private static final String METHOD_DEF = ''' + abstract meth() { + println 42 + } + ''' - void testAbstractMethodWithBody1() { - def err = shouldNotCompile '''\ - abstract def meth() { - println 42 - } - '''.stripIndent() - assert err =~ / You can not define a abstract method\[meth\] in the script. Try removing the 'abstract' / + void testAbstractMethodWithBodyInScript() { + def err = shouldNotCompile METHOD_DEF + assert err =~ / You cannot define an abstract method\[meth\] in the script. Try removing the 'abstract' / } - void testAbstractMethodWithBody2() { - def err = shouldNotCompile '''\ + void testAbstractMethodWithBodyInClass() { + def err = shouldNotCompile """ class Main { - abstract def meth() { - println 42 - } + $METHOD_DEF } - '''.stripIndent() + """ + // not a language requirement but class level check takes precedence in current implementation assert err =~ / Can't have an abstract method in a non-abstract class. / } + + void testAbstractMethodWithBodyInScript_oldParser() { + def cc = new CompilerConfiguration(parserVersion: V_2) + def err = shouldFail { + new GroovyShell(cc).evaluate METHOD_DEF + } + assert err =~ / Abstract methods do not define a body/ + } + } 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 0e54bb9..bd93781 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 @@ -1637,7 +1637,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov if (9 == ctx.ct) { // script if (isAbstractMethod || !hasMethodBody) { // method should not be declared abstract in the script - throw createParsingFailedException("You can not define a " + (isAbstractMethod ? "abstract" : "") + " method[" + methodNode.getName() + "] " + (!hasMethodBody ? "without method body" : "") + " in the script. Try " + (isAbstractMethod ? "removing the 'abstract'" : "") + (isAbstractMethod && !hasMethodBody ? " and" : "") + (!hasMethodBody ? " adding a method body" : ""), methodNode); + throw createParsingFailedException("You cannot define " + (isAbstractMethod ? "an abstract" : "a") + " method[" + methodNode.getName() + "] " + (!hasMethodBody ? "without method body " : "") + "in the script. Try " + (isAbstractMethod ? "removing the 'abstract'" : "") + (isAbstractMethod && !hasMethodBody ? " and" : "") + (!hasMethodBody ? " adding a method body" : ""), methodNode); } } else { if (4 == ctx.ct) { // trait @@ -1647,12 +1647,12 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> implements Groov } if (!isAbstractMethod && !hasMethodBody) { // non-abstract method without body in the non-script(e.g. class, enum, trait) is not allowed! - throw createParsingFailedException("You defined a method[" + methodNode.getName() + "] without body. Try adding a method body, or declare it abstract", methodNode); + throw createParsingFailedException("You defined a method[" + methodNode.getName() + "] without a body. Try adding a method body, or declare it abstract", methodNode); } boolean isInterfaceOrAbstractClass = asBoolean(classNode) && classNode.isAbstract() && !classNode.isAnnotationDefinition(); if (isInterfaceOrAbstractClass && !modifierManager.containsAny(DEFAULT) && isAbstractMethod && hasMethodBody) { - throw createParsingFailedException("You defined an abstract method[" + methodNode.getName() + "] with body. Try removing the method body" + (classNode.isInterface() ? ", or declare it default" : ""), methodNode); + throw createParsingFailedException("You defined an abstract method[" + methodNode.getName() + "] with a body. Try removing the method body" + (classNode.isInterface() ? ", or declare it default" : ""), methodNode); } }