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