Merge remote-tracking branch 'origin/master' into BETA_JAVA16

Change-Id: Ie2dab583cbdfede93d8b441e6922607d60324b07
diff --git a/org.eclipse.jdt.debug.tests/java7/Bug567801.java b/org.eclipse.jdt.debug.tests/java7/Bug567801.java
new file mode 100644
index 0000000..9d1d02f
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/java7/Bug567801.java
@@ -0,0 +1,17 @@
+import java.io.IOException;
+import java.sql.SQLException;
+
+public class Bug567801 {
+	public static void main(String[] args) {
+		try {
+			if(args.length == 0) {
+				throw new SQLException();
+			} else {
+				throw new IOException();
+			}
+		} catch(SQLException | IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.jdt.debug.tests/java8/Bug567801.java b/org.eclipse.jdt.debug.tests/java8/Bug567801.java
new file mode 100644
index 0000000..dd317d7
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/java8/Bug567801.java
@@ -0,0 +1,31 @@
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.Serializable;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.IntStream;
+
+public class Bug567801 {
+	public static void main(String[] args) {
+		testBody();
+	}
+	private static <T extends Closeable & Serializable> void testBody() {
+		List<Integer> numbers = new ArrayList<>();
+		List<List<Integer>> listOfNumberList = new ArrayList<>();
+		List<? extends Number> extendsList = Arrays.asList(10,20);
+		List<? super Integer> superList = Arrays.asList(10,20);
+		List<?> wildList = Arrays.asList(10,20);
+		List<T> intersectionList = Collections.emptyList();
+		List<long[]> parrayList = Arrays.asList(new long[] {100L});
+		List<String[]> arrayList = Arrays.asList(new String[] {"100"}, new String[] {"200"});
+		IntStream stream = IntStream.of(10);
+
+		numbers.add(11);
+		listOfNumberList.add(numbers);
+		
+		System.out.println(numbers);
+	}
+}
\ No newline at end of file
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 a6f1483..4f3e8fd 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
@@ -433,6 +433,7 @@
 	        	jp = createProject(ONE_SEVEN_PROJECT_NAME, JavaProjectHelper.TEST_1_7_SRC_DIR.toString(), JavaProjectHelper.JAVA_SE_1_7_EE_NAME, false);
 	    		cfgs.add(createLaunchConfiguration(jp, LiteralTests17.LITERAL_TYPE_NAME));
 				cfgs.add(createLaunchConfiguration(jp, "ThreadNameChange"));
+				cfgs.add(createLaunchConfiguration(jp, "Bug567801"));
 	    		loaded17 = true;
 	    		waitForBuild();
 	        }
@@ -484,6 +485,7 @@
 				cfgs.add(createLaunchConfiguration(jp, "AnonymousEvaluator"));
 				cfgs.add(createLaunchConfiguration(jp, "Bug564486"));
 				cfgs.add(createLaunchConfiguration(jp, "Bug564801"));
+				cfgs.add(createLaunchConfiguration(jp, "Bug567801"));
 	    		loaded18 = true;
 	    		waitForBuild();
 	        }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
index dde4e60..2334837 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
@@ -92,6 +92,7 @@
 import org.eclipse.jdt.debug.tests.core.WorkspaceSourceContainerTests;
 import org.eclipse.jdt.debug.tests.eval.GeneralEvalTests;
 import org.eclipse.jdt.debug.tests.eval.GenericsEvalTests;
+import org.eclipse.jdt.debug.tests.eval.LambdaVariableTest;
 import org.eclipse.jdt.debug.tests.eval.SyntheticVariableTests;
 import org.eclipse.jdt.debug.tests.launching.ClasspathShortenerTests;
 import org.eclipse.jdt.debug.tests.launching.ConfigurationEncodingTests;
@@ -327,6 +328,9 @@
 
 	//add the complete eval suite
 		addTest(new TestSuite(GeneralEvalTests.class));
+		if (JavaProjectHelper.isJava8Compatible()) {
+			addTest(new TestSuite(LambdaVariableTest.class));
+		}
 		//addTest(EvalTestSuite.suite());
 
 		// long classpath tests
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/GenericsEval17Test.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/GenericsEval17Test.java
new file mode 100644
index 0000000..041a240
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/GenericsEval17Test.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2020 Gayan Perera and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Gayan Perera - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.debug.tests.eval;
+
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+
+public class GenericsEval17Test extends AbstractDebugTest {
+	private IJavaThread javaThread;
+
+	@Override
+	protected IJavaProject getProjectContext() {
+		return get17Project();
+	}
+
+	public GenericsEval17Test(String name) {
+		super(name);
+	}
+
+	public void testEvaluate_Bug567801_UnionType_ExpectValueType() throws Exception {
+		debugWithBreakpoint("Bug567801", 13);
+		String snippet = "e instanceof java.lang.Exception";
+		IValue value = doEval(javaThread, snippet);
+
+		assertNotNull("value is null", value);
+		assertEquals("value is not true", "true", value.getValueString());
+	}
+
+	private void debugWithBreakpoint(String testClass, int lineNumber) throws Exception {
+		createLineBreakpoint(lineNumber, testClass);
+		javaThread = launchToBreakpoint(testClass);
+		assertNotNull("The program did not suspend", javaThread);
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		try {
+			terminateAndRemove(javaThread);
+		} finally {
+			super.tearDown();
+			removeAllBreakpoints();
+		}
+	}
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java
index 4ff72ea..53b5be3 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/eval/LambdaVariableTest.java
@@ -64,6 +64,87 @@
 		assertEquals("Actual value is not false", "false", value.toString());
 	}
 
+	public void testEvaluate_Bug567801_VariableWithTypeArgument_MustEvaluationWithCorrectType() throws Exception {
+		debugWithBreakpoint("Bug567801", 29);
+		String snippet = "numbers.stream().anyMatch(a -> a >= 10)";
+		IValue value = doEval(javaThread, snippet);
+
+		assertEquals("wrong type : ", "boolean", value.getReferenceTypeName());
+		assertEquals("Actual value is not true", "true", value.getValueString());
+	}
+
+	public void testEvaluate_Bug567801_VariableWithNestedTypeArgument_MustEvaluationWithCorrectType() throws Exception {
+		debugWithBreakpoint("Bug567801", 29);
+		String snippet = "listOfNumberList.stream().filter(l -> l.size() > 0).flatMap(l -> l.stream()).anyMatch(a -> a >= 10)";
+		IValue value = doEval(javaThread, snippet);
+
+		assertEquals("wrong type : ", "boolean", value.getReferenceTypeName());
+		assertEquals("Actual value is not true", "true", value.getValueString());
+	}
+
+	public void testEvaluate_Bug567801_VariableWithUpperBoundTypeArgument_MustEvaluationWithCorrectType() throws Exception {
+		debugWithBreakpoint("Bug567801", 29);
+		String snippet = "extendsList.stream().anyMatch(a -> a.intValue() >= 10)";
+		IValue value = doEval(javaThread, snippet);
+
+		assertEquals("wrong type : ", "boolean", value.getReferenceTypeName());
+		assertEquals("Actual value is not true", "true", value.getValueString());
+	}
+
+	public void testEvaluate_Bug567801_VariableWithLowerBoundTypeArgument_MustEvaluationWithCorrectType() throws Exception {
+		debugWithBreakpoint("Bug567801", 29);
+		String snippet = "superList.stream().anyMatch(a -> ((Integer)a).intValue() >= 10)";
+		IValue value = doEval(javaThread, snippet);
+
+		assertEquals("wrong type : ", "boolean", value.getReferenceTypeName());
+		assertEquals("Actual value is not true", "true", value.getValueString());
+	}
+
+	public void testEvaluate_Bug567801_VariableWithWildCardTypeArgument_MustEvaluationWithCorrectType() throws Exception {
+		debugWithBreakpoint("Bug567801", 29);
+		String snippet = "wildList.stream().anyMatch(a -> ((Integer)a).intValue() >= 10)";
+		IValue value = doEval(javaThread, snippet);
+
+		assertEquals("wrong type : ", "boolean", value.getReferenceTypeName());
+		assertEquals("Actual value is not true", "true", value.getValueString());
+	}
+
+	public void testEvaluate_Bug567801_VariableWithIntersectionTypeArgument_MustEvaluationWithCorrectType() throws Exception {
+		debugWithBreakpoint("Bug567801", 29);
+		String snippet = "intersectionList.stream().anyMatch(a -> a instanceof java.io.Closeable)";
+		IValue value = doEval(javaThread, snippet);
+
+		assertEquals("wrong type : ", "boolean", value.getReferenceTypeName());
+		assertEquals("Actual value is not false", "false", value.getValueString());
+	}
+
+	public void testEvaluate_Bug567801_VariableWithPrimitiveArrayTypeArgument_MustEvaluationWithCorrectType() throws Exception {
+		debugWithBreakpoint("Bug567801", 29);
+		String snippet = "parrayList.stream().anyMatch(a -> a.length > 0)";
+		IValue value = doEval(javaThread, snippet);
+
+		assertEquals("wrong type : ", "boolean", value.getReferenceTypeName());
+		assertEquals("Actual value is not true", "true", value.getValueString());
+	}
+
+	public void testEvaluate_Bug567801_VariableWithArrayTypeArgument_MustEvaluationWithCorrectType() throws Exception {
+		debugWithBreakpoint("Bug567801", 29);
+		String snippet = "arrayList.stream().anyMatch(a -> a.length > 0)";
+		IValue value = doEval(javaThread, snippet);
+
+		assertEquals("wrong type : ", "boolean", value.getReferenceTypeName());
+		assertEquals("Actual value is not true", "true", value.getValueString());
+	}
+
+	public void testEvaluate_Bug567801_PrimitiveTypeArgument_MustEvaluationWithCorrectType() throws Exception {
+		debugWithBreakpoint("Bug567801", 29);
+		String snippet = "stream.anyMatch(a -> a > 0)";
+		IValue value = doEval(javaThread, snippet);
+
+		assertEquals("wrong type : ", "boolean", value.getReferenceTypeName());
+		assertEquals("Actual value is not true", "true", value.getValueString());
+	}
+
 	private void debugWithBreakpoint(String testClass, int lineNumber) throws Exception {
 		createLineBreakpoint(lineNumber, testClass);
 		javaThread = launchToBreakpoint(testClass);
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 cfbf895..9349aa4 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
@@ -88,6 +88,22 @@
 		assertEquals("count is not 4000", "4000", value.getValueString());
 	}
 
+	public void testEvaluate_PrimitiveCastInLamndaExpr_ShouldEvaluatedWithCastType() throws Exception {
+		debugWithBreakpoint("RemoteEvaluator", 20);
+		IValue value = evaluate("java.util.stream.IntStream.of(1,2,3).anyMatch(i -> ((short) i) > (short)2)");
+
+		assertNotNull("result is null", value);
+		assertEquals("value is not true", "true", value.getValueString());
+	}
+
+	public void testEvaluate_TypeCastInLamndaExpr_ShouldEvaluatedWithCastType() throws Exception {
+		debugWithBreakpoint("RemoteEvaluator", 20);
+		IValue value = evaluate("java.util.stream.Stream.<java.util.List<Object>>of(new java.util.ArrayList<>()).anyMatch(l -> ((java.util.ArrayList<Object>)l).size() > 1)");
+
+		assertNotNull("result is null", value);
+		assertEquals("value is not false", "false", value.getValueString());
+	}
+
 	@Override
 	protected IJavaProject getProjectContext() {
 		return get18Project();
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/EvaluateAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/EvaluateAction.java
index 60641c0..ca23f88 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/EvaluateAction.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/EvaluateAction.java
@@ -245,7 +245,7 @@
                         IEvaluationEngine engine = null;
                         try {
                             Object selection= getSelectedObject();
-                            if (!(selection instanceof String)) {
+							if (!(selection instanceof String) || ((String) selection).isEmpty()) {
                                 return;
                             }
                             String expression= (String)selection;
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/PopupInspectAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/PopupInspectAction.java
index 2926229..c76491c 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/PopupInspectAction.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/PopupInspectAction.java
@@ -20,6 +20,7 @@
 import org.eclipse.jdt.internal.debug.ui.display.JavaInspectExpression;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.ui.IWorkbenchPart;
 import org.eclipse.ui.texteditor.ITextEditor;
 
@@ -71,6 +72,8 @@
         		return returnValue;
         	}
         };
-        displayPopup.open();
+		// Make sure the popup is shown after the BusyIndicator has focused the previous focus owner. This was a issue
+		// in MacOS which is reported under https://bugs.eclipse.org/bugs/show_bug.cgi?id=569600
+		Display.getDefault().asyncExec(displayPopup::open);
     }
 }
