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 <[email protected]> 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("čcč"))</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 "[email protected]" <[email protected]>.
