Bug 565752 - QuickFix is blocked by conditional expression

Quickfix for incorrect return type is blocked by conditional expression

- Add check if expression is part of return statement
- Add test case

Change-Id: Iabbb0b7b33a589243d47e9f91dacbb9bd984835b
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/ASTResolving.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/ASTResolving.java
index 0a8e866..4f73ee4 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/ASTResolving.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/core/manipulation/dom/ASTResolving.java
@@ -244,13 +244,27 @@
 			break;
 		case ASTNode.CONDITIONAL_EXPRESSION:
 			ConditionalExpression expression= (ConditionalExpression) parent;
-			if (node.equals(expression.getExpression())) {
+
+			if (node.getLocationInParent() == ConditionalExpression.EXPRESSION_PROPERTY) {
 				return parent.getAST().resolveWellKnownType("boolean"); //$NON-NLS-1$
 			}
-			if (node.equals(expression.getElseExpression())) {
+
+			if (node.getLocationInParent() == ConditionalExpression.THEN_EXPRESSION_PROPERTY
+					&& expression.getElseExpression().resolveTypeBinding() != null) {
+				return expression.getElseExpression().resolveTypeBinding();
+			}
+
+			if (node.getLocationInParent() == ConditionalExpression.ELSE_EXPRESSION_PROPERTY
+					&& expression.getThenExpression().resolveTypeBinding() != null) {
 				return expression.getThenExpression().resolveTypeBinding();
 			}
-			return expression.getElseExpression().resolveTypeBinding();
+
+			if (node.getLocationInParent() == ConditionalExpression.THEN_EXPRESSION_PROPERTY
+					|| node.getLocationInParent() == ConditionalExpression.ELSE_EXPRESSION_PROPERTY) {
+				return getPossibleReferenceBinding(expression);
+			}
+
+			break;
 		case ASTNode.POSTFIX_EXPRESSION:
 			return parent.getAST().resolveWellKnownType("int"); //$NON-NLS-1$
 		case ASTNode.PREFIX_EXPRESSION:
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/ReturnTypeQuickFixTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/ReturnTypeQuickFixTest.java
index 3ec360d..3211276 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/ReturnTypeQuickFixTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/ReturnTypeQuickFixTest.java
@@ -17,6 +17,7 @@
 
 import java.util.ArrayList;
 import java.util.Hashtable;
+import java.util.List;
 
 import org.junit.After;
 import org.junit.Before;
@@ -45,9 +46,8 @@
 import org.eclipse.jdt.internal.ui.JavaPlugin;
 
 public class ReturnTypeQuickFixTest extends QuickFixTest {
-
 	@Rule
-    public ProjectTestSetup projectSetup = new ProjectTestSetup();
+    public ProjectTestSetup projectSetup= new ProjectTestSetup();
 
 	private IJavaProject fJProject1;
 	private IPackageFragmentRoot fSourceFolder;
@@ -810,6 +810,62 @@
 	}
 
 	@Test
+	public void testCorrectReturnStatementInConditional() throws Exception {
+		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
+		String input= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "import java.util.Map;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    <K1, K2, V> V foo(K1 key1, Map<K1, Map<K2, V>> map) {\n" //
+				+ "        Map<K2, V> map2 = map.get(key1);\n" //
+				+ "        return map2 == null ? null : map2.entrySet();\n" //
+				+ "    }\n" //
+				+ "}\n"; //
+		ICompilationUnit cu= pack1.createCompilationUnit("E.java", input, false, null);
+
+		CompilationUnit astRoot= getASTRoot(cu);
+		List<IJavaCompletionProposal> proposals= collectCorrections(cu, astRoot);
+		assertNumberOfProposals(proposals, 2);
+		assertCorrectLabels(proposals);
+
+		ASTRewriteCorrectionProposal proposal= (ASTRewriteCorrectionProposal) proposals.get(0);
+		String preview1= getPreviewContent(proposal);
+
+		String expected1= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "import java.util.Map;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    <K1, K2, V> V foo(K1 key1, Map<K1, Map<K2, V>> map) {\n" //
+				+ "        Map<K2, V> map2 = map.get(key1);\n" //
+				+ "        return (V) (map2 == null ? null : map2.entrySet());\n" //
+				+ "    }\n" //
+				+ "}\n"; //
+
+		proposal= (ASTRewriteCorrectionProposal) proposals.get(1);
+		String preview2= getPreviewContent(proposal);
+
+		String expected2= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "import java.util.Map;\n" //
+				+ "import java.util.Map.Entry;\n" //
+				+ "import java.util.Set;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    <K1, K2, V> Set<Entry<K2, V>> foo(K1 key1, Map<K1, Map<K2, V>> map) {\n" //
+				+ "        Map<K2, V> map2 = map.get(key1);\n" //
+				+ "        return map2 == null ? null : map2.entrySet();\n" //
+				+ "    }\n" //
+				+ "}\n"; //
+
+		assertEqualStringsIgnoreOrder(new String[] { preview1, preview2 }, new String[] { expected1, expected2 });
+	}
+
+	@Test
 	public void testReturnVoid() throws Exception {
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
 		StringBuffer buf= new StringBuffer();
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/TypeMismatchSubProcessor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/TypeMismatchSubProcessor.java
index 99861b6..031301b 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/TypeMismatchSubProcessor.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/TypeMismatchSubProcessor.java
@@ -31,6 +31,7 @@
 import org.eclipse.jdt.core.dom.BodyDeclaration;
 import org.eclipse.jdt.core.dom.CastExpression;
 import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.ConditionalExpression;
 import org.eclipse.jdt.core.dom.EnhancedForStatement;
 import org.eclipse.jdt.core.dom.Expression;
 import org.eclipse.jdt.core.dom.FieldAccess;
@@ -55,6 +56,9 @@
 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.TypeLocation;
 
+import org.eclipse.jdt.internal.core.manipulation.StubUtility;
+import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving;
+import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
 import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
 import org.eclipse.jdt.internal.corext.dom.Bindings;
@@ -76,12 +80,8 @@
 import org.eclipse.jdt.internal.ui.text.correction.proposals.ImplementInterfaceProposal;
 import org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedCorrectionProposal;
 import org.eclipse.jdt.internal.ui.text.correction.proposals.NewVariableCorrectionProposal;
-import org.eclipse.jdt.internal.ui.text.correction.proposals.TypeChangeCorrectionProposal;
 import org.eclipse.jdt.internal.ui.text.correction.proposals.OptionalCorrectionProposal;
-
-import org.eclipse.jdt.internal.core.manipulation.StubUtility;
-import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving;
-import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
+import org.eclipse.jdt.internal.ui.text.correction.proposals.TypeChangeCorrectionProposal;
 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
 
 
@@ -198,7 +198,7 @@
 		boolean nullOrVoid= currBinding == null || "void".equals(currBinding.getName()); //$NON-NLS-1$
 
 		// change method return statement to actual type
-		if (!nullOrVoid && parentNodeType == ASTNode.RETURN_STATEMENT) {
+		if (!nullOrVoid && isTypeReturned(nodeToCast)) {
 			BodyDeclaration decl= ASTResolving.findParentBodyDeclaration(selectedNode);
 			if (decl instanceof MethodDeclaration) {
 				MethodDeclaration methodDeclaration= (MethodDeclaration) decl;
@@ -262,6 +262,21 @@
 
 	}
 
+	private static boolean isTypeReturned(final Expression nodeToCast) {
+		int parentNodeType= nodeToCast.getParent().getNodeType();
+
+		if (parentNodeType == ASTNode.RETURN_STATEMENT) {
+			return true;
+		}
+
+		if (parentNodeType == ASTNode.PARENTHESIZED_EXPRESSION
+				|| parentNodeType == ASTNode.CONDITIONAL_EXPRESSION && (nodeToCast.getLocationInParent() == ConditionalExpression.THEN_EXPRESSION_PROPERTY || nodeToCast.getLocationInParent() == ConditionalExpression.ELSE_EXPRESSION_PROPERTY)) {
+			return isTypeReturned((Expression) nodeToCast.getParent());
+		}
+
+		return false;
+	}
+
 	public static ITypeBinding boxUnboxPrimitives(ITypeBinding castType, ITypeBinding toCast, AST ast) {
 		/*
 		 * e.g: