IDEA-129221 (tolerate invalid signature attributes)

master
Roman Shevchenko 10 years ago
parent e2f7d09f37
commit e90f1de039
  1. 14
      src/org/jetbrains/java/decompiler/main/ClassWriter.java
  2. 116
      src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java
  3. 42
      test/org/jetbrains/java/decompiler/SingleClassesTest.java
  4. BIN
      testData/classes/InvalidMethodSignature.class
  5. 26
      testData/results/InvalidMethodSignature.dec

@ -626,12 +626,14 @@ public class ClassWriter {
StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)mt.getAttributes().getWithKey("Signature"); StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)mt.getAttributes().getWithKey("Signature");
if (attr != null) { if (attr != null) {
descriptor = GenericMain.parseMethodSignature(attr.getSignature()); descriptor = GenericMain.parseMethodSignature(attr.getSignature());
int actualParams = md.params.length; if (descriptor != null) {
if (isEnum && init) actualParams -= 2; int actualParams = md.params.length;
if (actualParams != descriptor.params.size()) { if (isEnum && init) actualParams -= 2;
String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor(); if (actualParams != descriptor.params.size()) {
DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor();
descriptor = null; DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
descriptor = null;
}
} }
} }
} }

@ -17,6 +17,7 @@ package org.jetbrains.java.decompiler.struct.gen.generics;
import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.code.CodeConstants;
import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.DecompilerContext;
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
import org.jetbrains.java.decompiler.struct.StructClass; import org.jetbrains.java.decompiler.struct.StructClass;
import java.util.ArrayList; import java.util.ArrayList;
@ -24,7 +25,7 @@ import java.util.List;
public class GenericMain { public class GenericMain {
private static final String[] typeNames = new String[]{ private static final String[] typeNames = {
"byte", "byte",
"char", "char",
"double", "double",
@ -36,63 +37,80 @@ public class GenericMain {
}; };
public static GenericClassDescriptor parseClassSignature(String signature) { public static GenericClassDescriptor parseClassSignature(String signature) {
String original = signature;
try {
GenericClassDescriptor descriptor = new GenericClassDescriptor();
GenericClassDescriptor descriptor = new GenericClassDescriptor(); signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds);
signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds); String superCl = GenericType.getNextType(signature);
descriptor.superclass = new GenericType(superCl);
String supercl = GenericType.getNextType(signature); signature = signature.substring(superCl.length());
descriptor.superclass = new GenericType(supercl); while (signature.length() > 0) {
String superIf = GenericType.getNextType(signature);
descriptor.superinterfaces.add(new GenericType(superIf));
signature = signature.substring(superIf.length());
}
signature = signature.substring(supercl.length()); return descriptor;
while (signature.length() > 0) { }
String superintr = GenericType.getNextType(signature); catch (RuntimeException e) {
descriptor.superinterfaces.add(new GenericType(superintr)); DecompilerContext.getLogger().writeMessage("Invalid signature: " + original, IFernflowerLogger.Severity.WARN);
signature = signature.substring(superintr.length()); return null;
} }
return descriptor;
} }
public static GenericFieldDescriptor parseFieldSignature(String signature) { public static GenericFieldDescriptor parseFieldSignature(String signature) {
GenericFieldDescriptor descriptor = new GenericFieldDescriptor(); try {
descriptor.type = new GenericType(signature); GenericFieldDescriptor descriptor = new GenericFieldDescriptor();
return descriptor; 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) { public static GenericMethodDescriptor parseMethodSignature(String signature) {
String original = signature;
try {
GenericMethodDescriptor descriptor = new GenericMethodDescriptor();
GenericMethodDescriptor descriptor = new GenericMethodDescriptor(); signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds);
signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds);
int to = signature.indexOf(")"); int to = signature.indexOf(")");
String pars = signature.substring(1, to); String pars = signature.substring(1, to);
signature = signature.substring(to + 1); signature = signature.substring(to + 1);
while (pars.length() > 0) { while (pars.length() > 0) {
String par = GenericType.getNextType(pars); String par = GenericType.getNextType(pars);
descriptor.params.add(new GenericType(par)); descriptor.params.add(new GenericType(par));
pars = pars.substring(par.length()); pars = pars.substring(par.length());
} }
String par = GenericType.getNextType(signature); String par = GenericType.getNextType(signature);
descriptor.ret = new GenericType(par); descriptor.ret = new GenericType(par);
signature = signature.substring(par.length()); signature = signature.substring(par.length());
if (signature.length() > 0) { if (signature.length() > 0) {
String[] excs = signature.split("\\^"); String[] exceptions = signature.split("\\^");
for (int i = 1; i < excs.length; i++) { for (int i = 1; i < exceptions.length; i++) {
descriptor.exceptions.add(new GenericType(excs[i])); descriptor.exceptions.add(new GenericType(exceptions[i]));
}
} }
}
return descriptor; return descriptor;
}
catch (RuntimeException e) {
DecompilerContext.getLogger().writeMessage("Invalid signature: " + original, IFernflowerLogger.Severity.WARN);
return null;
}
} }
private static String parseFormalParameters(String signature, List<String> fparameters, List<List<GenericType>> fbounds) { private static String parseFormalParameters(String signature, List<String> parameters, List<List<GenericType>> bounds) {
if (signature.charAt(0) != '<') { if (signature.charAt(0) != '<') {
return signature; return signature;
} }
@ -120,10 +138,10 @@ public class GenericMain {
signature = signature.substring(index + 1); signature = signature.substring(index + 1);
while (value.length() > 0) { while (value.length() > 0) {
int parto = value.indexOf(":"); int to = value.indexOf(":");
String param = value.substring(0, parto); String param = value.substring(0, to);
value = value.substring(parto + 1); value = value.substring(to + 1);
List<GenericType> lstBounds = new ArrayList<GenericType>(); List<GenericType> lstBounds = new ArrayList<GenericType>();
@ -146,8 +164,8 @@ public class GenericMain {
} }
} }
fparameters.add(param); parameters.add(param);
fbounds.add(lstBounds); bounds.add(lstBounds);
} }
return signature; return signature;
@ -162,8 +180,7 @@ public class GenericMain {
return s; return s;
} }
public static String getTypeName(GenericType type) { private static String getTypeName(GenericType type) {
int tp = type.type; int tp = type.type;
if (tp <= CodeConstants.TYPE_BOOLEAN) { if (tp <= CodeConstants.TYPE_BOOLEAN) {
return typeNames[tp]; return typeNames[tp];
@ -197,9 +214,9 @@ public class GenericMain {
} }
} }
GenericType genpar = type.getArguments().get(i); GenericType genPar = type.getArguments().get(i);
if (genpar != null) { if (genPar != null) {
buffer.append(getGenericCastTypeName(genpar)); buffer.append(getGenericCastTypeName(genPar));
} }
} }
buffer.append(">"); buffer.append(">");
@ -208,11 +225,10 @@ public class GenericMain {
return buffer.toString(); return buffer.toString();
} }
throw new RuntimeException("invalid type"); throw new RuntimeException("Invalid type: " + type);
} }
public static String buildJavaClassName(GenericType type) { private static String buildJavaClassName(GenericType type) {
String name = ""; String name = "";
for (GenericType tp : type.getEnclosingClasses()) { for (GenericType tp : type.getEnclosingClasses()) {
name += tp.value + "$"; name += tp.value + "$";

@ -43,30 +43,32 @@ public class SingleClassesTest {
fixture = null; fixture = null;
} }
@Test public void testClassFields() { doTest("TestClassFields"); } @Test public void testClassFields() { doTest("pkg/TestClassFields"); }
@Test public void testClassLambda() { doTest("TestClassLambda"); } @Test public void testClassLambda() { doTest("pkg/TestClassLambda"); }
@Test public void testClassLoop() { doTest("TestClassLoop"); } @Test public void testClassLoop() { doTest("pkg/TestClassLoop"); }
@Test public void testClassSwitch() { doTest("TestClassSwitch"); } @Test public void testClassSwitch() { doTest("pkg/TestClassSwitch"); }
@Test public void testClassTypes() { doTest("TestClassTypes"); } @Test public void testClassTypes() { doTest("pkg/TestClassTypes"); }
@Test public void testClassVar() { doTest("TestClassVar"); } @Test public void testClassVar() { doTest("pkg/TestClassVar"); }
@Test public void testClassNestedInitializer() { doTest("TestClassNestedInitializer"); } @Test public void testClassNestedInitializer() { doTest("pkg/TestClassNestedInitializer"); }
@Test public void testClassCast() { doTest("TestClassCast"); } @Test public void testClassCast() { doTest("pkg/TestClassCast"); }
@Test public void testDeprecations() { doTest("TestDeprecations"); } @Test public void testDeprecations() { doTest("pkg/TestDeprecations"); }
@Test public void testExtendsList() { doTest("TestExtendsList"); } @Test public void testExtendsList() { doTest("pkg/TestExtendsList"); }
@Test public void testMethodParameters() { doTest("TestMethodParameters"); } @Test public void testMethodParameters() { doTest("pkg/TestMethodParameters"); }
@Test public void testCodeConstructs() { doTest("TestCodeConstructs"); } @Test public void testCodeConstructs() { doTest("pkg/TestCodeConstructs"); }
@Test public void testConstants() { doTest("TestConstants"); } @Test public void testConstants() { doTest("pkg/TestConstants"); }
@Test public void testEnum() { doTest("TestEnum"); } @Test public void testEnum() { doTest("pkg/TestEnum"); }
@Test public void testDebugSymbols() { doTest("TestDebugSymbols"); } @Test public void testDebugSymbols() { doTest("pkg/TestDebugSymbols"); }
@Test public void testInvalidMethodSignature() { doTest("InvalidMethodSignature"); }
private void doTest(final String testName) {
private void doTest(String testFile) {
try { try {
File classFile = new File(fixture.getTestDataDir(), "/classes/pkg/" + testName + ".class"); File classFile = new File(fixture.getTestDataDir(), "/classes/" + testFile + ".class");
assertTrue(classFile.isFile()); assertTrue(classFile.isFile());
String testName = classFile.getName().replace(".class", "");
ConsoleDecompiler decompiler = fixture.getDecompiler(); ConsoleDecompiler decompiler = fixture.getDecompiler();
for (File inner : collectClasses(classFile)) { for (File file : collectClasses(classFile)) {
decompiler.addSpace(inner, true); decompiler.addSpace(file, true);
} }
decompiler.decompileContext(); decompiler.decompileContext();

@ -0,0 +1,26 @@
package a.a.a.a.e.f;
import a.a.a.a.a.k;
import a.a.a.a.c.c;
import a.a.a.a.c.j;
import a.a.a.a.e.bg;
import a.a.a.a.e.f.b;
import java.io.File;
class i implements bg {
private final j a;
private final b b;
i(b var1, j var2) {
this.b = var1;
this.a = var2;
}
public void a(c var1, k var2, boolean var3) {
File var4 = this.a.b().a(var1);
b.a(this.b).add(var4);
}
public void a(a.a.a.a.c.b var1) {
}
}
Loading…
Cancel
Save