// Path: plugin/src/java/su/msu/cs/lvk/secbugs/util/HierarchyUtil.java
// public class HierarchyUtil {
//     public static Set<XMethod> getResolvedMethods(TypeFrame typeFrame, InvokeInstruction invokeInstruction, ConstantPoolGen cpg) throws ClassNotFoundException, DataflowAnalysisException {
//         Set<JavaClassAndMethod> targetMethodSet = Hierarchy
//                 .resolveMethodCallTargets(invokeInstruction, typeFrame, cpg);
//         Set<XMethod> calledMethods = new HashSet<XMethod>();
//         for (JavaClassAndMethod m : targetMethodSet) {
//             calledMethods.add(XFactory.createXMethod(m));
//         }
//         calledMethods.add(XFactory.createXMethod(invokeInstruction, cpg));
//         return calledMethods;
//     }
// }


import edu.umd.cs.findbugs.SourceLineAnnotation;
import edu.umd.cs.findbugs.SystemProperties;
import edu.umd.cs.findbugs.ba.*;
import edu.umd.cs.findbugs.ba.type.TypeDataflow;
import edu.umd.cs.findbugs.ba.type.TypeFrame;
import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
import edu.umd.cs.findbugs.classfile.Global;
import org.apache.bcel.Constants;
import org.apache.bcel.generic.*;
import su.msu.cs.lvk.secbugs.util.HierarchyUtil;
import java.util.Collection;
        boolean callReturnsReference = (returnType instanceof ReferenceType);

        XMethod calledMethod = XFactory.createXMethod(obj, getCPG());
        propagateTaintedParameterToThis(calledMethod);

        if (!callReturnsReference) {
            handleNormalInstruction(obj);
        } else {
            modelCallReturnValue(obj, calledMethod);
        }
    }

    private void modelCallReturnValue(InvokeInstruction obj, XMethod calledMethod) {
        if (TaintAnalysis.DEBUG) {
            System.out.println("Check " + calledMethod + " for tainted data return...");
        }

        TypeDataflow typeDataflow;
        TypeFrame typeFact;
        try {
            XMethod caller = XFactory.createXMethod(javaClassAndMethod);
            typeDataflow = Global.getAnalysisCache()
                    .getMethodAnalysis(TypeDataflow.class, caller.getMethodDescriptor());
            typeFact = typeDataflow.getFactAtLocation(getLocation());
        } catch (CheckedAnalysisException e) {
            throw new InvalidBytecodeException("Can't obtain type dataflow for " + calledMethod, e);
        }

        Collection<XMethod> calledMethods;
        try {
// Path: plugin/src/java/su/msu/cs/lvk/secbugs/util/HierarchyUtil.java
// public class HierarchyUtil {
//     public static Set<XMethod> getResolvedMethods(TypeFrame typeFrame, InvokeInstruction invokeInstruction, ConstantPoolGen cpg) throws ClassNotFoundException, DataflowAnalysisException {
//         Set<JavaClassAndMethod> targetMethodSet = Hierarchy
//                 .resolveMethodCallTargets(invokeInstruction, typeFrame, cpg);
//         Set<XMethod> calledMethods = new HashSet<XMethod>();
//         for (JavaClassAndMethod m : targetMethodSet) {
//             calledMethods.add(XFactory.createXMethod(m));
//         }
//         calledMethods.add(XFactory.createXMethod(invokeInstruction, cpg));
//         return calledMethods;
//     }
// }


// Path: plugin/src/java/su/msu/cs/lvk/secbugs/ta/TaintValueFrameModelingVisitor.java
import edu.umd.cs.findbugs.SourceLineAnnotation;
import edu.umd.cs.findbugs.SystemProperties;
import edu.umd.cs.findbugs.ba.*;
import edu.umd.cs.findbugs.ba.type.TypeDataflow;
import edu.umd.cs.findbugs.ba.type.TypeFrame;
import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
import edu.umd.cs.findbugs.classfile.Global;
import org.apache.bcel.Constants;
import org.apache.bcel.generic.*;
import su.msu.cs.lvk.secbugs.util.HierarchyUtil;
import java.util.Collection;

        boolean callReturnsReference = (returnType instanceof ReferenceType);

        XMethod calledMethod = XFactory.createXMethod(obj, getCPG());
        propagateTaintedParameterToThis(calledMethod);

        if (!callReturnsReference) {
            handleNormalInstruction(obj);
        } else {
            modelCallReturnValue(obj, calledMethod);
        }
    }

    private void modelCallReturnValue(InvokeInstruction obj, XMethod calledMethod) {
        if (TaintAnalysis.DEBUG) {
            System.out.println("Check " + calledMethod + " for tainted data return...");
        }

        TypeDataflow typeDataflow;
        TypeFrame typeFact;
        try {
            XMethod caller = XFactory.createXMethod(javaClassAndMethod);
            typeDataflow = Global.getAnalysisCache()
                    .getMethodAnalysis(TypeDataflow.class, caller.getMethodDescriptor());
            typeFact = typeDataflow.getFactAtLocation(getLocation());
        } catch (CheckedAnalysisException e) {
            throw new InvalidBytecodeException("Can't obtain type dataflow for " + calledMethod, e);
        }

        Collection<XMethod> calledMethods;
        try {
            calledMethods = HierarchyUtil.getResolvedMethods(typeFact, obj, cpg);