/** * Return the greatest lower bound of two types. That is, return the largest type that is a * subtype of both inputs. If none exists return {@code thisType}. */ public JReferenceType strengthenType(JReferenceType thisType, JReferenceType thatType) { if (thisType == thatType) { return thisType; } if (thisType.isNullType() || thatType.isNullType()) { return JReferenceType.NULL_TYPE; } if (thisType.canBeNull() != thatType.canBeNull()) { // If either is non-nullable, the result should be non-nullable. return strengthenType(thisType.strengthenToNonNull(), thatType.strengthenToNonNull()); } if (typeOracle.castSucceedsTrivially(thisType, thatType)) { return thisType; } if (typeOracle.castSucceedsTrivially(thatType, thisType)) { return thatType; } // This types are incompatible; ideally this code should not be reached, but there are two // situations where this happens: // 1 - unrelated interfaces; // 2 - unsafe code. // The original type is preserved in this case. return thisType; }
private JReferenceType generalizeArrayTypes(JArrayType thisArrayType, JArrayType thatArrayType) { assert thisArrayType != thatArrayType; int thisDims = thisArrayType.getDims(); int thatDims = thatArrayType.getDims(); int minDims = Math.min(thisDims, thatDims); /* * At a bare minimum, any two arrays generalize to an Object array with * one less dim than the lesser of the two; that is, int[][][][] and * String[][][] generalize to Object[][]. If minDims is 1, then they * just generalize to Object. */ JReferenceType minimalGeneralType = (minDims == 1) ? typeJavaLangObject : getOrCreateArrayType(typeJavaLangObject, minDims - 1); if (thisDims == thatDims) { // Try to generalize by leaf types JType thisLeafType = thisArrayType.getLeafType(); JType thatLeafType = thatArrayType.getLeafType(); if (!(thisLeafType instanceof JReferenceType) || !(thatLeafType instanceof JReferenceType)) { return minimalGeneralType; } /* * Both are reference types; the result is the generalization of the leaf types combined with * the number of dims; that is, Foo[] and Bar[] generalize to X[] where X is the * generalization of Foo and Bar. * * Never generalize arrays to arrays of {@link JAnalysisDecoratedType}. One of the reasons is * that array initialization is not accounted for in {@link TypeTightener}. */ JReferenceType leafGeneralization = generalizeTypes((JReferenceType) thisLeafType, (JReferenceType) thatLeafType) .getUnderlyingType(); return getOrCreateArrayType(leafGeneralization, thisDims); } // Different number of dims if (typeOracle.castSucceedsTrivially(thatArrayType, thisArrayType)) { return thisArrayType; } if (typeOracle.castSucceedsTrivially(thisArrayType, thatArrayType)) { return thatArrayType; } // Totally unrelated return minimalGeneralType; }
private JReferenceType generalizeInterfaces( JInterfaceType thisInterface, JInterfaceType thatInterface) { if (typeOracle.castSucceedsTrivially(thisInterface, thatInterface)) { return thatInterface; } if (typeOracle.castSucceedsTrivially(thatInterface, thisInterface)) { return thisInterface; } // unrelated return typeJavaLangObject; }
private JReferenceType generalizeUnderlyingTypes( JReferenceType thisType, JReferenceType thatType) { // We should not have any analysis properties from this point forward. assert thisType == thisType.getUnderlyingType() && thatType == thatType.getUnderlyingType(); if (thisType == thatType) { return thisType; } if (thisType instanceof JInterfaceType && thatType instanceof JInterfaceType) { return generalizeInterfaces((JInterfaceType) thisType, (JInterfaceType) thatType); } if (thisType instanceof JArrayType && thatType instanceof JArrayType) { return generalizeArrayTypes((JArrayType) thisType, (JArrayType) thatType); } if (thisType instanceof JClassType && thatType instanceof JClassType) { return generalizeClasses((JClassType) thisType, (JClassType) thatType); } JInterfaceType interfaceType = thisType instanceof JInterfaceType ? (JInterfaceType) thisType : (thatType instanceof JInterfaceType ? (JInterfaceType) thatType : null); JReferenceType nonInterfaceType = interfaceType == thisType ? thatType : thisType; // See if the class or the array is castable to the interface type. if (interfaceType != null && typeOracle.castSucceedsTrivially(nonInterfaceType, interfaceType)) { return interfaceType; } // unrelated: the best commonality is Object return typeJavaLangObject; }