You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by ne...@apache.org on 2020/07/30 09:11:02 UTC

[netbeans] branch master updated: [NETBEANS-4311]: Added support for auto-completion of Java Record

This is an automated email from the ASF dual-hosted git repository.

neilcsmith pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 84ed378  [NETBEANS-4311]: Added support for auto-completion of Java Record
     new 277ab58  Merge pull request #2222 from arusinha/netbeans-4311
84ed378 is described below

commit 84ed378465d5ece29d5ff47b6f716a1209cedb5f
Author: Arunava Sinha <ar...@oracle.com>
AuthorDate: Mon Jun 29 19:53:29 2020 +0530

    [NETBEANS-4311]: Added support for auto-completion of Java Record
---
 .../modules/editor/resources/completion/record.png | Bin 0 -> 785 bytes
 .../java/completion/JavaCompletionTask.java        | 273 +++++++++++++++++++--
 .../JavaCompletionTaskTest/1.8/override.pass       |   1 +
 .../JavaCompletionTaskTest/1.8/record.pass         |   1 +
 .../1.8/typesRecordLocalMembersAndVars.pass        |   8 +
 .../1.8/typesRecordStaticMembersAndVars.pass       |   8 +
 .../14/typesRecordLocalMembersAndVars.pass         |   7 +
 .../14/typesRecordStaticMembersAndVars.pass        |   7 +
 .../modules/java/completion/data/Records.java      |  34 +++
 .../JavaCompletionTask114FeaturesTest.java         |  29 +++
 .../modules/editor/java/JavaCompletionItem.java    |  22 +-
 .../netbeans/modules/java/source/TreeShims.java    |   9 +
 .../refactoring/java/ui/WhereUsedPanel.java        |   5 +-
 13 files changed, 375 insertions(+), 29 deletions(-)

diff --git a/ide/editor/src/org/netbeans/modules/editor/resources/completion/record.png b/ide/editor/src/org/netbeans/modules/editor/resources/completion/record.png
new file mode 100644
index 0000000..220e6f3
Binary files /dev/null and b/ide/editor/src/org/netbeans/modules/editor/resources/completion/record.png differ
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 b6bbb7f..ef40212 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
@@ -199,7 +199,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
     private static final String WHILE_KEYWORD = "while"; //NOI18N
     private static final String WITH_KEYWORD = "with"; //NOI18N
     private static final String YIELD_KEYWORD = "yield"; //NOI18N
-    
+    private static final String RECORD_KEYWORD = "record"; //NOI18N
     private static final String JAVA_LANG_CLASS = "java.lang.Class"; //NOI18N
     private static final String JAVA_LANG_OBJECT = "java.lang.Object"; //NOI18N
     private static final String JAVA_LANG_ITERABLE = "java.lang.Iterable"; //NOI18N
@@ -237,9 +237,9 @@ public final class JavaCompletionTask<T> extends BaseTask {
     private static final SourceVersion SOURCE_VERSION_RELEASE_10;
     private static final SourceVersion SOURCE_VERSION_RELEASE_11;
     private static final SourceVersion SOURCE_VERSION_RELEASE_13;
-
+    private static final SourceVersion SOURCE_VERSION_RELEASE_14;
     static {
-        SourceVersion r10, r11, r13;
+        SourceVersion r10, r11, r13, r14;
 
         try {
             r10 = SourceVersion.valueOf("RELEASE_10");
@@ -256,10 +256,16 @@ public final class JavaCompletionTask<T> extends BaseTask {
         } catch (IllegalArgumentException ex) {
             r13 = null;
         }
+         try {
+            r14 = SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException ex) {
+            r14 = null;
+        }
 
         SOURCE_VERSION_RELEASE_10 = r10;
         SOURCE_VERSION_RELEASE_11 = r11;
         SOURCE_VERSION_RELEASE_13 = r13;
+        SOURCE_VERSION_RELEASE_14 = r14;
     }
 
     private final ItemFactory<T> itemFactory;
@@ -502,6 +508,8 @@ public final class JavaCompletionTask<T> extends BaseTask {
             default:
                 if (path.getLeaf().getKind().toString().equals(TreeShims.SWITCH_EXPRESSION)) {
                     insideSwitch(env);
+                } else if (TreeShims.isRecord(path.getLeaf())) {
+                    insideRecord(env);
                 }
                 break;
         }
@@ -726,7 +734,11 @@ public final class JavaCompletionTask<T> extends BaseTask {
             addPackages(env, null, false);
         }
         if (options.contains(Options.ALL_COMPLETION)) {
-            addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE), null);
+            EnumSet<ElementKind> classKinds = EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE);
+            if (isRecordSupported(env)) {
+                classKinds.add(TreeShims.getRecordKind());
+            }
+            addTypes(env, classKinds, null);
         } else {
             hasAdditionalClasses = true;
         }
