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); } } } } } } }