diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/basic/GroovySimpleTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/basic/GroovySimpleTests.java index 5e1353a8c0..8b6d67ffb8 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/basic/GroovySimpleTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/basic/GroovySimpleTests.java @@ -5377,6 +5377,30 @@ public void testGroovy9336() { runConformTest(sources, "65536.0"); } + @Test // https://issues.apache.org/jira/browse/GROOVY-9391 + public void testGroovy9391() { + //@formatter:off + String[] sources = { + "Main.groovy", + "class A { def m() {} }\n" + + "class B extends A { }\n" + + "class C extends B {\n" + + " def m() {\n" + + " ((A) super).m()\n" + // makes no sense + " }\n" + + "}\n", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in Main.groovy (at line 5)\n" + + "\t((A) super).m()\n" + + "\t ^^^^^^^^^\n" + + "Groovy:Cannot cast or coerce `super`\n" + + "----------\n"); + } + @Test // https://issues.apache.org/jira/browse/GROOVY-9906 public void testGroovy9906() { //@formatter:off diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java index 96d787f76b..5eabc66e93 100644 --- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java +++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java @@ -2768,8 +2768,9 @@ protected Expression asExpression(AST node) { ClassNode type = makeTypeWithArguments(rightNode); CastExpression asExpression = CastExpression.asExpression(type, leftExpression); - // GRECLIPSE edit -- set the sloc from the start of the target and the end of the type - //configureAST(asExpression, node); + /* GRECLIPSE edit -- set the sloc from the start of the target to the end of the type + configureAST(asExpression, node); + */ asExpression.setStart(leftExpression.getStart()); asExpression.setLineNumber(leftExpression.getLineNumber()); asExpression.setColumnNumber(leftExpression.getColumnNumber()); @@ -2789,6 +2790,9 @@ protected Expression asExpression(AST node) { // set the range of the type by itself asExpression.setNameStart(typeStart); asExpression.setNameEnd(asExpression.getEnd()); + + if (leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isSuperExpression()) + getController().addError(new SyntaxException("Cannot cast or coerce `super`", asExpression)); // GROOVY-9391 // GRECLIPSE end return asExpression; } @@ -2816,6 +2820,8 @@ protected Expression castExpression(AST castNode) { castExpression.setNameStart(locations.findOffset(typeNode.getLine(), typeNode.getColumn())); castExpression.setNameEnd(locations.findOffset(typeNode.getLineLast(), typeNode.getColumnLast())); } + if (expression instanceof VariableExpression && ((VariableExpression) expression).isSuperExpression()) + getController().addError(new SyntaxException("Cannot cast or coerce `super`", castExpression)); // GROOVY-9391 // GRECLIPSE end return castExpression; } diff --git a/base/org.codehaus.groovy30/src/org/apache/groovy/parser/antlr4/AstBuilder.java b/base/org.codehaus.groovy30/src/org/apache/groovy/parser/antlr4/AstBuilder.java index db57897fb7..05d206fa85 100644 --- a/base/org.codehaus.groovy30/src/org/apache/groovy/parser/antlr4/AstBuilder.java +++ b/base/org.codehaus.groovy30/src/org/apache/groovy/parser/antlr4/AstBuilder.java @@ -3162,9 +3162,13 @@ public CastExpression visitCastExprAlt(CastExprAltContext ctx) { ctx ); */ - CastExpression cast = new CastExpression(visitCastParExpression(ctx.castParExpression()), (Expression) visit(ctx.expression())); + Expression expr = (Expression) this.visit(ctx.expression()); + if (expr instanceof VariableExpression && ((VariableExpression) expr).isSuperExpression()) { + this.createParsingFailedException("Cannot cast or coerce `super`", ctx); // GROOVY-9391 + } + CastExpression cast = new CastExpression(this.visitCastParExpression(ctx.castParExpression()), expr); Expression name = configureAST(new ConstantExpression(null), ctx.castParExpression().type().primitiveType() != null - ? ctx.castParExpression().type().primitiveType() : ctx.castParExpression().type().classOrInterfaceType()); + ? ctx.castParExpression().type().primitiveType() : ctx.castParExpression().type().classOrInterfaceType()); cast.setNameStart(name.getStart()); cast.setNameEnd(name.getEnd()); return configureAST(cast, ctx); // GRECLIPSE end @@ -3288,9 +3292,13 @@ public Expression visitRelationalExprAlt(RelationalExprAltContext ctx) { CastExpression.asExpression(this.visitType(ctx.type()), (Expression) this.visit(ctx.left)), ctx); */ - CastExpression cast = CastExpression.asExpression(visitType(ctx.type()), (Expression) visit(ctx.left)); + Expression expr = (Expression) this.visit(ctx.left); + if (expr instanceof VariableExpression && ((VariableExpression) expr).isSuperExpression()) { + this.createParsingFailedException("Cannot cast or coerce `super`", ctx); // GROOVY-9391 + } + CastExpression cast = CastExpression.asExpression(this.visitType(ctx.type()), expr); Expression name = configureAST(new ConstantExpression(null), ctx.type().primitiveType() != null - ? ctx.type().primitiveType() : ctx.type().classOrInterfaceType()); + ? ctx.type().primitiveType() : ctx.type().classOrInterfaceType()); cast.setNameStart(name.getStart()); cast.setNameEnd(name.getEnd()); return configureAST(cast, ctx); // GRECLIPSE end diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java index 1c71f49df3..47269b4891 100644 --- a/base/org.codehaus.groovy30/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java +++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java @@ -2832,8 +2832,9 @@ protected Expression asExpression(AST node) { ClassNode type = makeTypeWithArguments(rightNode); CastExpression asExpression = CastExpression.asExpression(type, leftExpression); - // GRECLIPSE edit -- set the sloc from the start of the target and the end of the type - //configureAST(asExpression, node); + /* GRECLIPSE edit -- set the sloc from the start of the target to the end of the type + configureAST(asExpression, node); + */ asExpression.setStart(leftExpression.getStart()); asExpression.setLineNumber(leftExpression.getLineNumber()); asExpression.setColumnNumber(leftExpression.getColumnNumber()); @@ -2853,6 +2854,9 @@ protected Expression asExpression(AST node) { // set the range of the type by itself asExpression.setNameStart(typeStart); asExpression.setNameEnd(asExpression.getEnd()); + + if (leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isSuperExpression()) + getController().addError(new SyntaxException("Cannot cast or coerce `super`", asExpression)); // GROOVY-9391 // GRECLIPSE end return asExpression; } @@ -2880,6 +2884,8 @@ protected Expression castExpression(AST castNode) { castExpression.setNameStart(locations.findOffset(typeNode.getLine(), typeNode.getColumn())); castExpression.setNameEnd(locations.findOffset(typeNode.getLineLast(), typeNode.getColumnLast())); } + if (expression instanceof VariableExpression && ((VariableExpression) expression).isSuperExpression()) + getController().addError(new SyntaxException("Cannot cast or coerce `super`", castExpression)); // GROOVY-9391 // GRECLIPSE end return castExpression; } diff --git a/base/org.codehaus.groovy40/src/org/apache/groovy/parser/antlr4/AstBuilder.java b/base/org.codehaus.groovy40/src/org/apache/groovy/parser/antlr4/AstBuilder.java index 8c5211c08e..d68e3f81e4 100644 --- a/base/org.codehaus.groovy40/src/org/apache/groovy/parser/antlr4/AstBuilder.java +++ b/base/org.codehaus.groovy40/src/org/apache/groovy/parser/antlr4/AstBuilder.java @@ -3421,13 +3421,14 @@ public Expression visitUnaryNotExprAlt(final UnaryNotExprAltContext ctx) { @Override public CastExpression visitCastExprAlt(final CastExprAltContext ctx) { - CastExpression cast = new CastExpression( - this.visitCastParExpression(ctx.castParExpression()), - (Expression) this.visit(ctx.expression()) - ); + Expression expr = (Expression) this.visit(ctx.expression()); + if (expr instanceof VariableExpression && ((VariableExpression) expr).isSuperExpression()) { + this.createParsingFailedException("Cannot cast or coerce `super`", ctx); // GROOVY-9391 + } + CastExpression cast = new CastExpression(this.visitCastParExpression(ctx.castParExpression()), expr); // GRECLIPSE add Expression name = configureAST(new ConstantExpression(null), ctx.castParExpression().type().primitiveType() != null - ? ctx.castParExpression().type().primitiveType() : ctx.castParExpression().type().classOrInterfaceType()); + ? ctx.castParExpression().type().primitiveType() : ctx.castParExpression().type().classOrInterfaceType()); cast.setNameStart(name.getStart()); cast.setNameEnd(name.getEnd()); // GRECLIPSE end return configureAST(cast, ctx); @@ -3545,45 +3546,39 @@ public Expression visitShiftExprAlt(final ShiftExprAltContext ctx) { @Override public Expression visitRelationalExprAlt(final RelationalExprAltContext ctx) { switch (ctx.op.getType()) { - case AS: - /* GRECLIPSE edit - return configureAST( - CastExpression.asExpression(this.visitType(ctx.type()), (Expression) this.visit(ctx.left)), - ctx); - */ - CastExpression cast = CastExpression.asExpression(visitType(ctx.type()), (Expression) visit(ctx.left)); + case AS: + Expression expr = (Expression) this.visit(ctx.left); + if (expr instanceof VariableExpression && ((VariableExpression) expr).isSuperExpression()) { + this.createParsingFailedException("Cannot cast or coerce `super`", ctx); // GROOVY-9391 + } + CastExpression cast = CastExpression.asExpression(this.visitType(ctx.type()), expr); + // GRECLIPSE add Expression name = configureAST(new ConstantExpression(null), ctx.type().primitiveType() != null - ? ctx.type().primitiveType() : ctx.type().classOrInterfaceType()); + ? ctx.type().primitiveType() : ctx.type().classOrInterfaceType()); cast.setNameStart(name.getStart()); cast.setNameEnd(name.getEnd()); - return configureAST(cast, ctx); - // GRECLIPSE end + // GRECLIPSE end + return configureAST(cast, ctx); - case INSTANCEOF: - case NOT_INSTANCEOF: - ctx.type().putNodeMetaData(IS_INSIDE_INSTANCEOF_EXPR, true); - return configureAST( - new BinaryExpression((Expression) this.visit(ctx.left), - this.createGroovyToken(ctx.op), - configureAST(new ClassExpression(this.visitType(ctx.type())), ctx.type())), - ctx); - - case LE: - case GE: - case GT: - case LT: - case IN: - case NOT_IN: { - if (ctx.op.getType() == IN || ctx.op.getType() == NOT_IN ) { - return this.createBinaryExpression(ctx.left, ctx.op, ctx.right, ctx); - } + case INSTANCEOF: + case NOT_INSTANCEOF: + ctx.type().putNodeMetaData(IS_INSIDE_INSTANCEOF_EXPR, Boolean.TRUE); + return configureAST( + new BinaryExpression( + (Expression) this.visit(ctx.left), + this.createGroovyToken(ctx.op), + configureAST(new ClassExpression(this.visitType(ctx.type())), ctx.type())), + ctx); - return configureAST( - this.createBinaryExpression(ctx.left, ctx.op, ctx.right), - ctx); - } + case GT: + case GE: + case LT: + case LE: + case IN: + case NOT_IN: + return this.createBinaryExpression(ctx.left, ctx.op, ctx.right, ctx); - default: - throw createParsingFailedException("Unsupported relational expression: " + ctx.getText(), ctx); + default: + throw this.createParsingFailedException("Unsupported relational expression: " + ctx.getText(), ctx); } } diff --git a/base/org.codehaus.groovy40/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java b/base/org.codehaus.groovy40/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java index b4ac37c6fd..dfe1d8c343 100644 --- a/base/org.codehaus.groovy40/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java +++ b/base/org.codehaus.groovy40/src/org/codehaus/groovy/antlr/AntlrParserPlugin.java @@ -2832,8 +2832,9 @@ protected Expression asExpression(AST node) { ClassNode type = makeTypeWithArguments(rightNode); CastExpression asExpression = CastExpression.asExpression(type, leftExpression); - // GRECLIPSE edit -- set the sloc from the start of the target and the end of the type - //configureAST(asExpression, node); + /* GRECLIPSE edit -- set the sloc from the start of the target to the end of the type + configureAST(asExpression, node); + */ asExpression.setStart(leftExpression.getStart()); asExpression.setLineNumber(leftExpression.getLineNumber()); asExpression.setColumnNumber(leftExpression.getColumnNumber()); @@ -2853,6 +2854,9 @@ protected Expression asExpression(AST node) { // set the range of the type by itself asExpression.setNameStart(typeStart); asExpression.setNameEnd(asExpression.getEnd()); + + if (leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).isSuperExpression()) + getController().addError(new SyntaxException("Cannot cast or coerce `super`", asExpression)); // GROOVY-9391 // GRECLIPSE end return asExpression; } @@ -2880,6 +2884,8 @@ protected Expression castExpression(AST castNode) { castExpression.setNameStart(locations.findOffset(typeNode.getLine(), typeNode.getColumn())); castExpression.setNameEnd(locations.findOffset(typeNode.getLineLast(), typeNode.getColumnLast())); } + if (expression instanceof VariableExpression && ((VariableExpression) expression).isSuperExpression()) + getController().addError(new SyntaxException("Cannot cast or coerce `super`", castExpression)); // GROOVY-9391 // GRECLIPSE end return castExpression; } diff --git a/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/ui/SemanticHighlightingTests.groovy b/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/ui/SemanticHighlightingTests.groovy index 894faf9f55..7c413a7922 100644 --- a/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/ui/SemanticHighlightingTests.groovy +++ b/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/ui/SemanticHighlightingTests.groovy @@ -3739,6 +3739,26 @@ final class SemanticHighlightingTests extends GroovyEclipseTestSuite { assertHighlighting('class X { def \'\'\'test case name\'\'\'() {} }', new HighlightedTypedPosition(6, 1, CLASS)) } + @Test + void testCastAndCoerce() { + String contents = '''\ + |void test(obj) { + | def one = (String) obj + | def two = obj as String + |} + |'''.stripMargin() + + assertHighlighting(contents, + new HighlightedTypedPosition(contents.indexOf('test'), 4, METHOD), + new HighlightedTypedPosition(contents.indexOf('obj'), 3, PARAMETER), + new HighlightedTypedPosition(contents.indexOf('one'), 3, VARIABLE), + new HighlightedTypedPosition(contents.indexOf('String'), 6, CLASS), + new HighlightedTypedPosition(contents.indexOf('obj', contents.indexOf('String')), 3, PARAMETER), + new HighlightedTypedPosition(contents.indexOf('two'), 3, VARIABLE), + new HighlightedTypedPosition(contents.lastIndexOf('obj'), 3, PARAMETER), + new HighlightedTypedPosition(contents.lastIndexOf('String'), 6, CLASS)) + } + @Test void testAliasType1() { String contents = '''\