package accrue.analysis.defuse;

import accrue.analysis.pointer.HContext;

import java.util.LinkedHashSet;
import java.util.Set;

import polyglot.util.InternalCompilerError;

public class NewAllocAbsVal extends DefUseAbsVal {
    final Set<HContext> objects;

    public NewAllocAbsVal(Set<HContext> objects) {
        if (objects.isEmpty())
            throw new InternalCompilerError("Tried to create NewAllocAbsVal with empty pointsTo set");
        this.objects = objects;
    }

    public boolean leq(DefUseAbsVal that) {
        if (that instanceof NewAllocAbsVal)
            return equals(that);
        else return false;
    }

    public DefUseAbsVal upperBound(DefUseAbsVal that) {
        if (this == that || this.equals(that)) {
            return this;
        }
        else if (that instanceof NewAllocAbsVal) {
            // assertion: these HContexts should all have the same preciseType,
            // and maybe the same allocSite...
            Set<HContext> newObjects =
                    new LinkedHashSet<HContext>(this.objects);
            newObjects.addAll(((NewAllocAbsVal) that).objects());
            return new NewAllocAbsVal(newObjects);
        }
        else if (that instanceof DefUseAbsVal && that != EMPTY) {
            //XXX: maybe this is actually safe?
            //TODO: Think harder about this.  Upper bounds between new allocs and defuseabsvals occur
            // at places like ternary expressions and return statements.  
            // Will this affect using RHS expressions to refine points-to results?
            //throw new InternalCompilerError("Cannot take the upper bound of " + this + " and " + that);
            return that;
        }
        return this;
    }

    @Override
    public boolean equals(Object objects) {
        if (objects instanceof NewAllocAbsVal) {
            return this.objects.equals(((NewAllocAbsVal) objects).objects());
        }
        else return false;
    }

    @Override
    public int hashCode() {
        return objects.hashCode();
    }

    public Set<HContext> objects() {
        return objects;
    }

    public String toString() {
        return "NewAllocAbsVal[" + objects + "]";
    }

}
