/// <exception cref="System.IO.IOException"/> public virtual void WriteClass(StructClass cl, TextBuffer buffer) { ClassesProcessor.ClassNode root = mapRootClasses.GetOrNull(cl.qualifiedName); if (root.type != ClassesProcessor.ClassNode.Class_Root) { return; } DecompilerContext.GetLogger().StartReadingClass(cl.qualifiedName); try { ImportCollector importCollector = new ImportCollector(root); DecompilerContext.StartClass(importCollector); new LambdaProcessor().ProcessClass(root); // add simple class names to implicit import AddClassnameToImport(root, importCollector); // build wrappers for all nested classes (that's where actual processing takes place) InitWrappers(root); new NestedClassProcessor().ProcessClass(root, root); new NestedMemberAccess().PropagateMemberAccess(root); TextBuffer classBuffer = new TextBuffer(Average_Class_Size); new ClassWriter().ClassToJava(root, classBuffer, 0, null); int index = cl.qualifiedName.LastIndexOf("/"); if (index >= 0) { string packageName = Sharpen.Runtime.Substring(cl.qualifiedName, 0, index).Replace ('/', '.'); buffer.Append("package "); buffer.Append(packageName); buffer.Append(";"); buffer.AppendLineSeparator(); buffer.AppendLineSeparator(); } int import_lines_written = importCollector.WriteImports(buffer); if (import_lines_written > 0) { buffer.AppendLineSeparator(); } int offsetLines = buffer.CountLines(); buffer.Append(classBuffer); if (DecompilerContext.GetOption(IFernflowerPreferences.Bytecode_Source_Mapping)) { BytecodeSourceMapper mapper = DecompilerContext.GetBytecodeSourceMapper(); mapper.AddTotalOffset(offsetLines); if (DecompilerContext.GetOption(IFernflowerPreferences.Dump_Original_Lines)) { buffer.DumpOriginalLineNumbers(mapper.GetOriginalLinesMapping()); } if (DecompilerContext.GetOption(IFernflowerPreferences.Unit_Test_Mode)) { buffer.AppendLineSeparator(); mapper.DumpMapping(buffer, true); } } } finally { DestroyWrappers(root); DecompilerContext.GetLogger().EndReadingClass(); } }
private static StructField FindAssertionField(ClassesProcessor.ClassNode node) { ClassWrapper wrapper = node.GetWrapper(); bool noSynthFlag = DecompilerContext.GetOption(IFernflowerPreferences.Synthetic_Not_Set ); foreach (StructField fd in wrapper.GetClassStruct().GetFields()) { string keyField = InterpreterUtil.MakeUniqueKey(fd.GetName(), fd.GetDescriptor()); // initializer exists if (wrapper.GetStaticFieldInitializers().ContainsKey(keyField)) { // access flags set if (fd.HasModifier(ICodeConstants.Acc_Static) && fd.HasModifier(ICodeConstants.Acc_Final ) && (noSynthFlag || fd.IsSynthetic())) { // field type boolean FieldDescriptor fdescr = FieldDescriptor.ParseDescriptor(fd.GetDescriptor()); if (VarType.Vartype_Boolean.Equals(fdescr.type)) { Exprent initializer = wrapper.GetStaticFieldInitializers().GetWithKey(keyField); if (initializer.type == Exprent.Exprent_Function) { FunctionExprent fexpr = (FunctionExprent)initializer; if (fexpr.GetFuncType() == FunctionExprent.Function_Bool_Not && fexpr.GetLstOperands ()[0].type == Exprent.Exprent_Invocation) { InvocationExprent invexpr = (InvocationExprent)fexpr.GetLstOperands()[0]; if (invexpr.GetInstance() != null && invexpr.GetInstance().type == Exprent.Exprent_Const && "desiredAssertionStatus".Equals(invexpr.GetName()) && "java/lang/Class".Equals (invexpr.GetClassname()) && (invexpr.GetLstParameters().Count == 0)) { ConstExprent cexpr = (ConstExprent)invexpr.GetInstance(); if (VarType.Vartype_Class.Equals(cexpr.GetConstType())) { ClassesProcessor.ClassNode nd = node; while (nd != null) { if (nd.GetWrapper().GetClassStruct().qualifiedName.Equals(cexpr.GetValue())) { break; } nd = nd.parent; } if (nd != null) { // found enclosing class with the same name return(fd); } } } } } } } } } return(null); }
private static void MapClassMethods(ClassesProcessor.ClassNode node, Dictionary < ClassWrapper, MethodWrapper> map) { bool noSynthFlag = DecompilerContext.GetOption(IFernflowerPreferences.Synthetic_Not_Set ); ClassWrapper wrapper = node.GetWrapper(); foreach (MethodWrapper method in wrapper.GetMethods()) { StructMethod mt = method.methodStruct; if ((noSynthFlag || mt.IsSynthetic()) && mt.GetDescriptor().Equals("(Ljava/lang/String;)Ljava/lang/Class;" ) && mt.HasModifier(ICodeConstants.Acc_Static)) { RootStatement root = method.root; if (root != null && root.GetFirst().type == Statement.Type_Trycatch) { CatchStatement cst = (CatchStatement)root.GetFirst(); if (cst.GetStats().Count == 2 && cst.GetFirst().type == Statement.Type_Basicblock && cst.GetStats()[1].type == Statement.Type_Basicblock && cst.GetVars()[0].GetVarType ().Equals(new VarType(ICodeConstants.Type_Object, 0, "java/lang/ClassNotFoundException" ))) { BasicBlockStatement body = (BasicBlockStatement)cst.GetFirst(); BasicBlockStatement handler = (BasicBlockStatement)cst.GetStats()[1]; if (body.GetExprents().Count == 1 && handler.GetExprents().Count == 1) { if (Body_Expr.Equals(body.GetExprents()[0]) && Handler_Expr.Equals(handler.GetExprents ()[0])) { Sharpen.Collections.Put(map, wrapper, method); break; } } } } } } // iterate nested classes foreach (ClassesProcessor.ClassNode nd in node.nested) { MapClassMethods(nd, map); } }
public static void ExtractInitializers(ClassWrapper wrapper) { MethodWrapper method = wrapper.GetMethodWrapper(ICodeConstants.Clinit_Name, "()V" ); if (method != null && method.root != null) { // successfully decompiled static constructor ExtractStaticInitializers(wrapper, method); } ExtractDynamicInitializers(wrapper); // required e.g. if anonymous class is being decompiled as a standard one. // This can happen if InnerClasses attributes are erased LiftConstructor(wrapper); if (DecompilerContext.GetOption(IFernflowerPreferences.Hide_Empty_Super)) { HideEmptySuper(wrapper); } }
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 string IsClass14Invocation(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) { if (exprent.type == Exprent.Exprent_Function) { FunctionExprent fexpr = (FunctionExprent)exprent; if (fexpr.GetFuncType() == FunctionExprent.Function_Iif) { if (fexpr.GetLstOperands()[0].type == Exprent.Exprent_Function) { FunctionExprent headexpr = (FunctionExprent)fexpr.GetLstOperands()[0]; if (headexpr.GetFuncType() == FunctionExprent.Function_Eq) { if (headexpr.GetLstOperands()[0].type == Exprent.Exprent_Field && headexpr.GetLstOperands ()[1].type == Exprent.Exprent_Const && ((ConstExprent)headexpr.GetLstOperands()[ 1]).GetConstType().Equals(VarType.Vartype_Null)) { FieldExprent field = (FieldExprent)headexpr.GetLstOperands()[0]; ClassesProcessor.ClassNode fieldnode = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(field.GetClassname()); if (fieldnode != null && fieldnode.classStruct.qualifiedName.Equals(wrapper.GetClassStruct ().qualifiedName)) { // source class StructField fd = wrapper.GetClassStruct().GetField(field.GetName(), field.GetDescriptor ().descriptorString); // FIXME: can be null! why?? if (fd != null && fd.HasModifier(ICodeConstants.Acc_Static) && (fd.IsSynthetic() || DecompilerContext.GetOption(IFernflowerPreferences.Synthetic_Not_Set))) { if (fexpr.GetLstOperands()[1].type == Exprent.Exprent_Assignment && fexpr.GetLstOperands ()[2].Equals(field)) { AssignmentExprent asexpr = (AssignmentExprent)fexpr.GetLstOperands()[1]; if (asexpr.GetLeft().Equals(field) && asexpr.GetRight().type == Exprent.Exprent_Invocation) { InvocationExprent invexpr = (InvocationExprent)asexpr.GetRight(); if (invexpr.GetClassname().Equals(wrapper.GetClassStruct().qualifiedName) && invexpr .GetName().Equals(meth.methodStruct.GetName()) && invexpr.GetStringDescriptor(). Equals(meth.methodStruct.GetDescriptor())) { if (invexpr.GetLstParameters()[0].type == Exprent.Exprent_Const) { wrapper.GetHiddenMembers().Add(InterpreterUtil.MakeUniqueKey(fd.GetName(), fd.GetDescriptor ())); // hide synthetic field return(((ConstExprent)invexpr.GetLstParameters()[0]).GetValue().ToString()); } } } } } } } } } } } return(null); }