Bug549952 - Add support to evaluate expressions with anonymous classes
Change-Id: I94afc9ffa33f2f3e108671f547f75afc358005db
Signed-off-by: gayanper <gayanper@gmail.com>
diff --git a/org.eclipse.jdt.debug.tests/java8/AnonymousEvaluator.java b/org.eclipse.jdt.debug.tests/java8/AnonymousEvaluator.java
new file mode 100644
index 0000000..0441a38
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/java8/AnonymousEvaluator.java
@@ -0,0 +1,20 @@
+import java.util.function.IntSupplier;
+
+public class AnonymousEvaluator {
+ public static void main(String[] args) {
+ int calc = calculate(new IntSup());
+ }
+
+ public static int calculate(IntSupplier supplier) {
+ return supplier.getAsInt() * 2;
+ }
+
+ private static class IntSup implements IntSupplier {
+
+ @Override
+ public int getAsInt() {
+ return 10 * 20;
+ }
+ }
+
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
index 45a356c..bcce41a 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
@@ -476,6 +476,7 @@
cfgs.add(createLaunchConfiguration(jp, "Bug561715"));
cfgs.add(createLaunchConfiguration(jp, "Bug562056"));
cfgs.add(createLaunchConfiguration(jp, "RemoteEvaluator"));
+ cfgs.add(createLaunchConfiguration(jp, "AnonymousEvaluator"));
loaded18 = true;
waitForBuild();
}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/RemoteEvaluatorTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/RemoteEvaluatorTests.java
index 4c9c93f..cfbf895 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/RemoteEvaluatorTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/RemoteEvaluatorTests.java
@@ -60,6 +60,34 @@
assertEquals("count is not 0", "0", value.getValueString());
}
+ public void testEvaluate_AnonymousClassInstance_WithSemicolon() throws Exception {
+ debugWithBreakpoint("AnonymousEvaluator", 6);
+ IValue value = evaluate("calculate(new IntSupplier() {\n" +
+ "\n" +
+ " @Override\n" +
+ " public int getAsInt() {\n" +
+ " return 100 * 20;\n" +
+ " }\n" +
+ " });");
+
+ assertNotNull("result is null", value);
+ assertEquals("count is not 4000", "4000", value.getValueString());
+ }
+
+ public void testEvaluate_AnonymousClassInstance_WithoutSemicolon() throws Exception {
+ debugWithBreakpoint("AnonymousEvaluator", 6);
+ IValue value = evaluate("calculate(new IntSupplier() {\n" +
+ "\n" +
+ " @Override\n" +
+ " public int getAsInt() {\n" +
+ " return 100 * 20;\n" +
+ " }\n" +
+ " })");
+
+ assertNotNull("result is null", value);
+ assertEquals("count is not 4000", "4000", value.getValueString());
+ }
+
@Override
protected IJavaProject getProjectContext() {
return get18Project();
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluatorBuilder.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluatorBuilder.java
index 34d5aa8..e6a77df 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluatorBuilder.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/RemoteEvaluatorBuilder.java
@@ -82,6 +82,11 @@
acceptFunctionalExpression(node, expectedResult);
}
+ public void acceptAnonymousClass(ClassInstanceCreation node, ITypeBinding expectedResult) {
+ acceptFunctionalExpression(node, expectedResult);
+ }
+
+
private void acceptFunctionalExpression(Expression node, ITypeBinding expectedResult) {
FunctionalEvalVisitor visitor = new FunctionalEvalVisitor();
node.accept(visitor);
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTInstructionCompiler.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTInstructionCompiler.java
index 7cf7a2b..5d20aa0 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTInstructionCompiler.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTInstructionCompiler.java
@@ -1548,8 +1548,6 @@
if (!isActive()) {
return true;
}
- setHasError(true);
- addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Anonymous_type_declaration_cannot_be_used_in_an_evaluation_expression_2);
return false;
}
@@ -2008,9 +2006,22 @@
return true;
}
+ String rewrittenLocalType = null;
if (node.getAnonymousClassDeclaration() != null) {
- setHasError(true);
- addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Anonymous_type_declaration_cannot_be_used_in_an_evaluation_expression_7);
+ try {
+ RemoteEvaluatorBuilder builder = makeBuilder(node);
+ builder.acceptAnonymousClass(node, node.getType().resolveBinding());
+ RemoteEvaluator remoteEvaluator = builder.build();
+ push(new RemoteOperator(builder.getSnippet(), node.getStartPosition(), remoteEvaluator));
+
+ push(new PushType(getTypeName(node.getType().resolveBinding())));
+ storeInstruction();
+ return false;
+
+ } catch (JavaModelException | DebugException e) {
+ addErrorMessage(e.getMessage());
+ setHasError(true);
+ }
}
IMethodBinding methodBinding = node.resolveConstructorBinding();
@@ -2026,10 +2037,7 @@
boolean isInstanceMemberType = typeBinding.isMember()
&& !Modifier.isStatic(typeBinding.getModifiers());
- if (isALocalType(typeBinding)) {
- setHasError(true);
- addErrorMessage(EvaluationEngineMessages.ASTInstructionCompiler_Constructor_of_a_local_type_cannot_be_used_in_an_evaluation_expression_8);
- }
+ boolean isLocalType = isALocalType(typeBinding);
if (containsALocalType(methodBinding)) {
setHasError(true);
@@ -2057,12 +2065,18 @@
paramCount++;
}
- String signature = getMethodSignature(methodBinding,
- enclosingTypeSignature).replace('.', '/');
+ String signature = null;
+ if(isLocalType) {
+ String methodSignature = getMethodSignature(methodBinding, null);
+ signature = methodSignature.replace(methodBinding.getReturnType().getQualifiedName(), rewrittenLocalType).replace('.', '/');
+ } else {
+ signature = getMethodSignature(methodBinding,
+ enclosingTypeSignature).replace('.', '/');
+ }
push(new Constructor(signature, paramCount, fCounter));
- push(new PushType(getTypeName(typeBinding)));
+ push(new PushType(isLocalType ? rewrittenLocalType : getTypeName(typeBinding)));
storeInstruction();
if (isInstanceMemberType) {
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.java
index 138371d..ae75890 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.java
@@ -19,7 +19,6 @@
public class EvaluationEngineMessages extends NLS {
private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.debug.eval.ast.engine.EvaluationEngineMessages";//$NON-NLS-1$
- public static String ASTInstructionCompiler_Anonymous_type_declaration_cannot_be_used_in_an_evaluation_expression_2;
public static String ASTInstructionCompiler_Assert_statement_cannot_be_used_in_an_evaluation_expression_3;
public static String ASTInstructionCompiler_Unrecognized_assignment_operator____4;
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.properties b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.properties
index 125c9ce..61f40cd 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.properties
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationEngineMessages.properties
@@ -13,7 +13,6 @@
# Jesper Steen Moller - 427089: [1.8] Change value in Variables view with lambda or method reference
###############################################################################
-ASTInstructionCompiler_Anonymous_type_declaration_cannot_be_used_in_an_evaluation_expression_2=Anonymous type declaration cannot be used in an evaluation expression
ASTInstructionCompiler_Assert_statement_cannot_be_used_in_an_evaluation_expression_3=Assert statement cannot be used in an evaluation expression
ASTInstructionCompiler_Unrecognized_assignment_operator____4=Unrecognized assignment operator :
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java
index 3146f70..c733adf 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/EvaluationSourceGenerator.java
@@ -112,7 +112,8 @@
int i ;
for (i=0; i < chars.length; i++) {
// copy everything before the last statement or if whitespace
- if (i<= semicolonIndex || Character.isWhitespace(chars[i]) || chars[i] == '}'){
+ if (i<= semicolonIndex || Character.isWhitespace(chars[i]) || chars[i] == '}'
+ || (i > 0 && (chars[i - 1] == '}' && (chars[i] == ')' || chars[i] == ',')))) {
wordBuffer.append(codeSnippet.charAt(i));
}
else
@@ -131,7 +132,7 @@
if (needsReturn(lastSentence))
wordBuffer.append(returnString);
}
- } else if (chars[chars.length -1] !='}' && ( i+7 > chars.length || (i + 7 <= chars.length && !codeSnippet.substring(i, i+7).equals(returnString)))){
+ } else if (chars[chars.length -1] !='}' && ( (i+7 > chars.length && lastSentence.length() > 1) || (i + 7 <= chars.length && !codeSnippet.substring(i, i+7).equals(returnString)))){
// add return if last statement does not have return
if (needsReturn(lastSentence))
wordBuffer.append(returnString);
@@ -149,6 +150,11 @@
if ( j != -1 && (j!=k))
wordBuffer.append(';');
}
+
+ if(lastSentence.length() <= 1 && needsReturn(wordBuffer.toString())) {
+ wordBuffer.insert(0, returnString).append(' ');
+ }
+
return wordBuffer.toString();
}
@@ -225,8 +231,20 @@
else if ( (count == 3 || count == 1 ) && token == ITerminalSymbols.TokenNameIdentifier ){
return false;
}
- else {
- return true;
+ else if (count == 0 && token == ITerminalSymbols.TokenNamereturn) {
+ return false;
+ } else {
+ // ignore and continue the tokens specified here, handling following types of statements
+ // {return i > 0;}, {/**/};{return true;}
+ switch (token) {
+ case ITerminalSymbols.TokenNameLBRACE:
+ case ITerminalSymbols.TokenNameRBRACE:
+ case ITerminalSymbols.TokenNameSEMICOLON:
+ token = scanner.getNextToken();
+ break;
+ default:
+ return true;
+ }
}
}