Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManoj Palat2019-04-29 10:34:48 +0000
committerSarika Sinha2019-05-15 09:57:46 +0000
commit7dc84e51756c711b750c707c83946287f13d93ff (patch)
tree9b714d1fee48f86d60a938d74f88190d903f0ca2
parent53b07ab1b381d0f45dec4a55e6c77778075b2775 (diff)
downloadeclipse.jdt.core-7dc84e51756c711b750c707c83946287f13d93ff.tar.gz
eclipse.jdt.core-7dc84e51756c711b750c707c83946287f13d93ff.tar.xz
eclipse.jdt.core-7dc84e51756c711b750c707c83946287f13d93ff.zip
Bug 547148 - Expose Outer Synthetic Locals from Method Binding
Requested by JDT debug for bug 534687, to allow debug framework show captured lambda variable names as val$outerArg instead of arg$1 etc. Change-Id: I47a3719efbcb7fb82ea04b27321eb0f3fa92bd80 Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
-rw-r--r--org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java48
-rw-r--r--org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java13
-rw-r--r--org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java15
-rw-r--r--org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java23
4 files changed, 95 insertions, 4 deletions
diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
index d3d8222a0a..81294496d7 100644
--- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
+++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverter18Test.java
@@ -50,7 +50,7 @@ public class ASTConverter18Test extends ConverterTestSetup {
static {
// TESTS_NUMBERS = new int[] { 19 };
// TESTS_RANGE = new int[] { 1, -1 };
-// TESTS_NAMES = new String[] {"test0001"};
+// TESTS_NAMES = new String[] {"testLambdaSynthetic"};
}
public static Test suite() {
return buildModelTestSuite(ASTConverter18Test.class);
@@ -5378,5 +5378,51 @@ public void testBug526449_001() throws JavaModelException {
ASTNode node = buildAST(contents, this.workingCopy, false);
assertEquals("Not a compilation unit", ASTNode.COMPILATION_UNIT, node.getNodeType());
}
+public void testLambdaSynthetic() throws JavaModelException {
+ this.workingCopy = getWorkingCopy("/Converter18/src/xyz/X.java",
+ true/* resolve */);
+ String contents =
+ "package xyz;\n"+
+ "\n"+
+ "interface Function<T, R> {\n"+
+ " R apply(T t);\n"+
+ " }\n"+
+ "\n"+
+ "public class X {\n"+
+ "\n"+
+ " private int instanceField = 952;\n"+
+ "\n"+
+ " static public void main(String[] args) throws Exception {\n"+
+ " new X().callLambda(\"hello\");\n"+
+ " }\n"+
+ "\n"+
+ " void callLambda(String outerArg) throws Exception {\n"+
+ " double outerLocal = 1.0; // Effectively final\n"+
+ "\n"+
+ " Function<String, Integer> lambda = lambdaArg -> {\n"+
+ " int lambdaLocal = 6;\n"+
+ " System.out.println(instanceField);\n"+
+ " System.out.println(outerArg);\n"+
+ " System.out.println(outerLocal);\n"+
+ " System.out.println(lambdaArg);\n"+
+ " System.out.println(lambdaLocal);\n"+
+ " return lambdaArg.length();\n"+
+ " };\n"+
+ " int result = lambda.apply(\"degenerate case\");\n"+
+ " System.out.println(result);\n"+
+ " }\n"+
+ "}\n";
+ CompilationUnit cu = (CompilationUnit) buildAST(contents, this.workingCopy);
+ TypeDeclaration typedeclaration = (TypeDeclaration) getASTNode(cu, 1);
+ MethodDeclaration methodDeclaration = (MethodDeclaration) typedeclaration.bodyDeclarations().get(2);
+ VariableDeclarationStatement variableDeclarationStatement = (VariableDeclarationStatement) methodDeclaration.getBody().statements().get(1);
+ VariableDeclarationFragment fragment = (VariableDeclarationFragment)variableDeclarationStatement.fragments().get(0);
+ LambdaExpression lambdaExpression = (LambdaExpression) fragment.getInitializer();
+ IMethodBinding binding = lambdaExpression.resolveMethodBinding();
+ IVariableBinding[] synVars = binding.getSyntheticOuterLocals();
+ assertEquals(2, synVars.length);
+ assertEquals("val$outerArg",synVars[0].getName());
+ assertEquals("val$outerLocal",synVars[1].getName());
+}
}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
index cf8074a1ca..537d4e2679 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/DefaultBindingResolver.java
@@ -22,6 +22,7 @@ import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.core.dom.MethodBinding.LambdaMethod;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
import org.eclipse.jdt.internal.compiler.ast.AllocationExpression;
@@ -69,6 +70,7 @@ import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons;
import org.eclipse.jdt.internal.compiler.lookup.ProblemReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
+import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
@@ -894,6 +896,14 @@ class DefaultBindingResolver extends BindingResolver {
return null;
}
+ private IVariableBinding[] getSyntheticOuterLocalVariables(org.eclipse.jdt.internal.compiler.ast.LambdaExpression lambdaExpression) {
+ IVariableBinding[] syntheticOuterLocals = new IVariableBinding[lambdaExpression.outerLocalVariables.length];
+ int i = 0;
+ for (SyntheticArgumentBinding sab : lambdaExpression.outerLocalVariables) {
+ syntheticOuterLocals[i++] = getVariableBinding(sab);
+ }
+ return syntheticOuterLocals;
+ }
@Override
synchronized IMethodBinding resolveMethod(LambdaExpression lambda) {
Object oldNode = this.newAstToOldAst.get(lambda);
@@ -908,6 +918,9 @@ class DefaultBindingResolver extends BindingResolver {
if (methodBinding == null) {
return null;
}
+ if (methodBinding instanceof LambdaMethod) {
+ ((LambdaMethod) methodBinding).setSyntheticOuterLocals(getSyntheticOuterLocalVariables(lambdaExpression));
+ }
this.bindingsToAstNodes.put(methodBinding, lambda);
String key = methodBinding.getKey();
if (key != null) {
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java
index 9a949ab8f8..0848679f25 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/IMethodBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -383,4 +383,17 @@ public interface IMethodBinding extends IBinding {
* @since 3.1
*/
public boolean overrides(IMethodBinding method);
+
+
+ /**
+ * Returns a list of variable bindings representing the synthetic outer
+ * local variables. Returns an empty array for non-lambda expressions or if
+ * this method does not have any synthetic parameters.
+ *
+ * @return a (possibly empty) list of variable bindings for the synthetic
+ * outer locals of this method if this is a lambda expression, else an empty array.
+ * @since 3.18
+ */
+ public IVariableBinding[] getSyntheticOuterLocals();
+
}
diff --git a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
index 91b55ebf78..aaad277a16 100644
--- a/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
+++ b/org.eclipse.jdt.core/dom/org/eclipse/jdt/core/dom/MethodBinding.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2000, 2015 IBM Corporation and others.
+ * Copyright (c) 2000, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -40,6 +40,7 @@ class MethodBinding implements IMethodBinding {
Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED | Modifier.NATIVE |
Modifier.STRICTFP | Modifier.DEFAULT;
private static final ITypeBinding[] NO_TYPE_BINDINGS = new ITypeBinding[0];
+ static final IVariableBinding[] NO_VARIABLE_BINDINGS = new IVariableBinding[0];
protected org.eclipse.jdt.internal.compiler.lookup.MethodBinding binding;
protected BindingResolver resolver;
private volatile ITypeBinding[] parameterTypes;
@@ -515,6 +516,7 @@ class MethodBinding implements IMethodBinding {
private MethodBinding implementation;
private IBinding declaringMember;
+ private IVariableBinding[] syntheticOuterLocalVariables;
public LambdaMethod(DefaultBindingResolver resolver,
org.eclipse.jdt.internal.compiler.lookup.MethodBinding lambdaDescriptor,
@@ -571,5 +573,22 @@ class MethodBinding implements IMethodBinding {
public String toString() {
return super.toString().replace("public abstract ", "public "); //$NON-NLS-1$//$NON-NLS-2$
}
+
+ @Override
+ public IVariableBinding[] getSyntheticOuterLocals() {
+ if (this.syntheticOuterLocalVariables != null) {
+ return this.syntheticOuterLocalVariables;
+ }
+ return NO_VARIABLE_BINDINGS;
+ }
+
+ public void setSyntheticOuterLocals(IVariableBinding[] syntheticOuterLocalVariables) {
+ this.syntheticOuterLocalVariables = syntheticOuterLocalVariables;
+ }
+ }
+
+ @Override
+ public IVariableBinding[] getSyntheticOuterLocals() {
+ return NO_VARIABLE_BINDINGS;
}
-}
+} \ No newline at end of file

Back to the top