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

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


The following commit(s) were added to refs/heads/master by this push:
     new f21f266  Support for pattern matching in instanceof.
f21f266 is described below

commit f21f266c90ab7689fe970e1852505d517bd18cad
Author: Jan Lahoda <[email protected]>
AuthorDate: Fri Jan 17 07:28:42 2020 +0100

    Support for pattern matching in instanceof.
---
 .../ant/hints/errors/EnablePreviewAntProj.java     |   1 +
 .../netbeans/modules/java/completion/BaseTask.java |   8 +
 .../java/completion/JavaCompletionTask.java        |  41 ++--
 .../JavaCompletionTaskTest/1.8/BindingUse.pass     |   1 +
 .../java/completion/CompletionTestBase.java        |   6 +-
 .../JavaCompletionTask114FeaturesTest.java         |  58 ++++++
 .../editor/base/semantic/FindLocalUsagesQuery.java |  12 +-
 .../base/semantic/SemanticHighlighterBase.java     |  36 +++-
 .../java/editor/base/semantic/Utilities.java       |  68 ++++++-
 .../testErroneousMethodNETBEANS_224.pass           |   0
 .../java/editor/base/semantic/DetectorTest.java    |  26 +++
 .../java/editor/base/semantic/MarkOccDetTest.java  |  46 +++++
 .../netbeans/modules/editor/java/GoToSupport.java  |  19 +-
 .../modules/editor/java/JavaCompletionItem.java    |   6 +-
 .../modules/editor/java/GoToSupportTest.java       | 111 +++++++++++
 .../editor/rename/InstantRenamePerformerTest.java  |  12 ++
 .../java/hints/jdk/ConvertToPatternInstanceOf.java | 155 +++++++++++++++
 .../hints/jdk/ConvertToPatternInstanceOfTest.java  | 142 ++++++++++++++
 .../org/netbeans/api/java/source/TreeMaker.java    |  14 ++
 .../netbeans/modules/java/source/TreeShims.java    |  43 +++++
 .../modules/java/source/TreeShimsCopier.java       |   2 +
 .../modules/java/source/builder/TreeFactory.java   |   9 +
 .../modules/java/source/pretty/VeryPretty.java     |  18 +-
 .../modules/java/source/save/CasualDiff.java       |  21 ++-
 .../modules/java/source/save/Reformatter.java      |  34 +++-
 .../api/java/source/gen/InstanceOfTest.java        | 208 +++++++++++++++++++++
 .../modules/java/source/save/FormatingTest.java    |  40 ++++
 .../maven/hints/errors/EnablePreviewMavenProj.java |   1 +
 28 files changed, 1103 insertions(+), 35 deletions(-)

diff --git 
a/java/ant.hints/src/org/netbeans/modules/ant/hints/errors/EnablePreviewAntProj.java
 
b/java/ant.hints/src/org/netbeans/modules/ant/hints/errors/EnablePreviewAntProj.java
index c884782..ac66215 100644
--- 
a/java/ant.hints/src/org/netbeans/modules/ant/hints/errors/EnablePreviewAntProj.java
+++ 
b/java/ant.hints/src/org/netbeans/modules/ant/hints/errors/EnablePreviewAntProj.java
@@ -54,6 +54,7 @@ import org.openide.util.MutexException;
 public class EnablePreviewAntProj implements ErrorRule<Void> {
 
     private static final Set<String> ERROR_CODES = new 
HashSet<String>(Arrays.asList(
+            "compiler.err.preview.feature.disabled",          // NOI18N
             "compiler.err.preview.feature.disabled.plural")); // NOI18N
     private static final String ENABLE_PREVIEW_FLAG = "--enable-preview";   // 
NOI18N
     private static final String JAVAC_COMPILER_ARGS = "javac.compilerargs"; // 
NOI18N
diff --git 
a/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java 
b/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java
index e1d04f8..7be3a9f 100644
--- 
a/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java
+++ 
b/java/java.completion/src/org/netbeans/modules/java/completion/BaseTask.java
@@ -35,6 +35,7 @@ import javax.lang.model.util.Types;
 import javax.tools.Diagnostic;
 
 import com.sun.source.tree.*;
+import com.sun.source.tree.Tree.Kind;
 import com.sun.source.util.SourcePositions;
 import com.sun.source.util.TreePath;
 import org.netbeans.api.java.source.support.ErrorAwareTreeScanner;
@@ -344,6 +345,13 @@ abstract class BaseTask extends UserTask {
                     case CASE:
                         stmts = ((CaseTree) path.getLeaf()).getStatements();
                         break;
+                    case CONDITIONAL_AND: case CONDITIONAL_OR:
+                        BinaryTree bt = (BinaryTree) last;
+                        if 
(sourcePositions.getStartPosition(path.getCompilationUnit(), 
bt.getRightOperand()) == offset &&
+                            bt.getRightOperand().getKind() == Kind.ERRONEOUS) {
+                            last = bt.getRightOperand();
+                        }
+                        break;
                 }
                 if (stmts != null) {
                     for (StatementTree st : stmts) {
diff --git 
a/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
 
b/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
index a53e6b4..9a32b9c 100644
--- 
a/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
+++ 
b/java/java.completion/src/org/netbeans/modules/java/completion/JavaCompletionTask.java
@@ -2794,7 +2794,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
                 @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))
+                            || EnumSet.of(LOCAL_VARIABLE, PARAMETER, 
EXCEPTION_PARAMETER, 
RESOURCE_VARIABLE).contains(simplifyElementKind(e.getKind())) && 
controller.getSourceVersion().compareTo(SourceVersion.RELEASE_8) >= 0 && 
controller.getElementUtilities().isEffectivelyFinal((VariableElement)e))
                             && 
!illegalForwardRefs.containsKey(e.getSimpleName());
                 }
             };
@@ -2815,7 +2815,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
                 return;
             }
             TypeMirror tm = controller.getTrees().getTypeMirror(exPath);
-            switch (e.getKind()) {
+            switch (simplifyElementKind(e.getKind())) {
                 case ANNOTATION_TYPE:
                 case CLASS:
                 case ENUM:
@@ -2830,7 +2830,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
                             @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))
+                                        || EnumSet.of(LOCAL_VARIABLE, 
PARAMETER, EXCEPTION_PARAMETER, 
RESOURCE_VARIABLE).contains(simplifyElementKind(e.getKind())) && 
controller.getSourceVersion().compareTo(SourceVersion.RELEASE_8) >= 0 && 
controller.getElementUtilities().isEffectivelyFinal((VariableElement)e))
                                         && 
!illegalForwardRefs.containsKey(e.getSimpleName());
                             }
                         };
@@ -2862,7 +2862,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
                             @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))
+                                        || EnumSet.of(LOCAL_VARIABLE, 
PARAMETER, EXCEPTION_PARAMETER, 
RESOURCE_VARIABLE).contains(simplifyElementKind(e.getKind())) && 
controller.getSourceVersion().compareTo(SourceVersion.RELEASE_8) >= 0 && 
controller.getElementUtilities().isEffectivelyFinal((VariableElement)e))
                                         && 
!illegalForwardRefs.containsKey(e.getSimpleName());
                             }
                         };
@@ -2903,7 +2903,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
                 return;
             }
             TypeMirror tm = controller.getTrees().getTypeMirror(exPath);
-            switch (e.getKind()) {
+            switch (simplifyElementKind(e.getKind())) {
                 case ANNOTATION_TYPE:
                 case CLASS:
                 case ENUM:
@@ -2959,7 +2959,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
             }
             return;
         }
-        switch (e.getKind()) {
+        switch (simplifyElementKind(e.getKind())) {
             case ANNOTATION_TYPE:
             case CLASS:
             case ENUM:
@@ -2972,7 +2972,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
                     @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))
+                                || EnumSet.of(LOCAL_VARIABLE, PARAMETER, 
EXCEPTION_PARAMETER, 
RESOURCE_VARIABLE).contains(simplifyElementKind(e.getKind())) && 
controller.getSourceVersion().compareTo(SourceVersion.RELEASE_8) >= 0 && 
controller.getElementUtilities().isEffectivelyFinal((VariableElement)e))
                                 && 
!illegalForwardRefs.containsKey(e.getSimpleName());
                     }
                 };
