You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by jl...@apache.org on 2017/10/22 19:36:41 UTC

[incubator-netbeans] 01/01: A very crude prototype of editor for Java patterns.

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

jlahoda pushed a commit to branch jdk/amber/patterns
in repository https://gitbox.apache.org/repos/asf/incubator-netbeans.git

commit b062776b10e3cdad37c5eea2d8d87c757d8092d8
Author: Jan Lahoda <jl...@netbeans.org>
AuthorDate: Sun Oct 22 21:35:46 2017 +0200

    A very crude prototype of editor for Java patterns.
---
 .../java/completion/JavaCompletionTask.java        | 143 +++++++++++++++++++--
 .../modules/java/completion/Utilities.java         |  20 +--
 .../1.8/testBoundPatternVariable1.pass             |   1 +
 .../1.8/testBoundPatternVariable2.pass             |   1 +
 .../JavaCompletionTaskTest/1.8/testMatches1.pass   |   2 +
 .../1.8/testVariablePattern1.pass                  |   2 +
 .../1.8/testVariablePattern2.pass                  |   1 +
 .../1.8/testVariablePattern3.pass                  |   4 +
 .../1.8/testVariablePattern4.pass                  |   2 +
 .../1.8/testVariablePattern5.pass                  |   1 +
 .../1.8/testVariablePatternInSwitch1.pass          | 104 +++++++++++++++
 .../1.8/testVariablePatternInSwitch2.pass          |   2 +
 .../JavaCompletionTaskTest/10/javaLangTypes.pass   | 110 ++++++++++++++++
 .../modules/java/completion/data/Patterns.java     |  14 ++
 .../JavaCompletionTaskAmberPatternsTest.java       | 104 +++++++++++++++
 java.editor.base/nbproject/project.xml             |   4 +
 .../editor/base/semantic/FindLocalUsagesQuery.java |  11 +-
 .../base/semantic/SemanticHighlighterBase.java     |  62 ++++++++-
 .../java/editor/base/semantic/Utilities.java       |  11 ++
 .../base/semantic/DetectorTest/testPatterns.pass   |  14 ++
 .../base/semantic/MarkOccDetTest/testPatterns.pass |   2 +
 .../java/editor/base/semantic/data/Patterns.java   |  13 ++
 .../java/editor/base/semantic/DetectorTest.java    |   4 +
 .../java/editor/base/semantic/MarkOccDetTest.java  |   4 +
 .../netbeans/modules/editor/java/GoToSupport.java  |  14 +-
 .../java/editor/codegen/LoggerGenerator.java       |   2 +-
 .../modules/editor/java/GoToSupportTest.java       |  25 ++++
 .../java/navigation/BreadCrumbsNodeImplTest.java   |  10 +-
 .../netbeans/api/java/source/TreeUtilities.java    |  28 ++++
 .../modules/java/source/builder/TreeFactory.java   |  16 +++
 .../modules/java/hints/spiimpl/JackpotTrees.java   |   1 +
 .../modules/java/hints/spiimpl/Utilities.java      |  11 +-
 32 files changed, 719 insertions(+), 24 deletions(-)

diff --git a/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java b/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
index 234e0b3..564603b 100644
--- a/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
+++ b/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
@@ -163,6 +163,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
     private static final String INT_KEYWORD = "int"; //NOI18N
     private static final String INTERFACE_KEYWORD = "interface"; //NOI18N
     private static final String LONG_KEYWORD = "long"; //NOI18N
+    private static final String MATCHES_KEYWORD = "__matches"; //NOI18N
     private static final String MODULE_KEYWORD = "module"; //NOI18N
     private static final String NATIVE_KEYWORD = "native"; //NOI18N
     private static final String NEW_KEYWORD = "new"; //NOI18N
@@ -467,6 +468,15 @@ public final class JavaCompletionTask<T> extends BaseTask {
             case STRING_LITERAL:
                 insideStringLiteral(env);
                 break;
+            default:
+                switch (path.getLeaf().getKind().name()) {
+                    case "VARIABLE_PATTERN":
+                        insideVariablePattern(env);
+                        break;
+                    case "MATCHES":
+                        insideMatches(env);
+                        break;
+                }
         }
     }
 
@@ -909,6 +919,82 @@ public final class JavaCompletionTask<T> extends BaseTask {
         }
     }
 