diff --git a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
index f91b54d..e101bd0 100644
--- a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
@@ -3,8 +3,7 @@
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.debug; singleton:=true
 Bundle-Version: 3.17.100.qualifier
-Bundle-ClassPath: jdimodel.jar,
- tools.jar
+Bundle-ClassPath: jdimodel.jar
 Bundle-Activator: org.eclipse.jdt.internal.debug.core.JDIDebugPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
@@ -26,7 +25,7 @@
  org.eclipse.jdt.internal.debug.eval;x-friends:="org.eclipse.jdt.debug.ui",
  org.eclipse.jdt.internal.debug.eval.ast.engine;x-friends:="org.eclipse.jdt.debug.ui",
  org.eclipse.jdt.internal.debug.eval.ast.instructions;x-friends:="org.eclipse.jdt.debug.ui"
-Require-Bundle: org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)",
+Require-Bundle: org.eclipse.core.resources;bundle-version="[3.14.0,4.0.0)",
  org.eclipse.debug.core;bundle-version="[3.12.0,4.0.0)",
  org.eclipse.jdt.core;bundle-version="[3.22.0,4.0.0)",
  org.eclipse.core.runtime;bundle-version="[3.11.0,4.0.0)",
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 9c81676..149ff12 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
@@ -249,6 +249,18 @@
 			return localBindings.containsKey(binding);
 		}
 
