| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.jetbrains.java.decompiler.struct.gen.generics; |
| |
| import org.jetbrains.java.decompiler.code.CodeConstants; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| public class GenericType { |
| |
| public static final int WILDCARD_EXTENDS = 1; |
| public static final int WILDCARD_SUPER = 2; |
| public static final int WILDCARD_UNBOUND = 3; |
| public static final int WILDCARD_NO = 4; |
| |
| public int type; |
| |
| public int arraydim; |
| |
| public String value; |
| |
| |
| private List<GenericType> enclosingClasses = new ArrayList<GenericType>(); |
| |
| private List<GenericType> arguments = new ArrayList<GenericType>(); |
| |
| private List<Integer> wildcards = new ArrayList<Integer>(); |
| |
| |
| public GenericType(int type, int arraydim, String value) { |
| this.type = type; |
| this.arraydim = arraydim; |
| this.value = value; |
| } |
| |
| |
| public GenericType(String strtype) { |
| |
| parseSignature(strtype); |
| } |
| |
| private void parseSignature(String sig) { |
| |
| int index = 0; |
| while (index < sig.length()) { |
| |
| switch (sig.charAt(index)) { |
| case '[': |
| arraydim++; |
| break; |
| case 'T': |
| type = CodeConstants.TYPE_GENVAR; |
| value = sig.substring(index + 1, sig.length() - 1); |
| return; |
| case 'L': |
| type = CodeConstants.TYPE_OBJECT; |
| sig = sig.substring(index + 1, sig.length() - 1); |
| |
| while (true) { |
| String cl = getNextClassSignature(sig); |
| |
| String name = cl; |
| String args = null; |
| |
| int argfrom = cl.indexOf("<"); |
| if (argfrom >= 0) { |
| name = cl.substring(0, argfrom); |
| args = cl.substring(argfrom + 1, cl.length() - 1); |
| } |
| |
| if (cl.length() < sig.length()) { |
| sig = sig.substring(cl.length() + 1); // skip '.' |
| GenericType type = new GenericType(CodeConstants.TYPE_OBJECT, 0, name); |
| parseArgumentsList(args, type); |
| enclosingClasses.add(type); |
| } |
| else { |
| value = name; |
| parseArgumentsList(args, this); |
| break; |
| } |
| } |
| |
| return; |
| default: |
| value = sig.substring(index, index + 1); |
| type = getType(value.charAt(0)); |
| } |
| |
| index++; |
| } |
| } |
| |
| private static String getNextClassSignature(String value) { |
| |
| int counter = 0; |
| int index = 0; |
| |
| loop: |
| while (index < value.length()) { |
| switch (value.charAt(index)) { |
| case '<': |
| counter++; |
| break; |
| case '>': |
| counter--; |
| break; |
| case '.': |
| if (counter == 0) { |
| break loop; |
| } |
| } |
| |
| index++; |
| } |
| |
| return value.substring(0, index); |
| } |
| |
| private static void parseArgumentsList(String value, GenericType type) { |
| |
| if (value == null) { |
| return; |
| } |
| |
| while (value.length() > 0) { |
| |
| String tstr = getNextType(value); |
| int len = tstr.length(); |
| int wildcard = WILDCARD_NO; |
| |
| switch (tstr.charAt(0)) { |
| case '*': |
| wildcard = WILDCARD_UNBOUND; |
| break; |
| case '+': |
| wildcard = WILDCARD_EXTENDS; |
| break; |
| case '-': |
| wildcard = WILDCARD_SUPER; |
| break; |
| } |
| |
| type.getWildcards().add(wildcard); |
| |
| if (wildcard != WILDCARD_NO) { |
| tstr = tstr.substring(1); |
| } |
| |
| type.getArguments().add(tstr.length() == 0 ? null : new GenericType(tstr)); |
| |
| value = value.substring(len); |
| } |
| } |
| |
| public static String getNextType(String value) { |
| |
| int counter = 0; |
| int index = 0; |
| |
| boolean contmode = false; |
| |
| loop: |
| while (index < value.length()) { |
| switch (value.charAt(index)) { |
| case '*': |
| if (!contmode) { |
| break loop; |
| } |
| break; |
| case 'L': |
| case 'T': |
| if (!contmode) { |
| contmode = true; |
| } |
| case '[': |
| case '+': |
| case '-': |
| break; |
| default: |
| if (!contmode) { |
| break loop; |
| } |
| break; |
| case '<': |
| counter++; |
| break; |
| case '>': |
| counter--; |
| break; |
| case ';': |
| if (counter == 0) { |
| break loop; |
| } |
| } |
| |
| index++; |
| } |
| |
| return value.substring(0, index + 1); |
| } |
| |
| private static int getType(char c) { |
| switch (c) { |
| case 'B': |
| return CodeConstants.TYPE_BYTE; |
| case 'C': |
| return CodeConstants.TYPE_CHAR; |
| case 'D': |
| return CodeConstants.TYPE_DOUBLE; |
| case 'F': |
| return CodeConstants.TYPE_FLOAT; |
| case 'I': |
| return CodeConstants.TYPE_INT; |
| case 'J': |
| return CodeConstants.TYPE_LONG; |
| case 'S': |
| return CodeConstants.TYPE_SHORT; |
| case 'Z': |
| return CodeConstants.TYPE_BOOLEAN; |
| case 'V': |
| return CodeConstants.TYPE_VOID; |
| case 'G': |
| return CodeConstants.TYPE_GROUP2EMPTY; |
| case 'N': |
| return CodeConstants.TYPE_NOTINITIALIZED; |
| case 'A': |
| return CodeConstants.TYPE_ADDRESS; |
| case 'X': |
| return CodeConstants.TYPE_BYTECHAR; |
| case 'Y': |
| return CodeConstants.TYPE_SHORTCHAR; |
| case 'U': |
| return CodeConstants.TYPE_UNKNOWN; |
| default: |
| throw new RuntimeException("Invalid type"); |
| } |
| } |
| |
| |
| public List<GenericType> getArguments() { |
| return arguments; |
| } |
| |
| |
| public List<GenericType> getEnclosingClasses() { |
| return enclosingClasses; |
| } |
| |
| |
| public List<Integer> getWildcards() { |
| return wildcards; |
| } |
| } |