+    private void insideVariablePattern(Env env) throws IOException {
+        int offset = env.getOffset();
+        TreePath path = env.getPath();
+        VariableTree var = (VariableTree) path.getLeaf();
+        SourcePositions sourcePositions = env.getSourcePositions();
+        CompilationUnitTree root = env.getRoot();
+        CompilationController controller = env.getController();
+        Tree type = var.getType();
+        int typePos = type.getKind() == Tree.Kind.ERRONEOUS && ((ErroneousTree) type).getErrorTrees().isEmpty()
+                ? (int) sourcePositions.getEndPosition(root, type) : (int) sourcePositions.getStartPosition(root, type);
+        if (offset <= typePos) {
+            Tree parent = path.getParentPath().getLeaf();
+            if (parent.getKind() == Tree.Kind.CATCH) {
+                if (!options.contains(Options.ALL_COMPLETION)) {
+                    TreeUtilities tu = controller.getTreeUtilities();
+                    TreePath tryPath = tu.getPathElementOfKind(Tree.Kind.TRY, path);
+                    Set<TypeMirror> exs = tu.getUncaughtExceptions(tryPath);
+                    Elements elements = controller.getElements();
+                    for (TypeMirror ex : exs) {
+                        if (ex.getKind() == TypeKind.DECLARED && startsWith(env, ((DeclaredType) ex).asElement().getSimpleName().toString())
+                                && (Utilities.isShowDeprecatedMembers() || !elements.isDeprecated(((DeclaredType) ex).asElement()))
+                                && !Utilities.isExcluded(((TypeElement)((DeclaredType) ex).asElement()).getQualifiedName())) {
+                            env.addToExcludes(((DeclaredType) ex).asElement());
+                            results.add(itemFactory.createTypeItem(controller, (TypeElement) ((DeclaredType) ex).asElement(), (DeclaredType) ex, anchorOffset, env.getReferencesCount(), elements.isDeprecated(((DeclaredType) ex).asElement()), false, false, false, true, false));
+                        }
+                    }
+                }
+                TypeElement te = controller.getElements().getTypeElement("java.lang.Throwable"); //NOI18N
+                if (te != null) {
+                    addTypes(env, EnumSet.of(CLASS, INTERFACE, TYPE_PARAMETER), controller.getTypes().getDeclaredType(te));
+                }
+            } else if (parent.getKind() == Tree.Kind.TRY) {
+                TypeElement te = controller.getElements().getTypeElement("java.lang.AutoCloseable"); //NOI18N
+                if (te != null) {
+                    addTypes(env, EnumSet.of(CLASS, INTERFACE, TYPE_PARAMETER), controller.getTypes().getDeclaredType(te));
+                }
+            } else {
+                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);
+                ModifiersTree mods = var.getModifiers();
+                if (mods.getFlags().isEmpty() && mods.getAnnotations().isEmpty()) {
+                    addElementCreators(env);
+                }
+            }
+            return;
+        }
+        controller.toPhase(Phase.RESOLVED);
+        Tree init = unwrapErrTree(var.getInitializer());
+        if (init == null) {
+            TokenSequence<JavaTokenId> last = findLastNonWhitespaceToken(env, (int) sourcePositions.getEndPosition(root, type), offset);
+            if (last == null || last.token().id() == JavaTokenId.COMMA) {
+                insideExpression(env, new TreePath(path, type));
+            } else if (last.token().id() == JavaTokenId.EQ) {
+                localResult(env);
+                addValueKeywords(env);
+            }
+        } else {
+            int pos = (int) sourcePositions.getStartPosition(root, init);
+            if (pos < 0) {
+                return;
+            }
+            if (offset <= pos) {
+                TokenSequence<JavaTokenId> last = findLastNonWhitespaceToken(env, (int) sourcePositions.getEndPosition(root, type), offset);
+                if (last == null) {
+                    insideExpression(env, new TreePath(path, type));
+                } else if (last.token().id() == JavaTokenId.EQ) {
+                    localResult(env);
+                    addValueKeywords(env);
+                }
+            } else {
+                insideExpression(env, new TreePath(path, init));
+            }
+        }
+    }
+
     private void insideMethod(Env env) throws IOException {
         int offset = env.getOffset();
         TreePath path = env.getPath();
@@ -2292,7 +2378,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
         CaseTree cst = (CaseTree) path.getLeaf();
         SourcePositions sourcePositions = env.getSourcePositions();
         CompilationUnitTree root = env.getRoot();
-        CompilationController controller = env.getController();
+        final CompilationController controller = env.getController();
         if (cst.getExpression() != null && ((sourcePositions.getStartPosition(root, cst.getExpression()) >= offset)
                 || (cst.getExpression().getKind() == Tree.Kind.ERRONEOUS && ((ErroneousTree) cst.getExpression()).getErrorTrees().isEmpty() && sourcePositions.getEndPosition(root, cst.getExpression()) >= offset))) {
             TreePath path1 = path.getParentPath();
@@ -2307,8 +2393,27 @@ public final class JavaCompletionTask<T> extends BaseTask {
         } else {
             TokenSequence<JavaTokenId> ts = findLastNonWhitespaceToken(env, cst, offset);
             if (ts != null && ts.token().id() != JavaTokenId.DEFAULT) {
-                localResult(env);
-                addKeywordsForBlock(env);
+                int exprEnd = (int) sourcePositions.getEndPosition(root, cst.getExpression());
+                if (ts.offset() + ts.token().length() == exprEnd) {
+                    TypeMirror tm = controller.getTrees().getTypeMirror(new TreePath(env.getPath(), cst.getExpression()));
+                    final Map<Name, ? extends Element> illegalForwardRefs = env.getForwardReferences();
+                    Scope scope = env.getScope();
+                    final ExecutableElement method = scope.getEnclosingMethod();
+                    ElementUtilities.ElementAcceptor acceptor = new ElementUtilities.ElementAcceptor() {
+                        @Override
+                        public boolean accept(Element e, TypeMirror t) {
+                            return (method == null || method == e.getEnclosingElement() || e.getModifiers().contains(FINAL)
+                                    || EnumSet.of(LOCAL_VARIABLE, PARAMETER, EXCEPTION_PARAMETER, RESOURCE_VARIABLE).contains(e.getKind()) && controller.getSourceVersion().compareTo(SourceVersion.RELEASE_8) >= 0 && controller.getElementUtilities().isEffectivelyFinal((VariableElement)e))
+                                    && !illegalForwardRefs.containsKey(e.getSimpleName());
+                        }
+                    };
+                    for (String name : Utilities.varNamesSuggestions(tm, ElementKind.LOCAL_VARIABLE, EnumSet.noneOf(Modifier.class), null, env.getPrefix(), controller.getTypes(), controller.getElements(), controller.getTrees(), controller.getElementUtilities().getLocalMembersAndVars(scope, acceptor), CodeStyle.getDefault(controller.getDocument()))) {
+                        results.add(itemFactory.createVariableItem(env.getController(), name, anchorOffset, true, false));
+                    }
+                } else {
+                    localResult(env);
+                    addKeywordsForBlock(env);
+                }
             }
         }
     }
@@ -2369,6 +2474,14 @@ public final class JavaCompletionTask<T> extends BaseTask {
         }
     }
 
+    private void insideMatches(Env env) throws IOException {
+        Tree iot = env.getPath().getLeaf();
+        TokenSequence<JavaTokenId> ts = findLastNonWhitespaceToken(env, iot, env.getOffset());
+        if (ts != null && ts.token().id() == JavaTokenId.IDENTIFIER && MATCHES_KEYWORD.contentEquals(ts.token().text())) {
+            addTypes(env, EnumSet.of(CLASS, INTERFACE, ENUM, ANNOTATION_TYPE, TYPE_PARAMETER), null);
+        }
+    }
+
     private void insideArrayAccess(Env env) throws IOException {
         int offset = env.getOffset();
         ArrayAccessTree aat = (ArrayAccessTree) env.getPath().getLeaf();
@@ -2667,6 +2780,19 @@ public final class JavaCompletionTask<T> extends BaseTask {
             et = ((AnnotatedTypeTree) et).getUnderlyingType();
             exPath = new TreePath(exPath, et);
         }
+        if (et.getKind().name().equals("MATCHES") && endPos < offset) {
+            List<Tree> children = env.getController().getTreeUtilities().getChildren(et);
+            parent = et = children.get(1); //((MatchesTree) et).getPattern()
+            exPath = new TreePath(exPath, et);
+            switch (et.getKind().name()) {
+                case "CONSTANT_PATTERN":
+                    et = env.getController().getTreeUtilities().getChildren(et).get(0); //((ConstantPatternTree) et).getValue();
+                    break;
+                default:
+                    throw new IllegalStateException();
+            }
+            exPath = new TreePath(exPath, et);
+        }
         if (parent.getKind() != Tree.Kind.PARENTHESIZED
                 && (et.getKind() == Tree.Kind.PRIMITIVE_TYPE || et.getKind() == Tree.Kind.ARRAY_TYPE || et.getKind() == Tree.Kind.PARAMETERIZED_TYPE)) {
             TypeMirror tm = controller.getTrees().getTypeMirror(exPath);
@@ -2681,7 +2807,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                             && !illegalForwardRefs.containsKey(e.getSimpleName());
                 }
             };
