blob: 160a0ac46035aa3d66f199f1d941cce9b4be1c40 [file] [log] [blame]
/*
* 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;
}
}