src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Pretty.java
changeset 47216 71c04702a3d5
parent 40596 43b19b36e8e6
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeprscan/Pretty.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,274 @@
+/*
+ * 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 DESC_PAT = Pattern.compile("(?<name>.*)\\((?<args>.*)\\)(?<return>.*)");
+
+    /**
+     * 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 = DESC_PAT.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 = DESC_PAT.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();
+    }
+}