@@ -748,7 +760,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
         int idx = headerText.indexOf('{'); //NOI18N
         if (idx >= 0) {
             addKeywordsForClassBody(env);
-            addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+            addClassTypes(env, null);
             addElementCreators(env);
             return;
         }
@@ -866,7 +878,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
             addClassModifiers(env, cls.getModifiers().getFlags());
         } else {
             addMemberModifiers(env, cls.getModifiers().getFlags(), false);
-            addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+            addClassTypes(env, null);
         }
     }
 
@@ -919,7 +931,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                 }
                 boolean isLocal = !TreeUtilities.CLASS_TREE_KINDS.contains(parent.getKind());
                 addMemberModifiers(env, var.getModifiers().getFlags(), isLocal);
-                addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+                addClassTypes(env, null);
                 ModifiersTree mods = var.getModifiers();
                 if (mods.getFlags().isEmpty() && mods.getAnnotations().isEmpty()) {
                     addElementCreators(env);
@@ -1023,7 +1035,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
             switch (lastToken.token().id()) {
                 case LPAREN:
                     addMemberModifiers(env, Collections.<Modifier>emptySet(), true);
-                    addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+                    addClassTypes(env, null);
                     break;
                 case RPAREN:
                     Tree mthParent = path.getParentPath().getLeaf();
@@ -1062,13 +1074,13 @@ public final class JavaCompletionTask<T> extends BaseTask {
                 case GTGTGT:
                     addPrimitiveTypeKeywords(env);
                     addKeyword(env, VOID_KEYWORD, SPACE, false);
-                    addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+                    addClassTypes(env, null);
                     break;
                 case COMMA:
                     switch (state) {
                         case 3:
                             addMemberModifiers(env, Collections.<Modifier>emptySet(), true);
-                            addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+                            addClassTypes(env, null);
                             break;
                         case 4:
                             if (!options.contains(Options.ALL_COMPLETION) && mth.getBody() != null) {
@@ -1110,7 +1122,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
         switch (state) {
             case 0:
                 addMemberModifiers(env, mth.getModifiers().getFlags(), false);
-                addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+                addClassTypes(env, null);
                 break;
             case 1:
                 if (((TypeParameterTree) lastTree).getBounds().isEmpty()) {
@@ -1183,10 +1195,10 @@ public final class JavaCompletionTask<T> extends BaseTask {
             addClassModifiers(env, m);
         } else if (parent.getKind() != Tree.Kind.VARIABLE || grandParent == null || TreeUtilities.CLASS_TREE_KINDS.contains(grandParent.getKind())) {
             addMemberModifiers(env, m, false);
-            addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+            addClassTypes(env, null);
         } else if (parent.getKind() == Tree.Kind.VARIABLE && grandParent.getKind() == Tree.Kind.METHOD) {
             addMemberModifiers(env, m, true);
-            addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+            addClassTypes(env, null);
         } else {
             localResult(env);
             addKeywordsForBlock(env);
@@ -1296,7 +1308,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
         if (pos >= 0 && pos < offset) {
             insideExpression(env, new TreePath(env.getPath(), att.getUnderlyingType()));
         } else {
-            addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+            addClassTypes(env, null);
         }
     }
 
@@ -1452,7 +1464,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                             }
                         }
                     }
-                    addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+                    addClassTypes(env, null);
                     break;
                 case QUESTION:
                     addKeyword(env, EXTENDS_KEYWORD, SPACE, false);
@@ -1471,7 +1483,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
         String text = env.getController().getText().substring(blockPos, offset);
         if (text.indexOf('{') < 0) { //NOI18N
             addMemberModifiers(env, Collections.singleton(STATIC), false);
-            addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+            addClassTypes(env, null);
             return;
         }
         StatementTree last = null;
@@ -1592,9 +1604,11 @@ public final class JavaCompletionTask<T> extends BaseTask {
                     break;
                 case LT:
                 case COMMA:
+                    addClassTypes(env, null);
+                    break;
                 case EXTENDS:
                 case SUPER:
-                    addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+                    addClassTypes(env, null);
                     break;
             }
         } else if (lastNonWhitespaceTokenId != JavaTokenId.STAR) {
@@ -1922,7 +1936,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                     break;
                 case LT:
                 case COMMA:
-                    addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+                    addClassTypes(env, null);
                     break;
             }
         }
@@ -1941,7 +1955,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                 case COMMA:
                     if (let.getParameters().isEmpty()
                             || env.getController().getTrees().getSourcePositions().getStartPosition(path.getCompilationUnit(), let.getParameters().get(0).getType()) >= 0) {
-                        addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+                        addClassTypes(env, null);
                         addPrimitiveTypeKeywords(env);
                         addKeyword(env, FINAL_KEYWORD, SPACE, false);
                     }
@@ -1984,7 +1998,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
         }
         addLocalMembersAndVars(env);
         addValueKeywords(env);
-        addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+        addClassTypes(env,null);
         addPrimitiveTypeKeywords(env);
     }
 
