--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java Mon Oct 17 15:02:46 2016 +0100
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java Mon Oct 17 23:23:11 2016 +0900
@@ -116,6 +116,7 @@
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.QualifiedNameable;
+import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.ExecutableType;
@@ -132,6 +133,7 @@
import static jdk.jshell.Util.REPL_DOESNOTMATTER_CLASS_NAME;
import static java.util.stream.Collectors.joining;
import static jdk.jshell.SourceCodeAnalysis.Completeness.DEFINITELY_INCOMPLETE;
+import static jdk.jshell.TreeDissector.printType;
/**
* The concrete implementation of SourceCodeAnalysis.
@@ -1185,7 +1187,7 @@
proc.debug(ex, "SourceCodeAnalysisImpl.element2String(..., " + el + ")");
}
- return Util.expunge(elementHeader(el));
+ return Util.expunge(elementHeader(sourceCache.originalTask, el, !hasSyntheticParameterNames(el)));
}
private boolean hasSyntheticParameterNames(Element el) {
@@ -1248,7 +1250,7 @@
topLevelName2Signature2Method.put(binaryName, cache = createMethodCache(binaryName));
}
- String handle = elementHeader(method, false);
+ String handle = elementHeader(originalTask, method, false);
return cache.getOrDefault(handle, method);
}
@@ -1276,7 +1278,7 @@
Element currentMethod = trees.getElement(getCurrentPath());
if (currentMethod != null) {
- signature2Method.put(elementHeader(currentMethod, false), currentMethod);
+ signature2Method.put(elementHeader(originalTask, currentMethod, false), currentMethod);
}
return null;
@@ -1331,39 +1333,79 @@
return availableSources = result;
}
- private String elementHeader(Element el) {
- return elementHeader(el, true);
+ private String elementHeader(AnalyzeTask at, Element el) {
+ return elementHeader(at, el, true);
}
- private String elementHeader(Element el, boolean includeParameterNames) {
+ private String elementHeader(AnalyzeTask at, Element el, boolean includeParameterNames) {
switch (el.getKind()) {
- case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE:
- return ((TypeElement) el).getQualifiedName().toString();
+ case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE: {
+ TypeElement type = (TypeElement)el;
+ String fullname = type.getQualifiedName().toString();
+ Element pkg = at.getElements().getPackageOf(el);
+ String name = pkg == null ? fullname :
+ proc.maps.fullClassNameAndPackageToClass(fullname, ((PackageElement)pkg).getQualifiedName().toString());
+
+ return name + typeParametersOpt(at, type.getTypeParameters());
+ }
+ case TYPE_PARAMETER: {
+ TypeParameterElement tp = (TypeParameterElement)el;
+ String name = tp.getSimpleName().toString();
+
+ List<? extends TypeMirror> bounds = tp.getBounds();
+ boolean boundIsObject = bounds.isEmpty() ||
+ bounds.size() == 1 && at.getTypes().isSameType(bounds.get(0), Symtab.instance(at.getContext()).objectType);
+
+ return boundIsObject
+ ? name
+ : name + " extends " + bounds.stream()
+ .map(bound -> printType(at, proc, bound))
+ .collect(joining(" & "));
+ }
case FIELD:
- return elementHeader(el.getEnclosingElement()) + "." + el.getSimpleName() + ":" + el.asType();
+ return elementHeader(at, el.getEnclosingElement()) + "." + el.getSimpleName() + ":" + el.asType();
case ENUM_CONSTANT:
- return elementHeader(el.getEnclosingElement()) + "." + el.getSimpleName();
+ return elementHeader(at, el.getEnclosingElement()) + "." + el.getSimpleName();
case EXCEPTION_PARAMETER: case LOCAL_VARIABLE: case PARAMETER: case RESOURCE_VARIABLE:
return el.getSimpleName() + ":" + el.asType();
- case CONSTRUCTOR: case METHOD:
+ case CONSTRUCTOR: case METHOD: {
StringBuilder header = new StringBuilder();
- header.append(elementHeader(el.getEnclosingElement()));
- if (el.getKind() == ElementKind.METHOD) {
- header.append(".");
- header.append(el.getSimpleName());
+
+ boolean isMethod = el.getKind() == ElementKind.METHOD;
+ ExecutableElement method = (ExecutableElement) el;
+
+ if (isMethod) {
+ // return type
+ header.append(printType(at, proc, method.getReturnType())).append(" ");
+ } else {
+ // type parameters for the constructor
+ String typeParameters = typeParametersOpt(at, method.getTypeParameters());
+ if (!typeParameters.isEmpty()) {
+ header.append(typeParameters).append(" ");
+ }
}
+
+ // receiver type
+ String clazz = elementHeader(at, el.getEnclosingElement());
+ header.append(clazz);
+
+ if (isMethod) {
+ //method name with type parameters
+ (clazz.isEmpty() ? header : header.append("."))
+ .append(typeParametersOpt(at, method.getTypeParameters()))
+ .append(el.getSimpleName());
+ }
+
+ // arguments
header.append("(");
String sep = "";
- ExecutableElement method = (ExecutableElement) el;
for (Iterator<? extends VariableElement> i = method.getParameters().iterator(); i.hasNext();) {
VariableElement p = i.next();
header.append(sep);
if (!i.hasNext() && method.isVarArgs()) {
- header.append(unwrapArrayType(p.asType()));
- header.append("...");
-
+ header.append(printType(at, proc, unwrapArrayType(p.asType()))).append("...");
} else {
- header.append(p.asType());
+ header.append(printType(at, proc, p.asType()));
}
if (includeParameterNames) {
header.append(" ");
@@ -1372,8 +1414,18 @@
sep = ", ";
}
header.append(")");
+
+ // throws
+ List<? extends TypeMirror> thrownTypes = method.getThrownTypes();
+ if (!thrownTypes.isEmpty()) {
+ header.append(" throws ")
+ .append(thrownTypes.stream()
+ .map(type -> printType(at, proc, type))
+ .collect(joining(", ")));
+ }
return header.toString();
- default:
+ }
+ default:
return el.toString();
}
}
@@ -1383,6 +1435,12 @@
}
return arrayType;
}
+ private String typeParametersOpt(AnalyzeTask at, List<? extends TypeParameterElement> typeParameters) {
+ return typeParameters.isEmpty() ? ""
+ : typeParameters.stream()
+ .map(tp -> elementHeader(at, tp))
+ .collect(joining(", ", "<", ">"));
+ }
@Override
public String analyzeType(String code, int cursor) {
--- a/langtools/test/jdk/jshell/CompletionSuggestionTest.java Mon Oct 17 15:02:46 2016 +0100
+++ b/langtools/test/jdk/jshell/CompletionSuggestionTest.java Mon Oct 17 23:23:11 2016 +0900
@@ -23,8 +23,8 @@
/*
* @test
- * @bug 8131025 8141092 8153761
- * @summary Test Completion
+ * @bug 8131025 8141092 8153761 8145263
+ * @summary Test Completion and Documentation
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
* jdk.jdeps/com.sun.tools.javap
@@ -43,6 +43,8 @@
import java.util.Collections;
import java.util.Set;
import java.util.HashSet;
+import java.util.function.BiFunction;
+import java.util.function.Function;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
@@ -304,35 +306,35 @@
public void testDocumentation() throws Exception {
dontReadParameterNamesFromClassFile();
assertDocumentation("System.getProperty(|",
- "java.lang.System.getProperty(java.lang.String key)",
- "java.lang.System.getProperty(java.lang.String key, java.lang.String def)");
+ "String System.getProperty(String key)",
+ "String System.getProperty(String key, String def)");
assertEval("char[] chars = null;");
assertDocumentation("new String(chars, |",
- "java.lang.String(char[] arg0, int arg1, int arg2)");
+ "String(char[], int, int)");
assertDocumentation("String.format(|",
- "java.lang.String.format(java.lang.String arg0, java.lang.Object... arg1)",
- "java.lang.String.format(java.util.Locale arg0, java.lang.String arg1, java.lang.Object... arg2)");
- assertDocumentation("\"\".getBytes(\"\"|", "java.lang.String.getBytes(int arg0, int arg1, byte[] arg2, int arg3)",
- "java.lang.String.getBytes(java.lang.String arg0)",
- "java.lang.String.getBytes(java.nio.charset.Charset arg0)");
- assertDocumentation("\"\".getBytes(\"\" |", "java.lang.String.getBytes(int arg0, int arg1, byte[] arg2, int arg3)",
- "java.lang.String.getBytes(java.lang.String arg0)",
- "java.lang.String.getBytes(java.nio.charset.Charset arg0)");
+ "String String.format(String, Object...)",
+ "String String.format(java.util.Locale, String, Object...)");
+ assertDocumentation("\"\".getBytes(\"\"|", "void String.getBytes(int, int, byte[], int)",
+ "byte[] String.getBytes(String) throws java.io.UnsupportedEncodingException",
+ "byte[] String.getBytes(java.nio.charset.Charset)");
+ assertDocumentation("\"\".getBytes(\"\" |", "void String.getBytes(int, int, byte[], int)",
+ "byte[] String.getBytes(String) throws java.io.UnsupportedEncodingException",
+ "byte[] String.getBytes(java.nio.charset.Charset)");
}
public void testMethodsWithNoArguments() throws Exception {
dontReadParameterNamesFromClassFile();
assertDocumentation("System.out.println(|",
- "java.io.PrintStream.println()",
- "java.io.PrintStream.println(boolean arg0)",
- "java.io.PrintStream.println(char arg0)",
- "java.io.PrintStream.println(int arg0)",
- "java.io.PrintStream.println(long arg0)",
- "java.io.PrintStream.println(float arg0)",
- "java.io.PrintStream.println(double arg0)",
- "java.io.PrintStream.println(char[] arg0)",
- "java.io.PrintStream.println(java.lang.String arg0)",
- "java.io.PrintStream.println(java.lang.Object arg0)");
+ "void java.io.PrintStream.println()",
+ "void java.io.PrintStream.println(boolean)",
+ "void java.io.PrintStream.println(char)",
+ "void java.io.PrintStream.println(int)",
+ "void java.io.PrintStream.println(long)",
+ "void java.io.PrintStream.println(float)",
+ "void java.io.PrintStream.println(double)",
+ "void java.io.PrintStream.println(char[])",
+ "void java.io.PrintStream.println(String)",
+ "void java.io.PrintStream.println(Object)");
}
public void testErroneous() {
@@ -472,14 +474,14 @@
public void testDocumentationOfUserDefinedMethods() {
assertEval("void f() {}");
- assertDocumentation("f(|", "f()");
+ assertDocumentation("f(|", "void f()");
assertEval("void f(int i) {}");
- assertDocumentation("f(|", "f()", "f(int i)");
+ assertDocumentation("f(|", "void f()", "void f(int i)");
assertEval("<T> void f(T... ts) {}", DiagCheck.DIAG_WARNING, DiagCheck.DIAG_OK);
- assertDocumentation("f(|", "f()", "f(int i)", "f(T... ts)");
+ assertDocumentation("f(|", "void f()", "void f(int i)", "void <T>f(T... ts)");
assertEval("class A {}");
assertEval("void f(A a) {}");
- assertDocumentation("f(|", "f()", "f(int i)", "f(T... ts)", "f(A a)");
+ assertDocumentation("f(|", "void f()", "void f(int i)", "void <T>f(T... ts)", "void f(A a)");
}
public void testDocumentationOfUserDefinedConstructors() {
@@ -489,25 +491,25 @@
ste(MAIN_SNIPPET, VALID, VALID, true, null),
ste(a, VALID, OVERWRITTEN, false, MAIN_SNIPPET)));
assertDocumentation("new A(|", "A()", "A(int i)");
- assertEval("class A<T> { A(T t) {} A(int i) {}}",
+ assertEval("class A<T> { A(T a) {} A(int i) {} <U> A(T t, U u) {}}",
ste(MAIN_SNIPPET, VALID, VALID, true, null),
ste(a2, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
- assertDocumentation("new A(|", "A(T t)", "A(int i)");
+ assertDocumentation("new A(|", "A<T>(T a)", "A<T>(int i)", "<U> A<T>(T t, U u)");
}
public void testDocumentationOfOverriddenMethods() throws Exception {
dontReadParameterNamesFromClassFile();
assertDocumentation("\"\".wait(|",
- "java.lang.Object.wait(long arg0)",
- "java.lang.Object.wait(long arg0, int arg1)",
- "java.lang.Object.wait()");
+ "void Object.wait(long) throws InterruptedException",
+ "void Object.wait(long, int) throws InterruptedException",
+ "void Object.wait() throws InterruptedException");
assertEval("class Base {void method() {}}");
Snippet e = classKey(assertEval("class Extend extends Base {}"));
- assertDocumentation("new Extend().method(|", "Base.method()");
+ assertDocumentation("new Extend().method(|", "void Base.method()");
assertEval("class Extend extends Base {void method() {}}",
ste(MAIN_SNIPPET, VALID, VALID, true, null),
ste(e, VALID, OVERWRITTEN, false, MAIN_SNIPPET));
- assertDocumentation("new Extend().method(|", "Extend.method()");
+ assertDocumentation("new Extend().method(|", "void Extend.method()");
}
public void testDocumentationOfInvisibleMethods() {
@@ -534,13 +536,67 @@
assertEval("void method(int n, Object o) { }");
assertEval("void method(Object n, int o) { }");
assertDocumentation("method(primitive,|",
- "method(int n, java.lang.Object o)",
- "method(java.lang.Object n, int o)");
+ "void method(int n, Object o)",
+ "void method(Object n, int o)");
assertDocumentation("method(boxed,|",
- "method(int n, java.lang.Object o)",
- "method(java.lang.Object n, int o)");
+ "void method(int n, Object o)",
+ "void method(Object n, int o)");
assertDocumentation("method(object,|",
- "method(java.lang.Object n, int o)");
+ "void method(Object n, int o)");
+ }
+
+ public void testDocumentationWithGenerics() {
+ class TestDocumentationWithGenerics {
+ private final Function<Integer, String> codeFacotry;
+ private final BiFunction<String, Integer, String> evalFormatter;
+ private final BiFunction<String, Integer, String> docFormatter;
+ int count;
+
+ TestDocumentationWithGenerics(
+ Function<Integer, String> codeFactory,
+ BiFunction<String, Integer, String> evalFormatter,
+ BiFunction<String, Integer, String> documentationFormatter) {
+ this.codeFacotry = codeFactory;
+ this.evalFormatter = evalFormatter;
+ this.docFormatter = documentationFormatter;
+ }
+
+ void assertDoc(String generics) {
+ assertDoc(generics, generics);
+ }
+
+ void assertDoc(String generics, String expectedGenerics) {
+ assertEval(evalFormatter.apply(generics, count));
+ assertDocumentation(codeFacotry.apply(count), docFormatter.apply(expectedGenerics, count));
+ count++;
+ }
+ }
+
+ TestDocumentationWithGenerics[] tests = {
+ new TestDocumentationWithGenerics(
+ i -> "f" + i + "(|",
+ (g, i) -> "<" + g + "> void f" + i + "() {}",
+ (g, i) -> "void <" + g + ">f" + i + "()"
+ ),
+ new TestDocumentationWithGenerics(
+ i -> "new C" + i + "().f(|",
+ (g, i) -> "class C" + i + "<" + g + "> { void f() {} }",
+ (g, i) -> "void C" + i + "<" + g + ">.f()"
+ )
+ };
+
+ Arrays.stream(tests).forEach(t -> {
+ t.assertDoc("T");
+ t.assertDoc("T extends Object",
+ "T");
+ t.assertDoc("T extends String");
+ t.assertDoc("T extends java.lang.String",
+ "T extends String");
+ t.assertDoc("T extends Number & Comparable<T>");
+ t.assertDoc("T extends java.io.Serializable & CharSequence");
+ t.assertDoc("K, D, M extends java.util.Map<K, D>",
+ "K, D, M extends java.util.Map<K,D>");
+ });
}
public void testVarArgs() {