diff --git a/build.xml b/build.xml
index fa2607b2..1a8f4bc4 100644
--- a/build.xml
+++ b/build.xml
@@ -48,6 +48,14 @@
patches/7610.diff
patches/8036-draft.diff
patches/8038-draft.diff
+ patches/8210.diff
+ patches/8237.diff
+ patches/8242.diff
+ patches/8245.diff
+ patches/8255.diff
+ patches/8260.diff
+ patches/8280.diff
+ patches/8289.diff
patches/mvn-sh.diff
patches/project-marker-jdk.diff
patches/generate-dependencies.diff
diff --git a/patches/8210.diff b/patches/8210.diff
new file mode 100644
index 00000000..31bcf104
--- /dev/null
+++ b/patches/8210.diff
@@ -0,0 +1,435 @@
+diff --git a/java/java.editor/nbproject/project.xml b/java/java.editor/nbproject/project.xml
+index 0b5a6e5d585a..7c09e3513d2a 100644
+--- a/java/java.editor/nbproject/project.xml
++++ b/java/java.editor/nbproject/project.xml
+@@ -558,6 +558,10 @@
+
+
+
++
++ org.netbeans.modules.lexer.nbbridge
++
++
+
+ org.netbeans.modules.masterfs
+
+diff --git a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
+index bddc6dbc8e8c..09437294e148 100644
+--- a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
++++ b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
+@@ -221,26 +221,35 @@ public static Completion.Kind elementKind2CompletionItemKind(ElementKind kind) {
+ }
+ }
+
+- public static Supplier> addImport(Document doc, int offset, ElementHandle> handle) {
++ public static Supplier> addImportAndInjectPackageIfNeeded(Document doc, int offset, ElementHandle> handle) {
+ return () -> {
+- AtomicReference pkg = new AtomicReference<>();
+- List textEdits = modify2TextEdits(JavaSource.forDocument(doc), copy -> {
+- copy.toPhase(JavaSource.Phase.RESOLVED);
+- String fqn = SourceUtils.resolveImport(copy, copy.getTreeUtilities().pathFor(offset), handle.getQualifiedName());
+- if (fqn != null) {
+- int idx = fqn.lastIndexOf('.');
+- if (idx >= 0) {
+- pkg.set(fqn.substring(0, idx + 1));
+- }
+- }
+- });
+- if (textEdits.isEmpty() && pkg.get() != null) {
+- textEdits.add(new TextEdit(offset, offset, pkg.get()));
++ ResolvedImport resolved = addImport(doc, offset, handle);
++ List edits;
++ String insertName = resolved.insertName();
++ int dotIdx = insertName.lastIndexOf('.');
++ if (dotIdx >= 0) {
++ edits = new ArrayList<>(resolved.importEdits().size() + 1);
++ edits.addAll(resolved.importEdits());
++ edits.add(new TextEdit(offset, offset, insertName.substring(0, dotIdx + 1)));
++ } else {
++ edits = resolved.importEdits();
+ }
+- return textEdits;
++ return edits;
+ };
+ }
+
++ public static ResolvedImport addImport(Document doc, int offset, ElementHandle> handle) {
++ AtomicReference insertName = new AtomicReference<>();
++ List textEdits = modify2TextEdits(JavaSource.forDocument(doc), copy -> {
++ copy.toPhase(JavaSource.Phase.RESOLVED);
++ insertName.set(SourceUtils.resolveImport(copy, copy.getTreeUtilities().pathFor(offset), handle.getQualifiedName()));
++ });
++
++ return new ResolvedImport(textEdits, insertName.get());
++ }
++
++ public record ResolvedImport(List importEdits, String insertName) {}
++
+ public static boolean isOfKind(Element e, EnumSet kinds) {
+ if (kinds.contains(e.getKind())) {
+ return true;
+@@ -666,24 +675,19 @@ public Completion createAttributeValueItem(CompilationInfo info, String value, S
+
+ @Override
+ public Completion createStaticMemberItem(CompilationInfo info, DeclaredType type, Element memberElem, TypeMirror memberType, boolean multipleVersions, int substitutionOffset, boolean isDeprecated, boolean addSemicolon, boolean smartType) {
+- //TODO: prefer static imports (but would be much slower?)
+- //TODO: should be resolveImport instead of addImports:
+- Map imports = (Map) info.getCachedValue(KEY_IMPORT_TEXT_EDITS);
++ Map imports = (Map) info.getCachedValue(KEY_IMPORT_TEXT_EDITS);
+ if (imports == null) {
+ info.putCachedValue(KEY_IMPORT_TEXT_EDITS, imports = new HashMap<>(), CompilationInfo.CacheClearPolicy.ON_TASK_END);
+ }
+- TextEdit currentClassImport = imports.computeIfAbsent(type.asElement(), toImport -> {
+- List textEdits = modify2TextEdits(JavaSource.forFileObject(info.getFileObject()), wc -> {
+- wc.toPhase(JavaSource.Phase.ELEMENTS_RESOLVED);
+- wc.rewrite(info.getCompilationUnit(), GeneratorUtilities.get(wc).addImports(wc.getCompilationUnit(), new HashSet<>(Arrays.asList(toImport))));
+- });
+- return textEdits.isEmpty() ? null : textEdits.get(0);
++ ResolvedImport currentClassImport = imports.computeIfAbsent(type.asElement(), toImport -> {
++ return addImport(doc, offset, ElementHandle.create(toImport));
+ });
+ String label = type.asElement().getSimpleName() + "." + memberElem.getSimpleName();
+ String sortText = memberElem.getSimpleName().toString();
+ String memberTypeName;
+ StringBuilder labelDetail = new StringBuilder();
+- StringBuilder insertText = new StringBuilder(label);
++ StringBuilder insertText = new StringBuilder();
++ insertText.append(currentClassImport.insertName()).append(".").append(memberElem.getSimpleName());
+ boolean asTemplate = false;
+ if (memberElem.getKind().isField()) {
+ memberTypeName = Utilities.getTypeName(info, memberType, false).toString();
+@@ -740,12 +744,12 @@ public Completion createStaticMemberItem(CompilationInfo info, DeclaredType type
+ .labelDescription(memberTypeName)
+ .insertText(insertText.toString())
+ .insertTextFormat(asTemplate ? Completion.TextFormat.Snippet : Completion.TextFormat.PlainText)
+- .sortText(String.format("%04d%s", (memberElem.getKind().isField() ? 720 : 750) + (smartType ? 1000 : 0), sortText));
++ .sortText(String.format("%04d%s", (memberElem.getKind().isField() ? 720 : 750) + (smartType ? 0: 1000), sortText));
+ if (labelDetail.length() > 0) {
+ builder.labelDetail(labelDetail.toString());
+ }
+- if (currentClassImport != null) {
+- builder.additionalTextEdits(Collections.singletonList(currentClassImport));
++ if (!currentClassImport.importEdits().isEmpty()) {
++ builder.additionalTextEdits(currentClassImport.importEdits());
+ }
+ ElementHandle handle = SUPPORTED_ELEMENT_KINDS.contains(memberElem.getKind().name()) ? ElementHandle.create(memberElem) : null;
+ if (handle != null) {
+@@ -1041,7 +1045,7 @@ private Completion createTypeItem(CompilationInfo info, String prefix, ElementHa
+ if (handle != null) {
+ builder.documentation(getDocumentation(doc, off, handle));
+ if (!addSimpleName && !inImport) {
+- builder.additionalTextEdits(addImport(doc, off, handle));
++ builder.additionalTextEdits(addImportAndInjectPackageIfNeeded(doc, off, handle));
+ }
+ }
+ if (isDeprecated) {
+diff --git a/java/java.editor/src/org/netbeans/modules/java/editor/javadoc/JavadocCompletionCollector.java b/java/java.editor/src/org/netbeans/modules/java/editor/javadoc/JavadocCompletionCollector.java
+index 0289b2dcb13f..f7955ef64cf0 100644
+--- a/java/java.editor/src/org/netbeans/modules/java/editor/javadoc/JavadocCompletionCollector.java
++++ b/java/java.editor/src/org/netbeans/modules/java/editor/javadoc/JavadocCompletionCollector.java
+@@ -276,7 +276,7 @@ private Completion createTypeItem(ElementHandle handle, TypeElement
+ }
+ if (handle != null) {
+ builder.documentation(JavaCompletionCollector.getDocumentation(doc, offset, handle));
+- builder.additionalTextEdits(JavaCompletionCollector.addImport(doc, offset, handle));
++ builder.additionalTextEdits(JavaCompletionCollector.addImportAndInjectPackageIfNeeded(doc, offset, handle));
+ }
+ if (isDeprecated) {
+ builder.addTag(Completion.Tag.Deprecated);
+diff --git a/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/JavaCompletionCollectorTest.java b/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/JavaCompletionCollectorTest.java
+new file mode 100644
+index 000000000000..d6e3d5669e65
+--- /dev/null
++++ b/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/JavaCompletionCollectorTest.java
+@@ -0,0 +1,291 @@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements. See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership. The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing,
++ * software distributed under the License is distributed on an
++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++ * KIND, either express or implied. See the License for the
++ * specific language governing permissions and limitations
++ * under the License.
++ */
++package org.netbeans.modules.editor.java;
++
++import java.util.ArrayList;
++import java.util.List;
++import java.util.concurrent.atomic.AtomicBoolean;
++import java.util.stream.Collectors;
++import javax.swing.text.Document;
++import static junit.framework.TestCase.assertNotNull;
++import static junit.framework.TestCase.assertTrue;
++import org.netbeans.api.editor.mimelookup.MimePath;
++import org.netbeans.api.java.lexer.JavaTokenId;
++import org.netbeans.api.java.source.JavaSource;
++import org.netbeans.api.java.source.SourceUtilsTestUtil;
++import org.netbeans.api.java.source.TestUtilities;
++import org.netbeans.api.lsp.Completion;
++import org.netbeans.api.lsp.Completion.Context;
++import org.netbeans.api.lsp.Completion.TriggerKind;
++import org.netbeans.api.lsp.TextEdit;
++import org.netbeans.junit.NbTestCase;
++import org.netbeans.spi.editor.mimelookup.MimeDataProvider;
++import org.openide.cookies.EditorCookie;
++import org.openide.filesystems.FileObject;
++import org.openide.filesystems.FileUtil;
++import org.openide.filesystems.MIMEResolver;
++import org.openide.util.Lookup;
++import org.openide.util.lookup.Lookups;
++
++public class JavaCompletionCollectorTest extends NbTestCase {
++
++ public JavaCompletionCollectorTest(String name) {
++ super(name);
++ }
++
++ public void testStaticMembersAndImports() throws Exception {
++ AtomicBoolean found = new AtomicBoolean();
++ runJavaCollector(List.of(new FileDescription("test/Test.java",
++ """
++ package test;
++ public class Test {
++ public void test() {
++ if (call(|)) {
++ }
++ }
++ private boolean call(test.other.E e) {
++ return false;
++ }
++ }
++ """),
++ new FileDescription("test/other/E.java",
++ """
++ package test.other;
++ public enum E {
++ A, B, C;
++ }
++ """)),
++ completions -> {
++ for (Completion completion : completions) {
++ if (completion.getLabel().equals("E.A")) {
++ assertEquals("14-14:\\nimport test.other.E;\\n\\n",
++ completion.getAdditionalTextEdits()
++ .get()
++ .stream()
++ .map(JavaCompletionCollectorTest::textEdit2String)
++ .collect(Collectors.joining(", ")));
++ assertEquals("E.A",
++ completion.getInsertText());
++ found.set(true);
++ }
++ }
++ });
++ assertTrue(found.get());
++ }
++
++ public void testStaticMembersAndNoImports() throws Exception {
++ AtomicBoolean found = new AtomicBoolean();
++ runJavaCollector(List.of(new FileDescription("test/Test.java",
++ """
++ package test;
++ public class Test {
++ public void test() {
++ if (call(|)) {
++ }
++ }
++ private boolean call(Outter.E e) {
++ return false;
++ }
++ }
++ class Outter {
++ public enum E {
++ A, B, C;
++ }
++ }
++ """)),
++ completions -> {
++ for (Completion completion : completions) {
++ if (completion.getLabel().equals("E.A")) {
++ assertNull(completion.getAdditionalTextEdits());
++ assertEquals("Outter.E.A",
++ completion.getInsertText());
++ found.set(true);
++ }
++ }
++ });
++ assertTrue(found.get());
++ }
++
++ public void testTypeFromIndex1() throws Exception {
++ AtomicBoolean found = new AtomicBoolean();
++ runJavaCollector(List.of(new FileDescription("test/Test.java",
++ """
++ package test;
++ public class Test {
++ public void test() {
++ EEE|
++ }
++ }
++ """),
++ new FileDescription("test/other/EEE.java",
++ """
++ package test.other;
++ public class EEE {
++ }
++ """)),
++ completions -> {
++ for (Completion completion : completions) {
++ if (completion.getLabel().equals("EEE")) {
++ assertEquals("14-14:\\nimport test.other.EEE;\\n\\n",
++ completion.getAdditionalTextEdits()
++ .get()
++ .stream()
++ .map(JavaCompletionCollectorTest::textEdit2String)
++ .collect(Collectors.joining(", ")));
++ assertEquals("EEE",
++ completion.getInsertText());
++ found.set(true);
++ }
++ }
++ });
++ assertTrue(found.get());
++ }
++
++ public void testTypeFromIndex2() throws Exception {
++ AtomicBoolean found = new AtomicBoolean();
++ runJavaCollector(List.of(new FileDescription("test/Test.java",
++ """
++ package test;
++ public class Test {
++ public void test() {
++ EEE|
++ }
++ interface EEE {}
++ }
++ """),
++ new FileDescription("test/other/EEE.java",
++ """
++ package test.other;
++ public class EEE {
++ }
++ """)),
++ completions -> {
++ for (Completion completion : completions) {
++ if (completion.getLabel().equals("EEE") &&
++ completion.getKind() == Completion.Kind.Class) {
++ assertEquals("67-67:test.other.",
++ completion.getAdditionalTextEdits()
++ .get()
++ .stream()
++ .map(JavaCompletionCollectorTest::textEdit2String)
++ .collect(Collectors.joining(", ")));
++ assertEquals("EEE",
++ completion.getInsertText());
++ found.set(true);
++ }
++ }
++ });
++ assertTrue(found.get());
++ }
++
++ private void runJavaCollector(List files, Validator> validator) throws Exception {
++ SourceUtilsTestUtil.prepareTest(new String[]{"org/netbeans/modules/java/editor/resources/layer.xml"}, new Object[]{new MIMEResolverImpl(), new MIMEDataProvider()});
++
++ FileObject scratch = SourceUtilsTestUtil.makeScratchDir(this);
++ FileObject cache = scratch.createFolder("cache");
++ FileObject src = scratch.createFolder("src");
++ FileObject mainFile = null;
++ int caretPosition = -1;
++
++ for (FileDescription testFile : files) {
++ FileObject testFO = FileUtil.createData(src, testFile.fileName);
++ String code = testFile.code;
++
++ if (mainFile == null) {
++ mainFile = testFO;
++ caretPosition = code.indexOf('|');
++
++ assertTrue(caretPosition >= 0);
++
++ code = code.substring(0, caretPosition) + code.substring(caretPosition + 1);
++ }
++
++ TestUtilities.copyStringToFile(testFO, code);
++ }
++
++ assertNotNull(mainFile);
++
++ if (sourceLevel != null) {
++ SourceUtilsTestUtil.setSourceLevel(mainFile, sourceLevel);
++ }
++
++ SourceUtilsTestUtil.prepareTest(src, FileUtil.createFolder(scratch, "test-build"), cache);
++ SourceUtilsTestUtil.compileRecursively(src);
++
++ EditorCookie ec = mainFile.getLookup().lookup(EditorCookie.class);
++ Document doc = ec.openDocument();
++ JavaCompletionCollector collector = new JavaCompletionCollector();
++ Context ctx = new Context(TriggerKind.Invoked, null);
++ List completions = new ArrayList<>();
++
++ JavaSource.forDocument(doc).runUserActionTask(cc -> {
++ cc.toPhase(JavaSource.Phase.RESOLVED);
++ }, true);
++ collector.collectCompletions(doc, caretPosition, ctx, completions::add);
++ validator.validate(completions);
++ }
++
++ private static String textEdit2String(TextEdit te) {
++ return te.getStartOffset() + "-" + te.getEndOffset() + ":" + te.getNewText().replace("\n", "\\n");
++ }
++
++ private String sourceLevel;
++
++ private final void setSourceLevel(String sourceLevel) {
++ this.sourceLevel = sourceLevel;
++ }
++
++ interface Validator {
++ public void validate(T t) throws Exception;
++ }
++
++ static class MIMEResolverImpl extends MIMEResolver {
++
++ public String findMIMEType(FileObject fo) {
++ if ("java".equals(fo.getExt())) {
++ return "text/x-java";
++ } else {
++ return null;
++ }
++ }
++ }
++
++ static class MIMEDataProvider implements MimeDataProvider {
++
++ @Override
++ public Lookup getLookup(MimePath mimePath) {
++ if ("text/x-java".equals(mimePath.getPath())) {
++ return Lookups.fixed(JavaTokenId.language());
++ }
++ return null;
++ }
++
++ }
++
++ private static final class FileDescription {
++
++ final String fileName;
++ final String code;
++
++ public FileDescription(String fileName, String code) {
++ this.fileName = fileName;
++ this.code = code;
++ }
++ }
++}
diff --git a/patches/8237.diff b/patches/8237.diff
new file mode 100644
index 00000000..81a73761
--- /dev/null
+++ b/patches/8237.diff
@@ -0,0 +1,358 @@
+diff --git a/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java b/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
+index ac22658fe54f..567481a37952 100644
+--- a/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
++++ b/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
+@@ -91,6 +91,10 @@ public static interface ItemFactory {
+
+ T createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean smartType, int assignToVarOffset, boolean memberRef);
+
++ default T createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean afterConstructorTypeParams, boolean smartType, int assignToVarOffset, boolean memberRef) {
++ return createExecutableItem(info, elem, type, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, smartType, assignToVarOffset, memberRef);
++ }
++
+ T createThisOrSuperConstructorItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean isDeprecated, String name);
+
+ T createOverrideMethodItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean implement);
+@@ -1866,7 +1870,7 @@ private void insideMemberSelect(Env env) throws IOException {
+ String typeName = controller.getElementUtilities().getElementName(el, true) + "." + prefix; //NOI18N
+ TypeMirror tm = controller.getTreeUtilities().parseType(typeName, env.getScope().getEnclosingClass());
+ if (tm != null && tm.getKind() == TypeKind.DECLARED) {
+- addMembers(env, tm, ((DeclaredType) tm).asElement(), EnumSet.of(CONSTRUCTOR), null, inImport, insideNew, false, switchItemAdder);
++ addMembers(env, tm, ((DeclaredType) tm).asElement(), EnumSet.of(CONSTRUCTOR), null, inImport, insideNew, false, false, switchItemAdder);
+ }
+ }
+ }
+@@ -1901,7 +1905,7 @@ private void insideMemberSelect(Env env) throws IOException {
+ }
+ }
+ }
+- addMembers(env, type, el, kinds, baseType, inImport, insideNew, false, switchItemAdder);
++ addMembers(env, type, el, kinds, baseType, inImport, insideNew, false, false, switchItemAdder);
+ }
+ break;
+ default:
+@@ -1914,7 +1918,7 @@ private void insideMemberSelect(Env env) throws IOException {
+ String typeName = controller.getElementUtilities().getElementName(el, true) + "." + prefix; //NOI18N
+ TypeMirror tm = controller.getTreeUtilities().parseType(typeName, env.getScope().getEnclosingClass());
+ if (tm != null && tm.getKind() == TypeKind.DECLARED) {
+- addMembers(env, tm, ((DeclaredType) tm).asElement(), EnumSet.of(CONSTRUCTOR), null, inImport, insideNew, false, switchItemAdder);
++ addMembers(env, tm, ((DeclaredType) tm).asElement(), EnumSet.of(CONSTRUCTOR), null, inImport, insideNew, false, false, switchItemAdder);
+ }
+ }
+ if (exs != null && !exs.isEmpty()) {
+@@ -1939,7 +1943,7 @@ private void insideMemberSelect(Env env) throws IOException {
+ for (ElementHandle teHandle : ci.getDeclaredTypes(el.getSimpleName().toString(), ClassIndex.NameKind.SIMPLE_NAME, EnumSet.allOf(ClassIndex.SearchScope.class))) {
+ TypeElement te = teHandle.resolve(controller);
+ if (te != null && trees.isAccessible(scope, te)) {
+- addMembers(env, te.asType(), te, kinds, baseType, inImport, insideNew, true, switchItemAdder);
++ addMembers(env, te.asType(), te, kinds, baseType, inImport, insideNew, true, false, switchItemAdder);
+ }
+ }
+ }
+@@ -2215,7 +2219,7 @@ private void insideNewClass(Env env) throws IOException {
+ case GTGTGT:
+ controller = env.getController();
+ TypeMirror tm = controller.getTrees().getTypeMirror(new TreePath(path, nc.getIdentifier()));
+- addMembers(env, tm, ((DeclaredType) tm).asElement(), EnumSet.of(CONSTRUCTOR), null, false, false, false);
++ addMembers(env, tm, ((DeclaredType) tm).asElement(), EnumSet.of(CONSTRUCTOR), null, false, false, false, true, addSwitchItemDefault);
+ break;
+ }
+ }
+@@ -4073,10 +4077,10 @@ public boolean accept(Element e, TypeMirror t) {
+ }
+
+ private void addMembers(final Env env, final TypeMirror type, final Element elem, final EnumSet kinds, final DeclaredType baseType, final boolean inImport, final boolean insideNew, final boolean autoImport) throws IOException {
+- addMembers(env, type, elem, kinds, baseType, inImport, insideNew, autoImport, addSwitchItemDefault);
++ addMembers(env, type, elem, kinds, baseType, inImport, insideNew, autoImport, false, addSwitchItemDefault);
+ }
+
+- private void addMembers(final Env env, final TypeMirror type, final Element elem, final EnumSet kinds, final DeclaredType baseType, final boolean inImport, final boolean insideNew, final boolean autoImport, AddSwitchRelatedItem addSwitchItem) throws IOException {
++ private void addMembers(final Env env, final TypeMirror type, final Element elem, final EnumSet kinds, final DeclaredType baseType, final boolean inImport, final boolean insideNew, final boolean autoImport, final boolean afterConstructorTypeParams, AddSwitchRelatedItem addSwitchItem) throws IOException {
+ Set extends TypeMirror> smartTypes = getSmartTypes(env);
+ final TreePath path = env.getPath();
+ TypeMirror actualType = type;
+@@ -4220,7 +4224,7 @@ && isOfKindAndType(e.getEnclosingElement().asType(), e, kinds, baseType, scope,
+ break;
+ case CONSTRUCTOR:
+ ExecutableType et = (ExecutableType) asMemberOf(e, actualType, types);
+- results.add(itemFactory.createExecutableItem(env.getController(), (ExecutableElement) e, et, anchorOffset, autoImport ? env.getReferencesCount() : null, typeElem != e.getEnclosingElement(), elements.isDeprecated(e), inImport, false, isOfSmartType(env, actualType, smartTypes), env.assignToVarPos(), false));
++ results.add(itemFactory.createExecutableItem(env.getController(), (ExecutableElement) e, et, anchorOffset, autoImport ? env.getReferencesCount() : null, typeElem != e.getEnclosingElement(), elements.isDeprecated(e), inImport, false, afterConstructorTypeParams, isOfSmartType(env, actualType, smartTypes), env.assignToVarPos(), false));
+ break;
+ case METHOD:
+ et = (ExecutableType) asMemberOf(e, actualType, types);
+diff --git a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
+index 09437294e148..4eb78d72617c 100644
+--- a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
++++ b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionCollector.java
+@@ -482,17 +482,22 @@ public Completion createVariableItem(CompilationInfo info, String varName, int s
+
+ @Override
+ public Completion createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean smartType, int assignToVarOffset, boolean memberRef) {
+- return createExecutableItem(info, elem, type, null, null, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, smartType, assignToVarOffset, memberRef);
++ return createExecutableItem(info, elem, type, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, false, smartType, assignToVarOffset, memberRef);
++ }
++
++ @Override
++ public Completion createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean afterConstructorTypeParams, boolean smartType, int assignToVarOffset, boolean memberRef) {
++ return createExecutableItem(info, elem, type, null, null, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, afterConstructorTypeParams, smartType, assignToVarOffset, memberRef);
+ }
+
+ @Override
+ public Completion createTypeCastableExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, TypeMirror castType, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean smartType, int assignToVarOffset, boolean memberRef) {
+- return createExecutableItem(info, elem, type, null, castType, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, smartType, assignToVarOffset, memberRef);
++ return createExecutableItem(info, elem, type, null, castType, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, false, smartType, assignToVarOffset, memberRef);
+ }
+
+ @Override
+ public Completion createThisOrSuperConstructorItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean isDeprecated, String name) {
+- return createExecutableItem(info, elem, type, name, null, substitutionOffset, null, false, isDeprecated, false, false, false, -1, false);
++ return createExecutableItem(info, elem, type, name, null, substitutionOffset, null, false, isDeprecated, false, false, false, false, -1, false);
+ }
+
+ @Override
+@@ -1054,14 +1059,16 @@ private Completion createTypeItem(CompilationInfo info, String prefix, ElementHa
+ return builder.build();
+ }
+
+- private Completion createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, String name, TypeMirror castType, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean smartType, int assignToVarOffset, boolean memberRef) {
++ private Completion createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, String name, TypeMirror castType, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean afterConstructorTypeParams, boolean smartType, int assignToVarOffset, boolean memberRef) {
+ String simpleName = name != null ? name : (elem.getKind() == ElementKind.METHOD ? elem : elem.getEnclosingElement()).getSimpleName().toString();
+ Iterator extends VariableElement> it = elem.getParameters().iterator();
+ Iterator extends TypeMirror> tIt = type.getParameterTypes().iterator();
+ StringBuilder labelDetail = new StringBuilder();
+ StringBuilder insertText = new StringBuilder();
+ StringBuilder sortParams = new StringBuilder();
+- insertText.append(simpleName);
++ if (!afterConstructorTypeParams) {
++ insertText.append(simpleName);
++ }
+ labelDetail.append("(");
+ CodeStyle cs = CodeStyle.getDefault(doc);
+ if (!inImport && !memberRef) {
+diff --git a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItem.java b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItem.java
+index 09945ede0eaa..6c16e6df828d 100644
+--- a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItem.java
++++ b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItem.java
+@@ -191,12 +191,12 @@ public static JavaCompletionItem createVariableItem(CompilationInfo info, String
+ return new VariableItem(info, null, varName, substitutionOffset, newVarName, smartType, -1);
+ }
+
+- public static JavaCompletionItem createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, TypeMirror castType, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean smartType, int assignToVarOffset, boolean memberRef, WhiteListQuery.WhiteList whiteList) {
++ public static JavaCompletionItem createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, TypeMirror castType, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean afterConstructorTypeParams, boolean smartType, int assignToVarOffset, boolean memberRef, WhiteListQuery.WhiteList whiteList) {
+ switch (elem.getKind()) {
+ case METHOD:
+ return new MethodItem(info, elem, type, castType, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, smartType, assignToVarOffset, memberRef, whiteList);
+ case CONSTRUCTOR:
+- return new ConstructorItem(info, elem, type, substitutionOffset, isDeprecated, smartType, null, whiteList);
++ return new ConstructorItem(info, elem, type, substitutionOffset, isDeprecated, afterConstructorTypeParams, smartType, null, whiteList);
+ default:
+ throw new IllegalArgumentException("kind=" + elem.getKind());
+ }
+@@ -204,7 +204,7 @@ public static JavaCompletionItem createExecutableItem(CompilationInfo info, Exec
+
+ public static JavaCompletionItem createThisOrSuperConstructorItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, boolean isDeprecated, String name, WhiteListQuery.WhiteList whiteList) {
+ if (elem.getKind() == ElementKind.CONSTRUCTOR) {
+- return new ConstructorItem(info, elem, type, substitutionOffset, isDeprecated, false, name, whiteList);
++ return new ConstructorItem(info, elem, type, substitutionOffset, isDeprecated, false, false, name, whiteList);
+ }
+ throw new IllegalArgumentException("kind=" + elem.getKind());
+ }
+@@ -2489,6 +2489,7 @@ static class ConstructorItem extends WhiteListJavaCompletionItem modifiers;
+ private List params;
+ private boolean isAbstract;
+@@ -2497,11 +2498,12 @@ static class ConstructorItem extends WhiteListJavaCompletionItem();
+@@ -2551,7 +2553,7 @@ public CharSequence getSortText() {
+
+ @Override
+ public CharSequence getInsertPrefix() {
+- return simpleName;
++ return insertPrefix;
+ }
+
+ @Override
+diff --git a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItemFactory.java b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItemFactory.java
+index ac08274cb7e4..3078d30455a7 100644
+--- a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItemFactory.java
++++ b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItemFactory.java
+@@ -109,12 +109,17 @@ public JavaCompletionItem createVariableItem(CompilationInfo info, String varNam
+
+ @Override
+ public JavaCompletionItem createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean smartType, int assignToVarOffset, boolean memberRef) {
+- return JavaCompletionItem.createExecutableItem(info, elem, type, null, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, smartType, assignToVarOffset, memberRef, whiteList);
++ return createExecutableItem(info, elem, type, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, false, smartType, assignToVarOffset, memberRef);
++ }
++
++ @Override
++ public JavaCompletionItem createExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean afterConstructorTypeParams, boolean smartType, int assignToVarOffset, boolean memberRef) {
++ return JavaCompletionItem.createExecutableItem(info, elem, type, null, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, afterConstructorTypeParams, smartType, assignToVarOffset, memberRef, whiteList);
+ }
+
+ @Override
+ public JavaCompletionItem createTypeCastableExecutableItem(CompilationInfo info, ExecutableElement elem, ExecutableType type, TypeMirror castType, int substitutionOffset, ReferencesCount referencesCount, boolean isInherited, boolean isDeprecated, boolean inImport, boolean addSemicolon, boolean smartType, int assignToVarOffset, boolean memberRef) {
+- return JavaCompletionItem.createExecutableItem(info, elem, type, castType, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, smartType, assignToVarOffset, memberRef, whiteList);
++ return JavaCompletionItem.createExecutableItem(info, elem, type, castType, substitutionOffset, referencesCount, isInherited, isDeprecated, inImport, addSemicolon, false, smartType, assignToVarOffset, memberRef, whiteList);
+ }
+
+ @Override
+diff --git a/java/java.editor/src/org/netbeans/modules/java/editor/javadoc/JavadocCompletionItem.java b/java/java.editor/src/org/netbeans/modules/java/editor/javadoc/JavadocCompletionItem.java
+index 22151927877c..9f35779388b7 100644
+--- a/java/java.editor/src/org/netbeans/modules/java/editor/javadoc/JavadocCompletionItem.java
++++ b/java/java.editor/src/org/netbeans/modules/java/editor/javadoc/JavadocCompletionItem.java
+@@ -212,7 +212,7 @@ public CompletionItem createNameItem(String name, int startOffset) {
+ @Override
+ public CompletionItem createJavadocExecutableItem(CompilationInfo info, ExecutableElement e, ExecutableType et, int startOffset, boolean isInherited, boolean isDeprecated) {
+ CompletionItem delegate = JavaCompletionItem.createExecutableItem(
+- info, e, et, null, startOffset, null, isInherited, isDeprecated, false, false, false, -1, false, null);
++ info, e, et, null, startOffset, null, isInherited, isDeprecated, false, false, false, false, -1, false, null);
+ return new JavadocExecutableItem(delegate, e, startOffset);
+ }
+
+diff --git a/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/JavaCompletionCollectorTest.java b/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/JavaCompletionCollectorTest.java
+index d6e3d5669e65..bc1e4bdb87cf 100644
+--- a/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/JavaCompletionCollectorTest.java
++++ b/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/JavaCompletionCollectorTest.java
+@@ -19,7 +19,9 @@
+ package org.netbeans.modules.editor.java;
+
+ import java.util.ArrayList;
++import java.util.HashSet;
+ import java.util.List;
++import java.util.Set;
+ import java.util.concurrent.atomic.AtomicBoolean;
+ import java.util.stream.Collectors;
+ import javax.swing.text.Document;
+@@ -32,6 +34,7 @@
+ import org.netbeans.api.java.source.TestUtilities;
+ import org.netbeans.api.lsp.Completion;
+ import org.netbeans.api.lsp.Completion.Context;
++import org.netbeans.api.lsp.Completion.TextFormat;
+ import org.netbeans.api.lsp.Completion.TriggerKind;
+ import org.netbeans.api.lsp.TextEdit;
+ import org.netbeans.junit.NbTestCase;
+@@ -194,6 +197,108 @@ public class EEE {
+ assertTrue(found.get());
+ }
+
++ public void testNewWithTypeParameters() throws Exception {
++ Set found = new HashSet<>();
++
++ runJavaCollector(List.of(new FileDescription("test/Test.java",
++ """
++ package test;
++ import java.util.*;
++ public class Test {
++ public void test() {
++ Map