@@ -2057,7 +2071,11 @@ public final class JavaCompletionTask<T> extends BaseTask {
                         env.insideNew();
                     }
                     if (encl == null) {
-                        addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE), base);
+                        EnumSet<ElementKind> classKinds = EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE);
+                        if (isRecordSupported(env)) {
+                            classKinds.add(TreeShims.getRecordKind());
+                        }
+                        addTypes(env, classKinds, base);
                     } else {
                         TypeMirror enclType = controller.getTrees().getTypeMirror(new TreePath(path, nc.getEnclosingExpression()));
                         if (enclType != null && enclType.getKind() == TypeKind.DECLARED) {
@@ -2074,7 +2092,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                     }
                     addLocalMembersAndVars(env);
                     addValueKeywords(env);
-                    addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+                    addClassTypes(env,null);
                     addPrimitiveTypeKeywords(env);
                     break;
                 case GT:
@@ -2241,7 +2259,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
             TokenSequence<JavaTokenId> last = findLastNonWhitespaceToken(env, fl, offset);
             if (last != null && last.token().id() == JavaTokenId.LPAREN) {
                 addLocalFieldsAndVars(env);
-                addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+                addClassTypes(env,null);
                 addPrimitiveTypeKeywords(env);
             }
         } else {
@@ -2471,7 +2489,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                 }
             }
             addLocalMembersAndVars(env);
-            addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+            addClassTypes(env,null);
             addPrimitiveTypeKeywords(env);
             addValueKeywords(env);
         } else {
@@ -2483,7 +2501,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
         InstanceOfTree iot = (InstanceOfTree) env.getPath().getLeaf();
         TokenSequence<JavaTokenId> ts = findLastNonWhitespaceToken(env, iot, env.getOffset());
         if (ts != null && ts.token().id() == JavaTokenId.INSTANCEOF) {
-            addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+            addClassTypes(env, null);
         }
     }
 
@@ -3008,10 +3026,193 @@ public final class JavaCompletionTask<T> extends BaseTask {
             }
         }
     }
