--- /dev/null 2016-07-20 19:17:37.000000000 -0700 +++ new/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Pretty.java 2016-07-20 19:17:37.000000000 -0700 @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2016, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.tools.jdeprscan; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Utility class for pretty-printing various bits of API syntax. + */ +public class Pretty { + /** + * Converts deprecation information into an {@code @Deprecated} annotation. + * The output is minimized: an empty since string is omitted, a forRemoval + * value of false is omitted; and if both are omitted, the trailing parentheses + * are also omitted. + * + * @param since the since value + * @param forRemoval the forRemoval value + * @return string containing an annotation + */ + static String depr(String since, boolean forRemoval) { + String d = "@Deprecated"; + + if (since.isEmpty() && !forRemoval) { + return d; + } + + StringBuilder sb = new StringBuilder(d).append('('); + + if (!since.isEmpty()) { + sb.append("since=\"") + .append(since.replace("\"", "\\\"")) + .append('"'); + } + + if (forRemoval) { + if (!since.isEmpty()) { + sb.append(", "); + } + sb.append("forRemoval=true"); + } + + sb.append(')'); + + return sb.toString(); + } + + /** + * Converts a slash-$ style name into a dot-separated name. + * + * @param n the input name + * @return the result name + */ + static String unslashify(String n) { + return n.replace("/", ".") + .replace("$", "."); + } + + /** + * Converts a type descriptor to a readable string. + * + * @param desc the input descriptor + * @return the result string + */ + static String desc(String desc) { + return desc(desc, new int[] { 0 }); + } + + /** + * Converts one type descriptor to a readable string, starting + * from position {@code pos_inout[0]}, and updating it to the + * location following the descriptor just parsed. A type descriptor + * mostly corresponds to a FieldType in JVMS 4.3.2. It can be one of a + * BaseType (a single character denoting a primitive, plus void), + * an object type ("Lname;"), or an array type (one more more '[' followed + * by a base or object type). + * + * @param desc a string possibly containing several descriptors + * @param pos_inout on input, the start position; on return, the position + * following the just-parsed descriptor + * @return the result string + */ + static String desc(String desc, int[] pos_inout) { + int dims = 0; + int pos = pos_inout[0]; + final int len = desc.length(); + + while (pos < len && desc.charAt(pos) == '[') { + pos++; + dims++; + } + + String name; + + if (pos >= len) { + return null; + } + + char c = desc.charAt(pos++); + switch (c) { + case 'Z': + name = "boolean"; + break; + case 'B': + name = "byte"; + break; + case 'S': + name = "short"; + break; + case 'C': + name = "char"; + break; + case 'I': + name = "int"; + break; + case 'J': + name = "long"; + break; + case 'F': + name = "float"; + break; + case 'D': + name = "double"; + break; + case 'V': + name = "void"; + break; + case 'L': + int semi = desc.indexOf(';', pos); + if (semi == -1) { + return null; + } + name = unslashify(desc.substring(pos, semi)); + pos = semi + 1; + break; + default: + return null; + } + + StringBuilder sb = new StringBuilder(name); + for (int i = 0; i < dims; i++) { + sb.append("[]"); + } + pos_inout[0] = pos; + return sb.toString(); + } + + /** + * Converts a series of type descriptors into a comma-separated, + * readable string. This is used for the parameter types of a + * method descriptor. + * + * @param types the parameter types + * @return the readable string + */ + static String parms(String types) { + int[] pos = new int[] { 0 }; + StringBuilder sb = new StringBuilder(); + + boolean first = true; + + String t; + + while ((t = desc(types, pos)) != null) { + if (first) { + first = false; + } else { + sb.append(','); + } + sb.append(t); + } + + return sb.toString(); + } + + /** + * Pattern for matching a method descriptor. Match results can + * be retrieved from named capture groups as follows: "name(params)return". + */ + static final Pattern descPat = Pattern.compile("(?.*)\\((?.*)\\)(?.*)"); + + /** + * Pretty-prints the data contained in the given DeprData object. + * + * @param dd the deprecation data object + * @return the formatted string + */ + public static String print(DeprData dd) { + StringBuilder sb = new StringBuilder(); + sb.append(depr(dd.since, dd.forRemoval)) + .append(' '); + + switch (dd.kind) { + case ANNOTATION_TYPE: + sb.append("@interface "); + sb.append(unslashify(dd.typeName)); + break; + case CLASS: + sb.append("class "); + sb.append(unslashify(dd.typeName)); + break; + case ENUM: + sb.append("enum "); + sb.append(unslashify(dd.typeName)); + break; + case INTERFACE: + sb.append("interface "); + sb.append(unslashify(dd.typeName)); + break; + + case ENUM_CONSTANT: + case FIELD: + sb.append(unslashify(dd.typeName)) + .append('.') + .append(dd.nameSig); + break; + case CONSTRUCTOR: + Matcher cons = descPat.matcher(dd.nameSig); + sb.append(unslashify(dd.typeName)); + if (cons.matches()) { + sb.append('(') + .append(parms(cons.group("args"))) + .append(')'); + } else { + sb.append('.') + .append(dd.nameSig); + } + break; + case METHOD: + Matcher meth = descPat.matcher(dd.nameSig); + if (meth.matches()) { + sb.append(desc(meth.group("return"))) + .append(' ') + .append(unslashify(dd.typeName)) + .append('.') + .append(meth.group("name")) + .append('(') + .append(parms(meth.group("args"))) + .append(')'); + } else { + sb.append(unslashify(dd.typeName)) + .append('.') + .append(dd.nameSig); + } + break; + } + + return sb.toString(); + } + +// public static void main(String[] args) { +// System.out.println(depr("", false)); +// System.out.println(depr("9", false)); +// System.out.println(depr("", true)); +// System.out.println(depr("9", true)); +// +// int[] pos = new int[] { 0 }; +// String desc = "I[F[[Ljava/util/Map$Entry;Z"; +// String t; +// +// while ((t = desc(desc, pos)) != null) { +// System.out.println(t); +// } +// } +}