boolean (StructClass cl, StructClass enclosingCl) { // checking super class and interfaces int[] interfaces = cl.getInterfaces(); if (interfaces.length > 0) { boolean 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; boolean refNotNew = false; StructEnclosingMethodAttribute attribute = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_ENCLOSING_METHOD); String enclosingMethod = attribute != null ? attribute.getMethodName() : null; // checking references in the enclosing class for (StructMethod mt : enclosingCl.getMethods()) { if (enclosingMethod != null && !enclosingMethod.equals(mt.getName())) { continue; } try { mt.expandData(enclosingCl); 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, opc_instanceof -> { if (cl.qualifiedName.equals(pool.getPrimitiveConstant(instr.operand(0)).getString())) { refCounter++; refNotNew = true; } } case opc_new, opc_anewarray, opc_multianewarray -> { if (cl.qualifiedName.equals(pool.getPrimitiveConstant(instr.operand(0)).getString())) { refCounter++; } } case opc_getstatic, opc_putstatic -> { if (cl.qualifiedName.equals(pool.getLinkConstant(instr.operand(0)).classname)) { refCounter++; refNotNew = true; } } } } } mt.releaseResources(); } catch (IOException ex) { 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; }