+    
+    private void addClassTypes(final Env env, DeclaredType baseType) throws IOException{
+        EnumSet<ElementKind> classKinds = EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER);
+        if (isRecordSupported(env)) {
+            classKinds.add(TreeShims.getRecordKind());
+        }
+        addTypes(env, classKinds, baseType);
+    }
+
+    private boolean isRecordSupported(final Env env) {
+        return (SOURCE_VERSION_RELEASE_14 != null && env.getController().getSourceVersion().compareTo(SOURCE_VERSION_RELEASE_14) >= 0);
+    }
+
+    private void insideRecord(Env env) throws IOException {
+        int offset = env.getOffset();
+        env.insideClass();
+        TreePath path = env.getPath();
+        ClassTree cls = (ClassTree) path.getLeaf();
+        CompilationController controller = env.getController();
+        SourcePositions sourcePositions = env.getSourcePositions();
+        CompilationUnitTree root = env.getRoot();
+        int startPos = (int) sourcePositions.getEndPosition(root, cls.getModifiers());
+        if (startPos <= 0) {
+            startPos = (int) sourcePositions.getStartPosition(root, cls);
+        }
+        String headerText = controller.getText().substring(startPos, offset);
+        int idx = headerText.indexOf('{'); //NOI18N
+        if (idx >= 0) {
+            addKeywordsForClassBody(env);
+            addClassTypes(env, null);
+            addElementCreators(env);
+            return;
+        }
+        TreeUtilities tu = controller.getTreeUtilities();
+        Tree lastImpl = null;
+        for (Tree impl : cls.getImplementsClause()) {
+            int implPos = (int) sourcePositions.getEndPosition(root, impl);
+            if (implPos == Diagnostic.NOPOS || offset <= implPos) {
+                break;
+            }
+            lastImpl = impl;
+            startPos = implPos;
+        }
+        if (lastImpl != null) {
+            TokenSequence<JavaTokenId> last = findLastNonWhitespaceToken(env, startPos, offset);
+            if (last != null && last.token().id() == JavaTokenId.COMMA) {
+                controller.toPhase(Phase.ELEMENTS_RESOLVED);
+                env.addToExcludes(controller.getTrees().getElement(path));
+                addTypes(env, EnumSet.of(INTERFACE, ANNOTATION_TYPE), null);
+            }
+            return;
+        }
+        List<? extends Tree> members = cls.getMembers();
+
+        Tree lastParam = null;
+        for (Tree member : members) {
+            if (member.getKind() == Tree.Kind.VARIABLE) {
+                ModifiersTree modifiers = ((VariableTree) member).getModifiers();
+                Set<Modifier> modifierSet = modifiers.getFlags();
+
+                if (!modifierSet.contains(Modifier.STATIC)) {
+                    int paramPos = (int) sourcePositions.getEndPosition(root, member);
+                    if (paramPos == Diagnostic.NOPOS || offset <= paramPos) {
+                        break;
+                    }
+                    lastParam = member;
+                    startPos = paramPos;
+                }
+            }
+
+            if (lastParam != null) {
+                TokenSequence<JavaTokenId> first = findFirstNonWhitespaceToken(env, startPos, offset);
+                if (first != null && first.token().id() == JavaTokenId.COMMA) {
+                    controller.toPhase(Phase.ELEMENTS_RESOLVED);
+                    env.addToExcludes(controller.getTrees().getElement(path));
+                    addTypes(env, EnumSet.of(INTERFACE, ANNOTATION_TYPE), null);
+                    return;
+                }
+                if (first != null && first.token().id() == JavaTokenId.RPAREN) {
+                    first = nextNonWhitespaceToken(first);
+                    if (!tu.isInterface(cls) && first.token().id() == JavaTokenId.LBRACE) {
+                        addKeyword(env, IMPLEMENTS_KEYWORD, SPACE, false);
+                    }
+
+                }
+                return;
+            }
+
+        }
+
+        TypeParameterTree lastTypeParam = null;
+        for (TypeParameterTree tp : cls.getTypeParameters()) {
+            int tpPos = (int) sourcePositions.getEndPosition(root, tp);
+            if (tpPos == Diagnostic.NOPOS || offset <= tpPos) {
+                break;
+            }
+            lastTypeParam = tp;
+            startPos = tpPos;
+        }
+
+        TokenSequence<JavaTokenId> lastNonWhitespaceToken = findLastNonWhitespaceToken(env, startPos, offset);
+        if (lastNonWhitespaceToken != null) {
+            switch (lastNonWhitespaceToken.token().id()) {
+                case LPAREN:
+                    addMemberModifiers(env, Collections.<Modifier>emptySet(), true);
+                    addClassTypes(env, null);
+                    break;
+                case IMPLEMENTS:
+                    controller.toPhase(Phase.ELEMENTS_RESOLVED);
+                    env.addToExcludes(controller.getTrees().getElement(path));
+                    addTypes(env, EnumSet.of(INTERFACE, ANNOTATION_TYPE), null);
+                    break;
+                case RPAREN:
+                    if (!tu.isAnnotation(cls)) {
+                        if (!tu.isInterface(cls)) {
+                            addKeyword(env, IMPLEMENTS_KEYWORD, SPACE, false);
+                        }
+                    }
+                    break;
+            }
+            return;
+        }
+
+        if (lastTypeParam != null) {
+            TokenSequence<JavaTokenId> first = findFirstNonWhitespaceToken(env, startPos, offset);
+
+            if (first != null && (first.token().id() == JavaTokenId.GT
+                    || first.token().id() == JavaTokenId.GTGT
+                    || first.token().id() == JavaTokenId.GTGTGT)) {
+                first = nextNonWhitespaceToken(first);
+
+                TokenSequence<JavaTokenId> last = findLastNonWhitespaceToken(env, first.offset(), offset);
+                TokenSequence<JavaTokenId> old = first;
+                first = nextNonWhitespaceToken(first);
+                if (last != null && first.token().id() == last.token().id()) {
+                    first = nextNonWhitespaceToken(first);
+                } else {
+                    first = old;
+                }
+
+                if (first != null && first.offset() < offset) {
+                    if (first.token().id() == JavaTokenId.EXTENDS) {
+                        controller.toPhase(Phase.ELEMENTS_RESOLVED);
+                        env.afterExtends();
+                        env.addToExcludes(controller.getTrees().getElement(path));
+                        addTypes(env, tu.isInterface(cls) ? EnumSet.of(INTERFACE, ANNOTATION_TYPE) : EnumSet.of(CLASS), null);
+                        return;
+                    }
+                    if (first.token().id() == JavaTokenId.IMPLEMENTS) {
+                        controller.toPhase(Phase.ELEMENTS_RESOLVED);
+                        env.addToExcludes(controller.getTrees().getElement(path));
+                        addTypes(env, EnumSet.of(INTERFACE, ANNOTATION_TYPE), null);
+                        return;
+                    }
+                } else if (!tu.isAnnotation(cls)) {
+
+                    if (!tu.isInterface(cls) && first.token().id() == JavaTokenId.LBRACE) {
+                        addKeyword(env, IMPLEMENTS_KEYWORD, SPACE, false);
+                    } else if (!tu.isInterface(cls) && first.token().id() == JavaTokenId.RPAREN) {
+                        controller.toPhase(Phase.ELEMENTS_RESOLVED);
+                        env.addToExcludes(controller.getTrees().getElement(path));
+                        addTypes(env, EnumSet.of(INTERFACE, ANNOTATION_TYPE), null);
+                    }
+                    return;
+                }
+            } else if (lastTypeParam.getBounds().isEmpty()) {
+                addKeyword(env, EXTENDS_KEYWORD, SPACE, false);
+            }
+            return;
+        }
+
+        lastNonWhitespaceToken = findLastNonWhitespaceToken(env, (int) sourcePositions.getStartPosition(root, cls), offset);
+        if (lastNonWhitespaceToken != null && lastNonWhitespaceToken.token().id() == JavaTokenId.AT) {
+            addKeyword(env, INTERFACE_KEYWORD, SPACE, false);
+            addTypes(env, EnumSet.of(ANNOTATION_TYPE), null);
+        } else if (path.getParentPath().getLeaf().getKind() == Tree.Kind.COMPILATION_UNIT) {
+            addClassModifiers(env, cls.getModifiers().getFlags());
+        } else {
+            addMemberModifiers(env, cls.getModifiers().getFlags(), false);
+            addClassTypes(env, null);
+        }
+
+    }
 
     private void localResult(Env env) throws IOException {
         addLocalMembersAndVars(env);
-        addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+        addClassTypes(env, null);
         addPrimitiveTypeKeywords(env);
     }
 
