String methodName = obj.getMethodName(cpg);
String signature = obj.getSignature(cpg);
String className = obj.getClassName(cpg);
String returnValueSignature = new SignatureParser(signature).getReturnTypeSignature();
if (returnValueSignature.equals("V")) {
consumeStack(obj);
return;
}
if (methodName.equals("isInstance")) {
if (className.equals("java.lang.Class") && valueNumberDataflow != null) {
// Record the value number of the value checked by this
// instruction,
// and the type the value was compared to.
try {
ValueNumberFrame vnaFrame = valueNumberDataflow.getFactAtLocation(getLocation());
if (vnaFrame.isValid()) {
ValueNumber stackValue = vnaFrame.getStackValue(1);
if (stackValue.hasFlag(ValueNumber.CONSTANT_CLASS_OBJECT)) {
String c = valueNumberDataflow.getClassName(stackValue);
if (c != null) {
if (c.charAt(0) != '[' && !c.endsWith(";")) {
c = "L" + c.replace('.', '/') + ";";
}
Type type = Type.getType(c);
if (type instanceof ReferenceType) {
instanceOfValueNumber = vnaFrame.getTopValue();
instanceOfType = (ReferenceType) type;
sawEffectiveInstanceOf = true;
}
}
}
}
} catch (DataflowAnalysisException e) {
// Ignore
}
}
}
Type returnTypeOfMethod = obj.getType(cpg);
if (!(returnTypeOfMethod instanceof ReferenceType)) {
consumeStack(obj);
pushReturnType(obj);
return;
}
if (methodName.equals("cast") && className.equals("java.lang.Class")) {
try {
Type resultType = frame.popValue();
frame.popValue();
frame.pushValue(resultType);
} catch (DataflowAnalysisException e) {
AnalysisContext.logError("oops", e);
}
return;
}
mapGetCheck: if (methodName.equals("get") && signature.equals("(Ljava/lang/Object;)Ljava/lang/Object;")
&& className.endsWith("Map") && Subtypes2.instanceOf(className, "java.util.Map")
&& frame.getStackDepth() >= 2) {
try {
Type mapType = frame.getStackValue(1);
if (mapType instanceof GenericObjectType) {
GenericObjectType genericMapType = (GenericObjectType) mapType;
List<? extends ReferenceType> parameters = genericMapType.getParameters();
if (parameters == null || parameters.size() != 2) {
break mapGetCheck;
}
ClassDescriptor c = DescriptorFactory.getClassDescriptor(genericMapType);
if (!Subtypes2.instanceOf(c, Map.class)) {
break mapGetCheck;
}
if (!isStraightGenericMap(c)) {
break mapGetCheck;
}
ReferenceType valueType = parameters.get(1);
consumeStack(obj);
frame.pushValue(valueType);
return;
}
} catch (DataflowAnalysisException e) {
AnalysisContext.logError("oops", e);
}
}
if (className.equals("java.util.Map$Entry")) {
if (methodName.equals("getKey") && getResultTypeFromGenericType(frame, 0, 2) || methodName.equals("getValue")
&& getResultTypeFromGenericType(frame, 1, 2)) {
return;
}
}
if (methodName.equals("entrySet") && signature.equals("()Ljava/util/Set;") && className.startsWith("java.util")
&& className.endsWith("Map")) {
Type argType;
try {
argType = frame.popValue();
} catch (DataflowAnalysisException e) {
AnalysisContext.logError("oops", e);
return;
}
ObjectType mapType = (ObjectType) Type.getType("Ljava/util/Map$Entry;");
if (argType instanceof GenericObjectType) {
GenericObjectType genericArgType = (GenericObjectType) argType;
List<? extends ReferenceType> parameters = genericArgType.getParameters();
if (parameters != null && parameters.size() == 2) {
mapType = GenericUtilities.getType("java.util.Map$Entry", parameters);
}
}
GenericObjectType entrySetType = GenericUtilities.getType("java.util.Set", Collections.singletonList(mapType));
frame.pushValue(entrySetType);
return;
}
if (className.startsWith("java.util") && className.endsWith("Map")) {
if (methodName.equals("keySet") && signature.equals("()Ljava/util/Set;")
&& handleGetMapView(frame, "java.util.Set", 0, 2) || methodName.equals("values")
&& signature.equals("()Ljava/util/Collection;") && handleGetMapView(frame, "java.util.Collection", 1, 2)) {
return;
}
}
if (methodName.equals("iterator") && signature.equals("()Ljava/util/Iterator;") && className.startsWith("java.util")
&& handleGetMapView(frame, "java.util.Iterator", 0, 1)) {
return;
}
if (className.equals("java.util.Iterator") && methodName.equals("next") && signature.equals("()Ljava/lang/Object;")
&& getResultTypeFromGenericType(frame, 0, 1)) {
return;
}
if (methodName.equals("initCause") && signature.equals("(Ljava/lang/Throwable;)Ljava/lang/Throwable;")
&& (className.endsWith("Exception")
|| className.endsWith("Error"))) {
try {
frame.popValue();
return;
} catch (DataflowAnalysisException e) {
AnalysisContext.logError("Ooops", e);
}
}
if (handleToArray(obj)) {
return;
}
Type result = TopType.instance();
try {
Set<XMethod> targets = Hierarchy2.resolveMethodCallTargets(obj, frame, cpg);
if (DEBUG) {
System.out.println(" For call to " + className + "." + methodName + signature);
System.out.println(" for " + targets.size() + " targets: " + targets);
}
for (XMethod m : targets) {
m = m.resolveAccessMethodForMethod();
String sourceSignature = m.getSourceSignature();
if (DEBUG) {
System.out.println(" Call target: " + m);
if (sourceSignature != null) {
System.out.println(" source signature: " + sourceSignature);
}
}
boolean foundSomething = false;
XMethod m2 = m.bridgeTo();
if (m2 != null) {
m = m2;
}
if (sourceSignature != null && !sourceSignature.equals(m.getSignature())) {
GenericSignatureParser p = new GenericSignatureParser(sourceSignature);
String rv = p.getReturnTypeSignature();
if (rv.charAt(0) != 'T') {
try {
Type t = GenericUtilities.getType(rv);
if (t != null) {
assert t.getType() != T_VOID;
result = merge(result, t);
foundSomething = true;
}
} catch (RuntimeException e) {
AnalysisContext.logError("Problem analyzing call to " + m + " with source signature"
+ sourceSignature, e);
break;
}
}
}
if (m == m2) {
SignatureParser p = new SignatureParser(m.getSignature());
String rv = p.getReturnTypeSignature();
Type t = Type.getType(rv);
result = merge(result, t);
foundSomething = true;