+		private boolean isParentInLocalBinding(ASTNode parent) {
+			if (parent instanceof Name) {
+				// this will avoid unwanted upward traversals
+				if (isLocalBinding(((Name) parent).resolveBinding())) {
+					return true;
+				}
+				// traverse upstream to see if a parent is already handled
+				return isParentInLocalBinding(parent.getParent());
+			}
+			return false;
+		}
+
 		void addLocalBinding(IBinding binding, String name) {
 			localBindings.put(binding, name);
 		}
@@ -605,9 +617,9 @@
 
 		@Override
 		public boolean visit(CastExpression node) {
-			//buffer.append("(");//$NON-NLS-1$
+			buffer.append("(");//$NON-NLS-1$
 			node.getType().accept(this);
-			//buffer.append(")");//$NON-NLS-1$
+			buffer.append(")");//$NON-NLS-1$
 			node.getExpression().accept(this);
 			return false;
 		}
@@ -1494,7 +1506,10 @@
 		@Override
 		public boolean visit(SimpleName node) {
 			IBinding binding = node.resolveBinding();
-			if (!isLocalBinding(binding)) {
+			// when having code like arr.length the length is identified as a field variable. But since the arr is
+			// already pushed as a variable we don't need to handle length here. So if we have chained field access like
+			// obj.f1.f2 we will only push the obj as a variable.
+			if (!isLocalBinding(binding) && isParentInLocalBinding(node.getParent())) {
 				if (binding instanceof IVariableBinding) {
 					IVariableBinding vb = ((IVariableBinding) binding);
 					// For future optimization: Check for duplicates, so same value is only bound once
diff --git a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
index b5be5c5..d9dc4ae 100644
--- a/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
+++ b/org.eclipse.jdt.debug/eval/org/eclipse/jdt/internal/debug/eval/ast/engine/ASTEvaluationEngine.java
@@ -42,6 +42,7 @@
 import org.eclipse.debug.core.model.IVariable;
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.Signature;
+import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.core.compiler.IProblem;
 import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.core.dom.ASTParser;
@@ -80,6 +81,7 @@
 public class ASTEvaluationEngine implements IAstEvaluationEngine {
 	public static final String ANONYMOUS_VAR_PREFIX = "val$"; //$NON-NLS-1$
 	private static final int EVALUATION_DETAIL_BITMASK = DebugEvent.EVALUATION | DebugEvent.EVALUATION_IMPLICIT;
+	private static final String QN_OBJECT = "java.lang.Object"; //$NON-NLS-1$
 	private IJavaProject fProject;
 
 	private IJavaDebugTarget fDebugTarget;
@@ -403,19 +405,63 @@
 	}
 
 	private String getFixedUnresolvableGenericTypes(IJavaVariable variable) throws DebugException {
+		StringBuilder fixedSignature = new StringBuilder();
+		scanAndFixSignature(variable.getGenericSignature(), Signature.toString(variable.getSignature()), fixedSignature);
+		return fixedSignature.toString();
+	}
+
+	private void scanAndFixSignature(String genericSignature, String erasureSignature, StringBuilder fixedSignature) {
 		/*
 		 * This actually fix variables which are type of Generic Types which cannot be resolved to a type in the current content. For example variable
 		 * type like P_OUT in java.util.stream.ReferencePipeline.filter(Predicate<? super P_OUT>)
+		 *
+		 * and also generic signature such as Ljava/util/function/Predicate<+Ljava/util/List<Ljava/lang/Integer;>;>; Ljava/util/Comparator<-TT;>;
+		 * which will fail the properly resolved to the type.
 		 */
-
-		final String genericSignature = variable.getGenericSignature();
-		final String fqn = Signature.toString(genericSignature).replace('/', '.');
-		if (genericSignature.startsWith(String.valueOf(Signature.C_TYPE_VARIABLE))
-				|| Signature.getTypeArguments(genericSignature).length > 0) {
-			// resolve to the signature of the variable.
-			return Signature.toString(variable.getSignature()).replace('/', '.');
+		if (genericSignature.startsWith(String.valueOf(Signature.C_TYPE_VARIABLE)) ||
+				genericSignature.startsWith(String.valueOf(Signature.C_CAPTURE)) ||
+				genericSignature.startsWith(String.valueOf(Signature.C_STAR)) ||
+				genericSignature.startsWith(String.valueOf(Signature.C_SUPER)))
+		{
+			fixedSignature.append(toDotQualified(erasureSignature));
+			return;
 		}
-		return fqn;
+
+		if(genericSignature.startsWith(String.valueOf(Signature.C_EXTENDS))) {
+			fixedSignature.append(toDotQualified(Signature.toString(getUpperBoundTypeSignature(genericSignature))));
+			return;
+		}
+
+		// we have a proper type which might be parameterized so extract the type FQN
+		fixedSignature.append(toDotQualified(Signature.toString(Signature.getTypeErasure(genericSignature))));
+
+		String[] typeArguments = Signature.getTypeArguments(genericSignature);
+		if (typeArguments.length > 0) {
+			fixedSignature.append(Signature.C_GENERIC_START);
+			for (int i = 0; i < typeArguments.length; i++) {
+				if (i > 0) {
+					fixedSignature.append(',');
+				}
+				scanAndFixSignature(typeArguments[i], QN_OBJECT, fixedSignature);
+			}
+			fixedSignature.append(Signature.C_GENERIC_END);
+		}
+	}
+
+	private String toDotQualified(String fqn) {
+		return fqn.replace('/', '.');
+	}
+
+	private String getUpperBoundTypeSignature(String typeParamaterSignature) {
+		// +Ljava/util/List<Ljava/lang/Integer;>;
+		return String.valueOf(getBoudTypeParameterSignature(typeParamaterSignature.toCharArray(), Signature.C_EXTENDS));
+	}
+
+	private char[] getBoudTypeParameterSignature(char[] typeParamaterSignature, char boundType) {
+		if (typeParamaterSignature.length < 2 || typeParamaterSignature[0] != boundType) {
+			throw new IllegalArgumentException(Signature.toString(String.valueOf(typeParamaterSignature)));
+		}
+		return CharOperation.subarray(typeParamaterSignature, 1, typeParamaterSignature.length);
 	}
 
 	private CompilationUnit parseCompilationUnit(char[] source,
@@ -481,11 +527,11 @@
 			// Arrays with a base component type of a class or interface are
 			// treated
 			// as Object arrays and evaluated in Object.
-			String recTypeName = "java.lang.Object"; //$NON-NLS-1$
+			String recTypeName = QN_OBJECT;
 			String typeName = arrayType.getName();
 			if (componentType instanceof IJavaReferenceType) {
 				StringBuilder buf = new StringBuilder();
-				buf.append("java.lang.Object"); //$NON-NLS-1$
+				buf.append(QN_OBJECT);
 				for (int i = 0; i < dimension; i++) {
 					buf.append("[]"); //$NON-NLS-1$
 				}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaClassPrepareBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaClassPrepareBreakpoint.java
index d5c66ee..b81e674 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaClassPrepareBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaClassPrepareBreakpoint.java
@@ -91,9 +91,6 @@
 			final int charEnd, final boolean add, final Map<String, Object> attributes)
 			throws DebugException {
 		IWorkspaceRunnable wr = monitor -> {
-			// create the marker
-			setMarker(resource.createMarker(JAVA_CLASS_PREPARE_BREAKPOINT));
-
 			// add attributes
 			attributes.put(IBreakpoint.ID, getModelIdentifier());
 			attributes.put(IMarker.CHAR_START, Integer.valueOf(charStart));
@@ -103,7 +100,8 @@
 			attributes.put(ENABLED, Boolean.TRUE);
 			attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy()));
 
-			ensureMarker().setAttributes(attributes);
+			// create the marker
+			setMarker(resource.createMarker(JAVA_CLASS_PREPARE_BREAKPOINT, attributes));
 
 			register(add);
 		};
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaLineBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaLineBreakpoint.java
index 782809c..8ed1c06 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaLineBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaLineBreakpoint.java
@@ -145,16 +145,14 @@
 			throws DebugException {
 		IWorkspaceRunnable wr = monitor -> {
 
-			// create the marker
-			setMarker(resource.createMarker(markerType));
-
 			// add attributes
 			addLineBreakpointAttributes(attributes, getModelIdentifier(),
 					true, lineNumber, charStart, charEnd);
 			addTypeNameAndHitCount(attributes, typeName, hitCount);
 			// set attributes
 			attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy()));
-			ensureMarker().setAttributes(attributes);
+			// create the marker
+			setMarker(resource.createMarker(markerType, attributes));
 
 			// add to breakpoint manager if requested
 			register(add);
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaPatternBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaPatternBreakpoint.java
index 077c4d5..2c1096e 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaPatternBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaPatternBreakpoint.java
@@ -67,16 +67,14 @@
 			final String markerType) throws DebugException {
 		IWorkspaceRunnable wr = monitor -> {
 
-			// create the marker
-			setMarker(resource.createMarker(markerType));
-
 			// add attributes
 			addLineBreakpointAttributes(attributes, getModelIdentifier(),
 					true, lineNumber, charStart, charEnd);
 			addPatternAndHitCount(attributes, sourceName, pattern, hitCount);
 			// set attributes
 			attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy()));
-			ensureMarker().setAttributes(attributes);
+			// create the marker
+			setMarker(resource.createMarker(markerType, attributes));
 
 			register(add);
 		};
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaStratumLineBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaStratumLineBreakpoint.java
index de63d19..0aacd40 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaStratumLineBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaStratumLineBreakpoint.java
@@ -142,9 +142,6 @@
 			final String markerType) throws DebugException {
 		IWorkspaceRunnable wr = monitor -> {
 
-			// create the marker
-			setMarker(resource.createMarker(markerType));
-
 			// modify pattern
 			String pattern = classNamePattern;
 			if (pattern != null && pattern.length() == 0) {
@@ -158,7 +155,8 @@
 					sourcePath, pattern, hitCount);
 			// set attributes
 			attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy()));
-			ensureMarker().setAttributes(attributes);
+			// create the marker
+			setMarker(resource.createMarker(markerType, attributes));
 
 			register(register);
 		};
@@ -263,14 +261,17 @@
 				if (fSuffix[i].length() == 0) {
 					return true;
 				}
-				if (typeName.endsWith(fSuffix[i]))
+				if (typeName.endsWith(fSuffix[i])) {
 					return true;
+				}
 			} else if (fPrefix[i] != null) {
-				if (typeName.startsWith(fPrefix[i]))
+				if (typeName.startsWith(fPrefix[i])) {
 					return true;
+				}
 			} else {
-				if (typeName.startsWith(patterns[i]))
+				if (typeName.startsWith(patterns[i])) {
 					return true;
+				}
 			}
 		}
 
@@ -436,8 +437,9 @@
 	}
 
 	public synchronized String[] getTypeNamePatterns() throws CoreException {
-		if (fTypeNamePatterns != null)
+		if (fTypeNamePatterns != null) {
 			return fTypeNamePatterns;
+		}
 
 		String patterns = getPattern();
 
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaTargetPatternBreakpoint.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaTargetPatternBreakpoint.java
index fea4972..e541615 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaTargetPatternBreakpoint.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/breakpoints/JavaTargetPatternBreakpoint.java
@@ -64,16 +64,13 @@
 			throws DebugException {
 		IWorkspaceRunnable wr = monitor -> {
 
-			// create the marker
-			setMarker(resource.createMarker(markerType));
-
 			// add attributes
 			addLineBreakpointAttributes(attributes, getModelIdentifier(),
 					true, lineNumber, charStart, charEnd);
 			addSourceNameAndHitCount(attributes, sourceName, hitCount);
 			attributes.put(SUSPEND_POLICY, Integer.valueOf(getDefaultSuspendPolicy()));
-			// set attributes
-			ensureMarker().setAttributes(attributes);
+			// create the marker
+			setMarker(resource.createMarker(markerType, attributes));
 
 			register(add);
 		};