8234896: Tab completion does not work for method references in jshell
Reviewed-by: rfield
This commit is contained in:
parent
0c9983887d
commit
e44dcf09c0
src/jdk.jshell/share/classes/jdk/jshell
test/langtools/jdk/jshell
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,6 +32,7 @@ import com.sun.source.tree.ErroneousTree;
|
||||
import com.sun.source.tree.ExpressionTree;
|
||||
import com.sun.source.tree.IdentifierTree;
|
||||
import com.sun.source.tree.ImportTree;
|
||||
import com.sun.source.tree.MemberReferenceTree;
|
||||
import com.sun.source.tree.MemberSelectTree;
|
||||
import com.sun.source.tree.MethodInvocationTree;
|
||||
import com.sun.source.tree.MethodTree;
|
||||
@ -309,11 +310,53 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
|
||||
Predicate<Element> smartFilter;
|
||||
Iterable<TypeMirror> targetTypes = findTargetType(at, tp);
|
||||
if (targetTypes != null) {
|
||||
smartTypeFilter = el -> {
|
||||
TypeMirror resultOf = resultTypeOf(el);
|
||||
return Util.stream(targetTypes)
|
||||
.anyMatch(targetType -> at.getTypes().isAssignable(resultOf, targetType));
|
||||
};
|
||||
if (tp.getLeaf().getKind() == Kind.MEMBER_REFERENCE) {
|
||||
Types types = at.getTypes();
|
||||
smartTypeFilter = t -> {
|
||||
if (t.getKind() != ElementKind.METHOD) {
|
||||
return false;
|
||||
}
|
||||
ExecutableElement ee = (ExecutableElement) t;
|
||||
for (TypeMirror type : targetTypes) {
|
||||
if (type.getKind() != TypeKind.DECLARED)
|
||||
continue;
|
||||
DeclaredType d = (DeclaredType) type;
|
||||
List<? extends Element> enclosed =
|
||||
((TypeElement) d.asElement()).getEnclosedElements();
|
||||
for (ExecutableElement m : ElementFilter.methodsIn(enclosed)) {
|
||||
boolean matches = true;
|
||||
if (!m.getModifiers().contains(Modifier.ABSTRACT)) {
|
||||
continue;
|
||||
}
|
||||
if (m.getParameters().size() != ee.getParameters().size()) {
|
||||
continue;
|
||||
}
|
||||
ExecutableType mInst = (ExecutableType) types.asMemberOf(d, m);
|
||||
List<? extends TypeMirror> expectedParams = mInst.getParameterTypes();
|
||||
if (mInst.getReturnType().getKind() != TypeKind.VOID &&
|
||||
!types.isSubtype(ee.getReturnType(), mInst.getReturnType())) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < m.getParameters().size(); i++) {
|
||||
if (!types.isSubtype(expectedParams.get(i),
|
||||
ee.getParameters().get(i).asType())) {
|
||||
matches = false;
|
||||
}
|
||||
}
|
||||
if (matches) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
smartTypeFilter = el -> {
|
||||
TypeMirror resultOf = resultTypeOf(el);
|
||||
return Util.stream(targetTypes)
|
||||
.anyMatch(targetType -> at.getTypes().isAssignable(resultOf, targetType));
|
||||
};
|
||||
}
|
||||
|
||||
smartFilter = IS_CLASS.negate()
|
||||
.and(IS_INTERFACE.negate())
|
||||
@ -324,19 +367,31 @@ class SourceCodeAnalysisImpl extends SourceCodeAnalysis {
|
||||
smartTypeFilter = TRUE;
|
||||
}
|
||||
switch (tp.getLeaf().getKind()) {
|
||||
case MEMBER_SELECT: {
|
||||
MemberSelectTree mst = (MemberSelectTree)tp.getLeaf();
|
||||
if (mst.getIdentifier().contentEquals("*"))
|
||||
case MEMBER_REFERENCE, MEMBER_SELECT: {
|
||||
javax.lang.model.element.Name identifier;
|
||||
ExpressionTree expression;
|
||||
Function<Boolean, String> paren;
|
||||
if (tp.getLeaf().getKind() == Kind.MEMBER_SELECT) {
|
||||
MemberSelectTree mst = (MemberSelectTree)tp.getLeaf();
|
||||
identifier = mst.getIdentifier();
|
||||
expression = mst.getExpression();
|
||||
paren = DEFAULT_PAREN;
|
||||
} else {
|
||||
MemberReferenceTree mst = (MemberReferenceTree)tp.getLeaf();
|
||||
identifier = mst.getName();
|
||||
expression = mst.getQualifierExpression();
|
||||
paren = NO_PAREN;
|
||||
}
|
||||
if (identifier.contentEquals("*"))
|
||||
break;
|
||||
TreePath exprPath = new TreePath(tp, mst.getExpression());
|
||||
TreePath exprPath = new TreePath(tp, expression);
|
||||
TypeMirror site = at.trees().getTypeMirror(exprPath);
|
||||
boolean staticOnly = isStaticContext(at, exprPath);
|
||||
ImportTree it = findImport(tp);
|
||||
boolean isImport = it != null;
|
||||
|
||||
List<? extends Element> members = membersOf(at, site, staticOnly && !isImport);
|
||||
List<? extends Element> members = membersOf(at, site, staticOnly && !isImport && tp.getLeaf().getKind() == Kind.MEMBER_SELECT);
|
||||
Predicate<Element> filter = accessibility;
|
||||
Function<Boolean, String> paren = DEFAULT_PAREN;
|
||||
|
||||
if (isNewClass(tp)) { // new xxx.|
|
||||
Predicate<Element> constructorFilter = accessibility.and(IS_CONSTRUCTOR)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466 8197439 8221759
|
||||
* @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466 8197439 8221759 8234896
|
||||
* @summary Test Completion and Documentation
|
||||
* @library /tools/lib
|
||||
* @modules jdk.compiler/com.sun.tools.javac.api
|
||||
@ -675,6 +675,29 @@ public class CompletionSuggestionTest extends KullaTesting {
|
||||
assertCompletionIncludesExcludes("new Undefined() { int i = \"\".l|", Set.of("length()"), Set.of());
|
||||
}
|
||||
|
||||
public void testMemberReferences() {
|
||||
assertEval("class C {" +
|
||||
" public static String stat() { return null; }" +
|
||||
" public static void statVoid(String s) {}" +
|
||||
" public static Integer statConvert1(String s) { return null; }" +
|
||||
" public static String statConvert2(Integer s) { return null; }" +
|
||||
" public static String statConvert3(CharSequence s) { return null; }" +
|
||||
" public String inst() { return null; }" +
|
||||
" public void instVoid(String s) { }" +
|
||||
"}");
|
||||
assertEval("interface FI { public void t(String s); }");
|
||||
assertCompletion("FI fi = C::|", (Boolean) null, "stat", "statConvert1", "statConvert2", "statConvert3", "statVoid");
|
||||
assertCompletion("FI fi = C::|", true, "statConvert1", "statConvert3","statVoid");
|
||||
assertCompletion("FI fi = new C()::i|", (Boolean) null, "inst", "instVoid");
|
||||
assertCompletion("FI fi = new C()::i|", true, "instVoid");
|
||||
assertEval("interface FI2<R, P> { public R t(P p); }");
|
||||
assertCompletion("FI2<String, Integer> fi = C::|", (Boolean) null, "stat", "statConvert1", "statConvert2", "statConvert3", "statVoid");
|
||||
assertCompletion("FI2<String, Integer> fi = C::|", true, "statConvert2");
|
||||
assertCompletion("FI2<String, CharSequence> fi = C::|", true, "statConvert3");
|
||||
assertCompletion("FI2<String, String> fi = C::|", true, "statConvert3");
|
||||
assertCompletion("FI2<Object, String> fi = C::|", true, "statConvert1", "statConvert3");
|
||||
}
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() {
|
||||
super.setUp();
|
||||
|
Loading…
x
Reference in New Issue
Block a user