/* * Fernflower - The Analytical Java Decompiler * http://www.reversed-java.com * * (C) 2008 - 2010, Stiver * * This software is NEITHER public domain NOR free software * as per GNU License. See license.txt for more details. * * This software is distributed WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. */ package org.jetbrains.java.decompiler.main.rels; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import org.jetbrains.java.decompiler.code.CodeConstants; import org.jetbrains.java.decompiler.main.DecompilerContext; import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode; import org.jetbrains.java.decompiler.main.collectors.CounterContainer; import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent; import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent; import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent; import org.jetbrains.java.decompiler.modules.decompiler.exps.FieldExprent; import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent; import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent; import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph; import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode; import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar; import org.jetbrains.java.decompiler.struct.StructMethod; import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; import org.jetbrains.java.decompiler.util.InterpreterUtil; public class NestedMemberAccess { private static final int METHOD_ACCESS_NORMAL = 1; private static final int METHOD_ACCESS_FIELDGET = 2; private static final int METHOD_ACCESS_FIELDSET = 3; private static final int METHOD_ACCESS_METHOD = 4; private boolean notSetSync; private HashMap mapMethodType = new HashMap(); public void propagateMemberAccess(ClassNode root) { if(root.nested.isEmpty()) { return; } notSetSync = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET); computeMethodTypes(root); eliminateStaticAccess(root); } private void computeMethodTypes(ClassNode node) { if(node.type == ClassNode.CLASS_LAMBDA) { return; } for(ClassNode nd : node.nested) { computeMethodTypes(nd); } for(MethodWrapper meth : node.wrapper.getMethods()) { computeMethodType(node, meth); } } private void computeMethodType(ClassNode node, MethodWrapper meth) { int type = METHOD_ACCESS_NORMAL; if(meth.root != null) { DirectGraph graph = meth.getOrBuildGraph(); int flags = meth.methodStruct.getAccessFlags(); if(((flags & CodeConstants.ACC_SYNTHETIC) != 0 || meth.methodStruct.getAttributes().containsKey("Synthetic") || notSetSync) && (flags & CodeConstants.ACC_STATIC) != 0) { if(graph.nodes.size() == 2) { // incl. dummy exit node if(graph.first.exprents.size() == 1) { Exprent exprent = graph.first.exprents.get(0); MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor()); int parcount = mtdesc.params.length; Exprent exprCore = exprent; if(exprent.type == Exprent.EXPRENT_EXIT) { ExitExprent exexpr = (ExitExprent)exprent; if(exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) { exprCore = exexpr.getValue(); } } switch(exprCore.type) { case Exprent.EXPRENT_FIELD: FieldExprent fexpr = (FieldExprent)exprCore; if((parcount == 1 && !fexpr.isStatic()) || (parcount == 0 && fexpr.isStatic())) { if(fexpr.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field if(fexpr.isStatic() || (fexpr.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpr.getInstance()).getIndex() == 0)) { type = METHOD_ACCESS_FIELDGET; } } } break; case Exprent.EXPRENT_VAR: // qualified this if(parcount == 1) { // this or final variable if(((VarExprent)exprCore).getIndex() != 0) { type = METHOD_ACCESS_FIELDGET; } } break; case Exprent.EXPRENT_INVOCATION: type = METHOD_ACCESS_METHOD; break; case Exprent.EXPRENT_ASSIGNMENT: AssignmentExprent asexpr = (AssignmentExprent)exprCore; if(asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) { FieldExprent fexpras = (FieldExprent)asexpr.getLeft(); if((parcount == 2 && !fexpras.isStatic()) || (parcount == 1 && fexpras.isStatic())) { if(fexpras.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field if(fexpras.isStatic() || (fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) { if(((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) { type = METHOD_ACCESS_FIELDSET; } } } } } } if(type == METHOD_ACCESS_METHOD) { // FIXME: check for private flag of the method type = METHOD_ACCESS_NORMAL; InvocationExprent invexpr = (InvocationExprent)exprCore; if((invexpr.isStatic() && invexpr.getLstParameters().size() == parcount) || (!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)invexpr.getInstance()).getIndex() == 0 && invexpr.getLstParameters().size() == parcount-1)) { boolean equalpars = true; for(int i=0;i setVisited = new HashSet(); LinkedList stack = new LinkedList(); stack.add(graph.first); while(!stack.isEmpty()) { // TODO: replace with interface iterator? DirectNode nd = stack.removeFirst(); if(setVisited.contains(nd)) { continue; } setVisited.add(nd); for(int i=0;i