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:40 UTC

[incubator-netbeans] branch jdk/amber/patterns created (now b062776)

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

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


      at b062776  A very crude prototype of editor for Java patterns.

This branch includes the following new commits:

     new b062776  A very crude prototype of editor for Java patterns.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


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

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

Posted by jl...@apache.org.
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>.