diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java index 83760bca28..8935a9a15f 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/StaticCompilationTests.java @@ -807,16 +807,41 @@ public void testCompileStatic6137() { String[] sources = { "Main.groovy", "@groovy.transform.CompileStatic\n" + - "void test(a, b) {\n" + - " print(a in b)\n" + + "void test() {\n" + + " print(null in null)\n" + + " print(null in 'xx')\n" + + " print('xx' in null)\n" + + " print('xx' in 'xx')\n" + + " print('xx' in ['xx'])\n" + "}\n" + - "test(null,null)\n" + - "test(null,new Object())\n" + - "test(new Object(),null)\n", + "test()\n", }; //@formatter:on - runConformTest(sources, "truefalsefalse"); + runConformTest(sources, "truefalsefalsetruetrue"); + } + + @Test + public void testCompileStatic6137a() { + assumeTrue(isParrotParser()); + + //@formatter:off + String[] sources = { + "Main.groovy", + "@groovy.transform.CompileStatic\n" + + "void test() {\n" + + " print(null !in null)\n" + + " print(null !in 'xx')\n" + + " print('xx' !in null)\n" + + " print('xx' !in 'xx')\n" + + " print('xx' !in [''])\n" + + " print('xx' !in ['xx'])\n" + + "}\n" + + "test()\n", + }; + //@formatter:on + + runConformTest(sources, "falsetruetruefalsetruefalse"); } @Test @@ -1347,7 +1372,10 @@ public void testCompileStatic7473a() { runConformTest(sources, "not xyz"); String result = disassemble(getOutputFile("Main.class"), 1); - int pos = result.indexOf("createList"); + int pos = result.indexOf("ScriptBytecodeAdapter.isNotCase"); + if (isAtLeastGroovy(40)) assertTrue(pos < 0); //GROOVY-10383 + + pos = result.indexOf("createList"); assumeTrue(pos > 0); // the operand should be processed only once diff --git a/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java index c2f728dd33..4a06c775d2 100644 --- a/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java +++ b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java @@ -62,7 +62,6 @@ 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.constX; -import static org.codehaus.groovy.ast.tools.GeneralUtils.isNullX; import static org.codehaus.groovy.ast.tools.GeneralUtils.isOrImplements; import static org.codehaus.groovy.ast.tools.GeneralUtils.ternaryX; import static org.codehaus.groovy.ast.tools.GeneralUtils.varX; @@ -116,7 +115,9 @@ public Expression transformBinaryExpression(final BinaryExpression bin) { } break; case Types.KEYWORD_IN: - return transformInOperation(bin); + equal = true; //fallthrough + case Types.COMPARE_NOT_IN: + return transformInOperation(bin, equal); case Types.COMPARE_EQUAL: case Types.COMPARE_IDENTICAL: equal = true; //fallthrough @@ -227,12 +228,12 @@ private static Expression transformAssignmentToSetterCall( pos); } - private Expression transformInOperation(final BinaryExpression bin) { + private Expression transformInOperation(final BinaryExpression bin, final boolean in) { Expression leftExpression = bin.getLeftExpression(); Expression rightExpression = bin.getRightExpression(); - // transform "left in right" into "right.isCase(left)" - MethodCallExpression call = callX(rightExpression, "isCase", leftExpression); + // transform "left [!]in right" into "right.is[Not]Case(left)" + MethodCallExpression call = callX(rightExpression, in ? "isCase" : "isNotCase", leftExpression); call.setImplicitThis(false); call.setSourcePosition(bin); call.copyNodeMetaData(bin); call.setMethodTarget(bin.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET)); // GROOVY-7473: no null test for simple cases @@ -246,7 +247,7 @@ private Expression transformInOperation(final BinaryExpression bin) { // GROOVY-6137, GROOVY-7473: null safety and one-time evaluation call.setObjectExpression(rightExpression = transformRepeatedReference(rightExpression)); - Expression safe = ternaryX(isNullX( rightExpression ), isNullX( leftExpression ), call); + Expression safe = ternaryX(new CompareToNullExpression(rightExpression,true), new CompareToNullExpression(leftExpression,in), call); safe.putNodeMetaData("classgen.callback", classgenCallback(call.getObjectExpression())); return staticCompilationTransformer.transform(safe); }