public static TypeEx AddFieldToMethodEffects(IPexComponent host, TypeEx declaringType, SafeSet<string> res, 
            SafeSet<string> directSetFields, SafeDictionary<string, FieldModificationType> modificationTypeDic,
            OpCode prevOpcode, Field field, TypeEx fieldType)
        {
            SafeDebug.AssumeNotNull(field, "field");
            SafeDebug.Assume(!field.IsStatic, "!field.IsStatic");

            TypeEx fieldDeclaringType;

            //The following check ensures that the field belongs to this class
            //or its base classes
            if (field.TryGetDeclaringType(out fieldDeclaringType) &&
                declaringType.IsAssignableTo(fieldDeclaringType))
            {
                res.Add(field.ShortName);

                FieldModificationType fmt = FieldModificationType.UNKNOWN;
                if (fieldType == SystemTypes.Int32 || fieldType == SystemTypes.Int64 || fieldType == SystemTypes.Int16)
                {
                    if (prevOpcode == OpCodes.Add)
                        fmt = FieldModificationType.INCREMENT;
                    else if (prevOpcode == OpCodes.Sub)
                        fmt = FieldModificationType.DECREMENT;
                    else if (prevOpcode == OpCodes.Call || prevOpcode == OpCodes.Calli || prevOpcode == OpCodes.Callvirt)
                        fmt = FieldModificationType.METHOD_CALL;
                    else
                        host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype",
                                "Encountered unknown modification type for integer type " + prevOpcode);
                }
                else
                {
                    if (field.Type.IsReferenceType)
                    {
                        if (prevOpcode == OpCodes.Ldnull)
                            fmt = FieldModificationType.NULL_SET;
                        else if (prevOpcode == OpCodes.Newarr || prevOpcode == OpCodes.Newobj)
                            fmt = FieldModificationType.NON_NULL_SET;
                        else if (LdArgOpCodes.Contains(prevOpcode))
                            fmt = FieldModificationType.NON_NULL_SET;
                        else
                        {
                            fmt = FieldModificationType.METHOD_CALL;    //A method call is invoked on this field, which updates this field
                        }
                    }
                    else if (fieldType == SystemTypes.Bool)
                    {
                        if (prevOpcode == OpCodes.Ldc_I4_0)
                            fmt = FieldModificationType.FALSE_SET;
                        else if (prevOpcode == OpCodes.Ldc_I4_1)
                            fmt = FieldModificationType.TRUE_SET;
                        else
                            host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype",
                                    "Encountered unknown modification type for boolean type " + prevOpcode);
                    }
                }

                //Store the value of fmt. Sometimes, the same field
                //can be modified in different ways within the method, for example
                //setting a boolean field to both true or false. In that case, the modification
                //type is left as unknown
                FieldModificationType prevFMT;
                if (modificationTypeDic.TryGetValue(field.ShortName, out prevFMT))
                {
                    //There is some entry for this field
                    if (prevFMT != FieldModificationType.UNKNOWN && prevFMT != fmt)
                    {
                        modificationTypeDic[field.ShortName] = FieldModificationType.UNKNOWN;
                    }
                }
                else
                {
                    modificationTypeDic[field.ShortName] = fmt;
                }

                //A heuristic based approach for aliasing analysis for checking whether the field is directly
                //assigned any parameters
                if (LdArgOpCodes.Contains(prevOpcode))
                    directSetFields.Add(field.ShortName);
            }
            return fieldDeclaringType;
        }
        /// <summary>
        /// Computes method effects statically. All written fields of a method.
        /// Can be imprecise and conservative
        /// </summary>
        /// <param name="declaringType"></param>
        /// <param name="method"></param>
        /// <param name="effects"></param>
        /// <returns></returns>
        public static bool TryComputeMethodEffects(IPexComponent host, TypeEx declaringType, Method method,
            SafeSet<Method> visitedMethods, out MethodEffects effects)
        {
            SafeDebug.AssumeNotNull(declaringType, "declaringType");
            SafeDebug.AssumeNotNull(method, "method");

            try
            {
                if (visitedMethods == null)
                    visitedMethods = new SafeSet<Method>();

                if (visitedMethods.Contains(method))
                {
                    effects = null;
                    return false;
                }

                visitedMethods.Add(method);

                //Check whether this has been computed before
                var psd = host.GetService<IPexMeStaticDatabase>() as PexMeStaticDatabase;
                if (psd.MethodEffectsDic.TryGetValue(method.GlobalIndex, out effects))
                    return true;

                var res = new SafeSet<string>();
                var directSetFields = new SafeSet<string>();
                var directCalledMethods = new SafeSet<Method>();
                var returnFields = new SafeSet<Field>();
                var modificationTypeDic = new SafeDictionary<string, FieldModificationType>();
                var parameters = method.Parameters;

                MethodBodyEx body;
                if (!method.TryGetBody(out body) || !body.HasInstructions)
                {
                    effects = null;
                    return false;
                }

                int callDepth = 0;
                int offset = 0;
                Instruction instruction;
                OpCode prevOpcode = OpCodes.Nop;

                //Stack for load instructions
                Field lastAccessedArrayField = null;
                Field lastAccessedField = null;

                while (body.TryGetInstruction(offset, out instruction))
                {
                    SafeDebug.AssumeNotNull(instruction, "instruction");
                    OpCode opCode = instruction.OpCode;
                    if (LdcOpCodes.Contains(opCode))
                    {
                        //topIsConstant = true;
                    }
                    else if (ConvOpCodes.Contains(opCode))
                    {
                        // do not change topIsConstant
                    }
                    else
                    {
                        if (opCode == OpCodes.Stfld)
                        {
                            SafeDebug.Assume(opCode.OperandType == OperandType.InlineField, "opCode.OperandType == OperandType.InlineField");
                            Field field = instruction.Field;
                            AddFieldToMethodEffects(host, declaringType, res, directSetFields, modificationTypeDic, prevOpcode, field, field.Type);
                        }
                        else if (opCode == OpCodes.Ldfld || opCode == OpCodes.Ldflda)
                        {
                            SafeDebug.Assume(opCode.OperandType == OperandType.InlineField, "opCode.OperandType == OperandType.InlineField");
                            Field accessedField = instruction.Field;

                            if (accessedField.Type.Spec == TypeSpec.SzArray)
                            {
                                lastAccessedArrayField = accessedField;
                            }
                            else
                                lastAccessedField = accessedField;
                        }
                        else if (StElemOpCodes.Contains(opCode))
                        {
                            if (lastAccessedArrayField != null)
                            {
                                //Indicates that there is n array type modified
                                AddFieldToMethodEffects(host, declaringType, res, directSetFields, modificationTypeDic, prevOpcode, lastAccessedArrayField, lastAccessedArrayField.Type);
                                lastAccessedArrayField = null;
                            }
                        }
                        else if (opCode == OpCodes.Call || opCode == OpCodes.Callvirt)
                        {
                            SafeDebug.Assume(opCode.OperandType == OperandType.InlineMethod, "opCode.OperandType == OperandType.InlineMethod");
                            Method methodinner = instruction.Method;
                            SafeDebug.AssumeNotNull(method, "method");

                            directCalledMethods.Add(methodinner);
                            TypeEx methodDeclaringType;

                            //are these function calls are within the parent types
                            if (methodinner.TryGetDeclaringType(out methodDeclaringType) &&
                                declaringType.IsAssignableTo(methodDeclaringType))
                            {
                                MethodEffects methodEffects;
                                if (TryComputeMethodEffects(host, methodDeclaringType, methodinner, visitedMethods, out methodEffects))
                                {
                                    res.AddRange(methodEffects.WrittenInstanceFields);
                                    foreach (var key in methodEffects.ModificationTypeDictionary.Keys)
                                        modificationTypeDic[key] = methodEffects.ModificationTypeDictionary[key];
                                    directSetFields.AddRange(methodEffects.DirectSetterFields);
                                    if (methodEffects.CallDepth > callDepth)
                                        callDepth = methodEffects.CallDepth;
                                }
                            }
                            else
                            {
                                //introducing heuristics for inter-procedural static analysis
                                if (lastAccessedField != null && lastAccessedField.Type.IsReferenceType &&
                                    !(methodinner.ShortName.StartsWith("Get") || methodinner.ShortName.StartsWith("get")
                                    || methodinner.ShortName.StartsWith("Set") || methodinner.ShortName.StartsWith("set")))
                                {
                                    AddFieldToMethodEffects(host, declaringType, res, directSetFields, modificationTypeDic,
                                        prevOpcode, lastAccessedField, lastAccessedField.Type);
                                }
                            }
                        }
                        else if (opCode == OpCodes.Ret)
                        {
                            if (instruction.Field != null)
                                returnFields.Add(instruction.Field);
                        }
                        //topIsConstant = false;
                    }

                    prevOpcode = opCode;
                    offset = instruction.NextOffset;
                }

                effects = new MethodEffects((IFiniteSet<string>)res, directSetFields, directCalledMethods, returnFields, modificationTypeDic, callDepth + 1);
                psd.MethodEffectsDic[method.GlobalIndex] = effects;
                return true;
            }
            catch (Exception ex)
            {
                host.Log.LogErrorFromException(ex, WikiTopics.MissingWikiTopic, "methodeffects",
                    "Failed to compute method effects for method " + method.FullName + "," + ex.Message);
                effects = null;
                return false;
            }
        }
        private static TypeEx AddFieldToMethodEffects(IPexComponent host, TypeEx declaringType, SafeSet<Field> res,
            SafeSet<Field> directSetFields,
            SafeDictionary<Field, FieldModificationType> modificationTypeDic,
            OpCode prevOpcode, Field field, TypeEx fieldType)
        {
            SafeDebug.AssumeNotNull(field, "field");
            SafeDebug.Assume(!field.IsStatic, "!field.IsStatic");

            TypeEx fieldDeclaringType;
            //The following check ensures that the field belongs to this class
            //or its base classes
            if (field.TryGetDeclaringType(out fieldDeclaringType) &&
                declaringType.IsAssignableTo(fieldDeclaringType))
            {
                res.Add(field);

                var fieldTypeStr = fieldType.ToString();
                if (fieldTypeStr == "System.Int32" || fieldTypeStr == "System.Int64" || fieldTypeStr == "System.Int16")
                {
                    if (prevOpcode == OpCodes.Add)
                        modificationTypeDic[field] = FieldModificationType.INCREMENT;
                    else if (prevOpcode == OpCodes.Sub)
                        modificationTypeDic[field] = FieldModificationType.DECREMENT;
                    else
                        host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype",
                                            "Encountered unknown modification type for integer type " + prevOpcode);
                }
                else
                {
                    if (field.Type.IsReferenceType)
                    {
                        if (prevOpcode == OpCodes.Ldnull)
                            modificationTypeDic[field] = FieldModificationType.NULL_SET;
                        else if (prevOpcode == OpCodes.Newarr || prevOpcode == OpCodes.Newobj)
                            modificationTypeDic[field] = FieldModificationType.NON_NULL_SET;
                        else
                            host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype",
                                                "Encountered unknown modification type for reference type " + prevOpcode);
                    }
                    else if (fieldTypeStr == "System.Boolean")
                    {
                        if (prevOpcode == OpCodes.Ldc_I4_0)
                            modificationTypeDic[field] = FieldModificationType.FALSE_SET;
                        else if (prevOpcode == OpCodes.Ldc_I4_1)
                            modificationTypeDic[field] = FieldModificationType.TRUE_SET;
                        else
                            host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype",
                                                "Encountered unknown modification type for boolean type " + prevOpcode);
                    }
                }

                //A heuristic based approach for aliasing analysis for checking whether the field is directly
                //assigned any parameters
                if (LdArgOpCodes.Contains(prevOpcode))
                    directSetFields.Add(field);
            }
            return fieldDeclaringType;
        }
        // Find out how many fields require user provided factory methods
        public static bool GetTargetExplorableField(IEnumerable<Field> involvedFields, out Field targetField,
            out TypeEx declaringType, IPexComponent host,out TypeEx targetType)
        {
            targetField = null;
            var allInvolvedFields = new SafeList<Field>();
            allInvolvedFields.AddRange(involvedFields);
            int numFields = allInvolvedFields.Count;
            if (numFields < 1)
            {
                declaringType = null;
                targetType = null;
                return false;
            }
            //
            //            if (numFields == 1)
            //            {
            //                targetField = allInvolvedFields[0];
            //                if (!MethodOrFieldAnalyzer.TryGetDeclaringTypeDefinition(host, targetField, out declaringType))
            //                {
            //                    declaringType = null;
            //                    return false;
            //                }
            //                return true;
            //            }

            //            allInvolvedFields.Reverse();
            TypeEx prevFieldType = null;
            for (int count = 0; count < allInvolvedFields.Count; count++)
            {
                var currentField = allInvolvedFields[count];
            //                if (count + 1 < allInvolvedFields.Count)
            //                {
            //                    prevFieldType = allInvolvedFields[count + 1].Type;
            //                }

                if (!MethodOrFieldAnalyzer.TryGetDeclaringTypeDefinition(host, currentField, out declaringType))
                {
                    host.Log.LogError(WikiTopics.MissingWikiTopic, "targetfield",
                                      "Failed to get the declaring type for the field " + currentField.FullName);
                    ErrorLog.AppendLine("Failed to get the declaring type for the field " + currentField.FullName);
                    targetType = null;
                    return false;
                }

                try
                {
                    SafeDebug.Assume(
                        prevFieldType == null || prevFieldType == declaringType ||
                        prevFieldType.IsAssignableTo(declaringType)
                        || declaringType.IsAssignableTo(prevFieldType),
                        "The current field type (" + declaringType + ") should be the same as the previous field type (" +
                        prevFieldType + ")");

                    if (MethodOrFieldAnalyzer.IsFieldExternallyVisible(host, declaringType, currentField))
                    {
                        prevFieldType = currentField.Type;
                        continue;
                    }
                }
                catch (Exception ex)
                {
                    ErrorLog.AppendLine("Failed to compute external visibility of field " + currentField.FullName + " because of " + ex);
                }

                targetField = currentField;
                targetType = declaringType;
                return true;
            }

            targetField = allInvolvedFields[allInvolvedFields.Count - 1];
            if (!MethodOrFieldAnalyzer.TryGetDeclaringTypeDefinition(host, targetField, out declaringType))
            {
                host.Log.LogError(WikiTopics.MissingWikiTopic, "targetfield",
                                  "Failed to get the declaring type for the field " + targetField.FullName);
                targetType = null;
                return false;
            }
            targetType = targetField.Type;
            return true;
        }
        /// <summary>
        /// Adds a field to an unsuccessful code location.         
        /// </summary>
        /// <param name="location"></param>
        /// <param name="fields"></param>
        public void AddFieldsOfUncoveredCodeLocations(CodeLocation location, SafeList<Field> fields, FieldModificationType fmt, 
            Term condition, string terms, int fitnessval, TypeEx explorableType, SafeList<TypeEx> allFieldTypes)
        {
            //No need to process this location.
            if (fields.Count == 0)
            {
                return;
            }

            Field targetField;
            TypeEx declaringType;   //This declaring type is considered as explorable type in the rest of the analysis
            if (!PexMeFactoryGuesser.GetTargetExplorableField(this, fields, out targetField, out declaringType))
            {
                this.Log.LogError(WikiTopics.MissingWikiTopic, "factoryguesser",
                   "Failed to retrieve the target field for uncovered location " + location.ToString());
                return;
            }

            //Compare the declaring type and actual explorable type.
            //If there is a inheritance relation, use the actual one
            if (explorableType.IsAssignableTo(declaringType))
            {
                declaringType = explorableType;
            }

            var uclskey = UncoveredCodeLocationStore.GetKey(location.ToString(), declaringType.ToString(), condition.UniqueIndex);
            UncoveredCodeLocationStoreList uclslist;
            if (!this.unCoveredLocationDic.TryGetValue(uclskey, out uclslist))
            {
                uclslist = new UncoveredCodeLocationStoreList();
                uclslist.Location = location;
                uclslist.ExplorableType = declaringType.ToString();
                uclslist.TermIndex = condition.UniqueIndex;
                this.unCoveredLocationDic[uclskey] = uclslist;
            }

            var ucls = new UncoveredCodeLocationStore();
            ucls.Location = location;
            ucls.ExplorableType = declaringType;
            ucls.TargetField = targetField;
            ucls.AllFields.AddRange(fields);
            ucls.AllFieldTypes.AddRange(allFieldTypes);
            ucls.TermIndex = condition.UniqueIndex;
            //add the sequence of method calls
            ucls.MethodCallSequence = new MethodSignatureSequence();
            foreach (var m in this.LastExecutedFactoryMethodCallSequence)
            {
                ucls.MethodCallSequence.Sequence.Add(MethodOrFieldAnalyzer.GetMethodSignature(m));
            }
            ucls.IsADefectDetectingSequence = this.DefectDetectingSequence;
            ucls.CUTMethodCallSequence = this.LastExecutedCUTMethodCallSequence;

            if (!uclslist.StoreList.Contains(ucls))
            {
                ucls.TextualTerms.Add(terms);
                ucls.DesiredFieldModificationType = fmt;
                ucls.Fitnessvalue = fitnessval;
                uclslist.StoreList.Add(ucls);
            }
        }
        public static bool TryCheckReturnTypeOfMethod(PexMeDynamicDatabase pmd, TypeDefinition tdef, 
            MethodDefinition mdef, TypeEx targetTypeEx, out Method producingMethod)
        {
            var retType = mdef.ResultType;
            if (retType.ToString() == targetTypeEx.FullName)
            {
                producingMethod = mdef.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(pmd, tdef),
                    MethodOrFieldAnalyzer.GetGenericMethodParameters(pmd, mdef));
                return true;
            }

            //Get the actual type of return type and see whether it is assinable
            TypeEx retTypeEx;
            if (MethodOrFieldAnalyzer.TryGetTypeExFromName(pmd, pmd.CurrAssembly, retType.ToString(), out retTypeEx))
            {
                if (targetTypeEx.IsAssignableTo(retTypeEx))
                {
                    producingMethod = mdef.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(pmd, tdef),
                    MethodOrFieldAnalyzer.GetGenericMethodParameters(pmd, mdef));
                    return true;
                }
            }

            producingMethod = null;
            return false;
        }