Пример #1
0
        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));
                }
            }
        }
Пример #2
0
        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);
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
        /// <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;
                    }
                }
            }
        }