@@ -3092,7 +3293,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                     break;
             }
         }
-        addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+        addClassTypes(env, null);
     }
 
     private void addLocalMembersAndVars(final Env env) throws IOException {
@@ -3793,6 +3994,9 @@ public final class JavaCompletionTask<T> extends BaseTask {
     }
 
     private void addPackageContent(final Env env, PackageElement pe, EnumSet<ElementKind> kinds, DeclaredType baseType, boolean insideNew, boolean srcOnly) throws IOException {
+        if (isRecordSupported(env)) {
+            kinds.add(TreeShims.getRecordKind());
+        }
         Set<? extends TypeMirror> smartTypes = options.contains(Options.ALL_COMPLETION) ? null : getSmartTypes(env);
         CompilationController controller = env.getController();
         Elements elements = controller.getElements();
@@ -4306,6 +4510,9 @@ public final class JavaCompletionTask<T> extends BaseTask {
             kws.add(ENUM_KEYWORD);
             kws.add(FINAL_KEYWORD);
             kws.add(INTERFACE_KEYWORD);
+            if (isRecordSupported(env)) {
+                kws.add(RECORD_KEYWORD);
+            }
         }
         boolean beforeAnyClass = true;
         boolean beforePublicClass = true;
@@ -4374,6 +4581,9 @@ public final class JavaCompletionTask<T> extends BaseTask {
                 && env.getController().getTreeUtilities().getPathElementOfKind(Tree.Kind.INTERFACE, env.getPath()) != null) {
             results.add(itemFactory.createKeywordItem(DEFAULT_KEYWORD, SPACE, anchorOffset, false));
         }
+        if (isRecordSupported(env)) {
+            results.add(itemFactory.createKeywordItem(RECORD_KEYWORD, SPACE, anchorOffset, false));
+        }
         addPrimitiveTypeKeywords(env);
     }
 
@@ -4389,6 +4599,9 @@ public final class JavaCompletionTask<T> extends BaseTask {
                 results.add(itemFactory.createKeywordItem(kw, SPACE, anchorOffset, false));
             }
         }
