void (ClassNode node) { // class name -> constructor descriptor -> var to field link Map<String, Map<String, List<VarFieldPair>>> mapVarMasks = new HashMap<>(); int clTypes = 0; for (ClassNode nd : node.nested) { if (nd.type != ClassNode.CLASS_LAMBDA && !nd.classStruct.isSynthetic() && (nd.access & CodeConstants.ACC_STATIC) == 0 && (nd.access & CodeConstants.ACC_INTERFACE) == 0) { clTypes |= nd.type; Map<String, List<VarFieldPair>> mask = getMaskLocalVars(nd.getWrapper()); if (mask.isEmpty()) { String message = "Nested class " + nd.classStruct.qualifiedName + " has no constructor!"; DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN); } else { mapVarMasks.put(nd.classStruct.qualifiedName, mask); } } } // local var masks Map<String, Map<String, List<VarFieldPair>>> mapVarFieldPairs = new HashMap<>(); if (clTypes != ClassNode.CLASS_MEMBER) { // iterate enclosing class for (MethodWrapper method : node.getWrapper().getMethods()) { if (method.root != null) { // neither abstract, nor native method.getOrBuildGraph().iterateExprents(exprent -> { List<Exprent> lst = exprent.getAllExprents(true); lst.add(exprent); for (Exprent expr : lst) { if (expr.type == Exprent.EXPRENT_NEW) { InvocationExprent constructor = ((NewExprent)expr).getConstructor(); if (constructor != null && mapVarMasks.containsKey(constructor.getClassName())) { // non-static inner class constructor String refClassName = constructor.getClassName(); ClassNode nestedClassNode = node.getClassNode(refClassName); if (nestedClassNode.type != ClassNode.CLASS_MEMBER) { List<VarFieldPair> mask = mapVarMasks.get(refClassName).get(constructor.getStringDescriptor()); if (!mapVarFieldPairs.containsKey(refClassName)) { mapVarFieldPairs.put(refClassName, new HashMap<>()); } List<VarFieldPair> lstTemp = new ArrayList<>(); for (int i = 0; i < mask.size(); i++) { Exprent param = constructor.getParameters().get(i); VarFieldPair pair = null; if (param.type == Exprent.EXPRENT_VAR && mask.get(i) != null) { VarVersionPair varPair = new VarVersionPair((VarExprent)param); // FIXME: flags of variables are wrong! Correct the entire functionality. // if(method.varproc.getVarFinal(varPair) != VarTypeProcessor.VAR_NON_FINAL) { pair = new VarFieldPair(mask.get(i).fieldKey, varPair); // } } lstTemp.add(pair); } List<VarFieldPair> pairMask = mapVarFieldPairs.get(refClassName).get(constructor.getStringDescriptor()); if (pairMask == null) { pairMask = lstTemp; } else { for (int i = 0; i < pairMask.size(); i++) { if (!Objects.equals(pairMask.get(i), lstTemp.get(i))) { pairMask.set(i, null); } } } mapVarFieldPairs.get(refClassName).put(constructor.getStringDescriptor(), pairMask); nestedClassNode.enclosingMethod = InterpreterUtil.makeUniqueKey(method.methodStruct.getName(), method.methodStruct.getDescriptor()); } } } } return 0; }); } } } // merge var masks for (Entry<String, Map<String, List<VarFieldPair>>> enclosing : mapVarMasks.entrySet()) { ClassNode nestedNode = node.getClassNode(enclosing.getKey()); // intersection List<VarFieldPair> interPairMask = null; // merge referenced constructors if (mapVarFieldPairs.containsKey(enclosing.getKey())) { for (List<VarFieldPair> mask : mapVarFieldPairs.get(enclosing.getKey()).values()) { if (interPairMask == null) { interPairMask = new ArrayList<>(mask); } else { mergeListSignatures(interPairMask, mask, false); } } } List<VarFieldPair> interMask = null; // merge all constructors for (List<VarFieldPair> mask : enclosing.getValue().values()) { if (interMask == null) { interMask = new ArrayList<>(mask); } else { mergeListSignatures(interMask, mask, false); } } if (interPairMask == null) { // member or local and never instantiated interPairMask = interMask != null ? new ArrayList<>(interMask) : new ArrayList<>(); boolean found = false; for (int i = 0; i < interPairMask.size(); i++) { if (interPairMask.get(i) != null) { if (found) { interPairMask.set(i, null); } found = true; } } } mergeListSignatures(interPairMask, interMask, true); for (VarFieldPair pair : interPairMask) { if (pair != null && !pair.fieldKey.isEmpty()) { nestedNode.mapFieldsToVars.put(pair.fieldKey, pair.varPair); } } // set resulting constructor signatures for (Entry<String, List<VarFieldPair>> entry : enclosing.getValue().entrySet()) { mergeListSignatures(entry.getValue(), interPairMask, false); List<VarVersionPair> mask = new ArrayList<>(entry.getValue().size()); for (VarFieldPair pair : entry.getValue()) { mask.add(pair != null && !pair.fieldKey.isEmpty() ? pair.varPair : null); } nestedNode.getWrapper().getMethodWrapper(CodeConstants.INIT_NAME, entry.getKey()).synthParameters = mask; } } }