diff options
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics')
5 files changed, 600 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java new file mode 100644 index 000000000000..66fab96d35c3 --- /dev/null +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java @@ -0,0 +1,30 @@ +/* + * 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 java.util.ArrayList; +import java.util.List; + +public class GenericClassDescriptor { + + public GenericType superclass; + + public List<GenericType> superinterfaces = new ArrayList<GenericType>(); + + public List<String> fparameters = new ArrayList<String>(); + + public List<List<GenericType>> fbounds = new ArrayList<List<GenericType>>(); +} diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java new file mode 100644 index 000000000000..598d17bef2d0 --- /dev/null +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java @@ -0,0 +1,21 @@ +/* + * 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; + +public class GenericFieldDescriptor { + + public GenericType type; +} diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java new file mode 100644 index 000000000000..3082ecaf9ddd --- /dev/null +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java @@ -0,0 +1,249 @@ +/* + * 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 org.jetbrains.java.decompiler.main.DecompilerContext; +import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; +import org.jetbrains.java.decompiler.struct.StructClass; + +import java.util.ArrayList; +import java.util.List; + +public class GenericMain { + + private static final String[] typeNames = { + "byte", + "char", + "double", + "float", + "int", + "long", + "short", + "boolean", + }; + + public static GenericClassDescriptor parseClassSignature(String signature) { + String original = signature; + try { + GenericClassDescriptor descriptor = new GenericClassDescriptor(); + + signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds); + + String superCl = GenericType.getNextType(signature); + descriptor.superclass = new GenericType(superCl); + + signature = signature.substring(superCl.length()); + while (signature.length() > 0) { + String superIf = GenericType.getNextType(signature); + descriptor.superinterfaces.add(new GenericType(superIf)); + signature = signature.substring(superIf.length()); + } + + return descriptor; + } + catch (RuntimeException e) { + DecompilerContext.getLogger().writeMessage("Invalid signature: " + original, IFernflowerLogger.Severity.WARN); + return null; + } + } + + public static GenericFieldDescriptor parseFieldSignature(String signature) { + try { + GenericFieldDescriptor descriptor = new GenericFieldDescriptor(); + descriptor.type = new GenericType(signature); + return descriptor; + } + catch (RuntimeException e) { + DecompilerContext.getLogger().writeMessage("Invalid signature: " + signature, IFernflowerLogger.Severity.WARN); + return null; + } + } + + public static GenericMethodDescriptor parseMethodSignature(String signature) { + String original = signature; + try { + GenericMethodDescriptor descriptor = new GenericMethodDescriptor(); + + signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds); + + int to = signature.indexOf(")"); + String pars = signature.substring(1, to); + signature = signature.substring(to + 1); + + while (pars.length() > 0) { + String par = GenericType.getNextType(pars); + descriptor.params.add(new GenericType(par)); + pars = pars.substring(par.length()); + } + + String par = GenericType.getNextType(signature); + descriptor.ret = new GenericType(par); + signature = signature.substring(par.length()); + + if (signature.length() > 0) { + String[] exceptions = signature.split("\\^"); + + for (int i = 1; i < exceptions.length; i++) { + descriptor.exceptions.add(new GenericType(exceptions[i])); + } + } + + return descriptor; + } + catch (RuntimeException e) { + DecompilerContext.getLogger().writeMessage("Invalid signature: " + original, IFernflowerLogger.Severity.WARN); + return null; + } + } + + private static String parseFormalParameters(String signature, List<String> parameters, List<List<GenericType>> bounds) { + if (signature.charAt(0) != '<') { + return signature; + } + + int counter = 1; + int index = 1; + + loop: + while (index < signature.length()) { + switch (signature.charAt(index)) { + case '<': + counter++; + break; + case '>': + counter--; + if (counter == 0) { + break loop; + } + } + + index++; + } + + String value = signature.substring(1, index); + signature = signature.substring(index + 1); + + while (value.length() > 0) { + int to = value.indexOf(":"); + + String param = value.substring(0, to); + value = value.substring(to + 1); + + List<GenericType> lstBounds = new ArrayList<GenericType>(); + + while (true) { + if (value.charAt(0) == ':') { + // empty superclass, skip + value = value.substring(1); + } + + String bound = GenericType.getNextType(value); + lstBounds.add(new GenericType(bound)); + value = value.substring(bound.length()); + + + if (value.length() == 0 || value.charAt(0) != ':') { + break; + } + else { + value = value.substring(1); + } + } + + parameters.add(param); + bounds.add(lstBounds); + } + + return signature; + } + + public static String getGenericCastTypeName(GenericType type) { + String s = getTypeName(type); + int dim = type.arraydim; + while (dim-- > 0) { + s += "[]"; + } + return s; + } + + private static String getTypeName(GenericType type) { + int tp = type.type; + if (tp <= CodeConstants.TYPE_BOOLEAN) { + return typeNames[tp]; + } + else if (tp == CodeConstants.TYPE_VOID) { + return "void"; + } + else if (tp == CodeConstants.TYPE_GENVAR) { + return type.value; + } + else if (tp == CodeConstants.TYPE_OBJECT) { + StringBuilder buffer = new StringBuilder(); + buffer.append(DecompilerContext.getImportCollector().getShortName(buildJavaClassName(type))); + + if (!type.getArguments().isEmpty()) { + buffer.append("<"); + for (int i = 0; i < type.getArguments().size(); i++) { + if (i > 0) { + buffer.append(", "); + } + int wildcard = type.getWildcards().get(i); + if (wildcard != GenericType.WILDCARD_NO) { + buffer.append("?"); + + switch (wildcard) { + case GenericType.WILDCARD_EXTENDS: + buffer.append(" extends "); + break; + case GenericType.WILDCARD_SUPER: + buffer.append(" super "); + } + } + + GenericType genPar = type.getArguments().get(i); + if (genPar != null) { + buffer.append(getGenericCastTypeName(genPar)); + } + } + buffer.append(">"); + } + + return buffer.toString(); + } + + throw new RuntimeException("Invalid type: " + type); + } + + private static String buildJavaClassName(GenericType type) { + String name = ""; + for (GenericType tp : type.getEnclosingClasses()) { + name += tp.value + "$"; + } + name += type.value; + + String res = name.replace('/', '.'); + + if (res.contains("$")) { + StructClass cl = DecompilerContext.getStructContext().getClass(name); + if (cl == null || !cl.isOwn()) { + res = res.replace('$', '.'); + } + } + + return res; + } +} diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java new file mode 100644 index 000000000000..7b4c9dc381f1 --- /dev/null +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java @@ -0,0 +1,32 @@ +/* + * 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 java.util.ArrayList; +import java.util.List; + +public class GenericMethodDescriptor { + + public List<String> fparameters = new ArrayList<String>(); + + public List<List<GenericType>> fbounds = new ArrayList<List<GenericType>>(); + + public List<GenericType> params = new ArrayList<GenericType>(); + + public GenericType ret; + + public List<GenericType> exceptions = new ArrayList<GenericType>(); +} diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java new file mode 100644 index 000000000000..160a0ac46035 --- /dev/null +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java @@ -0,0 +1,268 @@ +/* + * 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; + } +} |