public ImportCollector(ClassesProcessor.ClassNode root) { // set of field names in this class and all its predecessors. string clName = root.classStruct.qualifiedName; int index = clName.LastIndexOf('/'); if (index >= 0) { string packageName = Sharpen.Runtime.Substring(clName, 0, index); currentPackageSlash = packageName + '/'; currentPackagePoint = packageName.Replace('/', '.'); } else { currentPackageSlash = string.Empty; currentPackagePoint = string.Empty; } Dictionary <string, StructClass> classes = DecompilerContext.GetStructContext().GetClasses (); LinkedList <string> queue = new LinkedList <string>(); StructClass currentClass = root.classStruct; while (currentClass != null) { if (currentClass.superClass != null) { queue.AddLast(currentClass.superClass.GetString()); } Sharpen.Collections.AddAll(queue, currentClass.GetInterfaceNames()); // all field names for the current class .. foreach (StructField f in currentClass.GetFields()) { setFieldNames.Add(f.GetName()); } // .. all inner classes for the current class .. StructInnerClassesAttribute attribute = currentClass.GetAttribute(StructGeneralAttribute .Attribute_Inner_Classes); if (attribute != null) { foreach (StructInnerClassesAttribute.Entry entry in attribute.GetEntries()) { if (entry.enclosingName != null && entry.enclosingName.Equals(currentClass.qualifiedName )) { setInnerClassNames.Add(entry.simpleName); } } } // .. and traverse through parent. currentClass = !(queue.Count == 0) ? classes.GetOrNull(Sharpen.Collections.RemoveFirst (queue)) : null; while (currentClass == null && !(queue.Count == 0)) { currentClass = classes.GetOrNull(Sharpen.Collections.RemoveFirst(queue)); } } }
public virtual void LoadClasses(IIdentifierRenamer renamer) { Dictionary <string, ClassesProcessor.Inner> mapInnerClasses = new Dictionary <string , ClassesProcessor.Inner>(); Dictionary <string, HashSet <string> > mapNestedClassReferences = new Dictionary <string , HashSet <string> >(); Dictionary <string, HashSet <string> > mapEnclosingClassReferences = new Dictionary <string, HashSet <string> >(); Dictionary <string, string> mapNewSimpleNames = new Dictionary <string, string>(); bool bDecompileInner = DecompilerContext.GetOption(IFernflowerPreferences.Decompile_Inner ); bool verifyAnonymousClasses = DecompilerContext.GetOption(IFernflowerPreferences .Verify_Anonymous_Classes); // create class nodes foreach (StructClass cl in context.GetClasses().Values) { if (cl.IsOwn() && !mapRootClasses.ContainsKey(cl.qualifiedName)) { if (bDecompileInner) { StructInnerClassesAttribute inner = cl.GetAttribute(StructGeneralAttribute.Attribute_Inner_Classes ); if (inner != null) { foreach (StructInnerClassesAttribute.Entry entry in inner.GetEntries()) { string innerName = entry.innerName; // original simple name string simpleName = entry.simpleName; string savedName = mapNewSimpleNames.GetOrNull(innerName); if (savedName != null) { simpleName = savedName; } else if (simpleName != null && renamer != null && renamer.ToBeRenamed(IIdentifierRenamer.Type .Element_Class, simpleName, null, null)) { simpleName = renamer.GetNextClassName(innerName, simpleName); Sharpen.Collections.Put(mapNewSimpleNames, innerName, simpleName); } ClassesProcessor.Inner rec = new ClassesProcessor.Inner(); rec.simpleName = simpleName; rec.type = entry.simpleNameIdx == 0 ? ClassesProcessor.ClassNode.Class_Anonymous : entry.outerNameIdx == 0 ? ClassesProcessor.ClassNode.Class_Local : ClassesProcessor.ClassNode .Class_Member; rec.accessFlags = entry.accessFlags; // enclosing class string enclClassName = entry.outerNameIdx != 0 ? entry.enclosingName : cl.qualifiedName; if (enclClassName == null || innerName.Equals(enclClassName)) { continue; } // invalid name or self reference if (rec.type == ClassesProcessor.ClassNode.Class_Member && !innerName.Equals(enclClassName + '$' + entry.simpleName)) { continue; } // not a real inner class StructClass enclosingClass = context.GetClasses().GetOrNull(enclClassName); if (enclosingClass != null && enclosingClass.IsOwn()) { // own classes only ClassesProcessor.Inner existingRec = mapInnerClasses.GetOrNull(innerName); if (existingRec == null) { Sharpen.Collections.Put(mapInnerClasses, innerName, rec); } else if (!ClassesProcessor.Inner.Equal(existingRec, rec)) { string message = "Inconsistent inner class entries for " + innerName + "!"; DecompilerContext.GetLogger().WriteMessage(message, IFernflowerLogger.Severity.Warn ); } // reference to the nested class mapNestedClassReferences.ComputeIfAbsent(enclClassName, (string k) => new HashSet <string>()).Add(innerName); // reference to the enclosing class mapEnclosingClassReferences.ComputeIfAbsent(innerName, (string k) => new HashSet < string>()).Add(enclClassName); } } } } ClassesProcessor.ClassNode node = new ClassesProcessor.ClassNode(ClassesProcessor.ClassNode .Class_Root, cl); node.access = cl.GetAccessFlags(); Sharpen.Collections.Put(mapRootClasses, cl.qualifiedName, node); } } if (bDecompileInner) { // connect nested classes foreach (KeyValuePair <string, ClassesProcessor.ClassNode> ent in mapRootClasses) { // root class? if (!mapInnerClasses.ContainsKey(ent.Key)) { HashSet <string> setVisited = new HashSet <string>(); LinkedList <string> stack = new LinkedList <string>(); stack.AddLast(ent.Key); setVisited.Add(ent.Key); while (!(stack.Count == 0)) { string superClass = Sharpen.Collections.RemoveFirst(stack); ClassesProcessor.ClassNode superNode = mapRootClasses.GetOrNull(superClass); HashSet <string> setNestedClasses = mapNestedClassReferences.GetOrNull(superClass); if (setNestedClasses != null) { StructClass scl = superNode.classStruct; StructInnerClassesAttribute inner = scl.GetAttribute(StructGeneralAttribute.Attribute_Inner_Classes ); if (inner == null || (inner.GetEntries().Count == 0)) { DecompilerContext.GetLogger().WriteMessage(superClass + " does not contain inner classes!" , IFernflowerLogger.Severity.Warn); continue; } foreach (StructInnerClassesAttribute.Entry entry in inner.GetEntries()) { string nestedClass = entry.innerName; if (!setNestedClasses.Contains(nestedClass)) { continue; } if (!setVisited.Add(nestedClass)) { continue; } ClassesProcessor.ClassNode nestedNode = mapRootClasses.GetOrNull(nestedClass); if (nestedNode == null) { DecompilerContext.GetLogger().WriteMessage("Nested class " + nestedClass + " missing!" , IFernflowerLogger.Severity.Warn); continue; } ClassesProcessor.Inner rec = mapInnerClasses.GetOrNull(nestedClass); //if ((Integer)arr[2] == ClassNode.CLASS_MEMBER) { // FIXME: check for consistent naming //} nestedNode.simpleName = rec.simpleName; nestedNode.type = rec.type; nestedNode.access = rec.accessFlags; // sanity checks of the class supposed to be anonymous if (verifyAnonymousClasses && nestedNode.type == ClassesProcessor.ClassNode.Class_Anonymous && !IsAnonymous(nestedNode.classStruct, scl)) { nestedNode.type = ClassesProcessor.ClassNode.Class_Local; } if (nestedNode.type == ClassesProcessor.ClassNode.Class_Anonymous) { StructClass cl = nestedNode.classStruct; // remove static if anonymous class (a common compiler bug) nestedNode.access &= ~ICodeConstants.Acc_Static; int[] interfaces = cl.GetInterfaces(); if (interfaces.Length > 0) { nestedNode.anonymousClassType = new VarType(cl.GetInterface(0), true); } else { nestedNode.anonymousClassType = new VarType(cl.superClass.GetString(), true); } } else if (nestedNode.type == ClassesProcessor.ClassNode.Class_Local) { // only abstract and final are permitted (a common compiler bug) nestedNode.access &= (ICodeConstants.Acc_Abstract | ICodeConstants.Acc_Final); } superNode.nested.Add(nestedNode); nestedNode.parent = superNode; Sharpen.Collections.AddAll(nestedNode.enclosingClasses, mapEnclosingClassReferences .GetOrNull(nestedClass)); stack.AddLast(nestedClass); } } } } } } }
private static bool IsAnonymous(StructClass cl, StructClass enclosingCl) { // checking super class and interfaces int[] interfaces = cl.GetInterfaces(); if (interfaces.Length > 0) { bool hasNonTrivialSuperClass = cl.superClass != null && !VarType.Vartype_Object.Equals (new VarType(cl.superClass.GetString(), true)); if (hasNonTrivialSuperClass || interfaces.Length > 1) { // can't have multiple 'sources' string message = "Inconsistent anonymous class definition: '" + cl.qualifiedName + "'. Multiple interfaces and/or super class defined."; DecompilerContext.GetLogger().WriteMessage(message, IFernflowerLogger.Severity.Warn ); return(false); } } else if (cl.superClass == null) { // neither interface nor super class defined string message = "Inconsistent anonymous class definition: '" + cl.qualifiedName + "'. Neither interface nor super class defined."; DecompilerContext.GetLogger().WriteMessage(message, IFernflowerLogger.Severity.Warn ); return(false); } // FIXME: check constructors // FIXME: check enclosing class/method ConstantPool pool = enclosingCl.GetPool(); int refCounter = 0; bool refNotNew = false; StructEnclosingMethodAttribute attribute = cl.GetAttribute(StructGeneralAttribute .Attribute_Enclosing_Method); string enclosingMethod = attribute != null?attribute.GetMethodName() : null; // checking references in the enclosing class foreach (StructMethod mt in enclosingCl.GetMethods()) { if (enclosingMethod != null && !enclosingMethod.Equals(mt.GetName())) { continue; } try { mt.ExpandData(); InstructionSequence seq = mt.GetInstructionSequence(); if (seq != null) { int len = seq.Length(); for (int i = 0; i < len; i++) { Instruction instr = seq.GetInstr(i); switch (instr.opcode) { case opc_checkcast: case opc_instanceof: { if (cl.qualifiedName.Equals(pool.GetPrimitiveConstant(instr.Operand(0)).GetString ())) { refCounter++; refNotNew = true; } break; } case opc_new: case opc_anewarray: case opc_multianewarray: { if (cl.qualifiedName.Equals(pool.GetPrimitiveConstant(instr.Operand(0)).GetString ())) { refCounter++; } break; } case opc_getstatic: case opc_putstatic: { if (cl.qualifiedName.Equals(pool.GetLinkConstant(instr.Operand(0)).classname)) { refCounter++; refNotNew = true; } break; } } } } mt.ReleaseResources(); } catch (IOException) { string message = "Could not read method while checking anonymous class definition: '" + enclosingCl.qualifiedName + "', '" + InterpreterUtil.MakeUniqueKey(mt.GetName (), mt.GetDescriptor()) + "'"; DecompilerContext.GetLogger().WriteMessage(message, IFernflowerLogger.Severity.Warn ); return(false); } if (refCounter > 1 || refNotNew) { string message = "Inconsistent references to the class '" + cl.qualifiedName + "' which is supposed to be anonymous"; DecompilerContext.GetLogger().WriteMessage(message, IFernflowerLogger.Severity.Warn ); return(false); } } return(true); }
/// <exception cref="IOException"/> public virtual void ProcessClass(ClassesProcessor.ClassNode node) { foreach (ClassesProcessor.ClassNode child in node.nested) { ProcessClass(child); } ClassesProcessor clProcessor = DecompilerContext.GetClassProcessor(); StructClass cl = node.classStruct; if (cl.GetBytecodeVersion() < ICodeConstants.Bytecode_Java_8) { // lambda beginning with Java 8 return; } StructBootstrapMethodsAttribute bootstrap = cl.GetAttribute(StructGeneralAttribute .Attribute_Bootstrap_Methods); if (bootstrap == null || bootstrap.GetMethodsNumber() == 0) { return; } // no bootstrap constants in pool BitSet lambda_methods = new BitSet(); // find lambda bootstrap constants for (int i = 0; i < bootstrap.GetMethodsNumber(); ++i) { LinkConstant method_ref = bootstrap.GetMethodReference(i); // method handle // FIXME: extend for Eclipse etc. at some point if (Javac_Lambda_Class.Equals(method_ref.classname) && (Javac_Lambda_Method.Equals (method_ref.elementname) || Javac_Lambda_Alt_Method.Equals(method_ref.elementname ))) { lambda_methods.Set(i); } } if (lambda_methods.IsEmpty()) { return; } // no lambda bootstrap constant found Dictionary <string, string> mapMethodsLambda = new Dictionary <string, string>(); // iterate over code and find invocations of bootstrap methods. Replace them with anonymous classes. foreach (StructMethod mt in cl.GetMethods()) { mt.ExpandData(); InstructionSequence seq = mt.GetInstructionSequence(); if (seq != null && seq.Length() > 0) { int len = seq.Length(); for (int i = 0; i < len; ++i) { Instruction instr = seq.GetInstr(i); if (instr.opcode == ICodeConstants.opc_invokedynamic) { LinkConstant invoke_dynamic = cl.GetPool().GetLinkConstant(instr.Operand(0)); if (lambda_methods.Get(invoke_dynamic.index1)) { // lambda invocation found List <PooledConstant> bootstrap_arguments = bootstrap.GetMethodArguments(invoke_dynamic .index1); MethodDescriptor md = MethodDescriptor.ParseDescriptor(invoke_dynamic.descriptor); string lambda_class_name = md.ret.value; string lambda_method_name = invoke_dynamic.elementname; string lambda_method_descriptor = ((PrimitiveConstant)bootstrap_arguments[2]).GetString (); // method type LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments[1]; ClassesProcessor.ClassNode node_lambda = new ClassesProcessor.ClassNode(content_method_handle .classname, content_method_handle.elementname, content_method_handle.descriptor, content_method_handle.index1, lambda_class_name, lambda_method_name, lambda_method_descriptor , cl); node_lambda.simpleName = cl.qualifiedName + "##Lambda_" + invoke_dynamic.index1 + "_" + invoke_dynamic.index2; node_lambda.enclosingMethod = InterpreterUtil.MakeUniqueKey(mt.GetName(), mt.GetDescriptor ()); node.nested.Add(node_lambda); node_lambda.parent = node; Sharpen.Collections.Put(clProcessor.GetMapRootClasses(), node_lambda.simpleName, node_lambda); if (!node_lambda.lambdaInformation.is_method_reference) { Sharpen.Collections.Put(mapMethodsLambda, node_lambda.lambdaInformation.content_method_key , node_lambda.simpleName); } } } } } mt.ReleaseResources(); } // build class hierarchy on lambda foreach (ClassesProcessor.ClassNode nd in node.nested) { if (nd.type == ClassesProcessor.ClassNode.Class_Lambda) { string parent_class_name = mapMethodsLambda.GetOrNull(nd.enclosingMethod); if (parent_class_name != null) { ClassesProcessor.ClassNode parent_class = clProcessor.GetMapRootClasses().GetOrNull (parent_class_name); parent_class.nested.Add(nd); nd.parent = parent_class; } } } }