169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba, and others. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.bytecode.analysis;
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.HashMap;
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Iterator;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Map;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.CtClass;
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * MultiType represents an unresolved type. Whenever two <literal>Type</literal>
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * instances are merged, if they share more than one super type (either an
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * interface or a superclass), then a <literal>MultiType</literal> is used to
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * represent the possible super types. The goal of a <literal>MultiType</literal>
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * is to reduce the set of possible types down to a single resolved type. This
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * is done by eliminating non-assignable types from the typeset when the
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <literal>MultiType</literal> is passed as an argument to
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * {@link Type#isAssignableFrom(Type)}, as well as removing non-intersecting
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * types during a merge.
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Note: Currently the <litera>MultiType</literal> instance is reused as much
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * as possible so that updates are visible from all frames. In addition, all
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <literal>MultiType</literal> merge paths are also updated. This is somewhat
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * hackish, but it appears to handle most scenarios.
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author Jason T. Greene
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* TODO - A better, but more involved, approach would be to track the instruction
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * offset that resulted in the creation of this type, and
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * whenever the typeset changes, to force a merge on that position. This
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * would require creating a new MultiType instance every time the typeset
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * changes, and somehow communicating assignment changes to the Analyzer
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class MultiType extends Type {
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Map interfaces;
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Type resolved;
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Type potentialClass;
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private MultiType mergeSource;
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean changed = false;
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public MultiType(Map interfaces) {
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this(interfaces, null);
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public MultiType(Map interfaces, Type potentialClass) {
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        super(null);
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.interfaces = interfaces;
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.potentialClass = potentialClass;
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Gets the class that corresponds with this type. If this information
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * is not yet known, java.lang.Object will be returned.
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public CtClass getCtClass() {
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (resolved != null)
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return resolved.getCtClass();
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return Type.OBJECT.getCtClass();
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Always returns null since this type is never used for an array.
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Type getComponent() {
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return null;
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Always returns 1, since this type is a reference.
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public int getSize() {
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return 1;
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Always reutnrs false since this type is never used for an array
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean isArray() {
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return false;
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns true if the internal state has changed.
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    boolean popChanged() {
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        boolean changed = this.changed;
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.changed = false;
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return changed;
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean isAssignableFrom(Type type) {
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        throw new UnsupportedOperationException("Not implemented");
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean isAssignableTo(Type type) {
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (resolved != null)
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return type.isAssignableFrom(resolved);
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (Type.OBJECT.equals(type))
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return true;
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (potentialClass != null && !type.isAssignableFrom(potentialClass))
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            potentialClass = null;
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Map map = mergeMultiAndSingle(this, type);
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (map.size() == 1 && potentialClass == null) {
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // Update previous merge paths to the same resolved type
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            resolved = Type.get((CtClass)map.values().iterator().next());
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            propogateResolved();
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return true;
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // Keep all previous merge paths up to date
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (map.size() >= 1) {
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            interfaces = map;
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            propogateState();
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return true;
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (potentialClass != null) {
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            resolved = potentialClass;
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            propogateResolved();
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return true;
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return false;
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void propogateState() {
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MultiType source = mergeSource;
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (source != null) {
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            source.interfaces = interfaces;
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            source.potentialClass = potentialClass;
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            source = source.mergeSource;
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private void propogateResolved() {
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MultiType source = mergeSource;
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (source != null) {
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            source.resolved = resolved;
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            source = source.mergeSource;
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Always returns true, since this type is always a reference.
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return true
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean isReference() {
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal       return true;
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Map getAllMultiInterfaces(MultiType type) {
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Map map = new HashMap();
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Iterator iter = type.interfaces.values().iterator();
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (iter.hasNext()) {
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            CtClass intf = (CtClass)iter.next();
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            map.put(intf.getName(), intf);
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            getAllInterfaces(intf, map);
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return map;
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Map mergeMultiInterfaces(MultiType type1, MultiType type2) {
18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Map map1 = getAllMultiInterfaces(type1);
19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Map map2 = getAllMultiInterfaces(type2);
19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return findCommonInterfaces(map1, map2);
19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private Map mergeMultiAndSingle(MultiType multi, Type single) {
19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Map map1 = getAllMultiInterfaces(multi);
19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Map map2 = getAllInterfaces(single.getCtClass(), null);
19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return findCommonInterfaces(map1, map2);
20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean inMergeSource(MultiType source) {
20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (source != null) {
20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (source == this)
20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return true;
20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            source = source.mergeSource;
20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return false;
21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Type merge(Type type) {
21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (this == type)
21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return this;
21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (type == UNINIT)
21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return this;
21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (type == BOGUS)
22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return BOGUS;
22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (type == null)
22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return this;
22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (resolved != null)
22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return resolved.merge(type);
22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (potentialClass != null) {
23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Type mergePotential = potentialClass.merge(type);
23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (! mergePotential.equals(potentialClass) || mergePotential.popChanged()) {
23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                potentialClass = Type.OBJECT.equals(mergePotential) ? null : mergePotential;
23369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                changed = true;
23469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
23569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
23669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
23769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Map merged;
23869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
23969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (type instanceof MultiType) {
24069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            MultiType multi = (MultiType)type;
24169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
24269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (multi.resolved != null) {
24369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                merged = mergeMultiAndSingle(this, multi.resolved);
24469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            } else {
24569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                merged = mergeMultiInterfaces(multi, this);
24669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (! inMergeSource(multi))
24769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    mergeSource = multi;
24869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
24969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        } else {
25069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            merged = mergeMultiAndSingle(this, type);
25169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
25269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
25369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // Keep all previous merge paths up to date
25469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (merged.size() > 1 || (merged.size() == 1 && potentialClass != null)) {
25569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // Check for changes
25669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (merged.size() != interfaces.size()) {
25769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                changed = true;
25869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            } else if (changed == false){
25969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                Iterator iter = merged.keySet().iterator();
26069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                while (iter.hasNext())
26169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    if (! interfaces.containsKey(iter.next()))
26269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        changed = true;
26369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
26469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
26569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            interfaces = merged;
26669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            propogateState();
26769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
26869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return this;
26969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
27069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (merged.size() == 1) {
27269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            resolved = Type.get((CtClass) merged.values().iterator().next());
27369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        } else if (potentialClass != null){
27469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            resolved = potentialClass;
27569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        } else {
27669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            resolved = OBJECT;
27769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
27869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
27969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        propogateResolved();
28069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return resolved;
28269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
28369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean equals(Object o) {
28569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (! (o instanceof MultiType))
28669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return false;
28769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
28869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        MultiType multi = (MultiType) o;
28969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (resolved != null)
29069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return resolved.equals(multi.resolved);
29169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        else if (multi.resolved != null)
29269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return false;
29369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
29469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return interfaces.keySet().equals(multi.interfaces.keySet());
29569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
29669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
29769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public String toString() {
29869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (resolved != null)
29969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return resolved.toString();
30069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
30169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        StringBuffer buffer = new StringBuffer("{");
30269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        Iterator iter = interfaces.keySet().iterator();
30369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        while (iter.hasNext()) {
30469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            buffer.append(iter.next());
30569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            buffer.append(", ");
30669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
30769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        buffer.setLength(buffer.length() - 2);
30869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (potentialClass != null)
30969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            buffer.append(", *").append(potentialClass.toString());
31069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        buffer.append("}");
31169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return buffer.toString();
31269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
31369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
314