@@ -3072,7 +3072,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
         }
         final TypeElement enclClass = scope.getEnclosingClass();
         for (Element e : getLocalMembersAndVars(env)) {
-            switch (e.getKind()) {
+            switch (simplifyElementKind(e.getKind())) {
                 case FIELD:
                     if (((VariableElement) e).getConstantValue() != null) {
                         TypeMirror tm = asMemberOf(e, enclClass != null ? 
enclClass.asType() : null, types);
@@ -3147,7 +3147,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
         }
         final TypeElement enclClass = scope.getEnclosingClass();
         for (Element e : locals) {
-            switch (e.getKind()) {
+            switch (simplifyElementKind(e.getKind())) {
                 case ENUM_CONSTANT:
                 case EXCEPTION_PARAMETER:
                 case LOCAL_VARIABLE:
@@ -3184,7 +3184,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
         Set<? extends TypeMirror> smartTypes = 
options.contains(Options.ALL_COMPLETION) ? null : getSmartTypes(env);
         final TypeElement enclClass = scope.getEnclosingClass();
         for (Element e : getLocalMembersAndVars(env)) {
-            switch (e.getKind()) {
+            switch (simplifyElementKind(e.getKind())) {
                 case ENUM_CONSTANT:
                 case EXCEPTION_PARAMETER:
                 case LOCAL_VARIABLE:
@@ -3216,7 +3216,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
             final Set<? extends TypeMirror> smartTypes = 
options.contains(Options.ALL_COMPLETION) ? null : getSmartTypes(env);
             final TypeElement enclClass = scope.getEnclosingClass();
             for (Element e : getLocalMembersAndVars(env)) {
-                switch (e.getKind()) {
+                switch (simplifyElementKind(e.getKind())) {
                     case EXCEPTION_PARAMETER:
                     case LOCAL_VARIABLE:
                     case RESOURCE_VARIABLE:
@@ -3258,7 +3258,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
             @Override
             public boolean accept(Element e, TypeMirror t) {
                 boolean isStatic = ctxStatic || (t != null && t.getKind() == 
TypeKind.DECLARED && ((DeclaredType) t).asElement() != enclClass && enclStatic);
-                switch (e.getKind()) {
+                switch (simplifyElementKind(e.getKind())) {
                     case CONSTRUCTOR:
                         return false;
                     case LOCAL_VARIABLE:
@@ -3358,7 +3358,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
             for (Element localElement : locals) {
                 TypeMirror localElementType = null;
                 TypeMirror type = null;
-                switch (localElement.getKind()) {
+                switch (simplifyElementKind(localElement.getKind())) {
                     case EXCEPTION_PARAMETER:
                     case LOCAL_VARIABLE:
                     case RESOURCE_VARIABLE:
@@ -3563,7 +3563,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
         ElementUtilities.ElementAcceptor acceptor = new 
ElementUtilities.ElementAcceptor() {
             @Override
             public boolean accept(Element e, TypeMirror t) {
-                switch (e.getKind()) {
+                switch (simplifyElementKind(e.getKind())) {
                     case FIELD:
                         if (!startsWith(env, e.getSimpleName().toString())) {
                             return false;
@@ -3656,7 +3656,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
         };
         boolean addCast = actualType != type && elem instanceof 
VariableElement && !elem.getKind().isField();
         for (Element e : 
controller.getElementUtilities().getMembers(actualType, acceptor)) {
-            switch (e.getKind()) {
+            switch (simplifyElementKind(e.getKind())) {
                 case ENUM_CONSTANT:
                 case EXCEPTION_PARAMETER:
                 case FIELD:
@@ -4161,7 +4161,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
                     ElementUtilities.ElementAcceptor acceptor = new 
ElementUtilities.ElementAcceptor() {
                         @Override
                         public boolean accept(Element e, TypeMirror t) {
-                            switch (e.getKind()) {
+                            switch (simplifyElementKind(e.getKind())) {
                                 case LOCAL_VARIABLE:
                                 case RESOURCE_VARIABLE:
                                 case EXCEPTION_PARAMETER:
@@ -4857,7 +4857,7 @@ public final class JavaCompletionTask<T> extends BaseTask 
{
                 if (!e.getSimpleName().contentEquals(simpleName)) {
                     return false;
                 }
-                switch (e.getKind()) {
+                switch (simplifyElementKind(e.getKind())) {
                     case LOCAL_VARIABLE:
                     case RESOURCE_VARIABLE:
                         if (isStatic && 
(e.getSimpleName().contentEquals(THIS_KEYWORD) || 
e.getSimpleName().contentEquals(SUPER_KEYWORD))) {
@@ -6023,4 +6023,11 @@ public final class JavaCompletionTask<T> extends 
BaseTask {
         return isFirstParamVarType;
 
     }
+    
+    private static ElementKind simplifyElementKind(ElementKind kind) {
+        if (TreeShims.BINDING_VARIABLE.equals(kind.name())) {
+            return ElementKind.LOCAL_VARIABLE;
+        }
+        return kind;
+    }
 }
diff --git 
a/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/BindingUse.pass
 
b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/BindingUse.pass
new file mode 100644
index 0000000..7d77f8e
--- /dev/null
+++ 
b/java/java.completion/test/unit/data/goldenfiles/org/netbeans/modules/java/completion/JavaCompletionTaskTest/1.8/BindingUse.pass
@@ -0,0 +1 @@
+String str
diff --git 
a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/CompletionTestBase.java
 
b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/CompletionTestBase.java
index 744b831..7aca46d 100644
--- 
a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/CompletionTestBase.java
+++ 
b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/CompletionTestBase.java
@@ -212,7 +212,11 @@ public class CompletionTestBase extends 
CompletionTestBaseBase {
         public CI createVariableItem(CompilationInfo info, VariableElement 
elem, TypeMirror type, int substitutionOffset, ReferencesCount referencesCount, 
boolean isInherited, boolean isDeprecated, boolean smartType, int 
assignToVarOffset) {
             String varName = elem.getSimpleName().toString();
             String typeName = type != null ? 
info.getTypeUtilities().getTypeName(type).toString() : null;
-            switch (elem.getKind()) {
+            ElementKind ek = elem.getKind();
+            if (TreeShims.BINDING_VARIABLE.equals(ek.name())) {
+                ek = ElementKind.LOCAL_VARIABLE;
+            }
+            switch (ek) {
                 case LOCAL_VARIABLE:
                 case RESOURCE_VARIABLE:
                 case PARAMETER:
diff --git 
a/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask114FeaturesTest.java
 
b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask114FeaturesTest.java
new file mode 100644
index 0000000..1f4b212
--- /dev/null
+++ 
b/java/java.completion/test/unit/src/org/netbeans/modules/java/completion/JavaCompletionTask114FeaturesTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.completion;
+
+import javax.lang.model.SourceVersion;
+import org.netbeans.junit.NbTestSuite;
+import org.netbeans.modules.java.source.parsing.JavacParser;
+/**
+ *
+ * @author arusinha
+ */
+public class JavaCompletionTask114FeaturesTest extends CompletionTestBase {
+
+    private static String SOURCE_LEVEL = "14"; //NOI18N
+
+    public JavaCompletionTask114FeaturesTest(String testName) {
+        super(testName);
+    }
+
+    public static NbTestSuite suite() {
+        NbTestSuite suite = new NbTestSuite();
+        try {
+            SourceVersion.valueOf("RELEASE_14"); //NOI18N
+            suite.addTestSuite(JavaCompletionTask114FeaturesTest.class);
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_13, skip tests
+            suite.addTest(new JavaCompletionTask114FeaturesTest("noop")); 
//NOI18N
+        }
+        return suite;
+    }
+
+    public void testBindingUse() throws Exception {
+        performTest("GenericMethodInvocation", 1231, "boolean b = argO 
instanceof String str && st", "BindingUse.pass", SOURCE_LEVEL);
+    }
+
+    public void noop() {
+    }
+
+    static {
+        JavacParser.DISABLE_SOURCE_LEVEL_DOWNGRADE = true;
+    }
+}
diff --git 
a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/FindLocalUsagesQuery.java
 
b/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/FindLocalUsagesQuery.java
index 7ceac64..8a8e2cd 100644
--- 
a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/FindLocalUsagesQuery.java
+++ 
b/java/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,14 @@ public class FindLocalUsagesQuery extends 
CancellableTreePathScanner<Void, Stack
         }
         return super.visitImport(node, p);
     }
+
+    @Override
+    public Void scan(Tree tree, Stack<Tree> p) {
+        if (tree != null && "BINDING_PATTERN".equals(tree.getKind().name())) {
+            handlePotentialVariable(new TreePath(getCurrentPath(), tree));
+        }
+        return super.scan(tree, p);
+    }
+    
+    
 }
diff --git 
a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java
 
b/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java
index 7afa926..31cf35b 100644
--- 
a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java
+++ 
b/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/SemanticHighlighterBase.java
@@ -361,9 +361,24 @@ public abstract class SemanticHighlighterBase extends 
JavaParserResultTask {
         return c;
     }
     
+    private static final Set<ElementKind> LOCAL_VARIABLES = EnumSet.of(
+            ElementKind.LOCAL_VARIABLE, ElementKind.RESOURCE_VARIABLE,
+            ElementKind.EXCEPTION_PARAMETER);
+    private static final ElementKind BINDING_VARIABLE;
+
+    static {
+        ElementKind bindingVariable;
+        try {
+            LOCAL_VARIABLES.add(bindingVariable = 
ElementKind.valueOf(TreeShims.BINDING_VARIABLE));
+        } catch (IllegalArgumentException ex) {
+            bindingVariable = null;
+        }
+        BINDING_VARIABLE = bindingVariable;
+    }
+
     private static boolean isLocalVariableClosure(Element el) {
-        return el.getKind() == ElementKind.PARAMETER || el.getKind() == 
ElementKind.LOCAL_VARIABLE
-                || el.getKind() == ElementKind.RESOURCE_VARIABLE || 
el.getKind() == ElementKind.EXCEPTION_PARAMETER;
+        return el.getKind() == ElementKind.PARAMETER ||
+               LOCAL_VARIABLES.contains(el.getKind());
     }
     
     /** Detects static final long SerialVersionUID 
@@ -436,7 +451,11 @@ public abstract class SemanticHighlighterBase extends 
JavaParserResultTask {
         }
         
         private void firstIdentifier(String name) {
-            tl.firstIdentifier(getCurrentPath(), name, tree2Tokens);
+            firstIdentifier(getCurrentPath(), name);
+        }
+
+        private void firstIdentifier(TreePath path, String name) {
+            tl.firstIdentifier(path, name, tree2Tokens);
         }
         
         private Token firstIdentifierToken(String... names) {
@@ -537,8 +556,7 @@ public abstract class SemanticHighlighterBase extends 
JavaParserResultTask {
                 return c;
             }
             
-            if (decl.getKind() == ElementKind.LOCAL_VARIABLE || decl.getKind() 
== ElementKind.RESOURCE_VARIABLE
-                    || decl.getKind() == ElementKind.EXCEPTION_PARAMETER) {
+            if (LOCAL_VARIABLES.contains(decl.getKind())) {
                 c.add(ColoringAttributes.LOCAL_VARIABLE);
                 
                 return c;
@@ -684,7 +702,7 @@ public abstract class SemanticHighlighterBase extends 
JavaParserResultTask {
                         } else if 
(method.getModifiers().contains(Modifier.ABSTRACT) || 
method.getModifiers().contains(Modifier.NATIVE) || 
!method.getModifiers().contains(Modifier.PRIVATE)) {
                             type.add(UseTypes.READ);
                         }
-                    } else if (decl.getKind().isField() || decl.getKind() == 
ElementKind.EXCEPTION_PARAMETER) {
+                    } else if (decl.getKind().isField() || decl.getKind() == 
ElementKind.EXCEPTION_PARAMETER || decl.getKind() == BINDING_VARIABLE) {
                         type.add(UseTypes.WRITE);
                     } else if (parent.getLeaf().getKind() == 
Kind.ENHANCED_FOR_LOOP &&
                                ((EnhancedForLoopTree) 
parent.getLeaf()).getVariable() == currentPath.getLeaf()) {
@@ -1113,6 +1131,12 @@ public abstract class SemanticHighlighterBase extends 
JavaParserResultTask {
                 if (t != null) {
                     contextKeywords.add(t);
                 }
+            } else if (tree != null && 
TreeShims.BINDING_PATTERN.equals(tree.getKind().name())) {
+                super.scan(tree, p);
+                TreePath tp = new TreePath(getCurrentPath(), tree);
+                handlePossibleIdentifier(tp, true, 
info.getTrees().getElement(tp));
+                
tl.moveToOffset(sourcePositions.getEndPosition(getCurrentPath().getCompilationUnit(),
 TreeShims.getBindingPatternType(tree)));
+                firstIdentifier(tp, TreeShims.getBinding(tree).toString());
             }
             return super.scan(tree, p);
         }
diff --git 
a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/Utilities.java
 
b/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/Utilities.java
index d3d4837..b00504a 100644
--- 
a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/Utilities.java
+++ 
b/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/Utilities.java
@@ -26,6 +26,7 @@ import com.sun.source.tree.ClassTree;
 import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.tree.ContinueTree;
 import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.InstanceOfTree;
 import com.sun.source.tree.LabeledStatementTree;
 import com.sun.source.tree.MemberReferenceTree;
 import com.sun.source.tree.MemberSelectTree;
@@ -237,6 +238,37 @@ public class Utilities {
         return null;
     }
 
+    private static Token<JavaTokenId> 
findIdentifierSpanImplForBindingPattern(CompilationInfo info, Tree tree, 
CompilationUnitTree cu, SourcePositions positions) {
+        int start = (int)positions.getStartPosition(cu, tree);
+        int endPosition = (int)positions.getEndPosition(cu, tree);
+        
+        if (start == (-1) || endPosition == (-1))
+            return null;
+
+        String member = TreeShims.getBinding(tree).toString();
+
+        TokenHierarchy<?> th = info.getTokenHierarchy();
+        TokenSequence<JavaTokenId> ts = 
th.tokenSequence(JavaTokenId.language());
+
+        if (ts.move(endPosition) == Integer.MAX_VALUE) {
+            return null;
+        }
+
+        if (ts.moveNext()) {
+            while (ts.offset() >= start) {
+                Token<JavaTokenId> t = ts.token();
+
+                if (t.id() == JavaTokenId.IDENTIFIER && 
member.equals(info.getTreeUtilities().decodeIdentifier(t.text()).toString())) {
+                    return t;
+                }
+
+                if (!ts.movePrevious())
+                    break;
+            }
+        }
+        return null;
+    }
+
     private static final Map<Class, List<Kind>> class2Kind;
     
     static {
@@ -370,7 +402,32 @@ public class Utilities {
             
            return findTokenWithText(info, name.toString(), start, end);
         }
-        throw new IllegalArgumentException("Only MethodDecl, VariableDecl, 
MemberSelectTree, IdentifierTree, ParameterizedTypeTree, AnnotatedTypeTree, 
ClassDecl, BreakTree, ContinueTree, and LabeledStatementTree are accepted by 
this method. Got: " + leaf.getKind());
+        if (class2Kind.get(InstanceOfTree.class).contains(leaf.getKind())) {
+            Tree pattern = TreeShims.getPattern((InstanceOfTree) leaf);
+
+            if (pattern == null || 
!"BINDING_PATTERN".equals(pattern.getKind().name()))
+                return null;
+
+            Name name = TreeShims.getBinding(pattern);
+
+            if (name == null || name.length() == 0)
+                return null;
+
+            SourcePositions positions = info.getTrees().getSourcePositions();
+            CompilationUnitTree cu = info.getCompilationUnit();
+            int start = (int)positions.getEndPosition(cu, ((InstanceOfTree) 
leaf).getType());
+            int end   = (int)positions.getEndPosition(cu, pattern);
+
+            if (start == (-1) || end == (-1)) {
+                return null;
+            }
+
+           return findTokenWithText(info, name.toString(), start, end);
+        }
+        if ("BINDING_PATTERN".equals(leaf.getKind().name())) {
+            return findIdentifierSpanImplForBindingPattern(info, leaf, 
info.getCompilationUnit(), info.getTrees().getSourcePositions());
+        }
+        throw new IllegalArgumentException("Only MethodDecl, VariableDecl, 
MemberSelectTree, IdentifierTree, ParameterizedTypeTree, AnnotatedTypeTree, 
ClassDecl, BreakTree, ContinueTree, LabeledStatementTree and BindingPatternTree 
are accepted by this method. Got: " + leaf.getKind());
     }
 
     public static int[] findIdentifierSpan( final TreePath decl, final 
CompilationInfo info, final Document doc) {
@@ -564,7 +621,8 @@ public class Utilities {
         
         //XXX: do not use instanceof:
         if (leaf instanceof MethodTree || leaf instanceof VariableTree || leaf 
instanceof ClassTree
-                || leaf instanceof MemberSelectTree || leaf instanceof 
AnnotatedTypeTree || leaf instanceof MemberReferenceTree) {
+                || leaf instanceof MemberSelectTree || leaf instanceof 
AnnotatedTypeTree || leaf instanceof MemberReferenceTree
+                || "BINDING_PATTERN".equals(leaf.getKind().name())) {
             return findIdentifierSpan(info, doc, tree);
         }
         
@@ -653,6 +711,12 @@ public class Utilities {
     }
 
     private static final Set<ElementKind> LOCAL_ELEMENT_KINDS = 
EnumSet.of(ElementKind.PARAMETER, ElementKind.LOCAL_VARIABLE, 
ElementKind.EXCEPTION_PARAMETER, ElementKind.RESOURCE_VARIABLE);
+    
+    static {
+        try {
+            
LOCAL_ELEMENT_KINDS.add(ElementKind.valueOf(TreeShims.BINDING_VARIABLE));
+        } catch (IllegalArgumentException ignore) {}
+    }
 
     public static boolean isPrivateElement(Element el) {
         return LOCAL_ELEMENT_KINDS.contains(el.getKind()) || 
el.getModifiers().contains(Modifier.PRIVATE);
diff --git 
a/java/java.editor.base/test/unit/data/goldenfiles/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest/testErroneousMethodNETBEANS_224.pass
 
b/java/java.editor.base/test/unit/data/goldenfiles/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest/testErroneousMethodNETBEANS_224.pass
new file mode 100644
index 0000000..e69de29
diff --git 
a/java/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java
 
b/java/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java
index afa9052..84bd5fd 100644
--- 
a/java/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java
+++ 
b/java/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/DetectorTest.java
@@ -528,6 +528,7 @@ public class DetectorTest extends TestBase {
             SourceVersion.valueOf("RELEASE_13");
         } catch (IllegalArgumentException iae) {
             //OK, presumably no support for raw string literals
+            return ;
         }
         setSourceLevel("13");
         performTest("RawStringLiteral",
@@ -552,6 +553,31 @@ public class DetectorTest extends TestBase {
                     "[UNINDENTED_TEXT_BLOCK], 7:16-7:29");
     }
 
+    public void testBindingPattern() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14");
+        } catch (IllegalArgumentException iae) {
+            //OK, presumably no support for pattern matching
+            return ;
+        }
+        setSourceLevel("14");
+        performTest("BindingPattern",
+                    "public class BindingPattern {\n" +
+                    "    public boolean test(Object o) {\n" +
+                    "        return o instanceof String str && 
str.isEmpty();\n" +
+                    "    }\n" +
+                    "}\n",
+                    "[PUBLIC, CLASS, DECLARATION], 0:13-0:27",
+                    "[PUBLIC, METHOD, DECLARATION], 1:19-1:23",
+                    "[PUBLIC, CLASS], 1:24-1:30",
+                    "[PARAMETER, DECLARATION], 1:31-1:32",
+                    "[PARAMETER], 2:15-2:16",
+                    "[PUBLIC, CLASS], 2:28-2:34",
+                    "[LOCAL_VARIABLE, DECLARATION], 2:35-2:38",
+                    "[LOCAL_VARIABLE], 2:42-2:45",
+                    "[PUBLIC, METHOD], 2:46-2:53");
+    }
+
     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/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest.java
 
b/java/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest.java
index 63f5b27..29b188e 100644
--- 
a/java/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest.java
+++ 
b/java/java.editor.base/test/unit/src/org/netbeans/modules/java/editor/base/semantic/MarkOccDetTest.java
@@ -21,6 +21,7 @@ package org.netbeans.modules.java.editor.base.semantic;
 import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
+import javax.lang.model.SourceVersion;
 import javax.swing.text.Document;
 import javax.swing.text.StyledDocument;
 import junit.framework.Test;
@@ -324,6 +325,30 @@ public class MarkOccDetTest extends TestBase {
         performTest("ErroneousMethod", 3, 24);
     }
 
+    public void testMatchBindings() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_14, skip tests
+            return ;
+        }
+        performTest("MatchBindings.java",
+                    "public class MatchBindings {\n" +
+                    "    public boolean t(Object o) {\n" +
+                    "        if (o instanceof String str && str.isEmpty()) 
{\n" +
+                    "            return str.equals(str);\n" +
+                    "        }\n" +
+                    "        return false;\n" +
+                    "    }\n" +
+                    "}\n",
+                   3,
+                   33,
+                   "[MARK_OCCURRENCES], 2:32-2:35",
+                   "[MARK_OCCURRENCES], 2:39-2:42",
+                   "[MARK_OCCURRENCES], 3:19-3:22",
+                   "[MARK_OCCURRENCES], 3:30-3:33");
+    }
+
     //Support for exotic identifiers has been removed 6999438
     public void REMOVEDtestExoticIdentifiers1() throws Exception {
         performTest("ExoticIdentifier", 3, 43);
@@ -370,4 +395,25 @@ public class MarkOccDetTest extends TestBase {
         }, doCompileRecursively);
     }
     
+    private void performTest(String fileName, String code, final int line, 
final int column, String... expected) throws Exception {
+        performTest(fileName, code, new Performer() {
+            public void compute(CompilationController info, Document doc, 
SemanticHighlighterBase.ErrorDescriptionSetter setter) {
+                int offset = NbDocument.findLineOffset((StyledDocument) doc, 
line) + column;
+                List<int[]> spans = new MarkOccurrencesHighlighterBase() {
+                    @Override
+                    protected void process(CompilationInfo info, Document doc, 
SchedulerEvent event) {
+                        throw new UnsupportedOperationException("Not supported 
yet.");
+                    }
+                }.processImpl(info, MarkOccurencesSettings.getCurrentNode(), 
doc, offset);
+                
+                if (spans != null) {
+                    setter.setHighlights(doc, spans.stream()
+                                                   .map(span -> Pair.of(span, 
MARK_OCCURRENCES))
+                                                   
.collect(Collectors.toList()),
+                                         Collections.<int[], 
String>emptyMap());
+                }
+            }
+        }, expected);
+    }
+
 }
diff --git 
a/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java 
b/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
index 903420f..c14b719 100644
--- a/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
+++ b/java/java.editor/src/org/netbeans/modules/editor/java/GoToSupport.java
@@ -24,6 +24,7 @@ import com.sun.source.tree.ExportsTree;
 import com.sun.source.tree.ExpressionTree;
 import com.sun.source.tree.IdentifierTree;
 import com.sun.source.tree.ImportTree;
+import com.sun.source.tree.InstanceOfTree;
 import com.sun.source.tree.MemberSelectTree;
 import com.sun.source.tree.MethodInvocationTree;
 import com.sun.source.tree.MethodTree;
@@ -668,6 +669,11 @@ public class GoToSupport {
     private static boolean isCaretInsideDeclarationName(CompilationInfo info, 
Tree t, TreePath path, int caret) {
         try {
             switch (t.getKind()) {
+                case INSTANCE_OF:
+                    Tree pattern = TreeShims.getPattern((InstanceOfTree) t);
+                    if (pattern == null || 
!"BINDING_PATTERN".equals(pattern.getKind().name())) {
+                        return false;
+                    }
                 case ANNOTATION_TYPE:
                 case CLASS:
                 case ENUM:
@@ -737,10 +743,18 @@ public class GoToSupport {
                 if (found != null) {
                     return null;
                 }
+                if (tree != null && 
"BINDING_PATTERN".equals(tree.getKind().name())) {
+                    if (process(new TreePath(getCurrentPath(), tree))) {
+                        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();
                     return true;
@@ -909,7 +923,8 @@ public class GoToSupport {
                 Element enclosing = e.getEnclosingElement();
                 
                 if (e.getKind() != ElementKind.PARAMETER && e.getKind() != 
ElementKind.LOCAL_VARIABLE
-                        && e.getKind() != ElementKind.RESOURCE_VARIABLE && 
e.getKind() != ElementKind.EXCEPTION_PARAMETER) {
+                        && e.getKind() != ElementKind.RESOURCE_VARIABLE && 
e.getKind() != ElementKind.EXCEPTION_PARAMETER
+                        && 
!TreeShims.BINDING_VARIABLE.equals(e.getKind().name())) {
                     result.append(" in ");
 
                     //short typename:
diff --git 
a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItem.java 
b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItem.java
index e644d96..39c1387 100644
--- 
a/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItem.java
+++ 
b/java/java.editor/src/org/netbeans/modules/editor/java/JavaCompletionItem.java
@@ -156,7 +156,11 @@ public abstract class JavaCompletionItem implements 
CompletionItem {
     }
 
     public static JavaCompletionItem createVariableItem(CompilationInfo info, 
VariableElement elem, TypeMirror type, TypeMirror castType, int 
substitutionOffset, ReferencesCount referencesCount, boolean isInherited, 
boolean isDeprecated, boolean smartType, int assignToVarOffset, 
WhiteListQuery.WhiteList whiteList) {
-        switch (elem.getKind()) {
+        ElementKind ek = elem.getKind();
+        if ("BINDING_VARIABLE".equals(ek.name())) {
+            ek = ElementKind.LOCAL_VARIABLE;
+        }
+        switch (ek) {
             case LOCAL_VARIABLE:
             case RESOURCE_VARIABLE:
             case PARAMETER:
diff --git 
a/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java
 
b/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java
index 8b423ad..da1a6b2 100644
--- 
a/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java
+++ 
b/java/java.editor/test/unit/src/org/netbeans/modules/editor/java/GoToSupportTest.java
@@ -1049,6 +1049,108 @@ public class GoToSupportTest extends NbTestCase {
         assertTrue(wasCalled[0]);
     }
 
+    public void testBindingVar() throws Exception {
+        if (hasPatterns()) return ;
+        final boolean[] wasCalled = new boolean[1];
+        this.sourceLevel = "14";
+        final String code = "package test;\n" +
+                      "public class Test {\n" +
+                      "    private static void method(Object o) {\n" +
+                      "        if (o instanceof String str) {\n" +
+                      "            System.err.println(s|tr);\n" +
+                      "        }\n" +
+                      "    }\n" +
+                      "}\n";
+
+        performTest(code, new UiUtilsCaller() {
+            @Override public boolean open(FileObject fo, int pos) {
+                assertTrue(source == fo);
+                assertEquals(code.indexOf("o instanceof String str"), pos);
+                wasCalled[0] = true;
+                return true;
+            }
+
+            @Override public void beep(boolean goToSource, boolean 
goToJavadoc) {
+                fail("Should not be called.");
+            }
+            @Override public boolean open(ClasspathInfo info, ElementHandle<?> 
el) {
+                fail("Should not be called.");
+                return true;
+            }
+            @Override public void warnCannotOpen(String displayName) {
+                fail("Should not be called.");
+            }
+        }, false, false);
+
+        assertTrue(wasCalled[0]);
+    }
+
+    public void testBindingVarInName() throws Exception {
+        if (hasPatterns()) return ;
+        final boolean[] wasCalled = new boolean[1];
+        this.sourceLevel = "14";
+        final String code = "package test;\n" +
+                      "public class Test {\n" +
+                      "    private static void method(Object o) {\n" +
+                      "        if (o instanceof String s|tr) {\n" +
+                      "        }\n" +
+                      "    }\n" +
+                      "}\n";
+
+        performTest(code, new UiUtilsCaller() {
+            @Override public boolean open(FileObject fo, int pos) {
+                fail("Should not be called.");
+                return true;
+            }
+
+            @Override public void beep(boolean goToSource, boolean 
goToJavadoc) {
+                wasCalled[0] = true;
+            }
+            @Override public boolean open(ClasspathInfo info, ElementHandle<?> 
el) {
+                fail("Should not be called.");
+                return true;
+            }
+            @Override public void warnCannotOpen(String displayName) {
+                fail("Should not be called.");
+            }
+        }, false, false);
+
+        assertTrue(wasCalled[0]);
+    }
+
+    public void testBindingVarToolTip() throws Exception {
+        if (hasPatterns()) return ;
+        final boolean[] wasCalled = new boolean[1];
+        this.sourceLevel = "14";
+        final String code = "package test;\n" +
+                      "public class Test {\n" +
+                      "    private static void method(Object o) {\n" +
+                      "        if (o instanceof String s|tr) {\n" +
+                      "        }\n" +
+                      "    }\n" +
+                      "}\n";
+
+        String tooltip = performTest(code, new UiUtilsCaller() {
+            @Override public boolean open(FileObject fo, int pos) {
+                fail("Should not be called.");
+                return true;
+            }
+
+            @Override public void beep(boolean goToSource, boolean 
goToJavadoc) {
+                wasCalled[0] = true;
+            }
+            @Override public boolean open(ClasspathInfo info, ElementHandle<?> 
el) {
+                fail("Should not be called.");
+                return true;
+            }
+            @Override public void warnCannotOpen(String displayName) {
+                fail("Should not be called.");
+            }
+        }, true, false);
+
+        assertEquals("<html><body>final java.lang.String <b>str</b>", tooltip);
+    }
+
     private String sourceLevel = "1.5";
     private FileObject source;
     
@@ -1171,4 +1273,13 @@ public class GoToSupportTest extends NbTestCase {
         
     }
     
+    private static boolean hasPatterns() {
+        try {
+            SourceVersion.valueOf("RELEASE_14"); //NOI18N
+            return true;
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_14, skip tests
+            return false;
+        }
+    }
 }
diff --git 
a/java/java.editor/test/unit/src/org/netbeans/modules/java/editor/rename/InstantRenamePerformerTest.java
 
b/java/java.editor/test/unit/src/org/netbeans/modules/java/editor/rename/InstantRenamePerformerTest.java
index dbbfe2f..4930bfa 100644
--- 
a/java/java.editor/test/unit/src/org/netbeans/modules/java/editor/rename/InstantRenamePerformerTest.java
+++ 
b/java/java.editor/test/unit/src/org/netbeans/modules/java/editor/rename/InstantRenamePerformerTest.java
@@ -23,6 +23,7 @@ import java.awt.event.KeyEvent;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.regex.Pattern;
+import javax.lang.model.SourceVersion;
 import javax.swing.JEditorPane;
 import javax.swing.JFrame;
 import javax.swing.event.ChangeEvent;
@@ -181,6 +182,17 @@ public class InstantRenamePerformerTest extends NbTestCase 
{
         performTest("package test; public class Test { public <T|T> void 
test(TT t) { } }", 64 - 22, ke, - 1, "package test; public class Test { public 
<RTT> void test(RTT t) { } }", true);
     }
 
+    public void testPatternBinding() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_14, skip tests
+            return ;
+        }
+        KeyEvent ke = new KeyEvent(new JFrame(), KeyEvent.KEY_TYPED, 0, 0, 
KeyEvent.VK_UNDEFINED, 'a');
+        performTest("package test; public class Test { public void test(Object 
o) {boolean b = o instanceof String s|tr && str.isEmpty(); } }", 117 - 22, ke, 
"package test; public class Test { public void test(Object o) {boolean b = o 
instanceof String satr && satr.isEmpty(); } }", true);
+    }
+
     private void performTest(String sourceCode, int offset, KeyEvent ke, 
String golden, boolean stillInRename) throws Exception {
         performTest(sourceCode, offset, ke, -1, golden, stillInRename);
     }
diff --git 
a/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToPatternInstanceOf.java
 
b/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToPatternInstanceOf.java
new file mode 100644
index 0000000..90699b4
--- /dev/null
+++ 
b/java/java.hints/src/org/netbeans/modules/java/hints/jdk/ConvertToPatternInstanceOf.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.hints.jdk;
+
+import com.sun.source.tree.BlockTree;
+import com.sun.source.tree.IfTree;
+import com.sun.source.tree.InstanceOfTree;
+import com.sun.source.tree.ParenthesizedTree;
+import com.sun.source.tree.StatementTree;
+import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
+import com.sun.source.tree.TypeCastTree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.TreePath;
+import com.sun.source.util.TreePathScanner;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.type.TypeMirror;
+import org.netbeans.api.java.source.CodeStyle;
+import org.netbeans.api.java.source.CompilationInfo;
+import org.netbeans.api.java.source.TreePathHandle;
+import org.netbeans.api.java.source.WorkingCopy;
+import org.netbeans.modules.java.hints.errors.Utilities;
+import org.netbeans.spi.editor.hints.ErrorDescription;
+import org.netbeans.spi.editor.hints.Fix;
+import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
+import org.netbeans.spi.java.hints.Hint;
+import org.netbeans.spi.java.hints.HintContext;
+import org.netbeans.spi.java.hints.JavaFix;
+import org.netbeans.spi.java.hints.MatcherUtilities;
+import org.netbeans.spi.java.hints.TriggerPattern;
+import org.netbeans.spi.java.hints.TriggerPatterns;
+import org.openide.util.NbBundle;
+
+/**
+ *
+ * @author sdedic
+ */
[email protected]({
+    "DN_ConvertToPatternInstanceOf=Convert to instanceof <pattern>",
+    "DESC_ConvertToPatternInstanceOf=Convert to instanceof <pattern>",
+    "ERR_ConvertToPatternInstanceOf=instanceof <pattern> can be used here",
+    "FIX_ConvertToPatternInstanceOf=Use instanceof <pattern>"
+})
+@Hint(displayName="#DN_ConvertToPatternInstanceOf", 
description="#DESC_ConvertToPatternInstanceOf", category="rules15")
+public class ConvertToPatternInstanceOf {
+    
+    @TriggerPatterns({
+        @TriggerPattern(value="if ($expr instanceof $typeI) { $statements$;} 
else $else$;"),
+    })
+    public static ErrorDescription trivial(HintContext ctx) {
+        //XXX: sideeffects in $expr
+        if (!MatcherUtilities.matches(ctx, ctx.getPath(), "if ($expr 
instanceof $typeI) { $typeV $var = ($typeC) $expr; $other$;} else $else$;", 
true)) {
+            Set<TreePath> convertPath = new HashSet<>();
+            new TreePathScanner<Void, Void>() {
+                @Override
+                public Void visitTypeCast(TypeCastTree node, Void p) {
+                    if (MatcherUtilities.matches(ctx, getCurrentPath(), 
/*TODO: different type*/"($typeI) $expr")) {
+                        convertPath.add(getCurrentPath());
+                    }
+                    return super.visitTypeCast(node, p);
+                }
+            }.scan(ctx.getPath(), null);
+            if (!convertPath.isEmpty()) {
+                TreePath typeI = ctx.getVariables().get("$typeI");
+                TypeMirror typeITM = 
ctx.getInfo().getTrees().getTypeMirror(typeI);
+                List<String> varNameCandidates = 
org.netbeans.modules.editor.java.Utilities.varNamesSuggestions(typeITM, 
ElementKind.LOCAL_VARIABLE, EnumSet.noneOf(Modifier.class), null, null, 
ctx.getInfo().getTypes(), ctx.getInfo().getElements(), Collections.emptyList(), 
CodeStyle.getDefault(ctx.getInfo().getFileObject()));
+                String varName = Utilities.makeNameUnique(ctx.getInfo(), 
ctx.getInfo().getTrees().getScope(ctx.getPath()), varNameCandidates.get(0));
+                Fix fix = new FixImpl(ctx.getInfo(), ctx.getPath(), varName, 
false, convertPath).toEditorFix();
+
+                return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), 
Bundle.ERR_ConvertToPatternInstanceOf(), fix);
+            }
+            return null;
+        }
+        if (ctx.getMultiVariables().get("$other$").isEmpty()) {
+            return null; //could be solved, but what's the point?
+        }
+        TypeMirror typeI = 
ctx.getInfo().getTrees().getTypeMirror(ctx.getVariables().get("$typeI"));
+        TypeMirror typeC = 
ctx.getInfo().getTrees().getTypeMirror(ctx.getVariables().get("$typeC"));
+        if (!ctx.getInfo().getTypes().isSameType(typeI, typeC)) {
+            System.err.println("different types (" + typeI + ", " + typeC + ") 
in " + ctx.getInfo().getFileObject());
+            return null;
+        }
+        IfTree it = (IfTree) ctx.getPath().getLeaf();
+        BlockTree bt = (BlockTree) it.getThenStatement();
+        VariableTree var = (VariableTree) bt.getStatements().get(0);
+        Fix fix = new FixImpl(ctx.getInfo(), ctx.getPath(), 
var.getName().toString(), true, Collections.emptySet()).toEditorFix();
+        
+        return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), 
Bundle.ERR_ConvertToPatternInstanceOf(), fix);
+    }
+
+    private static final class FixImpl extends JavaFix {
+
+        private final String varName;
+        private final boolean removeFirst;
+        private final Set<TreePathHandle> replaceOccurrences;
+
+        public FixImpl(CompilationInfo info, TreePath main, String varName, 
boolean removeFirst, Set<TreePath> replaceOccurrences) {
+            super(info, main);
+            this.varName = varName;
+            this.removeFirst = removeFirst;
+            this.replaceOccurrences = replaceOccurrences.stream().map(tp -> 
TreePathHandle.create(tp, info)).collect(Collectors.toSet());
+        }
+
+
+        @Override
+        protected String getText() {
+            return Bundle.FIX_ConvertToPatternInstanceOf();
+        }
+
+        @Override
+        protected void performRewrite(JavaFix.TransformationContext ctx) {
+            WorkingCopy wc = ctx.getWorkingCopy();
+            TreePath main = ctx.getPath();
+            IfTree it = (IfTree) main.getLeaf();
+            InstanceOfTree iot = (InstanceOfTree) ((ParenthesizedTree) 
it.getCondition()).getExpression();
+            StatementTree bt = it.getThenStatement();
+//            wc.rewrite(iot.getType(), 
wc.getTreeMaker().BindingPattern(var.getName(), iot.getType()));
+//            wc.rewrite(bt, wc.getTreeMaker().removeBlockStatement(bt, 0));
+            InstanceOfTree cond = 
wc.getTreeMaker().InstanceOf(iot.getExpression(), 
wc.getTreeMaker().BindingPattern(varName, iot.getType()));
+            StatementTree thenBlock = removeFirst ? 
wc.getTreeMaker().removeBlockStatement((BlockTree) bt, 0) : bt;
+            wc.rewrite(it, 
wc.getTreeMaker().If(wc.getTreeMaker().Parenthesized(cond), thenBlock, 
it.getElseStatement()));
+            replaceOccurrences.stream().map(tph -> tph.resolve(wc)).forEach(tp 
-> {
+                if (!removeFirst && tp.getParentPath().getLeaf().getKind() == 
Kind.PARENTHESIZED) {
+                    tp = tp.getParentPath();
+                }
+                wc.rewrite(tp.getLeaf(), 
wc.getTreeMaker().Identifier(varName));
+            });
+        }
+
+    }
+
+}
diff --git 
a/java/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToPatternInstanceOfTest.java
 
b/java/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToPatternInstanceOfTest.java
new file mode 100644
index 0000000..0db6d7f
--- /dev/null
+++ 
b/java/java.hints/test/unit/src/org/netbeans/modules/java/hints/jdk/ConvertToPatternInstanceOfTest.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.java.hints.jdk;
+
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.java.hints.test.api.HintTest;
+
+/**
+ *
+ * @author lahvac
+ */
+public class ConvertToPatternInstanceOfTest extends NbTestCase {
+    
+    public ConvertToPatternInstanceOfTest(String name) {
+        super(name);
+    }
+    
+    public void testSimple() throws Exception {
+        HintTest.create()
+                .input("package test;\n" +
+                       "public class Test {\n" +
+                       "    private int test(Object o) {\n" +
+                       "        if (o instanceof String) {\n" +
+                       "            String s = (String) o;\n" +
+                       "            return s.length();\n" +
+                       "        }\n" +
+                       "        return -1;\n" +
+                       "    }\n" +
+                       "}\n")
+                .run(ConvertToPatternInstanceOf.class)
+                .findWarning("3:8-3:10:verifier:" + 
Bundle.ERR_ConvertToPatternInstanceOf())
+                .applyFix()
+                .assertCompilable()
+                .assertOutput("package test;\n" +
+                              "public class Test {\n" +
+                              "    private int test(Object o) {\n" +
+                              "        if (o instanceof String s) {\n" +
+                              "            return s.length();\n" +
+                              "        }\n" +
+                              "        return -1;\n" +
+                              "    }\n" +
+                              "}\n");
+    }
+
+    public void testWithElse() throws Exception {
+        HintTest.create()
+                .input("package test;\n" +
+                       "public class Test {\n" +
+                       "    private int test(Object o) {\n" +
+                       "        if (o instanceof String) {\n" +
+                       "            String s = (String) o;\n" +
+                       "            return s.length();\n" +
+                       "        } else {\n" +
+                       "            return -1;\n" +
+                       "        }\n" +
+                       "    }\n" +
+                       "}\n")
+                .run(ConvertToPatternInstanceOf.class)
+                .findWarning("3:8-3:10:verifier:" + 
Bundle.ERR_ConvertToPatternInstanceOf())
+                .applyFix()
+                .assertCompilable()
+                .assertOutput("package test;\n" +
+                              "public class Test {\n" +
+                              "    private int test(Object o) {\n" +
+                              "        if (o instanceof String s) {\n" +
+                              "            return s.length();\n" +
+                              "        } else {\n" +
+                              "            return -1;\n" +
+                              "        }\n" +
+                              "    }\n" +
+                              "}\n");
+    }
+
+    public void testNoSoSimple() throws Exception {
+        HintTest.create()
+                .input("package test;\n" +
+                       "public class Test {\n" +
+                       "    private int test(Object o) {\n" +
+                       "        if (o instanceof String) {\n" +
+                       "            return ((String) o).length();\n" +
+                       "        }\n" +
+                       "        return -1;\n" +
+                       "    }\n" +
+                       "}\n")
+                .run(ConvertToPatternInstanceOf.class)
+                .findWarning("3:8-3:10:verifier:" + 
Bundle.ERR_ConvertToPatternInstanceOf())
+                .applyFix()
+                .assertCompilable()
+                .assertOutput("package test;\n" +
+                              "public class Test {\n" +
+                              "    private int test(Object o) {\n" +
+                              "        if (o instanceof String string) {\n" +
+                              "            return string.length();\n" +
+                              "        }\n" +
+                              "        return -1;\n" +
+                              "    }\n" +
+                              "}\n");
+    }
+
+    public void testNoSoSimpleNameClash() throws Exception {
+        HintTest.create()
+                .input("package test;\n" +
+                       "public class Test {\n" +
+                       "    private int test(Object o, String string) {\n" +
+                       "        if (o instanceof String) {\n" +
+                       "            return ((String) o).length();\n" +
+                       "        }\n" +
+                       "        return -1;\n" +
+                       "    }\n" +
+                       "}\n")
+                .run(ConvertToPatternInstanceOf.class)
+                .findWarning("3:8-3:10:verifier:" + 
Bundle.ERR_ConvertToPatternInstanceOf())
+                .applyFix()
+                .assertCompilable()
+                .assertOutput("package test;\n" +
+                              "public class Test {\n" +
+                              "    private int test(Object o, String string) 
{\n" +
+                              "        if (o instanceof String string1) {\n" +
+                              "            return string1.length();\n" +
+                              "        }\n" +
+                              "        return -1;\n" +
+                              "    }\n" +
+                              "}\n");
+    }
+
+}
diff --git 
a/java/java.source.base/src/org/netbeans/api/java/source/TreeMaker.java 
b/java/java.source.base/src/org/netbeans/api/java/source/TreeMaker.java
index 36592c8..78710dc 100644
--- a/java/java.source.base/src/org/netbeans/api/java/source/TreeMaker.java
+++ b/java/java.source.base/src/org/netbeans/api/java/source/TreeMaker.java
@@ -1211,6 +1211,20 @@ public final class TreeMaker {
     }
     
     /**
+     * Creates a new BindingPatternTree.
+     *
+     * @param name name of the binding variable
+     * @param type the type of the pattern
+     * @return the newly created BindingPatternTree
+     * @throws NoSuchMethodException if the used javac does not support
+     *                               BindingPatternTree.
+     */
+    public Tree BindingPattern(CharSequence name,
+                               Tree type) {
+        return delegate.BindingPattern(name, type);
+    }
+
+    /**
      * Creates a new VariableTree from a VariableElement.
      *
      * @param variable the VariableElement to reference.
diff --git 
a/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java 
b/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
index 824ac75..55e1a6a 100644
--- a/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
+++ b/java/java.source.base/src/org/netbeans/modules/java/source/TreeShims.java
@@ -21,6 +21,7 @@ package org.netbeans.modules.java.source;
 import com.sun.source.tree.BreakTree;
 import com.sun.source.tree.CaseTree;
 import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.InstanceOfTree;
 import com.sun.source.tree.SwitchTree;
 import com.sun.source.tree.Tree;
 import com.sun.tools.javac.tree.JCTree;
@@ -31,11 +32,15 @@ import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import javax.lang.model.element.Name;
+import org.openide.util.Exceptions;
 
 public class TreeShims {
 
+    public static final String BINDING_PATTERN = "BINDING_PATTERN"; //NOI18N
     public static final String SWITCH_EXPRESSION = "SWITCH_EXPRESSION"; 
//NOI18N
     public static final String YIELD = "YIELD"; //NOI18N
+    public static final String BINDING_VARIABLE = "BINDING_VARIABLE"; //NOI18N
 
     public static List<? extends ExpressionTree> getExpressions(CaseTree node) 
{
         try {
@@ -59,6 +64,17 @@ public class TreeShims {
         }
     }
 
+    public static Tree getPattern(InstanceOfTree node) {
+        try {
+            Method getPattern = 
InstanceOfTree.class.getDeclaredMethod("getPattern");
+            return (Tree) getPattern.invoke(node);
+        } catch (NoSuchMethodException ex) {
+            return null;
+        } catch (IllegalAccessException | IllegalArgumentException | 
InvocationTargetException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+    }
+
     public static List<? extends ExpressionTree> getExpressions(Tree node) {
         List<? extends ExpressionTree> exprTrees = new ArrayList<>();
 
@@ -116,6 +132,18 @@ public class TreeShims {
         }
     }
 
+    public static Name getBinding(Tree node) {
+        try {
+            Class bpt = 
Class.forName("com.sun.source.tree.BindingPatternTree");
+            Method getBinding = bpt.getDeclaredMethod("getBinding");
+            return (Name) getBinding.invoke(node);
+        } catch (NoSuchMethodException | ClassNotFoundException ex) {
+            return null;
+        } catch (IllegalAccessException | IllegalArgumentException | 
InvocationTargetException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+    }
+
     public static ExpressionTree getYieldValue(Tree node) {
         if (!node.getKind().toString().equals(YIELD)) {
             return null;
@@ -144,6 +172,21 @@ public class TreeShims {
         }
     }
   
+    public static Tree getBindingPatternType(Tree node) {
+        if (!node.getKind().toString().equals(BINDING_PATTERN)) {
+            return null;
+        }
+        try {
+            Class bindingPatternTreeClass = 
Class.forName("com.sun.source.tree.BindingPatternTree"); //NOI18N
+            Method getType = 
bindingPatternTreeClass.getDeclaredMethod("getType");  //NOI18N
+            return (Tree) getType.invoke(node);
+        } catch (NoSuchMethodException ex) {
+            return null;
+        } catch (IllegalAccessException | IllegalArgumentException | 
InvocationTargetException | ClassNotFoundException ex) {
+            throw TreeShims.<RuntimeException>throwAny(ex);
+        }
+    }
+
     @SuppressWarnings("unchecked")
     private static <T extends Throwable> RuntimeException throwAny(Throwable 
t) throws T {
         throw (T) t;
diff --git 
a/java/java.source.base/src/org/netbeans/modules/java/source/TreeShimsCopier.java
 
b/java/java.source.base/src/org/netbeans/modules/java/source/TreeShimsCopier.java
index 3633bdb..00aa9e6 100644
--- 
a/java/java.source.base/src/org/netbeans/modules/java/source/TreeShimsCopier.java
+++ 
b/java/java.source.base/src/org/netbeans/modules/java/source/TreeShimsCopier.java
@@ -96,5 +96,7 @@ public class TreeShimsCopier extends AbstractProcessor {
     private static final Map<String, String> ALLOWED_CLASSES2TARGET_PACKAGE = 
new HashMap<String, String>() {{
         
put("org.netbeans.modules.java.hints.infrastructure.ErrorHintsProvider", 
"org.netbeans.modules.java.hints");
         put("org.netbeans.modules.java.completion.JavaCompletionTask", 
"org.netbeans.modules.java.completion");
+        put("org.netbeans.modules.editor.java.GoToSupport", 
"org.netbeans.modules.editor.java");
+        
put("org.netbeans.modules.java.editor.base.semantic.SemanticHighlighterBase", 
"org.netbeans.modules.java.editor.base.semantic");
     }};
 }
diff --git 
a/java/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java
 
b/java/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java
index 1e89e99..6feef55 100644
--- 
a/java/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java
+++ 
b/java/java.source.base/src/org/netbeans/modules/java/source/builder/TreeFactory.java
@@ -913,6 +913,15 @@ public class TreeFactory {
                            (JCExpression)type, (JCExpression)initializer);
     }
     
+    public Tree BindingPattern(CharSequence name,
+                               Tree type) {
+        try {
+            return (Tree) make.getClass().getMethod("BindingPattern", 
Name.class, JCTree.class).invoke(make.at(NOPOS), 
names.fromString(name.toString()), type);
+        } catch (Throwable t) {
+            throw throwAny(t);
+        }
+    }
+
     public VariableTree Variable(VariableElement variable, ExpressionTree 
initializer) {
         return make.at(NOPOS).VarDef((Symbol.VarSymbol)variable, 
(JCExpression)initializer);
     }
diff --git 
a/java/java.source.base/src/org/netbeans/modules/java/source/pretty/VeryPretty.java
 
b/java/java.source.base/src/org/netbeans/modules/java/source/pretty/VeryPretty.java
index ada1ec2..89d147c 100644
--- 
a/java/java.source.base/src/org/netbeans/modules/java/source/pretty/VeryPretty.java
+++ 
b/java/java.source.base/src/org/netbeans/modules/java/source/pretty/VeryPretty.java
@@ -90,6 +90,8 @@ import com.sun.tools.javac.util.Name;
 import com.sun.tools.javac.util.Names;
 
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.net.URL;
 import java.util.*;
 import java.util.logging.Level;
@@ -118,6 +120,7 @@ import 
org.netbeans.modules.java.source.save.PositionEstimator;
 import org.netbeans.modules.java.source.save.Reformatter;
 import org.netbeans.modules.java.source.transform.FieldGroupTree;
 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
+import org.openide.util.Exceptions;
 
 /** Prints out a tree as an indented Java source program.
  */
@@ -1830,7 +1833,7 @@ public final class VeryPretty extends JCTree.Visitor 
implements DocTreeVisitor<V
     public void visitTypeTest(JCInstanceOf tree) {
        printExpr(tree.expr, TreeInfo.ordPrec);
        print(" instanceof ");
-       print(tree.clazz);
+       print(CasualDiff.getPattern(tree));
     }
 
     @Override
@@ -2065,6 +2068,19 @@ public final class VeryPretty extends JCTree.Visitor 
implements DocTreeVisitor<V
 
     @Override
     public void visitTree(JCTree tree) {
+        if ("BINDING_PATTERN".equals(tree.getKind().name())) {
+            try {
+                Class bindingPatternClass = 
Class.forName("com.sun.source.tree.BindingPatternTree");
+                Method getBinding = 
bindingPatternClass.getMethod("getBinding");
+                Method getType = bindingPatternClass.getMethod("getType");
+                print((JCTree) getType.invoke(tree));
+                print(' ');
+                print((Name) getBinding.invoke(tree));
+                return ;
+            } catch (NoSuchMethodException | SecurityException | 
IllegalAccessException | IllegalArgumentException | InvocationTargetException | 
ClassNotFoundException ex) {
+                Exceptions.printStackTrace(ex);
+            }
+        }
        print("(UNKNOWN: " + tree + ")");
        newline();
     }
diff --git 
a/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
 
b/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
index b175482..efbde5a 100644
--- 
a/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
+++ 
b/java/java.source.base/src/org/netbeans/modules/java/source/save/CasualDiff.java
@@ -131,6 +131,7 @@ import com.sun.tools.javac.util.Names;
 import com.sun.tools.javac.util.Position;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.util.*;
 import java.util.Map.Entry;
@@ -2577,14 +2578,30 @@ public class CasualDiff {
         copyTo(localPointer, exprBounds[0]);
         localPointer = diffTree(oldT.expr, newT.expr, exprBounds);
         // clazz
-        int[] clazzBounds = getBounds(oldT.clazz);
+        JCTree oldPattern = getPattern(oldT);
+        JCTree newPattern = getPattern(newT);
+        int[] clazzBounds = getBounds(oldPattern);
         clazzBounds[0] = copyUpTo(localPointer, clazzBounds[0]);
-        localPointer = diffTree(oldT.clazz, newT.clazz, clazzBounds);
+        localPointer = diffTree(oldPattern, newPattern, clazzBounds);
         localPointer = copyUpTo(localPointer, bounds[1]);
 
         return localPointer;
     }
 
+    public static JCTree getPattern(JCInstanceOf tree) {
+        try {
+            Field clazzField = JCInstanceOf.class.getField("clazz");
+            return (JCTree) clazzField.get(tree);
+        } catch (Throwable t) {
+            try {
+                Field patternField = JCInstanceOf.class.getField("pattern");
+                return (JCTree) patternField.get(tree);
+            } catch (Throwable t2) {
+                return (JCTree) tree.getType();
+            }
+        }
+    }
+
     protected int diffIndexed(JCArrayAccess oldT, JCArrayAccess newT, int[] 
bounds) {
         int localPointer = bounds[0];
         // indexed
diff --git 
a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
 
b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
index b5997a1..2e1d8a9 100644
--- 
a/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
+++ 
b/java/java.source.base/src/org/netbeans/modules/java/source/save/Reformatter.java
@@ -577,7 +577,23 @@ public class Reformatter implements ReformatTask {
             try {
                 if (endPos < 0)
                     return false;
-                Boolean ret = tokens.offset() <= endPos ? 
(tree.getKind().toString().equals(TreeShims.SWITCH_EXPRESSION)) ? 
scanSwitchExpression(tree, p) : 
(tree.getKind().toString().equals(TreeShims.YIELD)) ? scanYield(tree, p) : 
super.scan(tree, p) : null;
+                if (tokens.offset() > endPos)
+                    return true;
+                Boolean ret;
+                switch (tree.getKind().toString()) {
+                    case TreeShims.SWITCH_EXPRESSION:
+                        ret = scanSwitchExpression(tree, p);
+                        break;
+                    case TreeShims.YIELD:
+                        ret = scanYield(tree, p);
+                        break;
+                    case TreeShims.BINDING_PATTERN:
+                        ret = scanBindingPattern(tree, p);
+                        break;
+                    default:
+                        ret = super.scan(tree, p);
+                        break;
+                }
                 return ret != null ? ret : true;
             }
             finally {
@@ -2576,6 +2592,17 @@ public class Reformatter implements ReformatTask {
             return handleYield(node, p);
         }
 
+        private Boolean scanBindingPattern(Tree node, Void p) {
+            Name name = TreeShims.getBinding(node);
+            Tree type = TreeShims.getBindingPatternType(node);
+            scan(type, p);
+            if (name != null) {
+                space();
+                accept(IDENTIFIER);
+            }
+            return true;
+        }
+
         private Boolean handleYield(Tree node, Void p) {
             ExpressionTree exprTree = TreeShims.getYieldValue(node);
             if (exprTree != null) {
@@ -3131,7 +3158,10 @@ public class Reformatter implements ReformatTask {
             space();
             accept(INSTANCEOF);
             space();
-            scan(node.getType(), p);
+            Tree pattern = TreeShims.getPattern(node);
+            if (pattern == null)
+                pattern = node.getType();
+            scan(pattern, p);
             return true;
         }
 
diff --git 
a/java/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/InstanceOfTest.java
 
b/java/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/InstanceOfTest.java
new file mode 100644
index 0000000..4bf40b6
--- /dev/null
+++ 
b/java/java.source.base/test/unit/src/org/netbeans/api/java/source/gen/InstanceOfTest.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.api.java.source.gen;
+
+import com.sun.source.tree.ClassTree;
+import com.sun.source.tree.CompilationUnitTree;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.IfTree;
+import com.sun.source.tree.InstanceOfTree;
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.ParenthesizedTree;
+import com.sun.tools.javac.tree.JCTree;
+import java.io.File;
+import java.io.IOException;
+import org.netbeans.api.java.source.Task;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.JavaSource.Phase;
+import org.netbeans.api.java.source.TestUtilities;
+import org.netbeans.api.java.source.TreeMaker;
+import org.netbeans.api.java.source.WorkingCopy;
+import org.netbeans.junit.NbTestSuite;
+
+/**
+ * Tests correct adding cast to statement.
+ *
+ * @author Pavel Flaska
+ */
+public class InstanceOfTest extends GeneratorTestMDRCompat {
+    
+    /** Creates a new instance of AddCastTest */
+    public InstanceOfTest(String name) {
+        super(name);
+    }
+    
+    public static NbTestSuite suite() {
+        NbTestSuite suite = new NbTestSuite();
+        suite.addTestSuite(InstanceOfTest.class);
+        return suite;
+    }
+
+    public void testAddVariableName() throws Exception {
+        if (!typeTestPatternAvailable())
+            return ;
+
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, 
+            "package hierbas.del.litoral;\n\n" +
+            "public class Test {\n" +
+            "    public void taragui(Object o) {\n" +
+            "        if (o instanceof String) {\n" + 
+            "        }\n" + 
+            "    }\n" +
+            "}\n"
+            );
+        String golden =
+            "package hierbas.del.litoral;\n\n" +
+            "public class Test {\n" +
+            "    public void taragui(Object o) {\n" +
+            "        if (o instanceof String t) {\n" +
+            "        }\n" +
+            "    }\n" +
+            "}\n";
+        JavaSource src = getJavaSource(testFile);
+        
+        Task<WorkingCopy> task = new Task<WorkingCopy>() {
+
+            public void run(WorkingCopy workingCopy) throws IOException {
+                workingCopy.toPhase(Phase.RESOLVED);
+                CompilationUnitTree cut = workingCopy.getCompilationUnit();
+                TreeMaker make = workingCopy.getTreeMaker();
+                ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
+                MethodTree method = (MethodTree) clazz.getMembers().get(1);
+                IfTree ift = (IfTree) method.getBody().getStatements().get(0);
+                InstanceOfTree it = (InstanceOfTree) ((ParenthesizedTree) 
ift.getCondition()).getExpression();
+                InstanceOfTree nue = make.InstanceOf(it.getExpression(), 
make.BindingPattern("t", it.getType()));
+                workingCopy.rewrite(it, nue);
+            }
+
+        };
+        src.runModificationTask(task).commit();
+        String res = TestUtilities.copyFileToString(testFile);
+        System.err.println(res);
+        assertEquals(golden, res);
+    }
+    
+    public void testRemoveVariableName() throws Exception {
+        if (!typeTestPatternAvailable())
+            return ;
+
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, 
+            "package hierbas.del.litoral;\n\n" +
+            "public class Test {\n" +
+            "    public void taragui(Object o) {\n" +
+            "        if (o instanceof String t) {\n" + 
+            "        }\n" + 
+            "    }\n" +
+            "}\n"
+            );
+        String golden =
+            "package hierbas.del.litoral;\n\n" +
+            "public class Test {\n" +
+            "    public void taragui(Object o) {\n" +
+            "        if (o instanceof String) {\n" +
+            "        }\n" +
+            "    }\n" +
+            "}\n";
+        JavaSource src = getJavaSource(testFile);
+        
+        Task<WorkingCopy> task = new Task<WorkingCopy>() {
+
+            public void run(WorkingCopy workingCopy) throws IOException {
+                workingCopy.toPhase(Phase.RESOLVED);
+                CompilationUnitTree cut = workingCopy.getCompilationUnit();
+                TreeMaker make = workingCopy.getTreeMaker();
+                ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
+                MethodTree method = (MethodTree) clazz.getMembers().get(1);
+                IfTree ift = (IfTree) method.getBody().getStatements().get(0);
+                InstanceOfTree it = (InstanceOfTree) ((ParenthesizedTree) 
ift.getCondition()).getExpression();
+                InstanceOfTree nue = make.InstanceOf(it.getExpression(), 
it.getType());
+                workingCopy.rewrite(it, nue);
+            }
+
+        };
+        src.runModificationTask(task).commit();
+        String res = TestUtilities.copyFileToString(testFile);
+        System.err.println(res);
+        assertEquals(golden, res);
+    }
+    
+    public void testAddInstanceOf() throws Exception {
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, 
+            "package hierbas.del.litoral;\n\n" +
+            "public class Test {\n" +
+            "    public void taragui(Object o) {\n" +
+            "        if (true) {\n" + 
+            "        }\n" + 
+            "    }\n" +
+            "}\n"
+            );
+        String golden =
+            "package hierbas.del.litoral;\n\n" +
+            "public class Test {\n" +
+            "    public void taragui(Object o) {\n" +
+            "        if (o instanceof String) {\n" +
+            "        }\n" +
+            "    }\n" +
+            "}\n";
+        JavaSource src = getJavaSource(testFile);
+        
+        Task<WorkingCopy> task = new Task<WorkingCopy>() {
+
+            public void run(WorkingCopy workingCopy) throws IOException {
+                workingCopy.toPhase(Phase.RESOLVED);
+                CompilationUnitTree cut = workingCopy.getCompilationUnit();
+                TreeMaker make = workingCopy.getTreeMaker();
+                ClassTree clazz = (ClassTree) cut.getTypeDecls().get(0);
+                MethodTree method = (MethodTree) clazz.getMembers().get(1);
+                IfTree ift = (IfTree) method.getBody().getStatements().get(0);
+                ExpressionTree condition = ((ParenthesizedTree) 
ift.getCondition()).getExpression();
+                InstanceOfTree nue = make.InstanceOf(make.Identifier("o"), 
make.QualIdent("java.lang.String"));
+                workingCopy.rewrite(condition, nue);
+            }
+
+        };
+        src.runModificationTask(task).commit();
+        String res = TestUtilities.copyFileToString(testFile);
+        System.err.println(res);
+        assertEquals(golden, res);
+    }
+    
+    private boolean typeTestPatternAvailable() {
+        try {
+            Class.forName("com.sun.source.tree.BindingPatternTree", false, 
JCTree.class.getClassLoader());
+            return true;
+        } catch (ClassNotFoundException ex) {
+            //OK
+            return false;
+        }
+    }
+
+    String getGoldenPckg() {
+        return "";
+    }
+    
+    String getSourcePckg() {
+        return "";
+    }
+    
+    
+}
diff --git 
a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
 
b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
index 2497709..613864a 100644
--- 
a/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
+++ 
b/java/java.source.base/test/unit/src/org/netbeans/modules/java/source/save/FormatingTest.java
@@ -5072,6 +5072,46 @@ public class FormatingTest extends NbTestCase {
         reformat(doc, content, golden);
     }
 
+    public void testTypeTestPatterns() throws Exception {
+        try {
+            SourceVersion.valueOf("RELEASE_14"); //NOI18N
+        } catch (IllegalArgumentException ex) {
+            //OK, no RELEASE_14, skip test
+            return;
+        }
+        testFile = new File(getWorkDir(), "Test.java");
+        TestUtilities.copyStringToFile(testFile, "");
+        FileObject testSourceFO = FileUtil.toFileObject(testFile);
+        DataObject testSourceDO = DataObject.find(testSourceFO);
+        EditorCookie ec = 
(EditorCookie)testSourceDO.getCookie(EditorCookie.class);
+        final Document doc = ec.openDocument();
+        doc.putProperty(Language.class, JavaTokenId.language());
+        String content =
+                "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public boolean main(Object o) {\n"
+                + "        if (o instanceof String s) {\n"
+                + "            return s.isEmpty();\n"
+                + "        } else {\n"
+                + "            return false;\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+
+        String golden = // no change
+                "package hierbas.del.litoral;\n\n"
+                + "public class Test {\n\n"
+                + "    public boolean main(Object o) {\n"
+                + "        if (o instanceof String s) {\n"
+                + "            return s.isEmpty();\n"
+                + "        } else {\n"
+                + "            return false;\n"
+                + "        }\n"
+                + "    }\n"
+                + "}\n";
+        reformat(doc, content, golden);
+    }
+
     private void reformat(Document doc, String content, String golden) throws 
Exception {
         reformat(doc, content, golden, 0, content.length());
     }
diff --git 
a/java/maven.hints/src/org/netbeans/modules/maven/hints/errors/EnablePreviewMavenProj.java
 
b/java/maven.hints/src/org/netbeans/modules/maven/hints/errors/EnablePreviewMavenProj.java
index 08b3916..c4dc612 100644
--- 
a/java/maven.hints/src/org/netbeans/modules/maven/hints/errors/EnablePreviewMavenProj.java
+++ 
b/java/maven.hints/src/org/netbeans/modules/maven/hints/errors/EnablePreviewMavenProj.java
@@ -62,6 +62,7 @@ import org.openide.filesystems.FileSystem;
 public class EnablePreviewMavenProj implements ErrorRule<Void> {
 
     private static final Set<String> ERROR_CODES = new 
HashSet<String>(Arrays.asList(
+            "compiler.err.preview.feature.disabled",
             "compiler.err.preview.feature.disabled.plural")); // NOI18N
     private static final String ENABLE_PREVIEW_FLAG = "--enable-preview";   // 
NOI18N
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

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

Reply via email to