Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 417017

Summary: [1.8] Incorrect parameters in resolved method binding for LambdaExpression
Product: [Eclipse Project] JDT Reporter: Noopur Gupta <noopur_gupta>
Component: CoreAssignee: Manoj N Palat <manoj.palat>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: P3 CC: daniel_megert, manoj.palat, markus.kell.r, srikanth_sankaran
Version: 4.4Flags: manoj.palat: review? (srikanth_sankaran)
manoj.palat: review+
Target Milestone: BETA J8   
Hardware: All   
OS: All   
Whiteboard:
Bug Depends on:    
Bug Blocks: 407985    
Attachments:
Description Flags
Test case with modification as a patch
none
Proposed Patch
none
Proposed Patch
none
Proposed Patch
none
Alternate patch none

Description Noopur Gupta CLA 2013-09-11 11:42:48 EDT
---------------------------
package test.bugs;

@FunctionalInterface
interface FI {
	int foo1(int a);
}

class FI_1 {
	void fun(int a) {
		FI i1 = x1-> x1;
		FI i2 = xxx-> {
			i1.foo1(a);
			return xxx;
		};
	}
}
---------------------------
Steps:
1. To get the JLS8 AST, set org.eclipse.jdt.internal.ui.javaeditor.ASTProvider.SHARED_AST_LEVEL to AST.JLS8.
2. Open the file with above example or edit it so that reconciler is called.
3. Run this code after the call to unit.reconcile(..) in org.eclipse.jdt.internal.ui.text.java.JavaReconcilingStrategy#reconcile(ICompilationUnit, boolean):

AbstractTypeDeclaration test= (AbstractTypeDeclaration) ast.types().get(1);
MethodDeclaration meth= (MethodDeclaration) test.bodyDeclarations().get(0);
VariableDeclarationFragment vdf= (VariableDeclarationFragment) ((VariableDeclarationStatement) meth.getBody().statements().get(1)).fragments().get(0);
LambdaExpression lambda= (LambdaExpression) vdf.getInitializer();
List<VariableDeclaration> parameters= lambda.parameters();
System.out.println(parameters.size());
ITypeBinding[] parameterTypes= lambda.resolveMethodBinding().getParameterTypes();
System.out.println(parameterTypes.length);
for (ITypeBinding paramType : parameterTypes) {
	System.out.println(paramType.getName());
}

4. You can see that the number of parameters obtained from resolved method binding for lambda expr ('i2' in the example) is 3 instead of 1, which is incorrect.
Comment 1 Srikanth Sankaran CLA 2013-09-12 01:06:04 EDT
Manoj, please follow up.
Comment 2 Manoj N Palat CLA 2013-09-15 06:51:11 EDT
Created attachment 235490 [details]
Test case with modification as a patch

Test case as a patch with correction.

The behaviour is as expected for lambda. In the case of LambdaExpressions, the two additional parameterTypes are added for enclosing outer local variable accesses, namely i1 and foo, by the function  LambdaExpression.addSyntheticArgument(). 

Further note, if it helps: Assuming there are n parameters for lambda, and there are m (m >= n) parameterTypes, the last n of those parameterTypes correspond to the parameters in actual source code, since all the outer local variable access bindings are added to the front of the list. 

Srikanth: Any further pointers/comments?
Comment 3 Srikanth Sankaran CLA 2013-09-15 08:26:44 EDT
(In reply to Manoj Palat from comment #2)
> Created attachment 235490 [details]
> Test case with modification as a patch
> 
> Test case as a patch with correction.
> 
> The behaviour is as expected for lambda.

No. Please see the javadoc for org.eclipse.jdt.core.dom.IMethodBinding.getParameterTypes()
Comment 4 Manoj N Palat CLA 2013-09-25 00:06:50 EDT
Created attachment 235788 [details]
Proposed Patch
Comment 5 Manoj N Palat CLA 2013-10-03 02:09:00 EDT
Created attachment 236060 [details]
Proposed Patch

Corrected a cce plus made the patch up-to-date with latest code.
Comment 6 Manoj N Palat CLA 2013-10-03 04:31:54 EDT
Created attachment 236064 [details]
Proposed Patch

Added the test case which caused CCE at getParameterTypes() in the initial patch
Comment 7 Srikanth Sankaran CLA 2013-10-04 01:40:10 EDT
Created attachment 236088 [details]
Alternate patch

Here is an alternate patch that addresses some issues in original patch:

    - Tests: should not just assert on parameter count, also go ahead and
verify types.
    - We should not use synthetic methods in DBR in the first place. Instead
of working with what infrastructure exists, some times we can get cleaner
solution by adding more infrastructure. I added a getMethodBinding() call
on Lambda/ReferenceExpressions that returns the method binding void of all
synthetics (except where impossible).
   - Same problem exists for ReferenceExpressions also, instead of waiting
for it be discovered and reported, let us go ahead and fix it.
   - Method name (now defunct) getActualStart() is not a good choice of name
in MethodBinding class.
Comment 8 Srikanth Sankaran CLA 2013-10-04 01:41:29 EDT
Manoj, I ran only the ASTConverter18Tests. If you agree with the patch, please 
run all Java8 tests and release if green. Otherwise, let us discuss. Thanks.
Comment 9 Manoj N Palat CLA 2013-10-04 05:00:56 EDT
(In reply to Srikanth Sankaran from comment #8)
> Manoj, I ran only the ASTConverter18Tests. If you agree with the patch,
> please 
> run all Java8 tests and release if green. Otherwise, let us discuss. Thanks.

Thanks Srikanth. Patch looks good. Committed (after deleting a few extra whitespaces) via http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/?id=f5937020c6b957eed03745f57cfee671f23dd9b8