IDEA-127301: handling of static method references

master
Stiver 11 years ago
parent 6606a474bf
commit 7f116b6eb5
  1. 29
      src/de/fernflower/main/ClassWriter.java
  2. 17
      src/de/fernflower/main/ClassesProcessor.java
  3. 14
      src/de/fernflower/main/rels/LambdaProcessor.java
  4. 8
      src/de/fernflower/main/rels/NestedClassProcessor.java

@ -134,6 +134,16 @@ public class ClassWriter {
DecompilerContext.getLogger().startWriteClass(node.simpleName); DecompilerContext.getLogger().startWriteClass(node.simpleName);
if(node.lambda_information.is_method_reference) {
writer.write(ExprProcessor.getCastTypeName(new VarType(node.lambda_information.content_class_name, false)));
writer.write("::");
writer.write(node.lambda_information.content_method_name);
writer.flush();
} else {
// lambda method // lambda method
StructMethod mt = cl.getMethod(node.lambda_information.content_method_key); StructMethod mt = cl.getMethod(node.lambda_information.content_method_key);
MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()); MethodWrapper meth = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
@ -191,6 +201,7 @@ public class ClassWriter {
writer.write(InterpreterUtil.getIndentString(indent)); writer.write(InterpreterUtil.getIndentString(indent));
writer.write("}"); writer.write("}");
writer.flush(); writer.flush();
}
DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, nodeold); DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASSNODE, nodeold);
@ -345,7 +356,7 @@ public class ClassWriter {
} }
} }
if(isDeprecated) { if (isDeprecated) {
writer.write(indstr); writer.write(indstr);
writer.write("/** @deprecated */"); writer.write("/** @deprecated */");
writer.write(DecompilerContext.getNewLineSeparator()); writer.write(DecompilerContext.getNewLineSeparator());
@ -481,7 +492,7 @@ public class ClassWriter {
boolean isDeprecated = fd.getAttributes().containsKey("Deprecated"); boolean isDeprecated = fd.getAttributes().containsKey("Deprecated");
if(isDeprecated) { if (isDeprecated) {
writer.write(indstr); writer.write(indstr);
writer.write("/** @deprecated */"); writer.write("/** @deprecated */");
writer.write(DecompilerContext.getNewLineSeparator()); writer.write(DecompilerContext.getNewLineSeparator());
@ -705,7 +716,7 @@ public class ClassWriter {
} }
} }
if(isDeprecated) { if (isDeprecated) {
writer.write(indstr); writer.write(indstr);
writer.write("/** @deprecated */"); writer.write("/** @deprecated */");
writer.write(DecompilerContext.getNewLineSeparator()); writer.write(DecompilerContext.getNewLineSeparator());
@ -748,15 +759,15 @@ public class ClassWriter {
} }
String name = mt.getName(); String name = mt.getName();
if("<init>".equals(name)) { if ("<init>".equals(name)) {
if(node.type == ClassNode.CLASS_ANONYMOUS) { if (node.type == ClassNode.CLASS_ANONYMOUS) {
name = ""; name = "";
dinit = true; dinit = true;
} else { } else {
name = node.simpleName; name = node.simpleName;
init = true; init = true;
} }
} else if("<clinit>".equals(name)) { } else if ("<clinit>".equals(name)) {
name = ""; name = "";
clinit = true; clinit = true;
} }
@ -797,7 +808,7 @@ public class ClassWriter {
bufstrwriter.write(" extends "); bufstrwriter.write(" extends ");
bufstrwriter.write(GenericMain.getGenericCastTypeName(lstBounds.get(0))); bufstrwriter.write(GenericMain.getGenericCastTypeName(lstBounds.get(0)));
for(int j=1;j<lstBounds.size();j++) { for(int j = 1; j < lstBounds.size(); j++) {
bufstrwriter.write(" & " + GenericMain.getGenericCastTypeName(lstBounds.get(j))); bufstrwriter.write(" & " + GenericMain.getGenericCastTypeName(lstBounds.get(j)));
} }
} }
@ -834,8 +845,8 @@ public class ClassWriter {
int index = isEnum && init ? 3 : thisvar ? 1 : 0; int index = isEnum && init ? 3 : thisvar ? 1 : 0;
int start = isEnum && init && descriptor == null ? 2 : 0; int start = isEnum && init && descriptor == null ? 2 : 0;
int params = descriptor == null ? md.params.length : descriptor.params.size(); int params = descriptor == null ? md.params.length : descriptor.params.size();
for(int i=start;i<params;i++) { for(int i = start; i < params; i++) {
if(signFields == null || signFields.get(i) == null) { if (signFields == null || signFields.get(i) == null) {
if(!firstpar) { if(!firstpar) {
bufstrwriter.write(", "); bufstrwriter.write(", ");

@ -41,6 +41,7 @@ import de.fernflower.modules.decompiler.exps.InvocationExprent;
import de.fernflower.modules.decompiler.vars.VarVersionPaar; import de.fernflower.modules.decompiler.vars.VarVersionPaar;
import de.fernflower.struct.StructClass; import de.fernflower.struct.StructClass;
import de.fernflower.struct.StructContext; import de.fernflower.struct.StructContext;
import de.fernflower.struct.StructMethod;
import de.fernflower.struct.attr.StructInnerClassesAttribute; import de.fernflower.struct.attr.StructInnerClassesAttribute;
import de.fernflower.struct.gen.VarType; import de.fernflower.struct.gen.VarType;
import de.fernflower.util.InterpreterUtil; import de.fernflower.util.InterpreterUtil;
@ -378,7 +379,7 @@ public class ClassesProcessor {
public LambdaInformation lambda_information; public LambdaInformation lambda_information;
public ClassNode(String content_method_name, String content_method_descriptor, String lambda_class_name, String lambda_method_name, public ClassNode(String content_class_name, String content_method_name, String content_method_descriptor, String lambda_class_name, String lambda_method_name,
String lambda_method_descriptor, StructClass classStruct) { // lambda class constructor String lambda_method_descriptor, StructClass classStruct) { // lambda class constructor
this.type = CLASS_LAMBDA; this.type = CLASS_LAMBDA;
this.classStruct = classStruct; // 'parent' class containing the static function this.classStruct = classStruct; // 'parent' class containing the static function
@ -389,13 +390,22 @@ public class ClassesProcessor {
lambda_information.method_name = lambda_method_name; lambda_information.method_name = lambda_method_name;
lambda_information.method_descriptor = lambda_method_descriptor; lambda_information.method_descriptor = lambda_method_descriptor;
lambda_information.content_class_name = content_class_name;
lambda_information.content_method_name = content_method_name; lambda_information.content_method_name = content_method_name;
lambda_information.content_method_descriptor = content_method_descriptor; lambda_information.content_method_descriptor = content_method_descriptor;
lambda_information.content_method_key = InterpreterUtil.makeUniqueKey(lambda_information.content_method_name, lambda_information.content_method_descriptor); lambda_information.content_method_key = InterpreterUtil.makeUniqueKey(lambda_information.content_method_name, lambda_information.content_method_descriptor);
anonimousClassType = new VarType(lambda_class_name, true); anonimousClassType = new VarType(lambda_class_name, true);
lambda_information.is_content_method_static = ((classStruct.getMethod(content_method_name, content_method_descriptor).getAccessFlags() & CodeConstants.ACC_STATIC) != 0); if(content_class_name != classStruct.qualifiedName) { // method reference. FIXME: class name alone doesn't cover it. Synthetic flag seems to be the only 'reliable' difference.
lambda_information.is_method_reference = true;
lambda_information.is_content_method_static = true; // FIXME: consider argument flag
} else {
StructMethod mt = classStruct.getMethod(content_method_name, content_method_descriptor);
lambda_information.is_method_reference = false;
lambda_information.is_content_method_static = ((mt.getAccessFlags() & CodeConstants.ACC_STATIC) != 0);
}
} }
public ClassNode(int type, StructClass classStruct) { public ClassNode(int type, StructClass classStruct) {
@ -419,10 +429,13 @@ public class ClassesProcessor {
public String method_name; public String method_name;
public String method_descriptor; public String method_descriptor;
public String content_class_name;
public String content_method_name; public String content_method_name;
public String content_method_descriptor; public String content_method_descriptor;
public String content_method_key; public String content_method_key;
public boolean is_method_reference;
public boolean is_content_method_static; public boolean is_content_method_static;
} }
} }

@ -50,7 +50,9 @@ public class LambdaProcessor {
} }
StructBootstrapMethodsAttribute bootstrap = (StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS); StructBootstrapMethodsAttribute bootstrap = (StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
if(bootstrap != null && bootstrap.getMethodsNumber() > 0) { if(bootstrap == null || bootstrap.getMethodsNumber() == 0) {
return false; // no bootstrap constants in pool
}
Set<Integer> lambda_methods = new HashSet<Integer>(); Set<Integer> lambda_methods = new HashSet<Integer>();
@ -66,7 +68,7 @@ public class LambdaProcessor {
} }
if(lambda_methods.isEmpty()) { if(lambda_methods.isEmpty()) {
return false; return false; // no lambda bootstrap constant found
} }
Map<String, String> mapMethodsLambda = new HashMap<String, String>(); Map<String, String> mapMethodsLambda = new HashMap<String, String>();
@ -96,8 +98,8 @@ public class LambdaProcessor {
LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments.get(1); LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments.get(1);
ClassNode node_lambda = clprocessor.new ClassNode(content_method_handle.elementname, content_method_handle.descriptor, lambda_class_name, ClassNode node_lambda = clprocessor.new ClassNode(content_method_handle.classname, content_method_handle.elementname, content_method_handle.descriptor,
lambda_method_name, lambda_method_descriptor, cl); lambda_class_name, lambda_method_name, lambda_method_descriptor, cl);
node_lambda.simpleName = cl.qualifiedName + "##Lambda_" + invoke_dynamic.index1 + "_" + invoke_dynamic.index2; node_lambda.simpleName = cl.qualifiedName + "##Lambda_" + invoke_dynamic.index1 + "_" + invoke_dynamic.index2;
node_lambda.enclosingMethod = InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()); node_lambda.enclosingMethod = InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor());
@ -110,6 +112,8 @@ public class LambdaProcessor {
} }
} }
} }
mt.releaseResources();
} }
// build class hierarchy on lambda // build class hierarchy on lambda
@ -127,8 +131,6 @@ public class LambdaProcessor {
// FIXME: mixed hierarchy? // FIXME: mixed hierarchy?
}
return false; return false;
} }

