1 /*
   2  * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.classfile;
  27 
  28 import java.util.ArrayList;
  29 import java.util.List;
  30 import com.sun.tools.classfile.Type.*;
  31 
  32 /**
  33  * See JVMS 4.4.4.
  34  *
  35  *  <p><b>This is NOT part of any supported API.
  36  *  If you write code that depends on this, you do so at your own risk.
  37  *  This code and its internal interfaces are subject to change or
  38  *  deletion without notice.</b>
  39  */
  40 public class Signature extends Descriptor {
  41 
  42     public Signature(int index) {
  43         super(index);
  44     }
  45 
  46     public Type getType(ConstantPool constant_pool) throws ConstantPoolException {
  47         if (type == null)
  48             type = parse(getValue(constant_pool));
  49         return type;
  50     }
  51 
  52     @Override
  53     public int getParameterCount(ConstantPool constant_pool) throws ConstantPoolException {
  54         MethodType m = (MethodType) getType(constant_pool);
  55         return m.paramTypes.size();
  56     }
  57 
  58     @Override
  59     public String getParameterTypes(ConstantPool constant_pool) throws ConstantPoolException {
  60         MethodType m = (MethodType) getType(constant_pool);
  61         StringBuilder sb = new StringBuilder();
  62         sb.append("(");
  63         String sep = "";
  64         for (Type paramType: m.paramTypes) {
  65             sb.append(sep);
  66             sb.append(paramType);
  67             sep = ", ";
  68         }
  69         sb.append(")");
  70         return sb.toString();
  71     }
  72 
  73     @Override
  74     public String getReturnType(ConstantPool constant_pool) throws ConstantPoolException {
  75         MethodType m = (MethodType) getType(constant_pool);
  76         return m.returnType.toString();
  77     }
  78 
  79     @Override
  80     public String getFieldType(ConstantPool constant_pool) throws ConstantPoolException {
  81         return getType(constant_pool).toString();
  82     }
  83 
  84     private Type parse(String sig) {
  85         this.sig = sig;
  86         sigp = 0;
  87 
  88         List<TypeParamType> typeParamTypes = null;
  89         if (sig.charAt(sigp) == '<')
  90             typeParamTypes = parseTypeParamTypes();
  91 
  92         if (sig.charAt(sigp) == '(') {
  93             List<Type> paramTypes = parseTypeSignatures(')');
  94             Type returnType = parseTypeSignature();
  95             List<Type> throwsTypes = null;
  96             while (sigp < sig.length() && sig.charAt(sigp) == '^') {
  97                 sigp++;
  98                 if (throwsTypes == null)
  99                     throwsTypes = new ArrayList<>();
 100                 throwsTypes.add(parseTypeSignature());
 101             }
 102             return new MethodType(typeParamTypes, paramTypes, returnType, throwsTypes);
 103         } else {
 104             Type t = parseTypeSignature();
 105             if (typeParamTypes == null && sigp == sig.length())
 106                 return t;
 107             Type superclass = t;
 108             List<Type> superinterfaces = null;
 109             while (sigp < sig.length()) {
 110                 if (superinterfaces == null)
 111                     superinterfaces = new ArrayList<>();
 112                 superinterfaces.add(parseTypeSignature());
 113             }
 114             return new ClassSigType(typeParamTypes, superclass, superinterfaces);
 115 
 116         }
 117     }
 118 
 119     private Type parseTypeSignature() {
 120         switch (sig.charAt(sigp)) {
 121             case 'B':
 122                 sigp++;
 123                 return new SimpleType("byte");
 124 
 125             case 'C':
 126                 sigp++;
 127                 return new SimpleType("char");
 128 
 129             case 'D':
 130                 sigp++;
 131                 return new SimpleType("double");
 132 
 133             case 'F':
 134                 sigp++;
 135                 return new SimpleType("float");
 136 
 137             case 'I':
 138                 sigp++;
 139                 return new SimpleType("int");
 140 
 141             case 'J':
 142                 sigp++;
 143                 return new SimpleType("long");
 144 
 145             case 'Q':
 146             case 'L':
 147                 return parseClassTypeSignature();
 148 
 149             case 'S':
 150                 sigp++;
 151                 return new SimpleType("short");
 152 
 153             case 'T':
 154                 return parseTypeVariableSignature();
 155 
 156             case 'V':
 157                 sigp++;
 158                 return new SimpleType("void");
 159 
 160             case 'Z':
 161                 sigp++;
 162                 return new SimpleType("boolean");
 163 
 164             case '[':
 165                 sigp++;
 166                 return new ArrayType(parseTypeSignature());
 167 
 168             case '*':
 169                 sigp++;
 170                 return new WildcardType();
 171 
 172             case '+':
 173                 sigp++;
 174                 return new WildcardType(WildcardType.Kind.EXTENDS, parseTypeSignature());
 175 
 176             case '-':
 177                 sigp++;
 178                 return new WildcardType(WildcardType.Kind.SUPER, parseTypeSignature());
 179 
 180             default:
 181                 throw new IllegalStateException(debugInfo());
 182         }
 183     }
 184 
 185     private List<Type> parseTypeSignatures(char term) {
 186         sigp++;
 187         List<Type> types = new ArrayList<>();
 188         while (sig.charAt(sigp) != term)
 189             types.add(parseTypeSignature());
 190         sigp++;
 191         return types;
 192     }
 193 
 194     private Type parseClassTypeSignature() {
 195         assert sig.charAt(sigp) == 'L' || sig.charAt(sigp) == 'Q';
 196         sigp++;
 197         return parseClassTypeSignatureRest();
 198     }
 199 
 200     private Type parseClassTypeSignatureRest() {
 201         StringBuilder sb = new StringBuilder();
 202         List<Type> argTypes = null;
 203         ClassType t = null;
 204         char sigch ;
 205 
 206         do {
 207             switch  (sigch = sig.charAt(sigp)) {
 208                 case '<':
 209                     argTypes = parseTypeSignatures('>');
 210                     break;
 211 
 212                 case '.':
 213                 case ';':
 214                     sigp++;
 215                     t = new ClassType(t, sb.toString(), argTypes);
 216                     sb.setLength(0);
 217                     argTypes = null;
 218                     break;
 219 
 220                 default:
 221                     sigp++;
 222                     sb.append(sigch);
 223                     break;
 224             }
 225         } while (sigch != ';');
 226 
 227         return t;
 228     }
 229 
 230     private List<TypeParamType> parseTypeParamTypes() {
 231         assert sig.charAt(sigp) == '<';
 232         sigp++;
 233         List<TypeParamType> types = new ArrayList<>();
 234         while (sig.charAt(sigp) != '>')
 235             types.add(parseTypeParamType());
 236         sigp++;
 237         return types;
 238     }
 239 
 240     private TypeParamType parseTypeParamType() {
 241         int sep = sig.indexOf(":", sigp);
 242         String name = sig.substring(sigp, sep);
 243         Type classBound = null;
 244         List<Type> interfaceBounds = null;
 245         sigp = sep + 1;
 246         if (sig.charAt(sigp) != ':')
 247             classBound = parseTypeSignature();
 248         while (sig.charAt(sigp) == ':') {
 249             sigp++;
 250             if (interfaceBounds == null)
 251                 interfaceBounds = new ArrayList<>();
 252             interfaceBounds.add(parseTypeSignature());
 253         }
 254         return new TypeParamType(name, classBound, interfaceBounds);
 255     }
 256 
 257     private Type parseTypeVariableSignature() {
 258         sigp++;
 259         int sep = sig.indexOf(';', sigp);
 260         Type t = new SimpleType(sig.substring(sigp, sep));
 261         sigp = sep + 1;
 262         return t;
 263     }
 264 
 265     private String debugInfo() {
 266         return sig.substring(0, sigp) + "!" + sig.charAt(sigp) + "!" + sig.substring(sigp+1);
 267     }
 268 
 269     private String sig;
 270     private int sigp;
 271 
 272     private Type type;
 273 }