From 8e5798b21a0362e06af2e1d3dcf6967699fb1467 Mon Sep 17 00:00:00 2001 From: Eric Milles Date: Thu, 6 Jul 2023 14:18:29 -0500 Subject: [PATCH] Fix for #1493: context imports and re-write `in` and `instanceof` checks --- .../test/debug/EvaluationEngineTests.groovy | 147 +++++++++++++++++- .../eclipse/debug/EvaluationEngine.java | 18 ++- .../groovy/eclipse/debug/JDIComparator.java | 22 ++- 3 files changed, 178 insertions(+), 9 deletions(-) diff --git a/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/debug/EvaluationEngineTests.groovy b/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/debug/EvaluationEngineTests.groovy index b3df8424cd..ed7a1482c7 100644 --- a/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/debug/EvaluationEngineTests.groovy +++ b/ide-test/org.codehaus.groovy.eclipse.tests/src/org/codehaus/groovy/eclipse/test/debug/EvaluationEngineTests.groovy @@ -29,6 +29,7 @@ import org.eclipse.debug.core.ILaunch import org.eclipse.debug.core.ILaunchManager import org.eclipse.debug.core.model.IThread import org.eclipse.jdt.debug.core.IJavaDebugTarget +import org.eclipse.jdt.debug.core.IJavaObject import org.eclipse.jdt.debug.eval.IEvaluationResult import org.eclipse.jdt.internal.debug.ui.BreakpointUtils import org.junit.Before @@ -80,8 +81,65 @@ final class EvaluationEngineTests extends GroovyEclipseTestSuite { } } - @Test // https://github.com/groovy/groovy-eclipse/issues/1491 + @Test void testEvalSnippet3() { + def (launch, thread) = runToLine(3, '''\ + |public class Main { + | public static void main(String[] args) { + | System.out.println("hello world"); + | } + |} + |'''.stripMargin()) + + try { + IEvaluationResult result = evaluate('"baz" in args', thread) + assert !result.hasErrors() : result.errorMessages[0] + assert result.value.booleanValue + } finally { + launch.terminate() + } + } + + @Test + void testEvalSnippet4() { + def (launch, thread) = runToLine(3, '''\ + |public class Main { + | public static void main(String[] args) { + | System.out.println("hello world"); + | } + |} + |'''.stripMargin()) + + try { + IEvaluationResult result = evaluate('"buzz" !in args', thread) + assert !result.hasErrors() : result.errorMessages[0] + assert result.value.booleanValue + } finally { + launch.terminate() + } + } + + @Test + void testEvalSnippet5() { + def (launch, thread) = runToLine(3, '''\ + |public class Main { + | public static void main(String[] args) { + | System.out.println("hello world"); + | } + |} + |'''.stripMargin()) + + try { + IEvaluationResult result = evaluate('args[2] <=> args[1]', thread) + assert !result.hasErrors() : result.errorMessages[0] + assert result.value.intValue > 0 // 'baz' > 'bar' + } finally { + launch.terminate() + } + } + + @Test // https://github.com/groovy/groovy-eclipse/issues/1491 + void testEvalSnippet6() { def (launch, thread) = runToLine(4, '''\ |public class Main { | public static void main(String[] args) { @@ -101,7 +159,7 @@ final class EvaluationEngineTests extends GroovyEclipseTestSuite { } @Test // https://github.com/groovy/groovy-eclipse/issues/1492 - void testEvalSnippet4() { + void testEvalSnippet7() { def (launch, thread) = runToLine(3, '''\ |public class Main { | public static void main(String[] args) { @@ -120,7 +178,7 @@ final class EvaluationEngineTests extends GroovyEclipseTestSuite { } @Test // https://github.com/groovy/groovy-eclipse/issues/1492 - void testEvalSnippet5() { + void testEvalSnippet8() { def (launch, thread) = runToLine(3, '''\ |public class Main { | public static void main(String[] args) { @@ -138,13 +196,92 @@ final class EvaluationEngineTests extends GroovyEclipseTestSuite { } } + @Test // https://github.com/groovy/groovy-eclipse/issues/1493 + void testEvalSnippet9() { + def (launch, thread) = runToLine(4, '''\ + |public class Main { + | public static void main(String[] args) { + | var pe = new org.codehaus.groovy.ast.expr.PropertyExpression(null, "foo"); + | System.out.println("hello world"); + | } + |} + |'''.stripMargin()) + + try { + IEvaluationResult result = evaluate('getProperty() instanceof ConstantExpression', thread, thread.findVariable('pe').value) + assert !result.hasErrors() : result.errorMessages[0] + assert result.value.booleanValue + } finally { + launch.terminate() + } + } + + @Test // https://github.com/groovy/groovy-eclipse/issues/1493 + void testEvalSnippet10() { + def (launch, thread) = runToLine(4, '''\ + |public class Main { + | public static void main(String[] args) { + | var pe = new org.codehaus.groovy.ast.expr.PropertyExpression(null, "foo"); + | System.out.println("hello world"); + | } + |} + |'''.stripMargin()) + + try { + IEvaluationResult result = evaluate('getProperty() !instanceof VariableExpression', thread, thread.findVariable('pe').value) + assert !result.hasErrors() : result.errorMessages[0] + assert result.value.booleanValue + } finally { + launch.terminate() + } + } + + @Test // https://github.com/groovy/groovy-eclipse/issues/1493 + void testEvalSnippet11() { + def (launch, thread) = runToLine(3, '''\ + |public class Main { + | public static void main(String[] args) { + | System.out.println("hello world"); + | } + |} + |'''.stripMargin()) + + try { + IEvaluationResult result = evaluate('getState() instanceof State', thread, thread.threadObject) // State is an inner class + assert !result.hasErrors() : result.errorMessages[0] + assert result.value.booleanValue + } finally { + launch.terminate() + } + } + + @Test + void testEvalSnippet12() { + def (launch, thread) = runToLine(4, '''\ + |import static java.util.regex.Pattern.*; + |public class Main { + | public static void main(String[] args) { + | System.out.println("hello world"); + | } + |} + |'''.stripMargin()) + + try { + IEvaluationResult result = evaluate('compile("") !== null', thread) // StaticImportVisitor and JDIScriptLoader transforms + assert !result.hasErrors() : result.errorMessages[0] + assert result.value.booleanValue + } finally { + launch.terminate() + } + } + //-------------------------------------------------------------------------- - IEvaluationResult evaluate(String snippet, IThread thread) { + IEvaluationResult evaluate(String source, IThread thread, IJavaObject o = null) { assert thread.isSuspended() def result = new SynchronousQueue() def engine = jdiPlugin.getEvaluationEngine(packageFragmentRoot.javaProject, (IJavaDebugTarget) thread.debugTarget) - engine.evaluate(snippet, thread.topStackFrame, result.&put, DebugEvent.EVALUATION, false) + engine.evaluate(source, *(o ? [o, thread] : [thread.topStackFrame]), result.&put, DebugEvent.EVALUATION, false) result.poll(5, TimeUnit.SECONDS) } diff --git a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/debug/EvaluationEngine.java b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/debug/EvaluationEngine.java index 541ed99b62..6c288ce49d 100644 --- a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/debug/EvaluationEngine.java +++ b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/debug/EvaluationEngine.java @@ -190,7 +190,23 @@ public ICompiledExpression getCompiledExpression(String snippet, IJavaStackFrame @Override public ICompiledExpression getCompiledExpression(String snippet, IJavaReferenceType type) throws DebugException { - return getCompiledExpression(snippet, type, Collections.emptyMap()); + StringBuilder header = new StringBuilder(); + + String typeName = type.getName(); + if (!typeName.endsWith("]")) { + int i = typeName.lastIndexOf('.'); + if (i != -1) { + String packageName = typeName.substring(0, i); + if (!"java.lang".equals(packageName)) { + header.append("import ").append(packageName); + header.append(".*;\n"); + } + } + + header.append("import static ").append(typeName).append(".*;\n"); + } + + return getCompiledExpression(snippet, type, Collections.singletonMap("header", header.toString())); } @Override diff --git a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/debug/JDIComparator.java b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/debug/JDIComparator.java index 27e9a915dc..2ea7497f97 100644 --- a/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/debug/JDIComparator.java +++ b/ide/org.codehaus.groovy.eclipse.ui/src/org/codehaus/groovy/eclipse/debug/JDIComparator.java @@ -57,6 +57,10 @@ private boolean invoke(String methodName, Object o1, Object o2) throws DebugExce return result.getBooleanValue(); } + public boolean isCase(Object o1, Object o2) throws DebugException { + return invoke("isCase", o1, o2); + } + public boolean isEqual(Object o1, Object o2) throws DebugException { return invoke("compareEqual", o1, o2); } @@ -81,6 +85,10 @@ public boolean isLessThanOrEqual(Object o1, Object o2) throws DebugException { return invoke("compareLessThanEqual", o1, o2); } + public boolean isNotCase(Object o1, Object o2) throws DebugException { + return invoke("isNotCase", o1, o2); + } + public boolean isNotEqual(Object o1, Object o2) throws DebugException { return invoke("compareNotEqual", o1, o2); } @@ -91,6 +99,9 @@ public boolean isNotIdentical(Object o1, Object o2) throws DebugException { static String methodNameFor(Token operation) { switch (operation.getType()) { + case Types.COMPARE_TO: + return "compareTo"; + case Types.COMPARE_LESS_THAN: return "isLessThan"; @@ -103,6 +114,14 @@ static String methodNameFor(Token operation) { case Types.COMPARE_GREATER_THAN_EQUAL: return "isGreaterThanOrEqual"; + case Types.KEYWORD_IN: + case Types.KEYWORD_INSTANCEOF: + return "isCase"; + + case Types.COMPARE_NOT_IN: + case Types.COMPARE_NOT_INSTANCEOF: + return "isNotCase"; + case Types.COMPARE_EQUAL: return "isEqual"; @@ -115,9 +134,6 @@ static String methodNameFor(Token operation) { case Types.COMPARE_NOT_IDENTICAL: return "isNotIdentical"; - case Types.COMPARE_TO: - return "compareTo"; - default: return null; }