-            for (String name : Utilities.varNamesSuggestions(tm, varKind, varMods, null, prefix, controller.getTypes(), controller.getElements(), controller.getElementUtilities().getLocalMembersAndVars(scope, acceptor), CodeStyle.getDefault(controller.getDocument()))) {
+            for (String name : Utilities.varNamesSuggestions(tm, varKind, varMods, null, prefix, controller.getTypes(), controller.getElements(), controller.getTrees(), controller.getElementUtilities().getLocalMembersAndVars(scope, acceptor), CodeStyle.getDefault(controller.getDocument()))) {
                 results.add(itemFactory.createVariableItem(env.getController(), name, anchorOffset, true, false));
             }
             return;
@@ -2718,7 +2844,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                             }
                         };
                         for (String name : Utilities.varNamesSuggestions(tm, varKind, varMods, null, prefix, controller.getTypes(), controller.getElements(),
-                                controller.getElementUtilities().getLocalMembersAndVars(scope, acceptor), CodeStyle.getDefault(controller.getDocument()))) {
+                                controller.getTrees(), controller.getElementUtilities().getLocalMembersAndVars(scope, acceptor), CodeStyle.getDefault(controller.getDocument()))) {
                             results.add(itemFactory.createVariableItem(env.getController(), name, anchorOffset, true, false));
                         }
                     }
@@ -2735,6 +2861,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                 case PARAMETER:
                     if (tm != null && (tm.getKind() == TypeKind.DECLARED || tm.getKind() == TypeKind.ARRAY || tm.getKind() == TypeKind.ERROR)) {
                         addKeyword(env, INSTANCEOF_KEYWORD, SPACE, false);
+                        addKeyword(env, MATCHES_KEYWORD, SPACE, false);
                     }
                     TypeElement te = getTypeElement(env, e.getSimpleName().toString());
                     if (te != null) {
@@ -2750,7 +2877,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                             }
                         };
                         for (String name : Utilities.varNamesSuggestions(controller.getTypes().getDeclaredType(te), varKind, varMods, null, prefix, controller.getTypes(),
-                                controller.getElements(), controller.getElementUtilities().getLocalMembersAndVars(scope, acceptor), CodeStyle.getDefault(controller.getDocument()))) {
+                                controller.getElements(), controller.getTrees(), controller.getElementUtilities().getLocalMembersAndVars(scope, acceptor), CodeStyle.getDefault(controller.getDocument()))) {
                             results.add(itemFactory.createVariableItem(env.getController(), name, anchorOffset, true, false));
                         }
                     }
@@ -2859,7 +2986,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                                 && !illegalForwardRefs.containsKey(e.getSimpleName());
                     }
                 };
-                for (String name : Utilities.varNamesSuggestions(tm, varKind, varMods, null, prefix, controller.getTypes(), controller.getElements(), controller.getElementUtilities().getLocalMembersAndVars(scope, acceptor), CodeStyle.getDefault(controller.getDocument()))) {
+                for (String name : Utilities.varNamesSuggestions(tm, varKind, varMods, null, prefix, controller.getTypes(), controller.getElements(), controller.getTrees(), controller.getElementUtilities().getLocalMembersAndVars(scope, acceptor), CodeStyle.getDefault(controller.getDocument()))) {
                     results.add(itemFactory.createVariableItem(env.getController(), name, anchorOffset, true, false));
                 }
                 break;
@@ -2876,7 +3003,7 @@ public final class JavaCompletionTask<T> extends BaseTask {
                 }
         }
     }
-
+    
     private void insideBreakOrContinue(Env env) throws IOException {
         TreePath path = env.getPath();
         TokenSequence<JavaTokenId> ts = findLastNonWhitespaceToken(env, path.getLeaf(), env.getOffset());
diff --git a/java.completion/src/org/netbeans/modules/java/completion/Utilities.java b/java.completion/src/org/netbeans/modules/java/completion/Utilities.java
index e1f97b2..b1a1a63 100644
--- a/java.completion/src/org/netbeans/modules/java/completion/Utilities.java
+++ b/java.completion/src/org/netbeans/modules/java/completion/Utilities.java
@@ -19,6 +19,7 @@
 
 package org.netbeans.modules.java.completion;
 
+import com.sun.source.util.Trees;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
@@ -284,12 +285,12 @@ public final class Utilities {
         }
     }
 
