@Override
public void endVisit(JMethod x, Context ctx) {
if (!(x.getType() instanceof JReferenceType)) {
return;
}
JReferenceType refType = (JReferenceType) x.getType();
if (refType == typeNull) {
return;
}
// tighten based on non-instantiability
if (!program.typeOracle.isInstantiatedType(refType)) {
x.setType(typeNull);
myDidChange = true;
return;
}
JClassType concreteType = getSingleConcreteType(x.getType());
if (concreteType != null) {
x.setType(concreteType);
myDidChange = true;
}
/*
* The only information that we can infer about native methods is if they
* are declared to return a leaf type.
*/
if (x.isNative()) {
return;
}
// tighten based on both returned types and possible overrides
List<JReferenceType> typeList = new ArrayList<JReferenceType>();
/*
* Always assume at least one null assignment; if there really aren't any
* other assignments, then this variable will get the null type. If there
* are, it won't hurt anything because null type will always lose.
*/
typeList.add(typeNull);
Set<JExpression> myReturns = returns.get(x);
if (myReturns != null) {
for (JExpression expr : myReturns) {
typeList.add((JReferenceType) expr.getType());
}
}
Set<JMethod> myOverriders = overriders.get(x);
if (myOverriders != null) {
for (JMethod method : myOverriders) {
typeList.add((JReferenceType) method.getType());
}
}
JReferenceType resultType = program.generalizeTypes(typeList);
resultType = program.strongerType(refType, resultType);
if (refType != resultType) {
x.setType(resultType);
myDidChange = true;
}