diff options
author | Manoj Palat | 2019-04-29 10:34:48 +0000 |
---|---|---|
committer | Sarika Sinha | 2019-05-15 09:57:46 +0000 |
commit | 7dc84e51756c711b750c707c83946287f13d93ff (patch) | |
tree | 9b714d1fee48f86d60a938d74f88190d903f0ca2 | |
parent | 53b07ab1b381d0f45dec4a55e6c77778075b2775 (diff) | |
download | eclipse.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>
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 |