-    public static List<String> varNamesSuggestions(TypeMirror type, ElementKind kind, Set<Modifier> modifiers, String suggestedName, String prefix, Types types, Elements elements, Iterable<? extends Element> locals, CodeStyle codeStyle) {
+    public static List<String> varNamesSuggestions(TypeMirror type, ElementKind kind, Set<Modifier> modifiers, String suggestedName, String prefix, Types types, Elements elements, Trees trees, Iterable<? extends Element> locals, CodeStyle codeStyle) {
         List<String> result = new ArrayList<>();
         if (type == null && suggestedName == null) {
             return result;
         }
-        List<String> vnct = suggestedName != null ? Collections.singletonList(suggestedName) : varNamesForType(type, types, elements, prefix);
+        List<String> vnct = suggestedName != null ? Collections.singletonList(suggestedName) : varNamesForType(type, types, elements, trees, prefix);
         boolean isConst = false;
         String namePrefix = null;
         String nameSuffix = null;
@@ -379,17 +380,17 @@ public final class Utilities {
         return result;
     }
 
-    private static List<String> varNamesForType(TypeMirror type, Types types, Elements elements, String prefix) {
+    private static List<String> varNamesForType(TypeMirror type, Types types, Elements elements, Trees trees, String prefix) {
         switch (type.getKind()) {
             case ARRAY:
                 TypeElement iterableTE = elements.getTypeElement("java.lang.Iterable"); //NOI18N
                 TypeMirror iterable = iterableTE != null ? types.getDeclaredType(iterableTE) : null;
                 TypeMirror ct = ((ArrayType) type).getComponentType();
                 if (ct.getKind() == TypeKind.ARRAY && iterable != null && types.isSubtype(ct, iterable)) {
-                    return varNamesForType(ct, types, elements, prefix);
+                    return varNamesForType(ct, types, elements, trees, prefix);
                 }
                 List<String> vnct = new ArrayList<>();
-                for (String name : varNamesForType(ct, types, elements, prefix)) {
+                for (String name : varNamesForType(ct, types, elements, trees, prefix)) {
                     vnct.add(name.endsWith("s") ? name + "es" : name + "s"); //NOI18N
                 }
                 return vnct;
@@ -408,6 +409,9 @@ public final class Utilities {
             case TYPEVAR:
                 return Collections.<String>singletonList(type.toString().toLowerCase(Locale.ENGLISH));
             case ERROR:
+                TypeMirror orig = trees.getOriginalType((ErrorType) type);
+                if (orig != null && orig.getKind() != TypeKind.ERROR)
+                    return varNamesForType(orig, types, elements, trees, prefix);
                 String tn = ((ErrorType) type).asElement().getSimpleName().toString();
                 if (tn.toUpperCase(Locale.ENGLISH).contentEquals(tn)) {
                     return Collections.<String>singletonList(tn.toLowerCase(Locale.ENGLISH));
@@ -449,9 +453,9 @@ public final class Utilities {
                     if (tas.size() > 0) {
                         TypeMirror et = tas.get(0);
                         if (et.getKind() == TypeKind.ARRAY || (et.getKind() != TypeKind.WILDCARD && types.isSubtype(et, iterable))) {
-                            al.addAll(varNamesForType(et, types, elements, prefix));
+                            al.addAll(varNamesForType(et, types, elements, trees, prefix));
                         } else {
-                            for (String name : varNamesForType(et, types, elements, prefix)) {
+                            for (String name : varNamesForType(et, types, elements, trees, prefix)) {
                                 al.add(name.endsWith("s") ? name + "es" : name + "s"); //NOI18N
                             }
                         }
@@ -470,7 +474,7 @@ public final class Utilities {
                     bound = ((WildcardType) type).getSuperBound();
                 }
                 if (bound != null) {
-                    return varNamesForType(bound, types, elements, prefix);
+                    return varNamesForType(bound, types, elements, trees, prefix);
                 }
         }
         return Collections.<String>emptyList();
diff --git a/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testBoundPatternVariable1.pass b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testBoundPatternVariable1.pass
new file mode 100644
index 0000000..7d77f8e
--- /dev/null
+++ b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testBoundPatternVariable1.pass
@@ -0,0 +1 @@
+String str
diff --git a/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testBoundPatternVariable2.pass b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testBoundPatternVariable2.pass
new file mode 100644
index 0000000..c441e8c
--- /dev/null
+++ b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testBoundPatternVariable2.pass
@@ -0,0 +1 @@
+public int length()
diff --git a/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testMatches1.pass b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testMatches1.pass
new file mode 100644
index 0000000..5174d10
--- /dev/null
+++ b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testMatches1.pass
@@ -0,0 +1,2 @@
+__matches
+instanceof
diff --git a/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern1.pass b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern1.pass
new file mode 100644
index 0000000..8f5cbed
--- /dev/null
+++ b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern1.pass
@@ -0,0 +1,2 @@
+s
+string
diff --git a/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern2.pass b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern2.pass
new file mode 100644
index 0000000..0ddf2ba
--- /dev/null
+++ b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern2.pass
@@ -0,0 +1 @@
+i
diff --git a/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern3.pass b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern3.pass
new file mode 100644
index 0000000..d753425
--- /dev/null
+++ b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern3.pass
@@ -0,0 +1,4 @@
+l
+list
+ses
+strings
diff --git a/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern4.pass b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern4.pass
new file mode 100644
index 0000000..7011bd4
--- /dev/null
+++ b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern4.pass
@@ -0,0 +1,2 @@
+ses
+strings
diff --git a/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern5.pass b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern5.pass
new file mode 100644
index 0000000..f5cb132
--- /dev/null
+++ b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePattern5.pass
@@ -0,0 +1 @@
+is
diff --git a/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePatternInSwitch1.pass b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePatternInSwitch1.pass
new file mode 100644
index 0000000..0418331
--- /dev/null
+++ b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePatternInSwitch1.pass
@@ -0,0 +1,104 @@
+AbstractMethodError
+Appendable
+ArithmeticException
+ArrayIndexOutOfBoundsException
+ArrayStoreException
+AssertionError
+AutoCloseable
+Boolean
+BootstrapMethodError
+Byte
+CharSequence
+Character
+Class
+ClassCastException
+ClassCircularityError
+ClassFormatError
+ClassLoader
+ClassNotFoundException
+ClassValue
+CloneNotSupportedException
+Cloneable
+Comparable
+Compiler
+Deprecated
+Double
+Enum
+EnumConstantNotPresentException
+Error
+Exception
+ExceptionInInitializerError
+Float
+FunctionalInterface
+IllegalAccessError
+IllegalAccessException
+IllegalArgumentException
+IllegalMonitorStateException
+IllegalStateException
+IllegalThreadStateException
+IncompatibleClassChangeError
+IndexOutOfBoundsException
+InheritableThreadLocal
+InstantiationError
+InstantiationException
+Integer
+InternalError
+InterruptedException
+Iterable
+LinkageError
+Long
+Math
+NegativeArraySizeException
+NoClassDefFoundError
+NoSuchFieldError
+NoSuchFieldException
+NoSuchMethodError
+NoSuchMethodException
+NullPointerException
+Number
+NumberFormatException
+Object
+OutOfMemoryError
+Override
+Package
+Process
+ProcessBuilder
+Readable
+ReflectiveOperationException
+Runnable
+Runtime
+RuntimeException
+RuntimePermission
+SafeVarargs
+SecurityException
+SecurityManager
+Short
+StackOverflowError
+StackTraceElement
+StrictMath
+String
+StringBuffer
+StringBuilder
+StringIndexOutOfBoundsException
+SuppressWarnings
+System
+Test
+Thread
+ThreadDeath
+ThreadGroup
+ThreadLocal
+Throwable
+TypeNotPresentException
+UnknownError
+UnsatisfiedLinkError
+UnsupportedClassVersionError
+UnsupportedOperationException
+VerifyError
+VirtualMachineError
+Void
+com
+java
+javax
+oracle
+org
+sun
diff --git a/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePatternInSwitch2.pass b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePatternInSwitch2.pass
new file mode 100644
index 0000000..8f5cbed
--- /dev/null
+++ b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/testVariablePatternInSwitch2.pass
@@ -0,0 +1,2 @@
+s
+string
diff --git a/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/10/javaLangTypes.pass b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/10/javaLangTypes.pass
new file mode 100644
index 0000000..be3ce7c
--- /dev/null
+++ b/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/10/javaLangTypes.pass
@@ -0,0 +1,110 @@
+AbstractMethodError
+Appendable
+ArithmeticException
+ArrayIndexOutOfBoundsException
+ArrayStoreException
+AssertionError
+AutoCloseable
+Boolean
+BootstrapMethodError
+Byte
+CharSequence
+Character
+Class
+ClassCastException
+ClassCircularityError
+ClassFormatError
+ClassLoader
+ClassNotFoundException
+ClassValue
+CloneNotSupportedException
+Cloneable
+Comparable
+Compiler
+Deprecated
+Double
+Enum
+EnumConstantNotPresentException
+Error
+Exception
+ExceptionInInitializerError
+Float
+FunctionalInterface
+IllegalAccessError
+IllegalAccessException
+IllegalArgumentException
+IllegalCallerException
+IllegalMonitorStateException
+IllegalStateException
+IllegalThreadStateException
+IncompatibleClassChangeError
+IndexOutOfBoundsException
+InheritableThreadLocal
+InstantiationError
+InstantiationException
+Integer
+InternalError
+InterruptedException
+Iterable
+LayerInstantiationException
+LinkageError
+Long
+Math
+Module
+ModuleLayer
+NegativeArraySizeException
+NoClassDefFoundError
+NoSuchFieldError
+NoSuchFieldException
+NoSuchMethodError
+NoSuchMethodException
+NullPointerException
+Number
+NumberFormatException
+Object
+OutOfMemoryError
+Override
+Package
+Process
+ProcessBuilder
+ProcessHandle
+Readable
+ReflectiveOperationException
+Runnable
+Runtime
+RuntimeException
+RuntimePermission
+SafeVarargs
+SecurityException
+SecurityManager
+Short
+StackOverflowError
+StackTraceElement
+StackWalker
+StrictMath
+String
+StringBuffer
+StringBuilder
+StringIndexOutOfBoundsException
+SuppressWarnings
+System
+Test
+Thread
+ThreadDeath
+ThreadGroup
+ThreadLocal
+Throwable
+TypeNotPresentException
+UnknownError
+UnsatisfiedLinkError
+UnsupportedClassVersionError
+UnsupportedOperationException
+VerifyError
+VirtualMachineError
+Void
+com
+java
+javax
+netscape
+org
+sun
diff --git a/java.completion/test/unit/data/org/netbeans/modules/java/completion/data/Patterns.java b/java.completion/test/unit/data/org/netbeans/modules/java/completion/data/Patterns.java
new file mode 100644
index 0000000..ad1a8f8
--- /dev/null
+++ b/java.completion/test/unit/data/org/netbeans/modules/java/completion/data/Patterns.java
@@ -0,0 +1,14 @@
+package test;
+
+public class Test {
+
+    public void op(Object o) {
+        if (o __matches String str) {
+            System.err.println("len: ");
+        }
+        if (o) { }
+        switch (o) {
+            case null: System.err.println("null"); break;
+        }
+    }
+}
diff --git a/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTaskAmberPatternsTest.java b/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTaskAmberPatternsTest.java
new file mode 100644
index 0000000..d71884d
--- /dev/null
+++ b/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTaskAmberPatternsTest.java
@@ -0,0 +1,104 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License.  When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+package org.netbeans.modules.java.completion;
+
+import org.netbeans.modules.java.source.parsing.JavacParser;
+
+/**
+ *
+ * @author Dusan Balek
+ */
+//TODO: smart types
+public class JavaCompletionTaskAmberPatternsTest extends CompletionTestBase {
+
+    public JavaCompletionTaskAmberPatternsTest(String testName) {
+        super(testName);
+    }
+
+    public void testBoundPatternVariable1() throws Exception {
+        performTest("Patterns", 143, "+ st", "testBoundPatternVariable1.pass", "1.9");
+    }
+
+    public void testBoundPatternVariable2() throws Exception {
+        performTest("Patterns", 143, "+ str.len", "testBoundPatternVariable2.pass", "1.9");
+    }
+
+    public void testMatches1() throws Exception {
+        //TODO: fix the remaining instances of addKeyword(env, INSTANCEOF_KEYWORD, SPACE, false);
+        performTest("Patterns", 169, " ", "testMatches1.pass", "1.9");
+    }
+
+    public void testTypeAfterMatches() throws Exception {
+        performTest("Patterns", 169, " __matches ", "javaLangTypes.pass", "1.9");
+    }
+
+    public void testVariablePatternName() throws Exception {
+        performTest("Patterns", 169, " __matches String ", "testVariablePattern1.pass", "1.9");
+        performTest("Patterns", 169, " __matches int ", "testVariablePattern2.pass", "1.9");
+        performTest("Patterns", 169, " __matches java.util.List<String> ", "testVariablePattern3.pass", "1.9");
+        performTest("Patterns", 169, " __matches String[] ", "testVariablePattern4.pass", "1.9");
+        performTest("Patterns", 169, " __matches int[] ", "testVariablePattern5.pass", "1.9");
+    }
+
+    public void testVariablePatternInSwitch() throws Exception {
+        performTest("Patterns", 213, " ", "javaLangTypes.pass", "1.9");
+        performTest("Patterns", 213, "String ", "testVariablePatternInSwitch2.pass", "1.9");
+    }
+
+    @Override
+    protected void runTest() throws Throwable {
+        try {
+            Class.forName("com.sun.source.tree.MatchesTree");
+        } catch (ClassNotFoundException ex) {
+            //skip
+            return ;
+        }
+        super.runTest();
+    }
+    
+
+    static {
+        JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;
+    }
+}
diff --git a/java.editor.base/nbproject/project.xml b/java.editor.base/nbproject/project.xml
index 3e05345..51c0824 100644
--- a/java.editor.base/nbproject/project.xml
+++ b/java.editor.base/nbproject/project.xml
@@ -202,6 +202,10 @@
                         <compile-dependency/>
                     </test-dependency>
                     <test-dependency>
+                        <code-name-base>org.netbeans.modules.java.j2seplatform</code-name-base>
+                        <compile-dependency/>
+                    </test-dependency>
+                    <test-dependency>
                         <code-name-base>org.netbeans.modules.java.source.base</code-name-base>
                         <recursive/>
                         <compile-dependency/>
diff --git a/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/FindLocalUsagesQuery.java b/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/FindLocalUsagesQuery.java
index a4d7f9a..bbce89f 100644
--- a/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/FindLocalUsagesQuery.java
+++ b/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/FindLocalUsagesQuery.java
@@ -133,7 +133,7 @@ public class FindLocalUsagesQuery extends CancellableTreePathScanner<Void, Stack
         super.visitVariable(tree, d);
         return null;
     }
-    
+
     @Override
     public Void visitClass(ClassTree tree, Stack<Tree> d) {
         handlePotentialVariable(getCurrentPath());
@@ -191,4 +191,13 @@ public class FindLocalUsagesQuery extends CancellableTreePathScanner<Void, Stack
         }
         return super.visitImport(node, p);
     }
+
+    @Override
+    public Void scan(Tree tree, Stack<Tree> p) {
+        if (tree != null && tree.getKind().name().equals("VARIABLE_PATTERN")) {
+            handlePotentialVariable(new TreePath(getCurrentPath(), tree));
+        }
+        return super.scan(tree, p);
+    }
+
 }
diff --git a/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java b/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java
index 8a72f45..887620c 100644
--- a/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java
+++ b/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java
@@ -41,6 +41,7 @@ import com.sun.source.tree.IfTree;
 import com.sun.source.tree.ImportTree;
 import com.sun.source.tree.InstanceOfTree;
 import com.sun.source.tree.LambdaExpressionTree;
+//import com.sun.source.tree.MatchesTree;
 import com.sun.source.tree.MemberReferenceTree;
 import com.sun.source.tree.MemberSelectTree;
 import com.sun.source.tree.MethodInvocationTree;
@@ -63,12 +64,14 @@ import com.sun.source.tree.TypeParameterTree;
 import com.sun.source.tree.UnaryTree;
 import com.sun.source.tree.UnionTypeTree;
 import com.sun.source.tree.UsesTree;
+//import com.sun.source.tree.VariablePatternTree;
 import com.sun.source.tree.VariableTree;
 import com.sun.source.tree.WhileLoopTree;
 import com.sun.source.tree.WildcardTree;
 import com.sun.source.util.SourcePositions;
 import com.sun.source.util.TreePath;
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -105,7 +108,6 @@ import org.netbeans.modules.parsing.spi.Scheduler;
 import org.netbeans.modules.parsing.spi.SchedulerEvent;
 import org.netbeans.modules.parsing.spi.TaskIndexingMode;
 import org.openide.filesystems.FileUtil;
-import org.openide.util.Exceptions;
 
 
 /**
@@ -1540,6 +1542,64 @@ public abstract class SemanticHighlighterBase extends JavaParserResultTask {
             return null;
         }
 
+        private TreePath currentPath;
+
+        public TreePath getCurrentPath() {
+            return currentPath;
+        }
+
+        @Override
+        public Void scan(Tree tree, EnumSet<UseTypes> p) {
+            if (tree == null) {
+                return null;
+            }
+            TreePath oldPath = currentPath;
+            try {
+                currentPath = new TreePath(currentPath, tree);
+                switch (tree.getKind().name()) {
+                    case "MATCHES": return visitMatches(tree, p);
+                    case "VARIABLE_PATTERN": return visitVariablePattern(tree, p);
+                }
+                return super.scan(tree, p);
+            } finally {
+                currentPath = oldPath;
+            }
+        }
+
+        public Void visitMatches(Tree node, EnumSet<UseTypes> p) {
+            List<Tree> children = info.getTreeUtilities().getChildren(node);
+            scan(children.get(0) /*node.getExpression()*/, p);
+            tl.moveToEnd(children.get(0) /*node.getExpression()*/);
+            Token t = firstIdentifierToken("__matches", "matches");
+            if (t != null) {
+                contextKeywords.add(t);
+            }
+            scan(children.get(1) /*node.getPattern()*/, p);
+            return null;
+        }
+
+        public Void visitVariablePattern(Tree node, EnumSet<UseTypes> p) {
+            List<Tree> children = info.getTreeUtilities().getChildren(node);
+            handlePossibleIdentifier(getCurrentPath(), EnumSet.of(UseTypes.DECLARATION, UseTypes.WRITE));
+            
+            scan(children.get(0) /*tree.getType()*/, null);
+            
+            tl.moveToEnd(children.get(0) /*tree.getType()*/);
+            
+//            int[] span = info.getTreeUtilities().findNameSpan(tree);
+//            if (span != null)
+//                tl.moveToOffset(span[0]);
+
+            try {
+                Method getBinding = node.getClass().getMethod("getBinding");
+                firstIdentifier(String.valueOf(getBinding.invoke(node)));
+            } catch (Exception ex) {
+                ex.printStackTrace(); //XXX
+            }
+            
+            return null;
+        }
+
     }
 
     public static interface ErrorDescriptionSetter {
diff --git a/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/Utilities.java b/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/Utilities.java
index e127369..faf248e 100644
--- a/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/Utilities.java
+++ b/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/Utilities.java
@@ -578,6 +578,17 @@ public class Utilities {
         TokenHierarchy<?> th = info.getTokenHierarchy();
         TokenSequence<JavaTokenId> ts = th.tokenSequence(JavaTokenId.language());
         
+        if ("VARIABLE_PATTERN".equals(leaf.getKind().name())) {
+            ts.move(end);
+            if (ts.movePrevious()) {
+                Token<JavaTokenId> token = ts.token();
+                JavaTokenId id = token.id();
+                if (id == JavaTokenId.IDENTIFIER) {
+                    return token;
+                }
+            }
+        }
+        
         if (ts.move(start) == Integer.MAX_VALUE) {
             return null;
         }
diff --git a/java.editor.base/test/unit/data/goldenfiles/org/netbeans/modules/java/editor/base/semantic/DetectorTest/testPatterns.pass b/java.editor.base/test/unit/data/goldenfiles/org/netbeans/modules/java/editor/base/semantic/DetectorTest/testPatterns.pass
new file mode 100644
index 0000000..b8fd5fb
--- /dev/null
+++ b/java.editor.base/test/unit/data/goldenfiles/org/netbeans/modules/java/editor/base/semantic/DetectorTest/testPatterns.pass
@@ -0,0 +1,14 @@
+[PUBLIC, CLASS, DECLARATION], 2:13-2:21
+[STATIC, PUBLIC, METHOD, DECLARATION], 4:23-4:27
+[PUBLIC, CLASS], 4:28-4:34
+[PARAMETER, DECLARATION], 4:35-4:36
+[PARAMETER], 5:12-5:13
+[], 5:14-5:23
+[LOCAL_VARIABLE, DECLARATION], 5:31-5:35
+[PUBLIC, CLASS], 6:12-6:18
+[STATIC, PUBLIC, FIELD], 6:19-6:22
+[PUBLIC, METHOD], 6:23-6:30
+[LOCAL_VARIABLE], 6:41-6:45
+[PARAMETER], 8:12-8:13
+[], 8:14-8:23
+[LOCAL_VARIABLE, UNUSED, DECLARATION], 8:31-8:35
diff --git a/java.editor.base/test/unit/data/goldenfiles/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest/testPatterns.pass b/java.editor.base/test/unit/data/goldenfiles/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest/testPatterns.pass
new file mode 100644
index 0000000..28bdae1
--- /dev/null
+++ b/java.editor.base/test/unit/data/goldenfiles/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest/testPatterns.pass
@@ -0,0 +1,2 @@
+[MARK_OCCURRENCES], 5:31-5:35
+[MARK_OCCURRENCES], 6:41-6:45
diff --git a/java.editor.base/test/unit/data/org/netbeans/modules/java/editor/base/semantic/data/Patterns.java b/java.editor.base/test/unit/data/org/netbeans/modules/java/editor/base/semantic/data/Patterns.java
new file mode 100644
index 0000000..48d6664
--- /dev/null
+++ b/java.editor.base/test/unit/data/org/netbeans/modules/java/editor/base/semantic/data/Patterns.java
@@ -0,0 +1,13 @@
+package org.netbeans.modules.java.editor.semantic.data;
+
+public class Patterns {
+    
+    public static void main(Object o) {
+        if (o __matches String str1) {
+            System.err.println("str1=" + str1);
+        }
+        if (o __matches String str2) {
+        }
+    }
+    
+}
diff --git a/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java b/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java
index 1995fad..4b591ef 100644
--- a/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java
+++ b/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java
@@ -398,6 +398,10 @@ public class DetectorTest extends TestBase {
         performTest("IncDecReading230408");
     }
 
+    public void testPatterns() throws Exception {
+        performTest("Patterns");
+    }
+
     private void performTest(String fileName) throws Exception {
         performTest(fileName, new Performer() {
             public void compute(CompilationController parameter, Document doc, final ErrorDescriptionSetter setter) {
diff --git a/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest.java b/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest.java
index 125dd42..fe81fcb 100644
--- a/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest.java
+++ b/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest.java
@@ -316,6 +316,10 @@ public class MarkOccDetTest extends TestBase {
         performTest("ExitPoints", 115, 22);
     }
 
+    public void testPatterns() throws Exception {
+        performTest("Patterns", 6, 42);
+    }
+
     //Support for exotic identifiers has been removed 6999438
     public void REMOVEDtestExoticIdentifiers1() throws Exception {
         performTest("ExoticIdentifier", 3, 43);
diff --git a/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java b/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
index b5e8915..ed6c030 100644
--- a/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
+++ b/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
@@ -36,6 +36,7 @@ import com.sun.source.tree.Scope;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.Tree.Kind;
 import com.sun.source.tree.TypeParameterTree;
+//import com.sun.source.tree.VariablePatternTree;
 import com.sun.source.tree.VariableTree;
 import com.sun.source.util.TreePath;
 import org.netbeans.api.java.source.support.ErrorAwareTreePathScanner;
@@ -713,12 +714,21 @@ public class GoToSupport {
                 if (found != null) {
                     return null;
                 }
+                if (tree != null && tree.getKind().name().equals("VARIABLE_PATTERN")) {
+                    if (!process(new TreePath(getCurrentPath(), tree))) {
+                        return super.scan(tree, p);
+                    }
+                    return null;
+                }
                 return super.scan(tree, p);
             }
             private boolean process() {
-                Element resolved = info.getTrees().getElement(getCurrentPath());
+                return process(getCurrentPath());
+            }
+            private boolean process(TreePath path) {
+                Element resolved = info.getTrees().getElement(path);
                 if (toFind.equals(resolved)) {
-                    found = getCurrentPath();
+                    found = path;
                     return true;
                 }
                 return false;
diff --git a/java.editor/src/org/netbeans/modules/java/editor/codegen/LoggerGenerator.java b/java.editor/src/org/netbeans/modules/java/editor/codegen/LoggerGenerator.java
index fbcc66f..69f0376 100644
--- a/java.editor/src/org/netbeans/modules/java/editor/codegen/LoggerGenerator.java
+++ b/java.editor/src/org/netbeans/modules/java/editor/codegen/LoggerGenerator.java
@@ -139,7 +139,7 @@ public class LoggerGenerator implements CodeGenerator {
                             ClassTree cls = (ClassTree) path.getLeaf();
                             CodeStyle cs = CodeStyle.getDefault(component.getDocument());
                             Set<Modifier> mods = EnumSet.of(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL);
-                            List<String> names = Utilities.varNamesSuggestions(null, ElementKind.FIELD, mods, "LOG", null, copy.getTypes(), copy.getElements(), e.getEnclosedElements(), cs);
+                            List<String> names = Utilities.varNamesSuggestions(null, ElementKind.FIELD, mods, "LOG", null, copy.getTypes(), copy.getElements(), copy.getTrees(), e.getEnclosedElements(), cs);
                             VariableTree var = createLoggerField(copy.getTreeMaker(), cls, names.size() > 0 ? names.get(0) : "LOG", mods); //NOI18N
                             copy.rewrite(cls, GeneratorUtils.insertClassMembers(copy, cls, Collections.singletonList(var), caretOffset));
                         }
diff --git a/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java b/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java
index bf44269..0d5991c 100644
--- a/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java
+++ b/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java
@@ -929,6 +929,31 @@ public class GoToSupportTest extends NbTestCase {
         assertTrue(wasCalled[0]);
     }
 
+    public void testPatterns1() throws Exception {
+        final boolean[] wasCalled = new boolean[1];
+
+        performTest("package test; public class Test { t(Object o) { if (o __matches String str) { String s = str; } }", 91, new UiUtilsCaller() {
+            public boolean open(FileObject fo, int pos) {
+                assertTrue(source == fo);
+                assertEquals(64, pos);
+                wasCalled[0] = true;
+                return true;
+            }
+            public void beep(boolean goToSource, boolean goToJavadoc) {
+                fail("Should not be called.");
+            }
+            public boolean open(ClasspathInfo info, ElementHandle<?> el) {
+                fail("Should not be called.");
+                return false;
+            }
+            public void warnCannotOpen(String displayName) {
+                fail("Should not be called.");
+            }
+        }, false);
+
+        assertTrue(wasCalled[0]);
+    }
+
     public void testDeadlock135736() throws Exception {
         final CountDownLatch l1 = new CountDownLatch(1);
         final CountDownLatch l2 = new CountDownLatch(1);
diff --git a/java.navigation/test/unit/src/org/netbeans/modules/java/navigation/BreadCrumbsNodeImplTest.java b/java.navigation/test/unit/src/org/netbeans/modules/java/navigation/BreadCrumbsNodeImplTest.java
index d0fe02b..70480e5 100644
--- a/java.navigation/test/unit/src/org/netbeans/modules/java/navigation/BreadCrumbsNodeImplTest.java
+++ b/java.navigation/test/unit/src/org/netbeans/modules/java/navigation/BreadCrumbsNodeImplTest.java
@@ -24,7 +24,6 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
-import static org.junit.Assert.*;
 import org.netbeans.api.java.source.CompilationInfo;
 import org.netbeans.api.java.source.JavaSource;
 import org.netbeans.api.java.source.SourceUtilsTestUtil;
@@ -34,7 +33,6 @@ import org.netbeans.modules.editor.breadcrumbs.spi.BreadcrumbsElement;
 import org.netbeans.spi.queries.FileEncodingQueryImplementation;
 import org.openide.filesystems.FileObject;
 import org.openide.filesystems.FileUtil;
-import org.openide.nodes.Node;
 import org.openide.util.lookup.ServiceProvider;
 
 /**
@@ -99,6 +97,14 @@ public class BreadCrumbsNodeImplTest extends NbTestCase {
         performBreadcrumbsSelectionTest("package test; public class Test { t(String str) { if (str.equals(\"čcč|\")) { | } }", "test.Test>>>>t>>>>if <font color=#707070>(str.equals(&quot;čcč&quot;))</font>>>>>");
     }
     
+    public void testPatterns1() throws Exception {
+        performBreadcrumbsSelectionTest("package test; public class Test { t(Object o) { if (o __matches String str) { String s = st|r; } }", "test.Test>>>>t>>>>if <font color=#707070>(o matches String str)</font>>>>>s>>>>");
+    }
+    
+    public void testPatterns2() throws Exception {
+        performBreadcrumbsSelectionTest("package test; public class Test { t(Object o) { if (o __matches String s|tr) { String s = str; } }", "test.Test>>>>t>>>>if <font color=#707070>(o matches String str)</font>>>>>");
+    }
+    
     private void performBreadcrumbsSelectionTest(String code, String golden) throws Exception {
         int caret = code.indexOf('|');
         
diff --git a/java.source.base/src/org/netbeans/api/java/source/TreeUtilities.java b/java.source.base/src/org/netbeans/api/java/source/TreeUtilities.java
index aac8cee..6d705b9 100644
--- a/java.source.base/src/org/netbeans/api/java/source/TreeUtilities.java
+++ b/java.source.base/src/org/netbeans/api/java/source/TreeUtilities.java
@@ -71,6 +71,7 @@ import javax.tools.JavaFileObject;
 import javax.tools.SimpleJavaFileObject;
 
 import com.sun.source.util.DocTrees;
+import com.sun.source.util.TreeScanner;
 import com.sun.tools.javac.api.JavacTaskImpl;
 import com.sun.tools.javac.comp.ArgumentAttr;
 import com.sun.tools.javac.comp.Attr;
@@ -106,6 +107,8 @@ import org.openide.util.Exceptions;
  *
  * @author Jan Lahoda, Dusan Balek, Tomas Zezula
  */
+
+
 public final class TreeUtilities {
     
     /**{@link Kind}s that are represented by {@link ClassTree}.
@@ -1117,6 +1120,19 @@ public final class TreeUtilities {
         return findNameSpan(cont.getLabel().toString(), cont);
     }
     
+//    /**Find span of the {@link VariablePatternTree#getBinding()} identifier in the source.
+//     * Returns starting and ending offset of the name in the source code that was parsed
+//     * (ie. {@link CompilationInfo.getText()}, which may differ from the positions in the source
+//     * document if it has been already altered.
+//     * 
+//     * @param var variable pattern which name should be searched for
+//     * @return the span of the name, or null if cannot be found
+//     * @since 0.999
+//     */
+//    public int[] findNameSpan(VariablePatternTree var) {
+//        return findNameSpan(var.getBinding().toString(), var);
+//    }
+    
     /**Find span of the {@link MethodTree#getParameters()} parameter list in the source.
      * Returns the position of the opening and closing parentheses of the parameter list
      * in the source code that was parsed (ie. {@link CompilationInfo.getText()}, which
@@ -1842,6 +1858,18 @@ public final class TreeUtilities {
         return ref.paramTypes;
     }
     
+    public List<Tree> getChildren(Tree t) {
+        final List<Tree> result = new ArrayList<>();
+        t.accept(new TreeScanner<Void, Void>() {
+            @Override
+            public Void scan(Tree tree, Void p) {
+                result.add(tree);
+                return null;
+            }
+        }, null);
+        return result;
+    }
+
     private static final class NBScope implements Scope {
 
         private final JavacScope delegate;
diff --git a/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java b/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java
index 360e5a1..5598c1b 100644
--- a/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java
+++ b/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java
@@ -68,10 +68,13 @@ import com.sun.tools.javac.util.ListBuffer;
 import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Names;
 import com.sun.tools.javac.util.Context;
+import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import javax.lang.model.element.*;
 import javax.lang.model.type.ArrayType;
 import javax.lang.model.type.TypeKind;
@@ -1845,4 +1848,17 @@ public class TreeFactory {
         }
         return docMake.at(NOPOS).newReferenceTree("", (JCExpression) qualExpr, member != null ? (Name) names.fromString(member.toString()) : null, paramTypesList);
     }
+
+    public <R extends Tree> R createReflective(String factoryName, Class<R> apiType, Object... params) {
+        for (java.lang.reflect.Method m : make.getClass().getMethods()) {
+            if (m.getName().equals(factoryName) && m.isAccessible() && m.getParameterTypes().length == params.length) {
+                try {
+                    return apiType.cast(m.invoke(make.at(NOPOS), params));
+                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
+                    Logger.getLogger(TreeFactory.class.getName()).log(Level.FINE, null, ex);
+                }
+            }
+        }
+        throw new UnsupportedOperationException("Cannot find factory: " + factoryName);
+    }
 }
diff --git a/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JackpotTrees.java b/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JackpotTrees.java
index 453f390..d215544 100644
--- a/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JackpotTrees.java
+++ b/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/JackpotTrees.java
@@ -182,6 +182,7 @@ public class JackpotTrees {
         private final JCIdent jcIdent;
 
         public CaseWildcard(Context ctx, Name ident, JCIdent jcIdent) {
+//            super(new JCConstantPattern(jcIdent) {}, List.<JCStatement>nil());
             super(jcIdent, List.<JCStatement>nil());
             this.ident = ident;
             this.jcIdent = jcIdent;
diff --git a/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Utilities.java b/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Utilities.java
index 5962f8c..0f0f031 100644
--- a/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Utilities.java
+++ b/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/Utilities.java
@@ -162,6 +162,7 @@ import org.netbeans.spi.editor.hints.Severity;
 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
 import org.openide.filesystems.FileObject;
 import org.openide.filesystems.FileUtil;
+import org.openide.util.Exceptions;
 import org.openide.util.Lookup;
 import org.openide.util.NbCollections;
 import org.openide.util.WeakListeners;
@@ -1394,7 +1395,7 @@ public class Utilities {
 
         @Override
         protected JCCase switchBlockStatementGroup() {
-            if (token.kind == TokenKind.CASE) {
+            if (token.kind == TokenKind.CASE && /*XXX: patterns*/!hasPatterns()) {
                 Token peeked = S.token(1);
 
                 if (peeked.kind == TokenKind.IDENTIFIER) {
@@ -1420,6 +1421,14 @@ public class Utilities {
             return super.switchBlockStatementGroup();
         }
 
+        private boolean hasPatterns() {
+            try {
+                Class.forName("com.sun.source.tree.ConstantPatternTree");
+                return true;
+            } catch (ClassNotFoundException ex) {
+                return false;
+            }
+        }
 
         @Override
         protected JCTree resource() {

-- 
To stop receiving notification emails like this one, please contact
"commits@netbeans.apache.org" <co...@netbeans.apache.org>.