@ -79,9 +79,9 @@ public class NestedClassProcessor {
int nameless = 0, synthetics = 0; int nameless = 0, synthetics = 0;
for(ClassNode child : node.nested) { for(ClassNode child : node.nested) {
// ensure not-empty class name // ensure not-empty class name
if((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_MEMBER) && child.simpleName == null) { if ((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_MEMBER) && child.simpleName == null) {
StructClass cl = child.classStruct; StructClass cl = child.classStruct;
if(((child.access | cl.access_flags) & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic")) { if (((child.access | cl.access_flags) & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic")) {
child.simpleName = "SyntheticClass_" + (++synthetics); child.simpleName = "SyntheticClass_" + (++synthetics);
} else { } else {
DecompilerContext.getLogger().writeMessage("Nameless local or member class " + cl.qualifiedName + "!", IFernflowerLogger.WARNING); DecompilerContext.getLogger().writeMessage("Nameless local or member class " + cl.qualifiedName + "!", IFernflowerLogger.WARNING);
@ -112,6 +112,10 @@ public class NestedClassProcessor {
private void setLambdaVars(ClassNode parent, ClassNode child) { private void setLambdaVars(ClassNode parent, ClassNode child) {
if(child.lambda_information.is_method_reference) { // method reference, no code and no parameters
return;
}
final MethodWrapper meth = parent.wrapper.getMethods().getWithKey(child.lambda_information.content_method_key); final MethodWrapper meth = parent.wrapper.getMethods().getWithKey(child.lambda_information.content_method_key);
final MethodWrapper encmeth = parent.wrapper.getMethods().getWithKey(child.enclosingMethod); final MethodWrapper encmeth = parent.wrapper.getMethods().getWithKey(child.enclosingMethod);

Loading…
Cancel
Save