/* Soot - a J*va Optimization Framework
 * Copyright (C) 2007 Patrick Lam
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
package soot.jimple.toolkits.pointer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import soot.Local;
import soot.RefLikeType;
import soot.Value;
import soot.ValueBox;
import soot.jimple.DefinitionStmt;
import soot.jimple.NewExpr;
import soot.jimple.Stmt;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.scalar.ForwardFlowAnalysis;

/** LocalNotMayAliasAnalysis attempts to determine if two local
 * variables (at two potentially different program points) definitely
 * point to different objects.
 *
 * The underlying abstraction is that of definition expressions.  When
 * a local variable gets assigned a new object (unlike LocalMust, only
 * NewExprs), the analysis tracks the source of the value. If two
 * variables have different sources, then they are different.
 * 
 * @author Patrick Lam
 */
public class LocalNotMayAliasAnalysis extends ForwardFlowAnalysis
{
    protected static final Object UNKNOWN = new Object();
    protected List<Local> locals;

    public LocalNotMayAliasAnalysis(UnitGraph g)
    {
        super(g);
        locals = new LinkedList<Local>(); locals.addAll(g.getBody().getLocals());

        for (Local l : (Collection<Local>) g.getBody().getLocals()) {
            if (l.getType() instanceof RefLikeType)
                locals.add(l);
        }

        doAnalysis();
    }

    protected void merge(Object in1, Object in2, Object o)
    {
        HashMap inMap1 = (HashMap) in1;
        HashMap inMap2 = (HashMap) in2;
        HashMap outMap = (HashMap) o;

        for (Local l : locals) {
            Set l1 = (Set)inMap1.get(l), l2 = (Set)inMap2.get(l);
            Set out = (Set)outMap.get(l);
            out.clear();
            if (l1.contains(UNKNOWN) || l2.contains(UNKNOWN)) {
                out.add(UNKNOWN);
            } else {
                out.addAll(l1); out.addAll(l2);
            }
        }
    }
    

    protected void flowThrough(Object inValue, Object unit,
            Object outValue)
    {
        HashMap     in  = (HashMap) inValue;
        HashMap     out = (HashMap) outValue;
        Stmt    s   = (Stmt)    unit;

        out.clear();

        List<Local> preserve = new ArrayList();
        preserve.addAll(locals);
        for (ValueBox vb : (Collection<ValueBox>)s.getDefBoxes()) {
            preserve.remove(vb.getValue());
        }

        for (Local l : preserve) {
            out.put(l, in.get(l));
        }

        if (s instanceof DefinitionStmt) {
            DefinitionStmt ds = (DefinitionStmt) s;
            Value lhs = ds.getLeftOp();
            Value rhs = ds.getRightOp();
            if (lhs instanceof Local) {
                HashSet lv = new HashSet();
                out.put(lhs, lv);
                if (rhs instanceof NewExpr) {
                    lv.add(rhs);
                } else if (rhs instanceof Local) {
                    lv.addAll((HashSet)in.get(rhs));
                } else lv.add(UNKNOWN);
            }
        }
    }

    protected void copy(Object source, Object dest)
    {
        HashMap sourceMap = (HashMap) source;
        HashMap destMap   = (HashMap) dest;
            
        for (Local l : (Collection<Local>) locals) {
            destMap.put (l, sourceMap.get(l));
        }
    }

    protected Object entryInitialFlow()
    {
        HashMap m = new HashMap();
        for (Local l : (Collection<Local>) locals) {
            HashSet s = new HashSet(); s.add(UNKNOWN);
            m.put(l, s);
        }
        return m;
    }
        
    protected Object newInitialFlow()
    {
        HashMap m = new HashMap();
        for (Local l : (Collection<Local>) locals) {
            HashSet s = new HashSet(); 
            m.put(l, s);
        }
        return m;
    }

    /**
     * Returns true if this analysis has any information about local l
     * at statement s (i.e. it is not {@link #UNKNOWN}).
     * In particular, it is safe to pass in locals/statements that are not
     * even part of the right method. In those cases <code>false</code>
     * will be returned.
     * Permits s to be <code>null</code>, in which case <code>false</code> will be returned.
     */
    public boolean hasInfoOn(Local l, Stmt s) {
    	HashMap flowBefore = (HashMap) getFlowBefore(s);
    	if(flowBefore==null) {
    		return false;
    	} else {
    		Set info = (Set) flowBefore.get(l);
    		return info!=null && !info.contains(UNKNOWN);
    	}
    }

    /**
     * @return true if values of l1 (at s1) and l2 (at s2) are known
     * to point to different objects
     */
    public boolean notMayAlias(Local l1, Stmt s1, Local l2, Stmt s2) {
        Set l1n = (Set) ((HashMap)getFlowBefore(s1)).get(l1);
        Set l2n = (Set) ((HashMap)getFlowBefore(s2)).get(l2);

        if (l1n.contains(UNKNOWN) || l2n.contains(UNKNOWN))
            return false;

        Set n = new HashSet(); n.addAll(l1n); n.retainAll(l2n);
        return n.isEmpty();
    }
        
}

@@ -1890,17 +1890,105 @@
 Object()
-;
+ %7B%0A        public String toString() %7B%0A            return %22UNKNOWN%22;%0A        %7D%0A    %7D;%0A    
 %0A    pro

debug info