in src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java [444:649]
private static void insertLocalVars(ClassNode parent, ClassNode child) {
// enclosing method, is null iff member class
MethodWrapper enclosingMethod = parent.getWrapper().getMethods().getWithKey(child.enclosingMethod);
// iterate all child methods
for (MethodWrapper method : child.getWrapper().getMethods()) {
if (method.root != null) { // neither abstract nor native
Map<VarVersion, String> mapNewNames = new HashMap<>(); // local var names
Map<VarVersion, VarType> mapNewTypes = new HashMap<>(); // local var types
Map<VarVersion, LocalVariable> mapNewLVTs = new HashMap<>(); // local var table entries
Map<Integer, VarVersion> mapParamsToNewVars = new HashMap<>();
if (method.synthParameters != null) {
int index = 0, varIndex = 1;
MethodDescriptor md = MethodDescriptor.parseDescriptor(method.methodStruct.getDescriptor());
for (VarVersion pair : method.synthParameters) {
if (pair != null) {
VarVersion newVar = new VarVersion(method.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);
mapParamsToNewVars.put(varIndex, newVar);
String varName = null;
VarType varType = null;
LocalVariable varLVT = null;
if (child.type != ClassNode.CLASS_MEMBER) {
varName = enclosingMethod.varproc.getVarName(pair);
varType = enclosingMethod.varproc.getVarType(pair);
varLVT = enclosingMethod.varproc.getVarLVTEntry(pair);
enclosingMethod.varproc.setVarFinal(pair, VarProcessor.VAR_EXPLICIT_FINAL);
}
if (pair.var == -1 || "this".equals(varName) || (varLVT != null && "this".equals(varLVT.getName()))) {
if (parent.simpleName == null) {
// anonymous enclosing class, no access to this
varName = VarExprent.VAR_NAMELESS_ENCLOSURE;
}
else {
varName = parent.simpleName + ".this";
}
if (varLVT != null) {
varLVT = varLVT.rename(varName);
}
method.varproc.getThisVars().put(newVar, parent.classStruct.qualifiedName);
}
mapNewNames.put(newVar, varName);
mapNewTypes.put(newVar, varType);
mapNewLVTs.put(newVar, varLVT);
}
varIndex += md.params[index++].getStackSize();
}
}
Map<String, VarVersion> mapFieldsToNewVars = new HashMap<>();
for (ClassNode classNode = child; classNode != null; classNode = classNode.parent) {
for (Entry<String, VarVersion> entry : classNode.mapFieldsToVars.entrySet()) {
VarVersion newVar = new VarVersion(method.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);
mapFieldsToNewVars.put(InterpreterUtil.makeUniqueKey(classNode.classStruct.qualifiedName, entry.getKey()), newVar);
String varName = null;
VarType varType = null;
LocalVariable varLVT = null;
if (classNode.type != ClassNode.CLASS_MEMBER) {
MethodWrapper enclosing_method = classNode.parent.getWrapper().getMethods().getWithKey(classNode.enclosingMethod);
varName = enclosing_method.varproc.getVarName(entry.getValue());
varType = enclosing_method.varproc.getVarType(entry.getValue());
varLVT = enclosing_method.varproc.getVarLVTEntry(entry.getValue());
enclosing_method.varproc.setVarFinal(entry.getValue(), VarProcessor.VAR_EXPLICIT_FINAL);
}
if (entry.getValue().var == -1 || "this".equals(varName) || (varLVT != null && "this".equals(varLVT.getName()))) {
if (classNode.parent.simpleName == null) {
// anonymous enclosing class, no access to this
varName = VarExprent.VAR_NAMELESS_ENCLOSURE;
}
else {
varName = classNode.parent.simpleName + ".this";
}
if (varLVT != null) {
varLVT = varLVT.rename(varName);
}
method.varproc.getThisVars().put(newVar, classNode.parent.classStruct.qualifiedName);
}
mapNewNames.put(newVar, varName);
mapNewTypes.put(newVar, varType);
mapNewLVTs.put(newVar, varLVT);
// hide synthetic field
if (classNode == child) { // fields higher up the chain were already handled with their classes
StructField fd = child.classStruct.getFields().getWithKey(entry.getKey());
child.getWrapper().getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
}
}
}
Set<String> setNewOuterNames = new HashSet<>(mapNewNames.values());
setNewOuterNames.removeAll(method.setOuterVarNames);
method.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames));
method.setOuterVarNames.addAll(setNewOuterNames);
for (Entry<VarVersion, String> entry : mapNewNames.entrySet()) {
VarVersion pair = entry.getKey();
VarType type = mapNewTypes.get(pair);
LocalVariable lvt = mapNewLVTs.get(pair);
method.varproc.setVarName(pair, entry.getValue());
if (type != null) {
method.varproc.setVarType(pair, type);
}
if (lvt != null) {
method.varproc.setVarLVTEntry(pair, lvt);
}
}
iterateExprents(method.getOrBuildGraph(), new ExprentIteratorWithReplace() {
@Override
public Exprent processExprent(Exprent exprent) {
if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
AssignmentExprent assignExpr = (AssignmentExprent)exprent;
if (assignExpr.getLeft().type == Exprent.EXPRENT_FIELD) {
FieldExprent fExpr = (FieldExprent)assignExpr.getLeft();
String qName = child.classStruct.qualifiedName;
if (fExpr.getClassname().equals(qName) && // process this class only
mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(qName, fExpr.getName(), fExpr.getDescriptor().descriptorString))) {
return null;
}
}
}
if (child.type == ClassNode.CLASS_ANONYMOUS &&
CodeConstants.INIT_NAME.equals(method.methodStruct.getName()) &&
exprent.type == Exprent.EXPRENT_INVOCATION) {
InvocationExprent invokeExpr = (InvocationExprent)exprent;
if (invokeExpr.getFuncType() == InvocationExprent.TYPE_INIT) {
// invocation of the super constructor in an anonymous class
child.superInvocation = invokeExpr; // FIXME: save original names of parameters
return null;
}
}
Exprent ret = replaceExprent(exprent);
return ret == null ? exprent : ret;
}
private Exprent replaceExprent(Exprent exprent) {
if (exprent.type == Exprent.EXPRENT_VAR) {
int varIndex = ((VarExprent)exprent).getIndex();
if (mapParamsToNewVars.containsKey(varIndex)) {
VarVersion newVar = mapParamsToNewVars.get(varIndex);
method.varproc.getExternalVars().add(newVar);
VarExprent ret = new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc, exprent.bytecode);
LocalVariable lvt = method.varproc.getVarLVTEntry(newVar);
if (lvt != null) {
ret.setLVTEntry(lvt);
}
return ret;
}
}
else if (exprent.type == Exprent.EXPRENT_FIELD) {
FieldExprent fExpr = (FieldExprent)exprent;
String key = InterpreterUtil.makeUniqueKey(fExpr.getClassname(), fExpr.getName(), fExpr.getDescriptor().descriptorString);
if (mapFieldsToNewVars.containsKey(key)) {
//if(fExpr.getClassname().equals(child.classStruct.qualifiedName) &&
// mapFieldsToNewVars.containsKey(key)) {
VarVersion newVar = mapFieldsToNewVars.get(key);
method.varproc.getExternalVars().add(newVar);
VarExprent ret = new VarExprent(newVar.var, method.varproc.getVarType(newVar), method.varproc, exprent.bytecode);
LocalVariable lvt = method.varproc.getVarLVTEntry(newVar);
if (lvt != null) {
ret.setLVTEntry(lvt);
}
return ret;
}
}
boolean replaced = true;
while (replaced) {
replaced = false;
for (Exprent expr : exprent.getAllExprents()) {
Exprent retExpr = replaceExprent(expr);
if (retExpr != null) {
exprent.replaceExprent(expr, retExpr);
replaced = true;
break;
}
}
}
return null;
}
});
}
}
}