+        if (isRecordSupported(env)) {
+            results.add(itemFactory.createKeywordItem(RECORD_KEYWORD, SPACE, anchorOffset, false));
+        }
         if (Utilities.startsWith(RETURN_KEYWORD, prefix)) {
             TreePath tp = env.getController().getTreeUtilities().getPathElementOfKind(EnumSet.of(Tree.Kind.METHOD, Tree.Kind.LAMBDA_EXPRESSION), env.getPath());
             String postfix = SPACE;
@@ -4573,6 +4786,9 @@ public final class JavaCompletionTask<T> extends BaseTask {
         kws.add(CLASS_KEYWORD);
         kws.add(INTERFACE_KEYWORD);
         kws.add(ENUM_KEYWORD);
+        if (isRecordSupported(env)) {
+            kws.add(RECORD_KEYWORD);
+        }
         for (String kw : kws) {
             if (Utilities.startsWith(kw, prefix)) {
                 results.add(itemFactory.createKeywordItem(kw, SPACE, anchorOffset, false));
@@ -4627,6 +4843,9 @@ public final class JavaCompletionTask<T> extends BaseTask {
             kws.add(CLASS_KEYWORD);
             kws.add(INTERFACE_KEYWORD);
             kws.add(ENUM_KEYWORD);
+            if (isRecordSupported(env)) {
+                kws.add(RECORD_KEYWORD);
+            }
         }
         for (String kw : kws) {
             if (Utilities.startsWith(kw, prefix)) {
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/override.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/override.pass
new file mode 100644
index 0000000..be68102
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/override.pass
@@ -0,0 +1 @@
+Override
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/record.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/record.pass
new file mode 100644
index 0000000..d4141f0
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/record.pass
@@ -0,0 +1 @@
+record
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/typesRecordLocalMembersAndVars.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/typesRecordLocalMembersAndVars.pass
new file mode 100644
index 0000000..7bc4924
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/typesRecordLocalMembersAndVars.pass
@@ -0,0 +1,8 @@
+R
+R1
+Readable
+ReflectiveOperationException
+Runnable
+Runtime
+RuntimeException
+RuntimePermission
\ No newline at end of file
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/typesRecordStaticMembersAndVars.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/typesRecordStaticMembersAndVars.pass
new file mode 100644
index 0000000..7bc4924
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/typesRecordStaticMembersAndVars.pass
@@ -0,0 +1,8 @@
+R
+R1
+Readable
+ReflectiveOperationException
+Runnable
+Runtime
+RuntimeException
+RuntimePermission
\ No newline at end of file
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/14/typesRecordLocalMembersAndVars.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/14/typesRecordLocalMembersAndVars.pass
new file mode 100644
index 0000000..6acc0ac
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/14/typesRecordLocalMembersAndVars.pass
@@ -0,0 +1,7 @@
+Readable
+Record
+ReflectiveOperationException
+Runnable
+Runtime
+RuntimeException
+RuntimePermission
\ No newline at end of file
diff --git a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/14/typesRecordStaticMembersAndVars.pass b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/14/typesRecordStaticMembersAndVars.pass
new file mode 100644
index 0000000..6acc0ac
--- /dev/null
+++ b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/14/typesRecordStaticMembersAndVars.pass
@@ -0,0 +1,7 @@
+Readable
+Record
+ReflectiveOperationException
+Runnable
+Runtime
+RuntimeException
+RuntimePermission
\ No newline at end of file
diff --git a/java/java.completion/test/unit/data/org/netbeans/modules/java/completion/data/Records.java b/java/java.completion/test/unit/data/org/netbeans/modules/java/completion/data/Records.java
new file mode 100644
index 0000000..e1cb7ae
--- /dev/null
+++ b/java/java.completion/test/unit/data/org/netbeans/modules/java/completion/data/Records.java
@@ -0,0 +1,34 @@
+/*
+ * 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 test; 
+
+public class Test {
+
+ public record Records <R extends Number, R1 > ( )  {
+
+    public static 
+}
+    
+    public static void main(String args )
+    {
+        record Record1(@Ov )  {}
+        
+        record Rec( )  {}        
+    }
+    }
diff --git a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask114FeaturesTest.java b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask114FeaturesTest.java
index 1f4b212..4cdfe27 100644
--- a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask114FeaturesTest.java
+++ b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask114FeaturesTest.java
@@ -48,7 +48,36 @@ public class JavaCompletionTask114FeaturesTest extends CompletionTestBase {
     public void testBindingUse() throws Exception {
         performTest("GenericMethodInvocation", 1231, "boolean b = argO instanceof String str && st", "BindingUse.pass", SOURCE_LEVEL);
     }
+    
 
+    public void testBeforeLeftRecordBraces() throws Exception {
+        performTest("Records", 896, null, "implementsKeyword.pass", SOURCE_LEVEL);
+    }
+        
+        public void testBeforeRecParamsLeftParen() throws Exception {
+        performTest("Records", 892, null, "empty.pass", SOURCE_LEVEL);
+    }
+
+    public void testInsideRecParams() throws Exception {
+        performTest("Records", 894, "R", "typesRecordLocalMembersAndVars.pass", SOURCE_LEVEL);
+    }
+    
+    public void testAfterTypeParamInRecParam() throws Exception {
+        performTest("Records", 890, null, "extendsKeyword.pass", SOURCE_LEVEL);
+    }
+    
+    public void testInsideRecAfterStaticKeyWord() throws Exception {
+        performTest("Records", 918, "R", "typesRecordStaticMembersAndVars.pass", SOURCE_LEVEL);
+    }
+    
+    public void testAnnotationInRecordParam() throws Exception {
+        performTest("Records", 999, null, "override.pass", SOURCE_LEVEL);
+    } 
+    
+    public void testRecordKeywordInsideClass() throws Exception {
+        performTest("Records", 1014, "rec", "record.pass", SOURCE_LEVEL);
+    } 
+    
     public void noop() {
     }
 
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 39c1387..181e5e0 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
@@ -120,7 +120,9 @@ public abstract class JavaCompletionItem implements CompletionItem {
             case ANNOTATION_TYPE:
                 return new AnnotationTypeItem(info, elem, type, 0, substitutionOffset, referencesCount, isDeprecated, insideNew, addSimpleName, smartType, autoImportEnclosingType, whiteList);
             default:
-                throw new IllegalArgumentException("kind=" + elem.getKind());
+                if(elem.getKind().name().equals(TreeShims.RECORD))
+                    return new RecordItem(info, elem, type, 0, substitutionOffset, referencesCount, isDeprecated, insideNew, addSimpleName, smartType, autoImportEnclosingType, whiteList);
+                else throw new IllegalArgumentException("kind=" + elem.getKind());
         }
     }
 
@@ -1313,7 +1315,25 @@ public abstract class JavaCompletionItem implements CompletionItem {
             return icon;
         }
     }
+    
+    static class RecordItem extends ClassItem {
+
+        private static final String RECORD = "org/netbeans/modules/editor/resources/completion/record.png"; // NOI18N
+        private static ImageIcon icon;
 
+        private RecordItem(CompilationInfo info, TypeElement elem, DeclaredType type, int dim, int substitutionOffset, ReferencesCount referencesCount, boolean isDeprecated, boolean insideNew, boolean addSimpleName, boolean smartType, boolean autoImport, WhiteListQuery.WhiteList whiteList) {
+            super(info, elem, type, dim, substitutionOffset, referencesCount, isDeprecated, insideNew, false, addSimpleName, smartType, autoImport, whiteList);
+        }
+
+        @Override
+        protected ImageIcon getBaseIcon() {
+            if (icon == null) {
+                icon = ImageUtilities.loadImageIcon(RECORD, false);
+            }
+            return icon;
+        }
+    }
+    
     static class AnnotationTypeItem extends ClassItem {
 
         private static final String ANNOTATION = "org/netbeans/modules/editor/resources/completion/annotation_type.png"; // NOI18N
diff --git a/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java b/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
index 5e7b042..88504aa 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
@@ -228,4 +228,13 @@ public class TreeShims {
     public static boolean isRecordComponent(ElementKind kind) {
         return "RECORD_COMPONENT".equals(kind.name());
     }
+
+    public static ElementKind getRecordKind() {
+        try {
+            return ElementKind.valueOf(RECORD); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            return null;
+        }
+    }
+
 }
diff --git a/java/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/WhereUsedPanel.java b/java/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/WhereUsedPanel.java
index 2540b8e..583ac8d 100644
--- a/java/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/WhereUsedPanel.java
+++ b/java/refactoring.java/src/org/netbeans/modules/refactoring/java/ui/WhereUsedPanel.java
@@ -86,7 +86,10 @@ public class WhereUsedPanel extends JPanel implements CustomRefactoringPanel {
             case FIELD:
             case ENUM_CONSTANT:
             default: {
-                panel = new WhereUsedPanelVariable(parent);
+                if (kind.name().equals("RECORD"))   // NOI18N
+                     panel = new WhereUsedPanelClass(parent);
+                else
+                    panel = new WhereUsedPanelVariable(parent);
                 break;
             }
         }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists